import os
import sys
import signal
import configparser
import base64
import struct
import json
import socket
import time
import threading
import queue
from collections import defaultdict
from pathlib import Path

try:
    import winreg
except ImportError:
    winreg = None

def get_app_dir():
    """Return the folder where the editable ini should be read from.

    Normal Python:
        folder of this .py file

    PyInstaller EXE:
        folder of the .exe file
    """
    if getattr(sys, "frozen", False):
        return os.path.dirname(sys.executable)

    return os.path.dirname(os.path.abspath(__file__))


def get_resource_dir():
    """Return the folder where bundled read-only resources are located.

    Normal Python:
        folder of this .py file

    PyInstaller onefile/onedir:
        sys._MEIPASS when available, otherwise the exe folder

    This allows Boeing.dat to be included with:
        pyinstaller --onefile --add-data "Boeing.dat;." psx_winctrl_pfp.py
    """
    if getattr(sys, "frozen", False):
        return getattr(sys, "_MEIPASS", os.path.dirname(sys.executable))

    return os.path.dirname(os.path.abspath(__file__))


SCRIPT_DIR = get_app_dir()
RESOURCE_DIR = get_resource_dir()

CONFIG_FILE = os.path.join(SCRIPT_DIR, "psx_winctrl_pfp.ini")

# Prefer a loose Boeing.dat next to the exe/py for easy testing or custom fonts.
# If it is not present, use the bundled PyInstaller resource location.
LOCAL_FONT_FILE = os.path.join(SCRIPT_DIR, "Boeing.dat")
BUNDLED_FONT_FILE = os.path.join(RESOURCE_DIR, "Boeing.dat")
FONT_FILE = LOCAL_FONT_FILE if os.path.exists(LOCAL_FONT_FILE) else BUNDLED_FONT_FILE

# Embedded fallback font.
# A loose Boeing.dat next to the exe/py still overrides this for testing/custom fonts.
EMBEDDED_BOEING_DAT_B64 = """
cWJoYmYvQ3oyQXorQkNzamdaQ0hPTzYyVnRtU001NHRpWkhUR0haYUFPR3hHeGdwUkk0WWVibVJIb1pqeGFMVnNqd1k5SGMrNmx6
SEZsdlNGMDNYSmUyTkxSYnpXc0FocjVzKzczOTg0VHQxbjhpQzlBbjFuQjV5K2Rrb29JRUl0TDhVc3VYbWxNZE83OHBiUnQ0b2pO
U3BydWpxWTJpTDVwY2NUekZBaDZxTHV2ZlFNQmc5dUhwVkdRaGtBMGtqZ2JYRVdFKzdFNC9SUGZ2RzcwRUJoVW10N0E2eUR4YVVM
NVRLTllyQ2xYeWpRdkxjNk4wWWpZWW1jWXNzajBvNW1KVTVZclZ3OTEvTzQ0TVUvcjFnUXBIdXJDWE5YVnJTdUYrY3lmdTdQNWhx
Mm9Cb0haeVY1WGZBc0lFLzM1NE9TckhCZ3VDS2JZVnUxZU1SVmFTdmJzQjgwZ2hQQ05pT2xObFJOa1dzQ2VFbUhIbTYrV1VVQ2Ey
SGU5ckc5VlE2eFVCWW1zVkh2RGlLWllUQjhxR1N3RHJuSjVKUk1QMTBodGF3cEhneUorTW9MRUhIT2JXVWxiSUNyOWNHU1lpdG1T
TUhSY0YwUEwxQW9mdXAvdzQxMnFlTjh0T09zZ1RuSlpsa0pZK0IxcXI3eGtLeHZSUlZtKzlNR2lDRTJtMy9mOGh5S0FhZW1xWkJE
SUw1Q2paNkwrSFNhKzNIcStPVjB0T0ZiNG83ZFlDWmxUS0xRU3d3L1pGMEhBMGxUK1NSNFdpbGx4U0xDd0pZVXFrcUxoVUtVdjJz
YmZPbTRnNlVEcEZRem1FQVgwdi8wQ0NPTitEM243U2Y0MEVtSU95SVNHR0dIYS9zMFRDOFFmQjNwdkxudDNXUXRtY0htWnZzYmJJ
MXJlT3dZTzkrT3N2ZlR4UE1OR2FtVWdsQ3pRK1hhSnRqMUpya0NyZWhqUGx4bG1tSTlUVWFpSFdxeEIwRWpyK1U5bWpUOE9ZcUM5
VExEcWM3V1NrK29YYXlHQjNqMWtpYVF6cnoyUzJaQnduMHZ6V3d4VlVkZVVhN0FQZmY0bS91cGErMTArSXNXM3ZhazArTElZTHpl
aXBTZ1BNQ1E1ekFzWHRRa0hxWUc2QWxuejRBWTlYaXFUS3ErOS93dEVKbitoRXRBZlp4cmVybWs5QXVQd0pxQU9ubFZlN01nWHl3
emJmV3psUWJvcVdiSUdjZDdjTndUT3o5NFl4L3pBWEI1TTB5bXhZcnJIT0xpZlpad3dvOFU0bVdhMVhUWFdJbksrVmNGdzY4cUZz
RGxpdlFndmFMTnpqYnZuRUtQSWlOQU41bzZUamU4ZWlVaUw3SW1NcTRFQnlPd0k0RU9hS2RPVEc5YlNqM0RnYXUxMWJrUCtna00z
WlVyTWR4NkZvNzFWekJCYVFDWWY3KzlrZkRaWHR1T2xyVW5BNEw2NzkxQmJuMVNCMVVUUE1pVXJmbit4ZXpqQktLT3FHR1E3Mm5x
SW5zZXlGeTlJRnEwdUFRQ2h6U3lXN2dEUytWa3h2Z0FqZXBGcUpnakUrYmR5UzhUL2ZLZldUYlNKbE4zSTl3UFczckduOURpMVdZ
M1FqZ0xFZmExTzlpeld4RnpBN2tDbHZ5UmtGSFJiNWVtZ0ZKdnJXWlZwTDdSZW9JNFJyenR2a1JrZGw5MUFHUkRRTHFIR2xiRXcz
OVFEbjRubitjMktmemE1cnRYczhTYjJxdVQvNkZMSTMvb2RRckVzdCtJYyt5ODdVWk10WWpRcHk0M3Fsc3pUdFFVU2lMZnJtelpw
RDM5c1VRdWFNRnZwcXNIWWpYOHZ2VVlhVG0zczFHaWJqU3VVTGlZTXZxdERpZUpSTlJ5dktLM0ZJbWtFMTlLcUZTcHkxUWVJUkVs
b3JrM2NyVXYzYmJuSDhxdXU0ZkgyenVaNmYwK2xTZWtPd2k1dUd6cHYvanUvcVhPbmloa1RzWjlEUEtUV0lFRDhRRW1STjU3cWo3
MDQ4QVNudFk2VDJNK3M4WWJsL3hFZ3lPR0xWSm41SWFLQ1doMlZDT09rVVUvNUxSUHNZUm43Szd4bVB2ZzU2enJaNnBxVVFsdUg0
cEpFTndVcUp2MXJQRy9WZTg0WmRVVmJQN1hRdkpFdllrZVlYS0k0WW4vcFg1TEdHeGw5UXNZK25uNzVuM05DQ1Z5MzhmeUpRc3Yw
V2ZDYWdEK0EwbXZGSE5wdG9lcmhNeEkrYnNuNDN1akJyYUpHOEt0RDZPbnFRSmNFTk51bFgyVzdEbGZtdGltYlJjdGdVTis2Rnhk
aXUzRkMyL2ZCYXpTMHB0dXozeXc2RjFBRVJFZVV0U3FMQUZiSzBRN3JDWnQ0UDkrRkttMmNvN1ZDTkYwaFpzWnl3K1kvbllnNy9S
QUNOdmFRRUowR3UyMkdwZWJ3ZngwUDBTU2pRY0NZdzJ3VklJMG1GRnJHUmkxME9rWGhwS3RpR2NVOVoyQ0t2M1REU28rSm9BVEpw
aGN5WW5lcWlLSjhEdjFFQUVmMmpIc0JQSUVDUjlZeWtmcFRqY0JsQUlGWkorL0tacG52YVRwQmZNZVJqNWxrNnhwd21jT2xtQU1l
bG9DVkJla05tVG5ESHJKMDV3RDhHNzQzVStuNVo5TkJvOG9WcmxYcmM2WC9DL1FyY0dGZFV6N0xLbFo0ekRodldjcC8wTitpRXh3
OUUweDJ0QWZPc0Jhcmo3MlNCTm1EVUhldmxWcmZyYkNFM0RmYk9EMVVPWW9MS3NoUnNidTNxOGltVVh1TUF5V1lqNnRFVnpyb01G
SlhzUDRZWXkwZ2ozRzFtNURoRTZiK0ovMUg5RStSNS8xUkNiaUV5RXJMNU0veTZxdHNieE0vVmp1NTJTVTZzZ0Ntb0RlQ3R5TFlY
djRKbWtQcjZqUFh0WkpERlpoZTN5UTVvTXp6bDhFbnk0MnQxNUROVVF0cWtqSWZDcG5QcmJ5OXRlaHUrRVRFWFBmSkNENzJMU1RJ
Smdya1habytjVVEyU0w1WHZ4eFFmeWE5UXBjRnMwSDZqZHVZVWJnVlNGL3lTdXBxanN2REIwWFNQMUJtVmUwV1hFY2QxTXE0YlNF
QlB2eUpENG44ak11Z2NiOVdFdiszdDFHZW8vdHJrM0xMOGZzSlpQOFJLMVEwQmZ0L1l6MUE4cWVGVkpjbGZJM2c1S1FHSDFaK2VD
R3BNOStvdlVpOEl6TzRvcmw5V2hkTXNZS2dyL3RJNnFROWF0UlZBVGVzUHNNQ21vVDZ5VXQrbVozeUdtWU5FL1FwcndIUE0xRW1o
V3hZVlhDazVtRUloNkVxd2FZMDd3TXlXOHJxWnhXN29kbzUxRnJDVlIyNXFLV1lVYzBxeHFIOW10cUE4TmNBTUNqcC9PeUZTMW1I
cXEwdDRKb0ZodWdwdDJOcjk5UDRUbkpuR05BVWtsc1pQYkdSK0pwSnp6bkdBYy9XSEFBS3NwREdZYUp6VUo0TEwrYThRWElMS05Q
TU9FemE2ZUl2bDREc0F5VThRR09kUlZnOGUvaHRCM2Myd3NMbXd5eVQ5UEFveksveGpsdjVQQ0dMTzZCWS9UT0FuNEhoV0dWZGxw
QW9xVEpnWElTSWN1R1JpY1o3U0hsNDZtNXJmbzNTRU9FQ0orb0J2S1BLd2NtWElwQnJXTHlzbnFHb0dTeGQ5WTZSeHZUY3RTYW9I
WUo0djNaaFNKUEc0b3RXU1dTdFF1WEZ2a3hOQTVoUVo5SjNwWis3N0NlMktxUUZqdjlZS3dCbFBnazYvd0RyeWd4TjR6VC9WUEpz
amJmaXJvSC9wRXAvOVF4RmxIcVVyQ2YvMHpBZUJJMmFLMHFVYWJSTisza2l3L1FNcEViT0pXWkxYMjZXTTlFaWZBbisvVkUzUTl5
Ty9BWkpqVzV5b1dqMDNmTFlxRUQrb3BQZkZ2S2trclNxZVVRSnA2cjhPUjJmdXp6V2hsQjI3WHFBRVlCdDU0bmlGOTNWR1EyTlpm
Qm9wNHJFZTJELytWczF6cGxwM0FjT0JkL3c3Y2lxa3JscFJjem9lb3NRWXlIY2RiaGtRdGZkZHZvMDY1S2hHL2EzVDRkeXJaWlNq
YmVGcU53SU9tQTB0OFQ5Y01zaiswOHo5MERJRFFDb0Z5TmI0bDA4aUNlVzROWHRWUWU4aFhiUUZhamZRQWRJcFRQN1ZmVGtFMGg3
ak5SU3ZIaGVKTlJOU24yN2F2UHhGdjZ4bXd2T1gvQTlSRmhTQ1hQRVZmREd3aXF1SXZzRWNJdlhjQXI3WmRyMmtnZkxVNXJ4T1hL
MHdWcjFmWkIzZmNlK0tvemFYb25RQmRYN2F6TlVQZnRVVWpCNUdJbHFYRTR5VlBkdFVlZVROcUlLVFVzWkI2ZWJwbEltSk9lVnU4
TFk4RUtaNkNYbUVGRlhxaXRZUnJOakJOOXIyYnppeXlPK09ha0FjSVcxZmpZei96UDJNcVhuWWV3L2t1RndqTlRtb1h4bVR6MEZp
THZRV3U1UWJReTlBZnVyb1MzdGYvSmgzb1ZJS1NPa3VUTHdqcTlBYjBRamY5WmhZc3BWY2hNRXF5UWVtaEJpcnZFMGtiV0ZMMmVs
YnRqSkhuaVZteTV1WVJQQTlRRURQcWRkOTNpaDkrME8rMUpqODdTR3lBMXVQOTJCUWFwUUtFMnR5dkpKVURvSVNSZkRlY0s1V2o0
bDdMQlhHQndMNjdycDFKUTY5eHpIT2NMQ1hla09rTjlNMm9WWnhaUkZjSFJuYlowUS9vZ2tiUnpMOUFldXZLOVJSdWhSSDBJYXMv
SWNkVFVLQ0ZHNU1YemNPTW50TXhSNWxEOG5GYkpuVWp2VHdmYjl5WnN5dHpjZXVkTVZ4L2o4WXQ0MTZCcjdmRTNKQVR0anlNSzJG
OHI3bGVyNVN1dDRHekErTC9Qc0ZndXN0OGhkcHFOWWx6ZzQvQnU2TGJwSkVYVXQ3YmdxbTFhKzJvNG4wSEtwU1ZqeFFvWFpocUVW
RmdDRFVvaDYxM3NYWHJrYW9CWDB2SFNWZmJxYkU5Z280akRWWFR0S2pyUlJydUtzaGlSTDZLNDd5dXRId1JISTAzNHVkaVdybTBN
YmhXaFpIbEJMaGZsRktTVzRCZml2b2dRWGsvTzVvRExoWC9WL2NuanZEdmZjRlI3YlRtckVxVGN1ZHlvckZoYnQrQlRQS0l3WG5q
Sm10SnNhbndQRnoxZnlPdXBQY3MvbUphM1RnT2F5Y3JOaXM5clZZSDgzUW5XeHo3K0Y4a2RjVlMyRWh5OVQrclUvQjRESVI3RzY3
ZEgwT0p3ZWFKS0U2aU1hWmtBT3JaS2E3V0VzamthQXl0RnhhdHVIdDY2RjVPVHVzTEd1WHVtWU1PM0RzZWNWTUhlcGRrWXNEZlR2
L1NVd0NBSUt5NFg3N0lDZ2h3SW5tb0RoWXdTQUt2QmxtcGQ3aTlzS3ZENFJrU09aTnhDbXc0ZFNTeCtwbU45aWIrekovR0ZpMmJM
dmNHczRsOVV5UDRkdFhjNTZlMm4wd1kxQTBhTkxBcjlzN09Rb0tLbitQbk1XRmJQUDlCeXloczc0MEw5OVVycXNIYjQrU2ZWWEhS
R2RYNW1ITm5vYmxmZjhuemZKNFo2d21SMDFQMVhKUUVLbzVxOGJ4c1BQSTh1ZTJCZVhNVGM1Q20vKzhxQUxrTm5IMXZRU2JxakpX
UjY1QzlOckNKbS9XU01BR3ArZDl2MXFpb0s5bTFBdFZVTGxKOFNKVEVIVk05OGxGS2V3a0xzaHYybEdCVFgvU3A4Z0syem00VExS
RCtHRXJmVk1sS1BTTEk0WWlRVUhIKytMVUQ3S21ad1N5Mk12NjAxa1RsWTd4MGpuOXNEdElQRjVzelVVRUpRemJ0dWM0UE8vV3Ew
TmJyM3dxU0VPRGd5bTVnRVQwQ2RRSHg2b3dEbkkvYlU2NWFsTytLODZCSjZ2VHVPaDZsV1FmakxEM3Ryb05tazR0SnJXcDNnVUV5
c1dMNUtnenJUNm5yYklNTGtRQnp5Q0I4K1JQWmEweS93dCt2TllTTXJkeklWWmRHYTJIV2NzZ2VBMmJZU09VcDdhQmhIdXE0QTZL
RHhRZEFEdXZwdDdrVUJaOEc5TzN6TzlYMDJuR0RmamZ3d0hwcFJOMDdCb2RWODJTa2tKaDc5c3NqdDQySWdNQ0gxa0NkR0RCTFlR
cXFZNnhtdlVodTcxNm9MWWltV2g1ZDZabE9XU2NuL0dZdzBaMUhTbjl3NnU2K1cxSG5YQ2FiaHYvaFlQd2xKWFdOdGo4K1NkZVpl
M2JtMCtwaFhMQTZXVGRaQWRlVGJWK2FJckFXeENMY1RiN21QSTRvNFJhNFg2N0NuRU9MbDM4YU1WanRCc1Z5MWZRY21Zc01tSnR4
Y0pCclpNR0FSQlVudjh1bzVldmREK3psbVR3Rnl6dGlrUnA5NmFqd3lRT0RpNk9xTUZZOEN3YXgvYTlyWnRwc2lGK0pIdGdUYUpk
N0xoM1NyazFBZ05nZHZSVWJ3RlBTVW45WHhrNUppRk82TEVJNjNlaE0yZzRJM0EvYXcvZGc0Z1J3dVdNUUZRMzZJeHNBaUVHRmFI
NTNzSzJyL0N1ekJrUUlPS1FpdE5qNEJNVElLc3ppTmMrOWYyMkhSZHFFdXpSMFpZdy9uWElYd1IxTTFHbXRCM084Zi8wbU15ZHRs
ekttaUswdjRMcDZIV0UwRTFDZC9ETXFTK3cwWFlDeFU4STA4RFFUL1Rib3hhV1ZkQVZ6L1BZSXpSMWoyQnBHVjVPL0E5OXNNSmts
VE5YZGtOOUpVa29NSUZUb0F5SU9IZlhnZ2tsWFMzcGZKKzhEQlBwdm1Da2JIakxmSVJXVkpocmJhN2wzR3hOdFNHRzlsMWVYb2tn
VVB3bkxRZm5UNW91ZmFJUEFnaVh2V2psL0w1dnlhNk1SL1JHaG1FazZZVFpJbWxEMzZWT0N0dmVsZSs1SnJHbGJLa1dRcHRnTTBF
eEVTR3Rua0ZRY3VkSGRWTmtubXNHMFpFckRXdEhkUEZLd1ptSE1yelluQU54M2RHYzRhTTZkRExyNmpHMSsyZGZKK3hHaHVJOXlE
R1lMWWZXcGhzVGY3dHNtb3BGYmJGUUsrZXFSMkdnelJqZG9YNG90V21hK3d2RFowQi9WNmlmeFBTVFZ5a3Byd28wZFhsaDBhU2Q3
Q09ZWndnT3R3OTU5RytSTVNaNGJYR1Q1STFtbEIxaFdCUXhhQVlSeWtXQXU2YlNzblFISURTSFhrdzFjQ3d6MkI3dTBvV0h0TzRa
NnRxc2hTOFl2SnNxd2tLbXlLUXAxQUt2ZE4xMkR6THREZE96SkhEclRuWE91OGRuRU11TXZwbDBEdFBYK1ZRdmZ0TkNLdjVWN1Bm
S0Q1NkpVenp5eWlmZ3lvWmxqa2xwRGlKVytZNVMxK0hGZTVQQVhnOHdzUWpmS2Z4aEFtRENjSmNjLy9SeDg0MzNzb2hTQW5MenpS
aExOUFJLYU9qV2t5bi8xUGpyckNHeTF3djVpamtZdUVhbStDZlZZTndTVjk2ZTk2M1NLRnRaLzRaYlhmeDVFeTN2QkRvTHlXRDJD
YmFzM3ZwczBaRGx3dTYzdHZUTG5hSXRPYWozTkZ4dUJpeDdEbW5xb2QzbTVLODRqSkFhTkRGd2NtbThBR0NLVXI0Yk1LdXpZeFFF
eSs2czlrMHpmRmttNElZTmMzdDkyK3A2Yk56QXZSS2U5OHpVcUx6M3UvYktQeEo1WXBrR3E0dnVad2dRUU0yb2VqcGxKYTI3Ymdv
RS85OThXRFdqUUJTU3U0dllDR3ZnWnB2eGVyeXpUZVdESEhDSmlhc1Rma25BR3paSnhWSXFHWkJjRHV0cnpncDJWZm1kRzFpQ2lm
OXk1TmN0bENpYVU3VEkvODF1R3lOeGs4bXc5UG1kNzJiOHBpZFlvQzhEWkZaQVRveTBjSFJFN2I1R01TM2t0NXNQSEdtRnppRnhy
WWN4U0RBM25BWkxOOUNTUjhCNE1hMGpNTWRDelluWlpMNkFMVkx3ZjdLbnNJUDZzeVM1YU1DQnE5OUFmK09xdG5zUERKUUtmZnA4
ZGZiSUMxNXBNemNxR1M1M2hUUGw4eHZiSjZWZlVaa0lmb3FoVGRXRVdTL0hRRmNYeWRlNjFPOHh3Vk84SjRqMjlCVGRaZ253TmhO
WWdWOWRCaHpFL3dvTUhJQW9iZDZBSjhTWFJOVGlVUElSOXB1eFA3VGloaG05UGdRVHVEaXhMTytwVFJ2Z0gyL0h1S0FXakVOSkVu
Sll5VWFDOXNPemREUEhNN2FxR0o2Z3hvT0piMW8raDRtOEtnamgvMmZiK0NmVjRrYWVRQnZvYmdDWVpsZDJVZkg2eExXLzc1UGRx
eHgrMmpQNWRrR3hmdHRTWWtqZmt6eHNUUkVhdVJKS3hxR1owQjEvQVo5cUQ2YTRLMEVSak5lcVltZm1jcmZlZXNvaEJEeTBtRTVE
bjRyQWdUNHVXSzJacDJCRzBEc3V3bnRrUVlVYXpZa2pMSUw1cVZ5V29UbEJvRmQzR1RjOTNnbVAyTzNOU0dxN05LRnY5N0J6c3dz
cTRRMHhoSHdxeUxKbjNxWTllcnZNNXVsWDQwdWxOTEpKQ2N0Uyt6RFRGb1lQTERPeWV2MHoxU0xvTHR5cXJTRWZHZE5Fb0d1ejdN
bDN6ZFc2K0JPUHphQzV2dTlBZlFoODhaTDZReUtIMWNYM0JReTdWQXQ0dlhIMzFQUmpEVGVhYW83aDcwbTI5bndsL2xJbzBDMWhU
V0N6NFFDbXU4bFRLVDZuTmdodUVJcUphUTZ2MHduYVp2SU52N29ENVFGL2FTZTVuRW5JbTRRKytiTUgxeE4wOENqRFo2Tk84Qita
SHBuVFVXRWFmSmo4b2RXZlNnaVFkUHhsc1U1TkV0M0ZGVmgzTzAxaEpTSm1XOUZlZXNXMk9vOXNmeWdmVld5YlVEZW1ya0FEaVZG
RkFuT1RlVkZYTWw0bDN0STFDaHB0TnJxbGQybDZ1OWMycmZDRmUwRDBnYjBNWUVpSkV6T0FQRnlxUkRJYmgzWlhuZit2eWZuN0s4
YTJ0QkhBUy8xQ3dtTXRMbDFvQ0haejAwcGI1eExNZ3ZFSk5MSE8rQnJZcXVlZ1psS25PVHV5bDk0clJhajErWjJQb0FoUlBYYktk
czlWRGpMQkdvNDdHa3pRT2wySnN5RzZydFNHOFNRLzBndkNPdlBxdjNXeXRUcjVLby9TZDZZaWVuR0pCMzM3TjREV29SSXhvTUh6
NEJJbUR1SUtPMjYwSGI0N0dWTjBNUWFHS2Nha2Vydm1yNnB4ODlUbThuM09jZ3V5N2J3K1VRamFYZzZ6OUV3dVhVOGl3MkVRd01F
MVQzYkpZcFV6N2xQck8zaEsvaUx0UVlzbCtscDgvV3FaL01md1hjeTV2VXVJZzdldTFVQzBHaVJpWUJaNGtWbnJUdTU3KzJ4TGNj
MThPRE52YjZqWXVjRisrTDRWSHoxZkJoU2V0a1RQOGpvMExJa211WHNPZC85Qjl4R2ZGRHFoYU1aUktwZlZSZkoxUllKNVVmUkhV
WitWTzBlbTV0RkUzTldmc0xRNmROdzg1R1AwWjRUMTl0dTdJQjMrOTZRckVhSCsySHNmTW9oYWlhRnVyOXFNVzBLRGp3dm1MQ0Zn
R3phdHNaYUhmUkpyZzVoNUJLMFVKTWNXYitzeENGdEJJTE54dExYeG4rWDkrVWVDQld4UmxBL3JiV0F1SGZlc0RXRG5vNzBtSHZw
Y3dmY29IRzZzM0xwcWhDVjk1UXMvSXEzaTRVcTFXWFpTSjlVM0N6ajVycFE5V3hKNWhvUWRQNjVtQkhhSVFaWWNVSkFzalVCUElE
QW12ajFiSDA5NGNNQmpoei9lVTl2UFBDSDMrdWRyZ2ZneU1ucUJ3SUh6Qnpna2dhR2xHZDhGSDZ5K1dUVysvU0Z6Z1RrYmRLWnB0
UzVGUERTcEhiSTNOMWc3NDB5dE41TUhPaDVlRE5qY3NCRW1XWjM4SklmNEpRZ0RVamlZb1g0UExiankwbHNHOHJIZHdFVDNXZUVw
RzNFRjZaUnRXUUtrYnQ4TDRkbHRoM1YzVzIyeGhwcmkyL2lqcmY5RTBpd2F2UDg3Y2ZxOER2c29yUUQ0cGMvNWlEZXFrTHAwVGMv
Zk14Yi95Zm5oa0cxQkJnTStxWGh3YmJxUlN3U1QzcHJOeGo3eTJJeXVRWWoyOUVZR0xHM2F0UDFLL2FmUUJweE83R3FVU1BrVzkx
bzh5bWxNditXTExBak8vcFRISW4vTU1WVklPMXRteVZYeXN6ekhHSzBFeUErT1BsMzhkb29rUi9sUEpoYmdKaXh3OWJoMzlXeWE5
Rm9iTkVYZkFDUXd4d3ljdkNmVHRSME9yYTJ4REdVczhHWFlUZjA5YU9aMmErVDhnMkFkZDEzN21KZHAxVno2ZURhaU5TaXd3bmZt
UnVJeCthMTAzU0pBeE0wZXdGRXNleENSeVJJK1dmWWw3M1ZJbFk4YW9makNET0RFbWFqampnK05SYXRkR28wMW9Uazg4K3RpcTE4
YWc1amFwdTZhLzJQd0JvNGFJdUJLVnkzOC9MTU5sMWQzWGNVSnA2WkQ2emdmejcvOW4ycm0xMTV2d1lQOG5ubjRLeEFvaWRDeUZp
SytRNllYNTlQMkJaMTZPdFM2VWdvY0ptV0sxVkFOOFVWQjZrZVZ6TlNrM2I0YlBsdkRHQVo0OWd3YzV4djNWU1FXSFBjR1Q2QTVi
STZxWXJnUzZ0V1VFVThSY0daTk9ScFFpL1pVeGNSVFcrOE1hSFpBa0pIOFJ3QXpmZUlJWWpGNFVIdmxzZzFvZnFtYVQ1WVRkbFBz
SmZxK3RweXBlR3NwNXloc0REVGJia3REQ0VUeVVMWVhJd2ZyN1dRZDVMU3crQnBqOWpwTXphaTgxUEM5S0VhTUF1YklXWmtPS0tW
SURLa2FFK1QyNng5VkEyd29OYmxqMy82M25wWitqbUR0SzIraG1UL2xuK0JPVlI0KzhqWVhybStCbmZXY28vc0twMmxFTjZzMTFO
bmNBa0hab1V6UVR2VTRjWU0zcHpaS1IxSUJzbkh2QVR5U1dlTVhhaWc4c3BQZVQybk9ucTNlYlhkd1ptNm83QWZvR3dicFBpWEhw
S3ZTblBQekpVbi9Cald0S09majZGTXlTbEhLWlpKOEwwQUVuaGJRR0ZNYXR5UDFBdEpvdThLMnBjSEZtNGRKVVBYU2NiTnJpUmJ1
T3hESkZDZUVYUFBkYXJlZko1WTlZT25xUmRua2xBVjRBdHV3RnM0ZTlnZmZiSDBuQ1YrYTJuVVNOVFpvTnZ1YzZQWXZQRWR0d3Aw
TlZzZU9Sa3hBU28xRVBDQnZKRjRHWTVXdGZINXFHMDFFTUFDYTE4UzZiK2tvdWRjRGpSNW13SnUrWjA4K2VyclVKM3p4S1BiM2pq
S0JNM0tWVWtqMndyRksxRnhvTmxDN0lzN2JNMllxV2hWbk9KV21PWEozOTVwUmFRUS9VV3k1VEhzL2wyWG1hKzBOQjU3RHBnY25C
VVpreVo1ZmVKTW56OEprNUhuQkVVTHRZd2oyTDZlQzdjdnprWmdybi92VjJ0cytVMUNNS0UrN3FISVh2MUk4TWR1dnpoRTREcnV3
bHB3Q0Y0bTU3ZDdqQldqdm0zbnRHTHQ4c1ZYTkZ3U0JYc09LS1NmODJKUnorczJ0NnJ3bURXTjNKOFBmd0JXckorcjRocW1BSGFB
c2VnalM5RHVlaThaSWV5Zk9IUkRlOURxZm1aZjJrR2NodVJYSk5QdDg5RSs4aUxKcjh5UzkzN0crcmcrS21pdkFTVlNQNFA0bjRP
TXdXVUVVSFdEdVMrZXFmbHpibDNxTTRkdW5La1JVbVJGT1NDQzZrcUdMZTQxeklUelpFZTd4UjB3blR2M05Qd2RsbndUUEp1bUlP
T3FmeGh6SmtVeW5WK1NaeTVvTFdULzhOQUg5UnpFU3FvV2tmOFpnNzlmYXFyVU1Jem1OdXZUNkhuREJUYTVUSmlnSlRjQ1FTS014
N2JqUm0yMDZ2N3ZzUHF5WXNqNEVGNWhpVGNrZ3Vtd1AxcUhyVDJEMG51cTBBVEdlVHMwU0NyUzdWMWJNb3pvVUgyblhTUncxTElr
bThDeStVUk81NUVSd2h0T0ovVFRwazRQb05yTFk2dTNTcDN2dzJBbmZMeC9obGdkWXhDRFIzTEc3UjQvbTVwSEZOTHcwbG5SSzNC
Y1o4SzVtemI3SEJpNDNkcTJxZGVBNDZ0c2JqUmR0YmRDK3lxanZLaXF5Z0p5QVNCUEZabHRIYXlaQ2x2c0FhOXdqTDhrOWpkbWhI
dlRENGYyODYzRWZZZW1YSS8rOVREajZ2S09DZy9KS1RPZW1OMkk5NW01TnZPbVdpWW9ic0JucUZRcGUyMWp0OVFheTlXbllvVFZn
Y21FTVhoY2RIOHI3MFpTaTdvK21wKzUzTlhJcFZralZrTC9hT3JiSElpRXlsUG5iaDhSbTUwQ1JubGFMRVlrZkd2RnNYRkNqRG1S
WEd0ZEI1NUo4WGZsMkE5VVJBYlozWktnZ2EwZy9Oc1RINzQxVG02cjgvMXNwNDhpRFNtZ0xocmpGYjVhWVRYWlBXb3pXdGJhUHhG
dzVwckZhUDUrNG1CaXlsODdLSUNkZ2w0REYyRGJCTWg0ZUwvWjRaeS9DRGdmS1ZEUGg1RXBLYnJHRm1yU0JadDI0VUY1YURFUm1W
WHFFZEUxczE0eFNrYU9zdGViZzg1cGZqaVd0RHNTSElhTDBlTFBuWnBqVVgzTGFReXpvSHpHejlLZ2dSS3BrcGxDWEhDYzVQNXVv
U2YwUDg4VVpURG10dlJ5R0lsdkE3WktkeVQrOHlWc2dvWlJGT3VuZUVScm9NREVjQW56S29KL2E2cnI5N3d4UlB4bTF5MnhEMDdw
R054NFF1OTc0ZDY5NFkvZnkzWWwzcVNkNVREWjlmRy9EMVZkZ051cHl3UkpmdkpTRG1ldklpK2RIQUxhamFQalM2YW9ZemY5aXl6
a1RxTzEzWnlNaTRyNFB1ZXlGWXFkOVY4ZjI0VXpWVldSclVjRjdCQjcwTTRmS1RUZHFNYVIwcWd2eXYvZDhtZy9jRjRVL3c2Nm1k
TzY5SEhEVWZOYmVhTUFmRnVuOWEvYUYwU1JwamZoa1F1YlQxM0t5ODFuR1VHeStNbk1ZeVNOYW9nTEllS08rMVBmalF0TGpUSlMy
djN0bHAvNnZPTndSWGZab0VJeUNPRWR5amRyK1NuZlZNeE5FZGsyWDEydnp6SU95MFdQckhJOTc4RXVFN2l1Qko4M2VYaE5pbDBV
SnpablJEc1lyUVRBY2ZtcC9LU0lFQW9IeUhJZHVUZTlzcFlOSXJUL0l4dHUvRnRRY3RzRzV0YTFzd1lsbWJNb0RMNXdWME5TSjhl
SHRna3psb0JDNEVCRTJOWm84eHpRVlpMWit5anY3YVA4eGRqc1NRWW5tNTdOVkFmNjBhSGFjYU4vWmhoR0J5d2JHNEtTb3E1ME10
dllVVnpNRUFXTDJFeVpQMnlHU1c0R2huSThHSk1SWDR3WHE0RDJtaXdBWm9FajdWbE5NOUFXc0pOaXNLU2xaZ1Nrc2lBRU9tTTA1
MlNJUmMxdE1MaERVZFhwV25zTkluRCsvRDVOYlBPVDVZM1pOclorOWFoWEc2ZXBXcURsNHk1MGxQRklYTC9PNE8zQm9WemJUV21N
RkhNN21wV2h0UE5wWXQ4MWtGZWFqZitISllEVFQ1amFHdHNiNHczK2lEYnVoUGNZc2xhUDM5MUhmRHU0OGM5NFpFR0VZMEFIMWJ2
N2VmaHptWVZaQThsdFgrSXJuS2kwK1kyKzVKTDNZZEttYjJVUkpodllTQkVJcUZKMi9pWGVtV2ZFNTR0UUN5cHptZVhlTVJOMG92
RGF4cHVDSUp6REJ1c2ptaHU2a1lCVUpKdERLVU1nTE9QdTFqb3JFbDRCSURQM3NvTFVYSEQ4WFNYY0FBYUU5UldHeW9HK0Q0anJk
UEtqeGh4L09UVUpjUmFJS2J0ZThtZ09FT3hIaFp1MEZ3SVRjdE94MDF6NlRtOVovdjJoblRFeklDZjg2Y1R5YjZxYzVIWEtkbndD
c1hFc2Rlai9VUlhVRTB2LzhGeFJZTHQ0NDV2Skx3YnJiUXV1TVl5SVp3YSs5cWs0b3g3dkN6UHllbVp3WmdYTlZHbTV1djlsZW5P
OWtGZmhGL1NLQUJKVlJDbndmWjM2WUwrc1FhUUk3TjVla1VxdDdOZm9ESEJ5djlqYnFraWM2NmRiZWhMYkVqem9lZXRHdFlyYWor
Y2JWQnBPdURoT3dvRXV1TkxzNEYrZzhTZXh5b1VnbjBrRkUxZ0tBckpMRzFDVE1UTTNOeHdRRm9iWjhpWlFaM2lwTDRJTUNQUzhn
cDNUcXFWVTlBQml5OTFZWjNJN1B4NllYSVZ1SVBGWUxKdExhV0UwaWFlQUt1cjlHdjJmVVVnSzV3YWYyZXlGeFNLd201MzFQSU9u
bURHblZoeU1JT2drM0FWU3BPRi9LRHE4Q045V29qOGdHUElPNWVaOW80YU1mZzlEd2JIZTJoa05kOE0yWGxZTXl3Tm9ENGNmaVMr
YTM0dXNMRU85VTM3cXJHTCtXcjduMmZaejVJNG5LMVFmUWdGNnF2VUgwZkVMNWMrcENQeDBHamV2bnFuZFN3Z0thVW0vVm9xayt2
K09IaTZ5SmpoS1Y2aER4VWJzbGttdmdtSStEbUd3YWR1NkZ6Zk5PUGNlaVdXNGgxNHJMUVkxR1Jva1pNaHMxdXFiRS9mdndxc2cr
ZHl2enhTL2ZsNlp4elpDOEw4WDVPVjZLdHhYY2g0SEhpT0ZBNlBaK1VmcDFkVkpBTGxkOTFGRUQybFAreklNKzlxSkMvbFZQTW1q
a0QwclVvR0Q2RjV3S1lydG4zeEhRNzQvR2ErSjJzd09Ec3BMb2dxMUc0OFVMRmQ3em55bnFMVmdUakpJUzJmV0N3bFVIOHN1dXEy
UGNJVWFwdGdZZk9WNHpiS1dudWlveW9UWXJXK2pkNzRqUmJ1ZjA0MllhaG5sbzc1V2pMUFk4azJEdkQ2WFpYVDBYOEk5YUorRHpN
VXIrRjByZ0ZHaTBTWGJsUDFSUEwyMzJxbE9INW5uWm9vKzJzaXhock8wMFFNZjNPQzhoN3FlRnkzYU55aWw5VHlsWVcxN0xndUtE
T09mcXk3WXQyUFlQREUvYzRUUEEvZ2lISmdsUHVkdnhxek5jNDU1S21ycUtOdFhVb3Yzb3UxL0p3ZU4wWEJNaytrZ2J1VFVoaHBE
MDZqSFpGSzA4ODBBZHQrV2dQUS9kQXYva09HZ0pNRWtxTDBLMWNLM2xWdm1lQmc3ZjJLRDFwNFcyOEg5MHFwdyswK2VoZ3EzZUVw
dVVTRVZLREtYcVRSc0xTUFU5T3lldHhKUFZBY3dQV0pLYjZPWGtaYlRCaUJZN1NZOGZpSlBkWVpKNHM1amJ3eDJ2TDVLMjNiN0VT
UTFMR2poT1U0ZkZ3V1RkbjRVZ3dXOTZndkhjd1RVa2liVnllNE9tWmowcGhWbEJaM2ZDR1ZrUWQrWUxQNWRFa085WTlKQTJnUFN2
aFV5WWR3RkZOYmJuUWJlWlhHRjhkTSsvZHNicGdlc1ZmRXZPNC9JRFR1M0RZNWVXZStxOXArdUNCQitSQi9qSWtlRmdkR0FYZGlG
Zk42SlBhOU8yTUl6TFBhbldDZENCRzQ5UXdTZCtPdnYrenBla2FmZ0VEMlVnOVhRT1czbURZUCtMTGF3aTFYWlMyMzZqQUZRRWpv
YnpMMmJwbnB1R2UxY0hwVklRVERabEVTekhRY3ZDOTJ2bFZqaktwNWx3WTh4aFNCSVZTZUVGaDkwaEtHT0Z4ZzBMS3JnWENyazJ0
V3l0eHZkeUtWeUMvb3hqNit2OHpOVHRiMW5LQXVWVGhZOTVWaTZxMXh1Y2ZDSGZBOFd0emdjVWZUSzJFdlAzejlUdGJqYXdpNGMv
Y2lDWGdWTFpDOUJ2UDJBRmllbUwxaVFEb0FjVlBpRGV5S1VuRDhRWTVycGNrNENEMlNPN3U3QjR4SThJMXZ0UjVuOGVkRGFKRk9q
aUpyVmc4YityQk9VSVE2VVV5amJqMGhuRS9jcUlqVkxZSTVKQi83eXJhOEVTVnA0anVUcmVqV0JyTTVleEFPeDV2T1FDMmJtNm9n
Y2lQckRsS3hxeTdPMHRsNnoyUmpudjVWVnZSUWtWczVUNjhIWmxmOG9TZkxHZEVYNlQ0dGxONUVWclc0YVNLMXpCSEZjZDZZOTJL
bDhGeWtMSEp6R09nM3pIaHJGd25hd1FtRENSYlA3eFc5b1owcWtCTzBkalZIeHlEbFdEOHZIY3BvditnNWVUbzV6dm9tWnNibUYr
VUpoUFQ1RFQ1bURWV2dhZ3BCeDBDajEwVENyUnVwSGJ2blRZSERuc3MvNTBvUGtFOTB0dnU3c1lRZmhMWGxkMnliNHFRYmRDMjRC
dTlGaXNnMEFRVDVPVE5hS3ZWUC9Ba0p6aFlxSUpkL3JxbWI4R1BveEVsTE1CbjlXRHN3QnNvb0Ntb3lPZHVvWml5L3pzKzIxMmo4
dCtFUnRnV1hBK3lNU0ZVZFV2ei92VzdqdFJxTmpiTmROTzhwKzRXdnJWQWZJTi8wd1dmM3p0WGNvY3J4R1pxc0wwVWdMK2lCeTdT
VDJ5a1ZvN3Y0SEtsbkhNeDJ2TUppZVFOVTJlN0pNOHBKNHpmbEZFVVJoZGFsTVZVM1B0alpjVXdnRThDbUlZaGpNYit2bW82b1Nw
YzVVbXhoUXhQYk9pSVYxRXV3Nms5RjVUSnlHa0J4MktvTklDTmRzck5LcGhUeHFudjZRNGMvaEtteERRYTVXNUcxaEExZnZ3blJ1
M1VVdUdrMlUxR3FvaTRDS2VOMFpDMGwycnhxQkRJVk01VkpHMEZSZTF2K2VXWW9WYUlNN3JhSjEzeklmMXpmbXBrRDFQdTR0TWVV
SmtiK2ZXbkJxdEdFeGJpSGFwVWE3THh4cEhscjg3UnNtZTQwTGhpMncxVzNpcHlBcmUvRUtkdDAvSHBCYXNGZ3FXYVhIazdYcHpn
RThrMzZ5Rnp2N0pPVjRGdXQrc2lteVQyR1U0UTJYOU9jTkpmTmFKa3FBZzg2YkhrVjJTb2RuNGNTNnFhNW5nMHpvT0tuMzZTbkRU
T1Z0dDVVMjFaYytqN3Vta3dVL2xiSzhuM2VRTjdVQnN2MFpiQXArNmpwUkFzdkhhbGpxY2tmdENrWFlmWUNLalgwbFFlOC9lZVZH
amdtNlJlSVJ6cUtGOVpCZ25kRnlXQUQxeVBSWUNGcE5MU0dqL0dHUWVrM0hlcXByZStFYktnZ0VXNWlmQ0pzaHpCUG53REl6SzBj
blh5WXhmT3c1RmxIN2M4Nm9qUFBXS2NJTUFodm9uUE1kNEszV09LRXFjYmQvWE5MQ0p3eGlyNGtPTUgrWjNIdHNkUWNKUWFQdENP
WjVsUDhnd3dlM3U4QXBxZGlzaU1MU3MrUHU4V1laQkFnRWZQNmJNb0NWOVM1SW1qQ2xJbjBHeHFKbE96VUxac2NPZ2F5YzJpaXVk
WldVTDN5KzVUczFpZE9scm56eTJmNUxPOWtQM2orWFViayt5dGFLZUdrUnJaQUQ2K0ZMV3dhdFFoM003bXZuZmlFODF6WnBmVHdX
Z0kvd0dMMnJVQVdiTzBWdUExMExRVGg0UmFOS216OFVpZFN4dHEyME8wc0hGMGZjeUh2WGRJK0dOUlFLNFBHV3NwWjhkUVlBQWti
RkFkUzF3TFMxYkNCSEpHUy8rV2RERzVBNm9MbHFVL3RiVlJHSklKQlI3MG1TcFpCQlI2T1kxaGpldEpza2Jkam5KalpvK1NmQldt
R0hXOWxGb1BNS0pGSHFEdHVZYmVSelhDajYyeUlBUDNsc0V4ZlFyRWZmUklnaUE0eVF2Tm5veTd5QTErMzJSbHZ5OG04TmxBZXFO
cXdHeU9WL1BON3ZyeTFmRnJna1NIc05GM05MNVFCb09xT1RlQjRrcjBST2ZWRVRPbEhBMkpoQWlFZjFueTJFSEw2b1RhdW5OVlVB
RjQvSlVVYm1xUkUyNldwL0Nxak1IQlRMRUpiaEpBUG1oY1ZESU1ibmt0cnpiZUJxUmZLSVFTNFB4TUoydE5SeDBDdU9JK1B3bE1z
akFldVVCUDhwM2dac3FXNmxDZmhqeXRIMUh0TG1nb1pFUHpYTUs1ZnM1QXMvSFFPZ3JrbXFabzQ2Z3V4MHFJeWpjalNydVRvcmNa
VWZNSXY1c0xiVlp3MWp2eDhJaTlZWmtycG16eDJiWndMVGtha0V2RWFRakMvTEV3Q0hoWERjWXQ1K25HWFlqSFJaMHdiRUYzVFl5
cE1GNDJveDMwWnVRNUVZU0xjeVkxRHVodVRZZ2tqd1Mza3BRV2preEs2clJQZHlSdWF4Q3lJVFN6RE1mMjg1ZzRpYnlKampGRTNV
YTZobkM2Ni9tR3o5YlNEOXQ2UTdBeDlnYTRsNU9MeWVaVFBBUjJlWU9pbkd6bzYyUi8rcFFEeTlCNU5FMzR1NDk4akxnNGFYUlJB
dGFhTG1jbVozYmpRZUxWcU9kZllKeU9LdEN2TDBVdUU2RnNGVWpyVzdDQk9zc0dxMkdKNkpEc1M0d1FXOTRrNW5NdWtMVXFTUmZV
OXJyYWozTzJKU0drM2FpaGlqN3cwbjA4anlnN2NSeitsNXhGN0FlTHhJYk13WER4U2NLa1RHN3dXQ24wT0Q2bHV5QlJVaWRRazFG
TXlVcllPU2RzWFBQK2VldmFqNXNPWkNsSXNUdzNNcmpZMFhTaFFNYlR1ZDJTRjlxWllKbHhsSEhFcmJIemdTRWpXbWZDaFBOOVlx
NDZ3bmxmV29FQW9MYUFRZkF3U3YzRit1VzBsbTQ2TURVdTNwYmtnK1p4ZUU1RWNQZnpiNlkyMERxMlhNTHVTVGU1ZEh1VE8zR0Fm
d1JQeTRKT1pkY2dIYmVMb2ZIK1FLZVNha1NiU0wxdWg5c1puZkprM1Y1NlVEU3BoR3VJS3hBdWtyUmRNYzB5TlVmRnZyY1BhVkl3
c0xlS0VZWncwZnJycGcxRXRNbXhESWNEQzJDVnBpWlNjVGx3MUEwYmNwclFoeWxaMFEyM2NFN2NjNWQ3bXNmeml4cThxVGNqaXpz
Q1JZR29PMVpqNHA4SWErSllleHh3QkRtYmc3aDIzMXlnaDlVM1FxdXRnUWNoajdYWE9rYzFlL21LRkU4MTRIUlIrdFdNT2dtdzJs
SFkwREhvVGtYUU11Tlh3MmNxQXVlSzFNTXJuSjV5WWR5ZVpscUZSZSs4VDdTUkhXVzE5M3BwU2Jsd2FoYjM4ODQyK2RPVFhmUkJS
c1RFQTAvQjNJUDV5VThHWlVabHJ3R1UvM2xyaEtXUlhYNUovUWdWS2RpSVVuSTlNK2Y0aU8yVnpCRFdXaW9HK1hFbngrdmlIdFhl
bnU0enBpU0RZNDFYVWE4Mnp1Wlc1bFFiN25wVlFmM1JLaU1DOFVjVDY4NGw3cVNDWkpwT0xaSjNFV2MvakorVHBvTHZpeDBnejI1
QW5WckVyMUhVcGRwQkI0UVNpWVp4RmtGLzNicHl5aTdSNDBnUEFabHUrR0QzMEU0R3hERmVvZkVnVFFWcXR3L2RPSzFwU1EzR1dT
dWZrM3BGQkFvNjBjaUV2K3FES251dzFkcGhJRytwdUUxcTdOMFQ5ZFlDTE1QRTRSb3JURjNYS1N1RWVncGZGang4ajJVTnkrRVVQ
SUNpY0lCQ0g1anZoU1AxMGtCeGFZSHRpT3JZTmFLYlcxUUp3bGNROFRHM0J1ZnorMHg4amdzNWFwa2F0SDUyUDdSTW1TMjlEdVVE
NU82WitUQWtIWHA0dlU4eHlqZVNWeDFwYmdpZm1OSkk3d1ZPdVVON3hCMW9iQUJUTTZhRXJPK0pvVFE2WDdsUzVNNUhNWUdoV1Zq
TldCanVaSkM1eGIycmVjNGp0N0tRV0ZlSFlkU0F5SSt6KytGK05Dbk5vS1p1NlUxL3FkQ3QzWEJKMHczSUFKeCtOT1F3eFFqZTVz
RDhnTTRTTjJCbzlFelhsYnQ4WXdKVEhlNzNBK2ZjTTl6ajNCZXZhcHVDNFVIWnQrRW1xM2Z3M211UFgwZm5CbndrVXA5VHlLNUVw
Sks1T3BRRG9SK1FLQm9JZUJQcVhqTStWZ0hiQnJ1bVBBa29BTVRzTktxL1hHMjdRaTd6NFlEcXpUMkNEZlhyZkpicXhuejV1SDIy
bm1JNS9YYlNsUGgwUHI3TGFNcGNGSzZHVFpxaGlLdXZQK0VyZFF4VFZaNUhzdjNZS3VGUC9FUDV4YmZTMnRlS251Qi8wMGRyRzlj
cnRTVHh6MlNqNnNHZmhkLzk4cnZJOUNEcmR3UHNCSXdZOHpuc1pEQldyYUdCbFk1YXFocjQ5NWhSNzZyUXpqMm11YkhwTGZLOFRq
QS9wUW1MekJRNlRqSkc1NzljSzhLdGZJT0tLWU80cEZlZFEwTnliQXpOQlRaMVlza3JJZXlGQUlJWEdoVjc0TTVTYy9tZTFkR2Y5
eUFMdEpsMUNlRCtVcUp5QldRQ2FLbS9POEx0eHhydXFTeEZOZ2l2dEtoS1Q0SkNITnFoWnowa0RWMDBjZzNBVUsvTzVWTW1vMkhl
WjMvNnhKT0xtdTNRaVk4RTkrNjBtZTlKdnVRR0kyWE9IK3ZmU29QbWNmMlNaVW9lRVA5QzBEN0l4VDkwUGlVVVdjb2hEcmgwYVFs
WXFIazArNDlWNWxBNTYwM3hjak1RRDZzUzVyTVJFQXRHS3BEWWVseDhOaGZrNUJxL3pwbHozcjBUYlZNNFJrSjhHT2dSSTA2MGY2
Ynk5YzdMYWdQQTBlQ0NYS3YyR0l5QXBreDBFd3JkeFFiT2VTVVNydjV1VnY5bVVPeWE1Q2NKSjA0enIxRjkvTkVZTklPVWNXNHJo
WGUrSDRnN0xrdTNUV3VBUGRqMm1JemdldklnaTg0dGcxZWFxTnpTdjlWd1dlZVo1S1pJWkJyaTZONG9wTjQraHFwWDlVem5VUy9H
Z1psSlJQbndYZnFXeUpwbi9MTUM3eGhQbVBwZzh3TExqbU1QQUpqQUkyUlNoVDFxSTIxNkpTSTFKU2NJWjlkOGNyMnlIcWJZTHdq
UGV1RjFITW1tK3k1eXhVT0J3UmtJbHV2RVhmSzl5dk5QQmR3NGJLK2hPWVV6cE1MMGtsZ0xmN3JoOGRhMFBBZnhnblU2QjdVTHUy
L242bzBFVy9QeFM4QStCUVl5YmU3czFacFNxNFZRcHdvaU9ZNEhLYUxvZ0tVRmpCWUFVWUZnVGJFdEhmeTdtVjVtVVhpWk5hL2gr
UEtwbHFESW9RaWFTU3MzcWFaZDlxY0RDOEtuWjlDYXdocU9hc0JRQ2hraDRoVncvZmVvRkFHSHppOEpjWTNBVzBieW4xdXhheEFx
RGhpT0lySk9qWjg3bkw2L2Z5cThNd0N6SmNEUmZjNmNZdk11c0ZvUWVxYisvWVZFbDFxdlIrNHBxbUNVcHZIa1VPaGd5amJVMW1u
VFI0OWdzZTBJNTVmL1NEbS8vallNZW1qa1VxQ1RCVWtheTVBM3ptTFhMcTZNdFMxZXhKZnpLS1ZGL213SXg0ZjRmQ0Q4U2VkRnRI
NEdMMEpoeGFySXJuUFJuSzZFbzdNUTA1WXpWZXRSeUE2WEczbXJaSkJRa2JGMFJYUUQrRDRLWkJrb2llbjJJSGR1VHArbWRyYkJ6
bUFJa2dyUlErMjNYUG5zU3BzSE1ZQ2NnVEp1OFNVQXFPNzFHVmdHYWZ4ZldzY3phNTc1ejlsdHU1aHZuZWRWQVZ5Qi9LU1ZubTha
NHNQZENQdEZmZzB0SmxvK0VuditqcUdwUDJiVnBrRk55b28wM25WeDlRa2N6OVNHYkVrcHZXbkZ0aWx4UDgwdWNCbXErbWNkUmdn
b3VjaWtuUW9IdGtqSVBMMGxGUHcrNUFISkJ6d1NuUXJqbGxhbm8ydWZYV3pRckVHUzA1dDAwTlk0MVZkQm1TemMzZzdTRFh3NmU0
TUxSZXVaTkN6bElDd08xOW82QnBOWUo0TWh1cm9paXFlTnZaN3crVHRRMmJlTXNCdE9MRUxVaVhCZUI3TVg3ZFE3YzlBUlVRcUFY
Y2xMTlBGSVhUYlAxSExUZ1NIWGZqR3RuVmYzS05IQzNMek9XV0tOajdkSEU5S3ZvZWp1NGFyL1paVWZMSi9seDBNYXVDdVhUUFRZ
VDQ5V1VIa1BzMVpyUG1MT242bC9YRU5IUUFBVGg3UzdsUFNkN3U5NkQ2elVER1dUS0xpaEhwbi9PZCtuc0tkR1MweXdCT3lkcW9t
a05Zc05nTmRma21uWDFBQzdZdTB1MWhFbmJGN2VWODVQc3dUYUdMNE5LWmZhbHh5S21QQXJPUXhqL0lsa09vcUp0d3NjMysrbTY4
TDRoZHJTYjBzV2Y2V0UzTHFjTi9Wd3hJNHd3dHU5L0g1MGx5M0dLQWlKZmJ0T0xPM3lhUk12Uy9qc2pxL2Q5UjhWRHB4Q3lQRlhl
bzN6azRRdDBEa3VzTy9LUFBlcVIwdzE5VlduRWkwK1NxV1dCN2lPZTlJMElCMDMwU3NySHFkNlhud2haOS93YkI5bG81K2lpeUpu
cVJnU2p1cXR2b2pEVi9jZ1BjYjVNQkRrMTVJb1hjeWJDVndNakRhZExqVkh0SG9rLytkWXhabWU1YXE0THZqQXY0a28xdXI5VUQ5
YW54dlRCWE4yWmR3L1k1ZldEL0hzV1lTOFhYVGlQTkRacG9SeVR0cHBUeEp2QnVKV2NVUFprZ2Zud1VUby80ZG5jVFdtTC9WWk9y
TEMyY09wdkNWbzRHUlFzZGxIbjBQYUtCbkYvS0lYeXZ5YmVvTFZWdlB5aVdxbHMwSlFCaWNMemdzK1FSWXBxWnJoMm4yOWh2dTZu
SytmY2o4S3lONjhJZnRSMWpzYitudDI2WVB6Mko4akdtMnd6bDk2ZU5xMmkveGRocjNHN01KdWh2dHZQS1RtdlRNeElFSlJOTTVo
TjRsMmI5aGNobTQvNHFnR01YK2l1R1VaZTFnVTFYUkxUUDhPZzNhdDdDNFhWV0xIVWRIQ1hsWWYrMGMzRXhPU3k4aW9QV1RRUnB2
MDU3QkxndEJ6c1JMS1NDVGxNNTJ1MGg2L3NCRnV0TzUvTGdlWHQyWjBoRHlHc0QyK3pTN3V4YThFNjZGYUtRc2xjOW1aei9MR0pM
a1ZnRE5PZk9RYjBzZHNMcFdPSHh6RVNLZ1hnSEhlOUxQWnBGVk01WXJMT3VmYndsUnk1bm5keExtM21uQ2lsaTUwWkw2aklCSUVq
ajNmQmloaTBSME9zVWRoR2RMKzYvQlIzcXhqMllsbzZYRnpEN2taUzVkamlkdWZIN3hLd3BDVGtpamEyVkJmUW9YY2wvY1Ircit5
cWdsdG44MG1pblNMVFpLd0d6RWJDaEI2NjBtUWZtWEVrdVArM0FKeGcvZHlpa0wxREdFbXhpaEZITVlhQW5GTm9NYTZNMU5GdmFs
aXoxVHRGOExKNFZTemVqbThTc3AwTHlMbjh4c0FWZUkyWk9yNDNuczhaZnNNbUE0dkZTeWhrYTErU0NSRStQblhsY2Y4dFJua1Jh
VUZQSDJib2FCMm8wTWN0VnZTTFBoK3V1SWFCUkY5RmZyWktaLzJJZVEveUY0Z0JWWTRJTXRreGJjSGp5Z2laVlcrb09SRDNYS3gx
YnhWT1AxaXk5RlhJNmRSVWhhQjJMOUo0all5bE5YTE8vYkt4SmVBcUQrb2JKVDl5MmVTdDlmV0ZzbGpBN2FSZENlQ1FlWVBxc3l1
aG5VYnZrMVFwamFkSnZYUW8wRVRycVFZdjIyRnFONEQ0UkJGaHltSVVFUnJhc2MrTnB5M1dqa1RFWGhMblRwdzU4QTFETXB3ODJI
Y24rYWozUFU4V1FuVkwyYUsyL0QwMHV1dm1YZVEydVJOMmE3WDlrT3h1dzc2c0xVTzZNVXhMR1U3Skg0SStsNXladGoyYTNodU9P
VEx1NFd0aFB3aDV5cXpEMHd1Y1B5bGd0cERUYWx5TTV3SVFSb1FKL2dwWnNBeHg3NVdya1RCVU5SWEZkOFRJeHcwa01TUkQ2Ry9z
YnNhcmh0Z20rTkNFVEttRCsvbmtWUzRvUW1BTDFzbzVvd3huWmd1S0VYaTRwMVBTejA3OUs5d2RDaFRPaFpPN2dKclNjdS85VTRX
ZGNHUGhTcjhWdFZud0pvd2ZNdHJRbDJBc2J4ZytuUm5uK2s1WCs0MjNSTG5XU2dBays0eUVVVHAvQlBGN0U1OFNTcGo4b1N3NGRZ
aUY2UHhvRkZPd0FOR29aUm52ci9PSVJnYXBkWlIwakJaaTZqZjhXcTZzL0s2amZtbmtEUE9VU2pWUTM3eWI1TVpCOFhrOGxDamln
eXVzRFpLbHcyb0NXbHM3eWJ1MFpQMk5YdGMvMFovcjZEeWRCTnJBTHN1T3hDS2dJSENEdWx2TEtXMXAwSWZ0VzVjeU45cmJ2dTUv
VEdJdmIyM0ZVMlkwb3lhWlpRWU9PaVFzczFwbW1VMkZyVTdYWnJQVnhVY1A5ZXdFNmdWSXJPYXhwRzBUVUZmY3hNWlZrdEtROHpR
RERYQWEweHM3ZVA0WS85MDdVYml0K0REdTg1cjlRUVdjV1JhOUlFcUV0SFBMY1NDanlXS0xRQUR4ZmtyRHJYT1hzNFFTZmh6L3lS
bmlFUGNrRTNMSjJuRmxvS25oZjFZVVZiVVRQZ243NHlacHM1aWVBUU9xVUx2VWQweW1KcU5FRWlUOTlJMCtjbVRqL2JvS2Ntd3Mw
VG95dFVZbmRtNFNUL3N4bVZxbWQ1ZGdGVmd2eTRzQkE1WTdrZFRXUWFCTUcrQy8wbjFYWXZldW5wUFdKdEZqcnFXajFBUWNrZTNr
Qk5kQ2E5QkpuTXFJaytlWWtVMVNzN3R0MGJJVWp0YTFNQ2htY083RTZZalFkL1RESW9NQXAwRDhvQ21IcExLRkZUZFd1WmN0OTNi
WGJrbnViZURlUGNtdHovM2RnbzdPMHMvRVl0YW81QnA2TUx5d2ZQUHNIc0xwYXd5ekl4MzU4MWxNM0Y1a2J5NC9RV2E5R3RqZ2dk
NTkrTEYzMzVkTksvMStPQjEvcHpyeGFYWXl1WE1icUYwQ3pXK2p6NU0vNW1ha0dMUW1Yb1dDb3JLM3pxNnFJbkdiUUcyTSthZ2M5
MkhwSVpXOHBLQzh3Wng1dUUreGRpUTVnelhqeDVBSDZFaEUyYmk3aG94eFV2amRFRW9pc3JNNExRUkR5OU51WTNJRkwvK01zK3RF
azA4YXprektlSkt0aEU3RGhrUmloMGM3Y1pNZ2hieERmNFVuZzg0azh1ZVZEdHBLVTJyQTlxbnV6elZobFg4SHpOVnFMQ2JLcTZB
dFlENFRKNVRUL3JZSHV3bmZuRjVJYzZrT3REVlZOS2lJcFJOTnlUcDJHWVRiWVNnSTlXY25DWnB4dXJVVk1UWHFPbmtrQ0I1bU5D
bUpEQlV4S1hEaGF4K3RZTWg0YldxZlB6RVBnU3lQTlJBM3JNY1grWHFPMUpJZkw3MlNuOGJEVDlIUktZWEFycXdOK2JtbFJ5aStW
TlhwUjVZcERrMzFIdUJQNTh2OTIyRG5taGJYR21qV2hjdVVqZ0lvNGZTQjlpK3V6dEZuMXUwNEI0UExPQWxMSDV5aDVYYmNobXAv
VWhQaElrSVdReUZ4RFBieGVXMlk5QmZNVVI0S01IeUdjVmF1NGJPZzl6aUtxVXBYMFVEQXdzL3V0dGJlWDUxZjFSZ0NmKzZPeEVo
UFJLNXY4TE9xRE8zcjlnMndzdXNRelRnblVqN21CNWcxK0lnbG9JVzVoUGpsZWJOVURRM2djTWEzZzhxcS9EZDFZYndsbmh1akt1
Yzg4VDZ5SHpvYUZ4TGpFcjFqbTJlN3Y4OU1zUmppUnpocHlNa1NmWlV4d01ZRkpDeUIxcnhRNjIvTEpGTVp2REdMU2ltaDU1K1VY
blE0VUpHMURsbWo3d01ZM2h3RmNqbFlzSlJ3Zkdzdkc3aXpyS2lNZEFMbHF3cDA3Rmd2U2J4NFR4UXNmdFh2OUZrdFJIbkZjN3lK
TnBLZUpDMld0RTV6ek1QOXJCenh3T1MyOG5QQmJNVXpkaFI4K0k2dDJuM1NIK3l4blZmWmlXRnVEbHNleitPSndpb045enhKQjdk
emlPNXNQRC9GRnRocmlkd3VsYjhhaTEyTVZJVjZxVE05eXBUUDNZc1U0R0xGRkkra0JzMU8yd1BwTTJ1dlVtMHJPQXJWa2xGYWtZ
WFN4eUwrR2o1c044eXhXbGtaV1BPSTU1TWg4Y1I5RnJ4QTRtNVN5a2k0WXJIOWZ6TXhJRU9vS2xUMFRsL3VqcVJOektkQ3krUG5t
YzNtcGxzK1BQWDBYSXJCTUY0STRvZHErejFGUGYzV01vRzkzaUJ5MWZ6NnNvNVp2YzhVU09OcGh3RGF0VngzUktGYmxKSHlqcU5S
UUtMNlFFZkJFVE13MHNBZ3c4bmpEN1Q0dWpvK0M1UnNmd29vMFV2cVhQVTF6d3VKOWJMckRta1VTem5KSUhKS2Q4T0lTc1N1cjdG
bFF3MjFqNGtBdjk0YkZSRUZvMFR2ZFJLZFdmeEwrY3N3WWhvV2U1TllIS3VVdEhmRVRBQkUySU9jV3o5STVxTTJlRU0xb2JtNVlz
VmlBMXZsK2ZvaU5HVEFROW1zTEl1dXVNYVdWYVJqK3REZnFqaE1rM0hpR3hqTUJNclBhNnI1NU4rYSs3aEo3NUFiWXFVSmRGU0x5
bmx5dWVVa1FJZ2tuaElrMXFxQW1sMXBjakJHckppNkk3YU5GOVJ3Mit3dFJXY3AzMDBpR0VpR0tYSjl4RFpLdlpoM2RhZ0NHZzY3
YmdVK3h1VnhaeWQzSjhGTDJITm5nWUkwZ0QrdWFBRGt5UEN6YzBpYlRWVXpWZzlFRzRWRXptdTN4R09LY0ZBd3Baem5HR2JLZ01u
VU9jNHJJZ1YwL3d5dWVydjBwSUMvR1diakhrMGRTTTV2L01HM1YwcFh5Y3FCSlhMdCszQ25mT1BHd0Y3TG9IeUxLL3Bla1JDdm95
RUppUnRDOVJrcS9oOTludWtvdGkrSzN2TDVXaTh0YStZdUpzdU00di9qUW1TUVlBb3Yza0JCS0w0SXVXaVd3VnMzM2V5VDk1cmNq
L05iV3cwdGtXS09yYUNaMThqTDJvWERJanFZMGhHS0VRQ1BwODlpcm4vdnUrOXZmd2FieXp0b3krejl0bjBsZXVZUFV4WWxjZGsr
OFNZV3EvWDdsMWFrTGsrUzR4MnNTYXJWOTRwRlV3ZnZ0cEFRUmU2dUlWdTJac0NSMG9kZW5tUWoyc2FSbExnNzFBekVOOUVSd1Np
eEY5MUlsQ0tnMldoWHVsR3F5V3cwelViNnIvRUU4cmxrYVQ2TExsNThjNm9yL3pQcUU1QkZ3MlZqOGNCV3BXRHR6cEo3MU1HdVpn
U1BIM01sMzlCbmplazd5enROSndIZnNwQm5ZZjdLOVlJRGxYRDhhdE81VTNkM0ladkpBOXRMVmJYNlpLZi9FQ01nM25zYjFpa284
VDRiL3hzRUE5VkZMMTMyQVExTE9wREphRzN6akwwVVY5WHRmakpLVmk4WGxZNXo4RDE1b3JYSFpwdzRBVk1YMWVqUnJvTUZCMHpN
a0xkTHppbC9GcEdwNm1CK0t5d2NkRFRFS0dqVFluRGRoNnNLWUZxanFSZHZxWEtMc1B0b3RNejRmRE1OblpmbURTSkFnRHpCSmlB
bUNYcGdxUnBqZ0Y0dHgvK3cwWmQwUk5mUGVpSU43Z09xbEJ0bU1pL1VCVkNLM2NtQmMrbFRnZVZZN1VIZG13VW5sTVNzcFlZeDJi
eHdsOE5sVjh1WU1PL2Y0MWtTOHJLT3FNM2k3NmJDNStGQ0tyU3dhL0paeFRBcmJpV2cvVmE2aXRRRVA1NGxXcno5VTNiOVhHbysv
cEhtMlE5eS9YRzBab0xOdWdwMEVNVDR0Lzgwb0l4Tm01YXBpeEJ2VmdxUi9OVks4QWV4TDZBU01EUGlTcWxydGtsMjFRa0VKQlRB
bjNYYmhUWjdtaFpiQ09DRFVqMDZyU0dsM0Z5Rzc5d1haMUsrQUJZVjlmbi9OUUpNY0h2UWZYSDREbzV3WjdOenQ3MEJ1N0xSUEEx
M0htUzZSTFNYTU5oeWcyNkV2cHZUenZrWmpjdExGZ2hEUHZ1b3RaWmFDZ1NjaHhid0s4YnZMcFdjYlQ2K0FyZDRSSXN0bzdnVnpJ
YysvSkVyK3F2N3JiMU9UYlY4eXM3SjRTdGJNa1BlUTdmUk5ZNlpzcXk2TldtcHNIam5XR3dkTGhjZlNHVjVNZEQxT2xRS2VrZTJR
NnBaUWx6a0xGQUpxbVUvRWVPaVNpKzVjN1JIWkRrZG5raW5sQ1R5UkNORVQvaXVqYU5JY1ptSVNMWmcvS1lZVS8xbVFsdVZQSUZk
anhqemJDOUlDMEtaOVlJZW5FR0FoeVZiMUtvd01kSFUraHRCSVNhcmZoMzBhY3pGYnZ0WU55dWxyU3cvSGhramFaak04M0ZETVBU
dU1GN1BlY2lKRS9kL0FGWWc4SXlIa2V1SDRJemo0STBYNW1mTnhlVkFtdDgvNExwSnhiK05qN3NVVGYyMU5YRkVvMjNmbUw5cTQv
STQ4NnUyTEM1TTFMK3MrbWhXTytqOVBCWFYxZFVMTTRiUEJQeTREZUhTU1pZOVNRYk5ZVkNPV3o5SUUyYkNLWjhhZXpXd1VoS2FP
a0RhMy9oNWV3UlRBV1BUMzJaUEJWU1pPemhTbllkWFI1cXNOcHd2bGMwQy9vRlErUnBFeWFNcGg0d1hlNHJWQU04dWkzLzdkZXA3
c3RGRmh3cjlJR3dmZ05XdDV1ek5hOHRxZ2V2THBaTkM4UlpubzBiR0VUYXhlME5aYXcySGRmSFo1ZlFxUnUxVEE4eENpSFV2Ukly
cWk4bFR4QllDZDhSVWVZTmY4RU5VNDlFNU5GUDhmQ24vWGluLyttQitQVEZ2TnpON2JtMTQrNXRXRXpRaGU5K3FtOG1zUVhqRDhU
V3o2N1JGdklQaFBQSlhrU21nUGFzYkorZE8vcXQ5d3VUOGlTbk1NZlpmOG95RGRGNU5IWmxraXBWRENLODF2WUpnRkpuWDRVRFFk
SERVeW9QSnliQXdCUVErZWszUWZCRkVkNStaT2Jrb3lnVVhJay95ZmVaYytpTlA3ajF3bVpPaDdmVnZsVHFBWU90UVZNSUNwMXZy
a3cvdi9rTy8wU1NhTDNGSnBVY3BiOEozV2tlazNPeC9qQldjbXROaHFKODU4SGhmUWZ6ZmNRYVZ4Q3RPMDk1UEd6VG55aXU4TGFJ
eE1zWWhIMWRpY2NiTUpkNUpLY2xXZXhBMHo3R3lwaS9xcklCMmwxOWxZcmdxaUJUMno4WWNYR1VMMlNjdWdjTmlZd3ZaVzU5QTFN
NWdwb0U1eG5XZzJ4clBvZ1R1dlRZRm9GamRISXNSRVhicWRrL0VxUjdTQ2xWTTBuQTlUOFdUSk0rNG1TNk5saVRWRVJwYnlyaDdk
aHFZMkJLWmtUMmtwSTUxQ1NtQjFDSDZRcGhDVU91N3FQdnBmSGtYR0N0dXB2T1pFMElmQ0MwdzV1cmY4eis4dnVqTis3Q3cwMllP
WHZDWkw3WEVqVFF6ZUJseEg0NFpNcUVEeWl5TzZST0Y1ajk3TzBTUFE5dy9vNVNnSEJzQXY0WVlzWW1pNnVrdmx1NTJXbFNkMXIy
cnVGMEt1TllMTXhwbURCVlNqQ3d6UHI0YmxQMTR0Umk2SE1kSjBoY296clVWaEhTN3ZKTjk5Z3dVNGFrVkVVK01DMDlFTmtzenFC
SGUyR3JmMTRBVUhqU1YvT1FlTW55T1lBdmZwRzA1cUhOZ0wwb3pjeGNMTTR6bHFmTUY3c3Jqa2JEaFZEdGtJSTV6NHRUT2RodkNR
ZkJIT0E2RzRTek1XTUVZT1hyYlhTYlZMUm1IdHk3d203WSt0NERWTG5DdnQ0ZHlNeGdsNUVFcU5oekpoblgyOWZmUjFXZ1A4Y0tY
ZGtOUDFlM2dTRGtwbFVKWDFpWDVrM3VwZEJUaHQ2R0R5UWNxeVUycDJmcnhLTWRZcDJjM3hoSk1DZVRnQnRiWkMwY29KNkU3SmhO
anN2YWhsbFNJeUYxMU5UWC8xM3RTSG45bVdoNDJmRitmOHhVU0FWS1BTL3ZXalMrZHNiM1JZWXJKYzM1cDNrbFFxVWZ4Mm1CYnhI
djhHMHIzVlF2eTQ5NGthYWE1UEFQOGRNUXhuU0dlL0F2SFdOZmpPTjJLOS9NYTNpTFltUDVMN0F1a2VGZkVVeHNWVDdkOFFzV2U3
YTdhRVE5VXFuTEZxcEo2YlhTdzI3ZnlOZVM1V3o3RW5MeWRFWXMrM0tWT1lmelRrYXpQeEsxZUdyYVhMNkhwWFluNGV2L2RDZFBH
alpsckQwSG9xYjQ5d0NBSkpWNUxqdTJ0enpjRVpMVXRjYTJaaWhpeUl4QlRQRXJiTFZJM1QyWFg4Q3BsTzl6T2FiWjhGUDNrOVZp
dEJ4bHhvVjBhNFpGZW9xei9VdC9yNDdXd2RoeFYyUGE2c3J6UXNyalJDLzJ0OTFqUDRZSldDMVQvbkNVZi9Ca2IyTi9nRW5aYndw
UW9kZDZSQ2NLWUxzbUZmY25pT3YzUWNSR0dFVlhCdkd1ZWNadzVYdlU3Tmd4TjAycjY4WHRubkVNcVJDZHI3bmdNRWRUaklEQ3ZY
Q1hmYTZBSmlXY3NrQXdJTS9oRytoWjRXakp6c1AxUitTTFIxK0JaSXJBWU9hQ3dNTldVYVNPR3dJbG9BaDZ0dFpCS0krUXo3MDVQ
RHhUN1FYU05xMHUvMWVpWVdtMTdJb2pEeGdzcWFGWHp5NGM1WEZlVTdRcnptMGdjOW54L0JMWDZjd2NacjhPZzRUWG4veGxmeXBE
TVRDTEgrWkJTbGhNUS9RUkhxMWtpUUpoeGR3WU9vNGlWY3JnWXphcVJjTHd2ZHhDSGJiYng2S2M3V2x3dVdXdVdzRHlQZnhXR2pD
cTl6c2oxVTJQRVBlUHd2eDRmR2ZRaExFUkphWWdkcGR4Mjg1b2hiU1FrQjRPSjZpZGVMbUM3UURvK1dTOWFKaHhHSXZkQXB0K1pn
NzNldS9XUGFwVDlmNUlXNzNzU1djLzlCSC9iY0pDOHhEZmhZNy9lZ1Y2OU55YlI1WTVwekhNbVZCN0E3bUFxYlZyS2RCU2ppRU5o
OHc4NUwvVnZkNTZLNlkremkrbU41UEw1NVBnbGs0d2R0MW1XZGp1VFJkbm5EaDlPUE5KaEhJSmU2a2xTNWNZdU9NYlpFSVN4N2pX
cWJYUXRoUHpZaVpxRnc1Sko5enJBUStLRDloNVZ2c1pvY1hwL3pmOGN5NnFqWGZyWHRIRk5YQmhocUd4NksxZTMvL3BLdjRjZEdD
M1lHZUZLNDdqWE0yWGJweFRjQnZKRnZ6QjhxbVdFY3NIay85TVdjTGIzNExyc3lrd0FKUzQ3bFEvWUk0V3p5bk9YY3ZwZkFkTE56
UU9uZDZVMlFuMmlBN01McEVIWGFaQ3o4YkdobEhRakRjbVFVY0lTR2pFTTRUbEkrTnJOcWhjVmgvK1RMd3ArTzBWeDhiTCtiSUhw
czJGUTg4NXM0cmY5Tncwa2s0TFplYU9XVDNkNk1NZVgzejVYNUo3L3NwWDdNTjRmVFgzWFc2QzAxaWNNTGl2TTN2Q1AyUHIvU281
K3ozTVFDNndKUm1STWMxRzIxbHlSeUtBdncrdyszTXUyYnVvbTcvRnJmTlIxc3ZZMnFXTTdENG1KRnp3aUswNjc0ODFWTDJDVUZU
TVhNYStaT2pWa3JoZ1N6dXJWTGl6ejl3SXNHWGx5aGtIWVNPTDBtQ0tVdHhQR2k2ZnhGU0FveWhXdXVlZlhNZXBHUUVISUhuQlly
Z1BtL3J3MWpTaDRUWnJsd0NIeHRFY1UydEN0WkJDaDdJdko2T3p0M1BTM0VKa29NcWtwOTR2VWNRQ2REYmovTDB1aEFEbzkxamUz
MUFrUi8wMTJkZkQ2b0pZOXhFeHFOYzJnUFRQM2czL01yUVdIdWgvcUpPdnQ3dXhyeVhPZWdDZnpUT0ZZT0RYaU1jclM2ODJMc0hC
VllVUFJIWnVuK3FQZzBxNHF3NEdPVHJiL2RUUFNjbll2UzE5OGNGYzhHNTNEMU15WTBWSlB6Qk15WFJqVUxvUUpsd1A2RXVKeFBH
eGRyUkNrRHN5bExiNzdLKy9nN3VIb285M1ZST00yajNKbXhzTDNIbGEreDZVSFZXVStVQTE4a2o2aGkxSklrVEllMWdUcmZsRDc2
VXF6Qkl3Z3hZWGtQOTBFaTNnOWltbjFGQ2NWZzBnZjZyalFhcnd4MWJteEdTc3JldmZha1lob3NxQVh0bGNCN0xTVHFzUEdmalJw
UDQza2RKTzFpNUNpUXY2MjBPc2xBdjJxRk1YVmJ3bTlWTTkzQnNadWQveXExbU9tTlhYcTVPTW5nSWVuOGRJcTg4b1QxY09uMXJF
Q0VGQkx5UVpZdmxzMjNQYk01OExtYW5sMkcwZ0orOURzYllvQ3lyaDdJaGcyZC8xUlhFbERzOHZBeS96aEI3eDlrZTRYY1gzcWtG
TTZBTGRvKytDbXgyWHFPM2NMbndaZTNlMjhtdndpZEpQVy9NMlk2U1luMHhVWW5NTEYyQkdLbkxnZlYyZEU3bDdWeTQ4NmN1OXA2
bE9DSU14ZmdkSis2SktwKzZHN3dhTm5CeGhKalpEa3ZIZnUwUzNiR2llcm91QVpNazBwUXZDWURhajhnNHl6L2ZPTmJRd0dzUTV5
eElrVEFGMG9ZL05tVFVnM3NRa0k5QnY5bVZxdUFVbU5DYTlpZzRDMnBxcXoxcCs0bFNhVml3V3ZMdUVJNlA2RDR0YjJ0Y1ZiR2hQ
RzZBODJ0SmhsUU8vRTFFL2U3MjVoSjBLOXQyTGFEbVhLdVVzRTZqLzdnSVY3eG81dTNOS0NVdWtZeFA4bzFRUW5iWUNuZjdyaGRW
ZXJSVDk2VURzckRTTVZGblorcUdQODlGWjhTMXlzUFVUV1NsOC9YTElmWk5LWEF1UXgyTzhXTENjQW9vNC9pMkZ1QXpVVmtGZEpD
UTRtY0xFVmhnOXk0K29VYTQwSysrNUJXU2R4YVQ5UWtvenl4L291cHZSQnNJK2FJTHFKZmVkNjRTQ1RCL0NZNnBtK3hmQnZXZ29C
aEQzTmNlY2toNEZWbmpVaDhIWHVGb3VpbWViNkNPSTZSQjlFN3N5SHVBdVd1QzVUYUgvQy9tWlgwWXhTMlJOT0swS25jSHE2SE8v
eGQ1SXc4OHQ3cDJmWHhPOVdxQmF5eGhJV2YyaXV6NEYrNHFuK2t6VFVqenExU1FIc1ZwRTVVREVpSkhXYktrQnMyUGdKSmdnMlht
dGRqVjMrS1lGNno5ODU5eWZqTVhHcWp1VnNmUEo2YjBhMG4ybHhKdEoyayt2TXh4OFlNNEpET0huNUhUU2V4YTFEdTBXUVdoWnh0
TVk1SlMxUnUvaEZEMjVTM2J6elZmd1MxWWV4SXNlV1F3QTNpc2hGaE05S01qcnJuTUZiZkM2RXhtVmtCTnZaU0t2V1BDQjVFZjNa
L1BsVWgvbk9QQTE3S09ObUVQK01sQzMxb2dzRHVYL1ZGZ0NQTHZCdjlqRjErVmNoOVVQaVA1REN2bmV6NklPWEJIUCtLeTZGYWpW
YXJ0cXlWY0NMMHg0THlBdjBiejhDcy9LUG53UzRJdzZDeitxMnFKZW5rMHcrNW94VHBOSkVUb2JGL3dLUWxIU0NiWCsrWEozMFJC
S1NseWNPSGVKL3lPWjc2clRXRnBrUklCUUJhRDdNWTdTZTY4TXZyN2VkM3pPM3FybUNidlkvakl4eFFINUgwNkNNMnFRTEVESERw
bEhjQkE1ZTUvbUxhdXB5SFhjcDZnMkpLd3JobmdIUHp6bW9QYkdOWFc0VFhKbGNlRms0S3RnT1F5WE9IUXJYckMxRko4NC9kRGJZ
NnhvZFo3b3BDd0xBODdpZDdVSzR0TTV0aXVPMUNZMEpDcGx3M1AwZk91S0tCM0NCNXo0ZHRhelhJd1RUUHpPOWVPRTJQYVJtbmU1
L242TXMvN3YrNnJPYllrVzR2M0tMV20rT0M5dU1zNXFIbmREc1VBbEZTK3JNRWVTR1VWQXFsaFRTaXd4eitXSE1xYnRsbkZpUU1v
NG1sTmM0Nkt3LzArVitIYi9TeG9mMmFtMlA1dkkyRGN1N1RIZCtUYnFqRDRwOTNRRzVvOXV0ZW1BTUQ1N3hpanhzbUV3K3JETU5h
bFNna0ViQlUxQStPaGNDVE94V3hCTGZMSmdkRWRLSDVuZUF3RFY3NTlFV1NRQ1gwUnJFRm1rQzAvMXgwYUc5eUZ4SHRtaVl1T3BT
bWhsa3FpVlBmck0xK1FsbUh3cFdwTHcrcXNaNjZnbG1Yc3FWL3NCVm9xS2ljMzNDYU8vdjBHVGhwano5dkhDcTZUaEZ3TDhsYmdQ
bG93TmtvaFh0ZXNGK2hhN0VIbDFlY3pqQUZPVEtHWnBhcCtzUzQ2SEJFU3dKSkF3R2xuUlpvbGxERmR5ZUJrRWhzdndnLzZLR0lh
akdhWFpIVGRUWm5FNjdNK1cxUjducVRDczlrZGs1MDhWM2FqeVlmc2lzcW9QNXJwbGhNRkxGemF2eE51N1RmSkdqZXNIWDhrK2I4
c2V6UGVmUSt4VHdpalZQd1N4MmdJck5ya1YvbTdwMDE2THB0WnllQjRDWlVFYXZJQUtWSUp0dHNmZ002KzluSzF6ZFZxY1ZtK0Nr
ZDcrR0lOamhKcUhyVCsydFBoZEkxaFZyM2R1SFRpK01RNmsrWCthQzJMZW52bklQVTdrZExmQjExZVVyTkwzZnN0emM3ZVdaTTgr
azMxaVBVa3ZnVm02a3RjbDB6ekY4aGJ4ZzJXUC9VSndkUS9ySWNjb0Q0ekNsSG5SMDFPY09yczlEV01oQ3h6UE1sK0RpNHFPbW9V
bTRxamZ0ZEVaTUcwbGprRllLRlhSU3lCdlVOSVlTaE52Mkttc0RsS2YwbVpNdjM5T2VxTTIrQUUwT0NEOTZUTGUxNWpKRTB6Sjgw
MEttV3VqV3BQa1h0bGJKeXpLV1Z6ZE4xWnA2SElUb2dmcXQ5NTZKakFmTFBZNG9PR1JWaXhIS2hUUWhuQjdZaTUyU2RtbTZCSWxk
MHEvWlZoeEJBTnhnYTlJeDdzNTBJR05iYW9rNjRoNDVHc0cweUl5RGN5TkE1THE1d01pYXV4M25GU2NMYlB6a0krZGl5UHIzQ0Mv
ajI1Znc5NkhGRHNtcHV2bWlHNkFTamdLNnppRUp0WjlrRmJxOHV2amZINjJwVGVsU0RKNVpyamVFTWxQVDJVOE5GVGdwaG9tSk4z
V1pFd3lGQS9STEZ3UHd6VUNQNFozM2xVbzZtMkN0ZGNKUzBySW5wQThPUUtBTDRuTlJFUTVkUE1ObjkvV3h5OWExWEhIL2JlUUF2
My9KMnVHSjZwM29BbWtva0pZUFNBbnhNZVJ1K2tLQWhlaXNaaGJUR3FqNEFoNVBnUVMwQ1Q2Z09nbXI1M1RTMlNCaU1DMnR2bERm
MGNBTVZ6VWU3WEFhYXNRVEx5MDk0ZUJIbm92bTFNNWZYYVRLdnJraFpQblZJSDB2NWIrRGJ5YUtURnR4YVZYMVdwMHNnRUx0VXNm
aytMc1RKeW93bWJ4ZjVka2NFL0FSMTlIZU1jSGY4MkRCU3c1cm9rT2RmelpYR2tIN0R2YnZNUk5Menh0VGhMa1JOMEhka0IrbUpC
ZG5Md2pkL3luRklNcTlkc25vTTV2VWtZMUlDS3ZFVnF4RWFtNDkycTFyVU5XelNRTnJmMHlNNzNPSkNkSjdyQmNUbisyUnVsd0dh
cGNNRVI0djZ3MExnVHlMZ3dvRVloSGRRblVuRExZeTNGVFROdDdXYnY0czVwVFJ4MmtkeHBSa3B0TlBrTmdaTE1lYUdWS3o0UGRu
enMzMkZUTjVvUDRqZmduTzVGZzlKOUpGM0RGbWVlY1dER1hITGsvalFGM3hvcXFOSnZaRmc1TGY4c0xBQU5oZ1pFU01VOXFCUlgw
MEhJa1U4RHVsb0M4UDluQXYzam1nRndSZTRUK3crNW5lYjVwb3NqZndINzFnRHhwdFplZDdlUlFYcXRzaEdZNHZyRVJseDlOVTVG
ZXdEVjlFekJxMXVOSmxVb2lsWUdKYldmM0ZzeGdmUkpVVmxhczRTcUg2a3lJNi9aYXROYUZvMUtreWFTbGk5YVlkZCtuN3I3OUNB
OUlvUHlTVlFMOVgzNEtYMXRVUXk2dmhiVm1oRTl5Z2ZkRFloSUo0L1pXVlhBaDlNdkJkaXBiWHdoYXdHUE9aVmhRT0NZQWI1VzJs
Q1hrWGh5UDA4clV5TzNkczd1QjFkakVoUGtBL0VqRW1yU3lpVktldWdsNTBSY3V1NG9kUmxJYm5oU1lubjdQU3NTT3NuUXBqZEZh
VjVNenlIbC83R3l5cm1sZW9ETlZPeWdYT2pjWFhBVzlZUUptZktrVnlqMmxBdUdPdzFXMlI0NnY1WGxKOEREbmRwU0txbE9odnRx
TUVyeVk1bjBYSCt0bEhwNzdsNm5nSDZrRHNQTVZ6S0hMaVlVQ0MzdzMrbHhqeExLVEMrQ3Q4ZmprMWJZbHJqNk95Z1YzcEdvQ2k4
VklxQTZHSVV4eUtrajhzSzRpbXJpZ0pvNkxyOWUxeWVnME1nMU5rZWJwbHBvbUU2MmNGcGZEZVNHTjMrUnVzV1VkY3ZnR3pNOGVS
UDg2eDYyaWJMUEdMN1ppa0p6Q21YQlcwNUdkSVFKcGFvY3BjMkFyNFVRbVVVaEZzUTU4cTVUN3ZWVnd2ekx6b29jN0ptb2JCcDgz
K3pBNm9tQytyZm5NLzFCZWZKdnczcHdadlVyVThqeUVCODZJOGRIYVlzMHVtc21BQ0dUYzJBVGdOSVl2dGQ3Wlg4ZEdZd2g0SS9i
bHY0RUthaUx1S2ErS3NZTHY4b1ZvN1ZERlFaYzBnL1hYMngydVkrZlJTYVp1a1JIT2RuSTZjcHN2dE00VjMyeFN5SFdVVkhxQTdO
VXdHV3FqU2dWUHVFZGZ6UUdCakh4cW12eVpEV21rd09TYUxmT2ZGSTd2K2dZbFFGQ2ZEN3gxVmFJaXNUUVV6Vy9iaXk2S0F5M3hs
ZnNwOU5FZ3VFWTV6emIvbVpqUGtodlpqbEc0ZC9VdWdoYzdqbXo1ZTMvbUdjcFo4dU5qM05HTHE1ZXdHNHJaSE1uUzZtV2hFOW52
MkJhWkNBSlZBTXNpeDNySWlTMjA3M1JkT1lnL1YxWWtocXM0V3hkV2ZSdmRjZ0ZuNkZVWHFNSWRhOXd3RzFVRUVldm5SeUlVZkQ2
aWNubFF3d21TM1NUcUtqSTZhYUhVdlgrQ3BqWmFoblRHbjExZUhvMTBHQ05FR2t3elc3dVVvaTk4NmordlphRkQwTUg0UnB2WklU
aUlMWitlclZhSk85cWNtcStDZkRwR25kSnZ5SHR5b2xhMnh4R1dKd1J3R3pUY3dUMW51dkNhSnUzRXZ4ek4zUHdvZ1RTYVlrT0VG
VkRGOXJwcWg4WHYrV0Nmd3JKbERmZHpiSFd6clp4dCtHWXJPM1YwY3k5dHRPWjlMcEpZbUhIcjBGY3FKTnVUYVlJeU44bW12WG56
RkxUY1dIcDdFS1AzRklGelBHSkNUWDF3TWlneXFTNXlkOGhSY1ZwSnpFMldyeC8xV29oZmRka1E3T05leDhXY1JNOWpWNG5HR0s4
TmxWbm9KMkNrYXdxMFNVVjBvWWIrWENuaTBhUVZxL2FNajZVOGk3K1MxTU1LREVaWmkzUjlFSksrUW1YY2VtMlNyV3ZaWENJWjZP
Qm5MSDBqNHNuRXFtbmoxRnZlbXhXSjl5bGl4cWNtb1hBOEJzU2dwN25ONkU5bG0xZGR3cDdreVpqTmRzZlE0dUVrV3FUN29aRWVi
d0F2Q0dQOFJzQnZKOVIyODI5SldnbG9vR3ZQdXNTOWRsVXdmazFacWg2NkhtNDdMTEpLdTVuSFpab055RWlJQTFHcE5XVk56aHJS
QVkwMEJWWEt3Mm1mYXFtSCtJaVBvN1dSNUE5YW5oVHhtU3V5elp5R29lYVpWUDJ2bEttQ3FVNnBxK0pscGVVQ0U1ZUpINS9OV2pq
OStGY1dYVEhpRTJsb0tiRWRFbEZZY2pZZ3BDYWF3Q2U2RHRpMjdXZm9ZVTF3S3FyY1REUDNwOVg2Z3podlkvRmFqK21LMVZPOHRI
cmZyV0tyWmhhVUZNazlta2UrcGV3RkFIL2NhdzE1eEhqRlRGTDJxRVhRUzRKaUJsTk5lcjlObWZodFYxT3V3RzVMeUJXcnIwaXgv
eUJOUGIwN1dXT1RDSXIvNzJZZjBNQkY0ZndVRWF0OEJINjU3RktLZmpMMlo0YXF4dy83Yk5xN21laERXM3p6eFpZdUN5QkdDcE9F
Z3ZCdkJxckJDNkdyaHdvcFU1eVR4U01YWGl4VnRxUS9Zd3RzdWZUZmJUYWhoZGI1M0s0dHgzazN0NGc2L3BuMzJoZnZqYk9tclhh
dTZXc2p4TjR6Qm82Q2s2U00xUUJSRThXVlc0bVBIb2YrWjhyaTVCWmhaL3BuYjh3M2FFRWVIalJBOFRFdkZmMGpTc3pMYTg3Qmk0
SVZWMkYzRmlubzdhaDNnNVhCR2paZVBRNXNvZUQxRWthZHovaXFSbVN6Ti96R2ZDOThoYk5XNm5OZWIxc3gvTkg1bmhOWG1XTGhp
dnJYbDJrS0dSL2x4RGQ1ZXZTZUE0ZzBPMTVCRHh6eGh0MnNsTy9aa3pMUE0vcFIxUzV5NXhNbmpUUmtTUnZUVEZ2elQxakRFanB1
VDVFUng1WnBPMWI0QjhQd2VWNkZEdHB0ZVZoSE9GZHRLbUVqYm1MazZOU0tNZmU5cDM1TmMxRitWQmJxTy9RVEx5Z2NTWm4yRmR0
ZFFLS29iTC8xbE9oakdsd1pzNzhZVW5Ya1U4aUI2UnRZT2pmTFo2aEczS0tRNW4vY2NUUGNidVpLNzRuTnk0eng3RDJQVmhjUTdD
SHNhamtVMkxJazFycTB2ai9kWkhGYU14WlF2dnZYSEU0dTlEcVNZSHg0cUpiOUhLNHJMYnM5dTk2RG9xUmZiUnVzMzc4ZDVzTnZ1
ZHBPQ0VvVzM2eWo1ODZnL0pVaU1WcG1pKzN1Q0ZVbldjcGEvakJ5S0NwSzd4UTFhVUN5WGJQWERZWEt6bEU2bkNCRHI3NmdqWnZD
emlHUDJ6NENLaHJsb2lENWdGNzdOVlpqOGQ2U3NVekF3cHhscGFoME5oVmJkMklSZERpZ0JHZlZwRzN1bFFuOXNzc25wSVNtdW1B
NE4rKzIxREd3KzFmL3lMeSt0RmpZTkxqLzRjajNMZ3haOE9nMHZmYU1HNVl6OHZYT21yNWRWNUxXcVN1SUZWckFGQ2ExakFlMnJH
YlJTU1psWTVhS1FLNTQ0VW1zY2pRUXhQZ09haXZhK1Z0akVTSk1PaWJLd1Zhd3d6Umxhc3J2ZHZVZlZmN21PRm92ZzJKc0F6V3lt
VVdPR01sM3lSWlVNTzcrVWYvRFRDRGpkQnl3OTdwSWJxSzJzbkx4NFVOSENxUlowVUVQZ2hGaDNiNlA5cGVjVXVDOU9mYmJBL2h3
TVhEdnRzL1l5dnJLQzI5TlBrL2xQY2JNckJ0OW1SMDNYK1VNRSttT0ZBNmNXcDUvWTlqTGFBdDAwdy95WUdaTjg0TUd0b0c3OGFv
Ullnc2dhV2R1bE45TUQ1UTVlY3dKUHJlaXlYUDNuRzZUWjNMbm5oSEw2SlliSjAvWHVwRW5lNExFSW5vU3c2OHBXMi82bGkyUHVO
WkI5bEhycTBTM055dU1KclNkNEhtTSt6N2FZZlJSV01reWtEUnk5YmRoZlFnd25wN1ZZTFYzb1NGYzhsbzRLUWNiZjhEWkp5elpN
TnhwWWpKR0lCQ1NhRlVhTU9NUThtYUxxS003RWtlNTZpL1pJMDk2ZEVSSE9EeFNibVhUcVkyQ015bjJFWlMwK0cwOWxSZG1ITmFP
Z2JDckRMQWxGdU02WnhobXpmWUh5bjNQSjhCbEhzOGZzbDFwSjdaQjlxOEYzR3VqNHJ5cVhqeE5KbmVBQjhEczhlTnRBb0cwRDRQ
YUJsaHZNc3o2MVdaU2U5ckJNamtwdnhYelpNMDNPb2xDU1c5U0dtdnA5elYzYnV0ZTNZcFBjaVdBTi9DbUFBUEpMUVY3L1B2Ym00
NmxxVFhiWGJnNnZTaDFFRk9uVEZ0aXBQb1VhL29QRHdSK3JtVE9wMzI0UE11dXBxM1FyTkp1L054cUwxUzZjTE9EMnBYRTFBTi92
M0dLWStaZ1BWOGxUNVN0RFdra09qaE9aY29POFRBYVNBTHBJOGJEKzRwVFZkOUFKdTA1Ykl5MnBrc0xIakRBRnB4R3I3ODJwUVI0
T2J4VVEwc2RuQ1pmN2laSnVmWnlyeVBKNkVvVnRObTdBS2xEandHcmpMOURVR0c3b3lqWEdWcG1PandtakFhcFZXaW4rQXNZaDVQ
UW5OdUNaRk1rczI4TExEYUFpZWhld3UxUVRYQkdHYmoxRktBeGNTbmlkV3BFV1E5R0c4RzZKSFRhbzhIa2NXeXNJejI2RFI3UVlT
c2V5ekRQUEczbDNFbGFzbzJLUDllMnJoRFc4OWNyM0o3NTFrSkY3SE82VHd4Nklzb0dRbWhhYkNobmpOWUdmck1OaVg5ajBUYklo
WUNBc09lWXJZUk5hNFRxU2Z6TzhKa1V1US9pc1I0OXBFNzRJVWZOS096cGx0Ry8yWC9TNmg2Um4vS2JGMm5KcGdndlBxRkNJNUxv
ci9SRmIzdVpoWlYwdURzcFpyM3A0OWRwUCtxT3FYS1krOUNyeUcwanpFQkcya3J6NjRpWThkWWtwSFMzdXJ4VndScXFaOEJEV28v
bWdQYTRqUHVBc3JBRUJFYXc0VTRlSzcrSW4zQmEzajRBVVNRVFpvbHFtV1dFNTMvRlFOOFZuUEw2aW8yblJ4VHdFQmxDOVI1MFZ3
T09zMFh5NDc2dENsQnBrNXllcThuQm41dU40ajVZUFBQaVFxNXVUQlVQSEJ4amM3MjNTVWNab0sveVQrRTNrdUtnNVcyNllHWkJM
c2dGWFJDNy91VVowMXJ0UEJUMTZxOGZBSWNrNW9nb1FtTlZYQytHSGhpQzd2NFl1T2N3VWdmNjZ4Rm5rK0F2NjlESWFEWFZlc0R2
MURNYzcyR2dXdm13RGdVNnpmZ2MrL3c1WU5NczVQMldmZzMzcE43STJQeXBPcjVGVnhJWnRwY1NFWnpqS2hScFdvVkpzL2NVUVo2
elZBM1FSeHYzZkkzd1hTWEhXT0NsaURoU3RLN2dMdW1rYVEwWk12SXhhUGpYTlp4eVdNaDAzTmR4U0Q3VFlHU0FwdDRnTkZMczhO
M1krRW52N1pNdkcxa0lUUFh1OW9aV01BU2FJaGlIcFBsMzJzK1RVcERMenFBY3l1YThWdXBnWTNoMWk1ME44ZXBObkZpVDlKOHVV
VzVRb0RlRzZvSFRSZmtRSWZVdVF4amxSQURCSVVkeWFOcEVxZFUxZXQwbVQ2cVZkdTEycXYwVzlZR0djeUphMGZSVWRzdFErZnla
bjh6c0ZlQU9YVzR1aXV0NHduTVNSV2hmeEprT3RBZXFpZGdzYTNtSENxQTBjRTJ6OXZ6SkJrSXNFeDBnbXFFRjM3UitWYk1TRVl3
Z3JIaDlNWm1Fck5yaUp4TU1kTTYwYkg3ZzQvWWxMOHVIenpIckRRUE9DL2E3YzVlZngwTk1qTU9PQUY3bjIxTEFXQ0dORTdselBD
QmdQVDFhL3VTc2VMYVNWcXdJazVTbHBMZUExejA5dXJNajIycnRHQ3RFRmtTS0JsejBrcjVPdGpZSm1GUmVQTmRDOGw1M0lGVGdH
SEpNTmlUa3NRRzNPMnlwWVZYSjJMbHJ5TEtBRFIySWs5aHlJUmJSWDhJUFUranJ0NnU2UGFxY1hNRzZsTzlScHFybzRwRzliU25D
RXhNNm1ScU0yNmhKbkduNjJ2NnF3TTZDUGxsWHdzVy8yNnMwRWlZaTNkOWpDTGVTRzZvRjJGN01ySnhNbVM3RS9CRG9TUkt2MFh2
OXFrenJ1c2ZZVDJIekZXc2pJRmZiSDRqU1RndUFIY2VaQmVkaVA0WVErbHVEdUw3QWRWVThFVVgvK3E5K21QVXh4aWU2eXZUTzhK
NklPd1UyMVJrR2szK1lTbEIveng3SkJqUEVDNmR2NWlrMS9Pd0M0Y0dkcGM1YlZhbGc5ZllLdVVjL0t1aW84WUhFb21JQ0xwUGdp
cVRVc3Vza2dYMTlaMnlJUnFPK3NWU2EwZGtDQ05qdjFjMmhNT1JjZ0hZU0hsUGJPZHJienNCRW1QYVpoMC9tT1NHbms3aDVLb242
VzNINy9jMFE5bEFEc29NS25MZndzWjIyY1Z3QU1yRlRrRS9Ya1QrUjBXcmFFa0hiMmV5ekhlcUV3MTJYbXd5TlFZUEpqQkNrRDcw
TVQzM0ZDbUN3cFBjajRIRHV4NnltSGJsaGw3ek5oU1UyelhWZ3BOOFdCUEtjTFlCK3d2NnQzQzkxM2xPQ1o1K3k0bGRsNFB2N2U1
SmJ5NHoxdlp3YUYzR2k4OWVwZ2Z3REhFeklFa2p4RXJxdnFXT1V3Y2h6bDZsWFZrcXNNaU83SmI2cTg2eVJpS3ZBVGw0bEJsa1pE
bHpNM25pUFgzaW56akpRT3MzcHI0SkkrOUhSVFB2cjFpRUJpbHlsWDUzaEk1a1BBRm1EbXVMSmFVaVUxSWtWV0JTNm1NOVEyNUIx
c05YbWJmM0ZNTElSb2JSeGF6SDlZNXpVbEVKendubmgzNkFaOUFhMUVocmVacFpDT25pVXlxK3dzTlVVc29kcytJS2sxaDZCb2tz
S0RCWFJ2a0RXOWpiN0ZMQlFBcTF2RmlUbE1mWXVmZGVWVlpPNzZwaTNydGxiR2I1eGtBZ0RLaVY4YUxGU0xsQm9JQk04MHFkR3JB
NVJUTjMzM2F0RHIvYzhUZkU4emltbEt1VkVVUFFVaUljY2gwUVA0dE9wZTd1L2tBUVZGVmtMU09VTEVtd3FNVlFBQnVNNlhaVDNO
Q1FIRllSOUJORy9mZGd1a2NrUkpxUktvK0FhQWUyejRRck1kejhWRXhXcVJocW9CdVdubC9QTjQxZnNvWU1Xb0ZVN0h6bVFqQmxX
aExxTXcxenliVk5pVjhzb0NnRGdDMkNsU0l6YU1CS3pLV3h5blJic0Z0dUlhcWRpS0c1eEh2RDdQZGpTRi9nMFRqaVF6c2xtQ3ls
THlLN1dicDJmN0JaVXNLN0gzdVNuWVVIVGJFWTltNjFBTUVpZWFxcml4TFpFbGo0T3lWYndaeS9OZHpXMzRZRXdKTmczbGVwd3Jz
Q0FQSEJYZWZCSlNaRUZTRXRqMEFUTTNVcDNBbUdqWjE1YnJ5WTlTeEwvUDR3K1huejNPeGdYc3Q1dzhwcjkxYWdtRmpRYjBZNUcr
QkZNWHBBamM2TWU4V1MrR2o5ZkhVL1BsekFPZHJ2dU5LK2JRbzU2WWxwVGRLSFZhL0VBYTJWNHZRbWxHN3VnUWNaUStzSDNZRlV2
dkVwb0xNS0M0bGJxdHBHNG1ySFpYdytIVlV0K0RlSk9HbGV5WDl5U25PcDcrQXZPTk1LVzA4aHI2bThITHdPWktkNTBqNmdySXFD
V3JJYkRRU2REaVFoYUdLTDNHNndYRGNlNk9RbC9DWUVsRDI5YTAycjFDQWkvQW9RVkM0T0c5anhHcktnYnM2cG9zT21jQmpzRTFP
MkRZOHBXYWRycjV5aFlZUiszMVpXNEwvYjAzQ2dmQ0x2LzZpdFFxanZoamd5NmhyeXpDVkpIcFBDc0hxbElQWTVzTDN0RTVHcXdD
NnEwWkJsQ3doeDNPR3M3Z3o0ZTFhUngxWW0ydkRHOG5VZ1lUSXdJcnpJempUMGtsdGJlY0Vkcmg5S3dBakIvb0VXc0MxRFQwVlU3
UjZBcEEyZ3piVU5vNmxUUUxKM3YrVXFFeENTdkdrZTdFcENIWktsNnNreU5UWDcxSzNEd2wrQjhldExKUHFGSHArYWwvbms3ak9z
YjR0NDEvNTdiaVFZcFhFSDN2ak1DNk5tek5VbXpzWVhsZ0NUd0FvUFp5ZVdpaHJjZFNZMnBUNnFEL0psOUZCb3ZKc2JIQWltNHpT
ZGtFemVhMS8zRmtjL2l3WWtodGloS2dybU9VSjA0MFlzWnNmSjRaL1RrMFZRWWdMSDVxOGhDcTJpUVdLTVhCZVJLdGN6YS9ja2Nx
djZHM3dtVmNiTzNiNk5rUDUrVVllK3lvNVNFVTJrdXVrUE94MzZ5NTNGQUNZcXJIaGVOdFFSSzF5YndCbTA1Q2tiODhKUlQ1SFRW
TTNCRlBFNmFzbUlyalU1NzBkeHJCbWh1WkZ0VlhENXMwRGp1RW0rQkNrMXNlTU9YYTFnMi9vL1Vmb1pmWjNEak5rNWVCeWhKbU5K
YzBEaHgyWWxxUXBnbXVVQkNYenQ4N1hmNmNuQUg0bFZaSVZoTTBpZ0dOaENVUktyNlZGQnNic2I5SUtzQU55RjI1c0pvVlEwdVU5
YW5ycHpDMW5kSUFZNGk3WXdCZ1hCSHZvVmxmTUR5RXhtbkN3eTZXa3YxbytIb3VhUVducTdUWklWcXF3Mlc4WUxIc2E3QWtjZWhG
eGdQSFJsM3Z0aE1jVjNVV2xpcjBMc1VLZHBSOWVFc2dGbk5qRnhyWDROWkpGVnJ0T1V5MHlwV25XczV0NG9FT0tjM2tsRHZHM0ZG
cGxoNkdrajZ6dDkwMEM0ZUtBMVg5enpGSW45aXVVdnFxeVlKMm5qa0hUdVRYVjBScHNCSUgwLzFKaDBFVnIvZm54M0NEZHVQSlBk
ZjBmcm85a1gxZFZTR0tiUGxMSW1QRS9HOVdQYml1VTdDNE5tczUra3E4RW1FOVVYeU5Sc2xSWGo3SHNpZDlacmpTaEo5ZmQrL0pn
d3FaYk44aC9VK3YzelV0VXZMNlNsTzJYQ2wxdlB1WEp6cFRGbW4yZmlnT0RRcnlmUmcwb25QMUJlbkNOaVZaU1I4WTYyNVpOMW1S
c1VNdzFyTGFCYUl6RVNINGJ1S1laMXdYdVVVeUU1LytUK255N1JSRnNWVXY5L2taTStFVUdrZVJNRGR5bWxEamlieDNJK09XNnJL
c0F1YWJXTm82cGlsTERZSU9jdWpHOXFmSVdZNHVPZUdFd1lFS2Jrc00zaDJhZUFta0RJNzkrQjRlZDIrcGRsZkREbXFKNEQxbFJO
eWJwcUo0eUpUTVFueUlrMVdUY29mcTJxUG5YMnMzWTNmK0wvNjhjd2s4OXRqYzZySnB5YW1wVXdVUzRsNFZtcHRmdDQ0Q0hjemdi
ZWNuU1F2OHdNYUx5QjkrNFphekxyYmZCZXVNdmIyWXcwTWxISTREL3dJeFppSStCaTBLWS83ZWhJN2NUYmJYd3AzYnJIS3Fpakg0
cmUyTHVSRzEveDBpaHdwOEt5MHFVbFFBbGNUUEVIZkJPZlhQK1JZS3h3WFVXc3RSTS9ncklRVUttU1FCY1JDTEZmWkIyUGNDODFs
S2N5RDQ3Y1pqTUlURUUxS2xCa0NPclJJOXFKbXBJMjZ6QkFtSlhWT29SZU80MUFnb1Q0NDNGVG9QNlFFbmVyTGN5T3lISmpRS3hp
TVJMZTRFNjR0OS9VcVpGdFo2dzRpK2t2Z05CNGdSZ2ZnQU1WSFQ1YUdRU2dJcW52bE1IVS8wREZkUW5VallLN016VmErSTB5OU9h
TFpKQWNQTWZjdlZ5cGRUQWlYK0s3QjFDbXNxVklhUHZOZS9YcHFJUEdhb0RVazB5U3pwSUZaTSt2Z2gyeUsvaVB1QmVqdXZhWXBL
TnhxRmxldGFzZzBldzg5OVR5QWU4YkRWQzczQVpVRkViWkRGWjZIVWxIcE1qWUVhNXMraEJMbndreStKRXV1MWE1Q0xsVm5jNFc4
TzFWckozRTNCbUYra3JpR3JYNi9CZ1NUMHFPamJvWlYzRkJXakNIUGE0TTNLOG94N2M2cUZXc0xoNWNDR3FGSnFjd3NoUG9CVjZZ
ZDk1TElrc1N2S1grVzdKb3A3M0Z4ZGVhVTJHT0RmUitpZEt5VHJ1eDh2MWF4cTBQOXZGN2VXdE52MkVFZmFLaHNKcnMzVXFzeDJr
RDhERnRqckU1dHN0dGh4L1dCVC9VbVlKZUdxUUNyd2htNVJZVFg5VXpVcEpxUVVyb0U5eEd6Z3NNd3BBK2NSVE9MNjNzWFpjVGk3
NWlhRVlFL1VUeFFCWnB1cHNDN2FEYit4VlUvNjN5cHJ4Rko2UWhVRm9sbkNhNnZZT1A3Zkt1QWpFaGxWSUpyTFpKbC9GZWxFelU4
b0FudkxYTTRkeDNSNWtGZnhpRlUzWGtYRmxXN0E4MGU1cXVMUEZMZkpUbkhnbjhSTjNRZ2FNVEticFNMaU1vc3A2bzExaTJFVi91
UW81VlVNRFhJejJTNWMwTkxYZUIrd1I2TkN6d1pMcDB2Zm95Q2k5b2s4VTNCaVA2dTlnZTRhRWlRNnkwMXd4UE5ETzErVXVmU1M1
R2ZreVNiSXpQcUNYaUJ4MWZwMjhPYzNEY0FNaGR6Zm4wMWMrc1kxcW5xZjlRTEQ1QUVPNW01bE5ZUFVMRWVkMkorYisxaXFVQ2lX
a0p0TTlCRHlxK2wrZGhZWlhGR0hBS1c4d1c0QUxIeU96UjF5eEJsb29Iamd4SEljUmZIUnVlcWxBclp4c1lodE1oelZWK1Y3TlpJ
L1cyTGsycjFIWFl0YTY3Q3YwNU5tQ09sMm80TE5zQUFFdXdrZHpJU25IUFJrc0NsWVpOenBMcUpuYkhSeFpQWDZLeGlxd1hncklu
cXNwWXNjbG9YZ2VkOGVxYVF5R01pd0hLeWhwZFU3b1FqdjdHRSs1M0FYb2lmaHN1Mm5TRmNobWM2WFhJbjYzSk83ekpPb1o1YUYv
Ui9UalNONGlMRnB2Z1hHTjY1UjRvSFVKcVI1Zk43TXBVY3ZNY09LRXl1enc4SEJGRk1JaHNyZ05UcUlSbmNVMUxwV3lxSFJuMVYx
bmdqbURVVWFOZjdnUEVrR1AzVml3MmpKYTVKMTBqTFhFSnRMKzMzUjFFbjl6dkI5Sis5cXdmZVJkd3RjSzBxK2RITHh5cnZSM3hu
eHFJSGUzbkxWK0Vtd3JEME5MQmlxNy9Fd05FbnVKb05VM1YvQzhLZUJldUtOOUdnQmxiQjN0ZkFlYjZiYjZORFRlR2hFeUtKYWRM
QnIrVVRDNHIzVldGbGRUa3FnRkJ1bHZFOC9GbmZydWVjMTkxL1l6YU1xaFc4V3QyRnpVUlN2M1FPQWpvaERxeFRuK1l3OS85blRX
YWlVeE43K1RNcUlCMDJHRDJDdTAvTnRPRUZHcDFjSjgwL0JXNVhBUTEyZElEeEEwRFJMS2cvZDhSamUzQmlWa1k3bDZlVVhVakFq
NjFzZ2lmUFFHZlgyU0J1UW9qVm1Yc1BBR05CdSt2R2pxUlJMMmw2RmlJQ0Vjbk1naXFrcEdxOXorVGZIdXUyb2NtUjZ6SjZBb0Q4
M3RkN09ORlkrOHZOWkN0NUtBQ3NTSTN6Wk1wMmc0TkE5c1ZTRWRZN29BMmhZUythMmlIR1piY0tMTFhBSjd0MUZVVkQ1NGcrV21Y
VGpLWjBzVUN6SHJNTkswOWRsbXhjQjJaUEhpdWk3NExpWVZHZTJ6WS9tbnJWL0JJTU1oM1J1aytkakFKT1R4T1FDZXlFNDV6K3Ew
a1E2UGJBTHpuNUhaTTBMWGIvdzNSU2hCbXNiS21sQ1pFWDlGN1ZCRU9IdUJvbFkvVWs0a2ladUZueStWNHB0bmdnNU9lQkpWK3V1
YWZCTjZLRkF2c1NoNnF6WDJxNFRYdDFtWFVNbCtsdVdGdUhsdHhEaXFCWS95RlhYYU9vZDZkMWNjRTYzZlJkb1kzeWtvcjFneFhZ
RSt1ZG9HVzlscWtUdSsrNm11cERJQUFHK3pMQzByWFZsOVJEUmhuYnY0UE41bVFheWcwdFlBVko5S3RzeEtuQ2dsMXNVN3orV3h3
cWxsb3luMHFCOVMxYmxndGVlL0VLUzJkUVEvWjlNYXgwRkZmdHVubW50WE45VEk0UklUazVQK0dsS0htazBtSEZDeWtOZ1B2NGlD
elZGZG1ZY0VFeDN1YkFNZElMYnVNejZWb3VRZE0yeFdsSldocE5KZ0s4MkZidllxMUJPWlRDdEFiNWt5L1k3Yk82c3ZWQXptb3Nk
YlNuWVJYMVRXbU1qWkkwODVwUUQxSVkwejN5TmNlUXA4cUlPdThmanBVR0x5QkxjQkluNVd5a3FQOHZGck1pSGZhKzNvTW1tNTV1
Qm1QWEd3NzF1VnNnRlF4UzRYV245SzhFaFZyU3RSaCt2ekRuVTAvMTFWRXg1RTFEbjVocUYza05jaTdsVW5sWWR6d2V1V0lyMzNG
c3Q5UkhRRUlGZ3AyMDdOeWZXcDRDazV3azRjdjhmbEtiYzVkZXdnb1NWWXg2d0VUMHBOK3pMbUhaSEszTjhlQXJGNlh0ckh3UGRE
WXdpaTZLQ1JsY0hWcFc0WGVwR1pNek85elRLbXZ5QUtvZ3cwN3crUFh1eUF0R0tPWDBObFNxakNBNmR4dkNRYzBKRWZBc2NTeXFr
Q3FPQ2FXUmp4VUxaRDYxTkJLT2tPdURubzlPYklJdWpiTzRvZzRuNWZWTVZMa1pIMVhzYldGaFB5azNaWml6OTBTTThUbDRvVm5i
akg5ZEdvbXJJVm53NHpLUE9ZV1IzNkpxdG1YUTU0TWswVGVqN0NYeWczRTlpL29NZEFTQWQ4c2k2bExGTkg5WmtBMnlJNlppRkhz
cVViNnk5REtBSU1wZmJ1a25lQVR5UmE1ajNsZk5lN21QeXhpekNlN2wxb2Q1WjdyeU4wUnpRNEl3V0tncDU0WFZvL3l5bFJzRkoz
U01qRlUwamp2TG5JQWNnUk9UM0wzZWZHbWljNFlrdlVwVWI3YTZaM2VxdU9XOURDeXJSR0V1WXBzVmJKQW14bTFVVXJLSDdFS01Z
N0QyMTRYV3cxK2wzb3VHR2JkTDhhUlZYTUVaWDlUejVPbmpQZ0ZpWmlwRUt3N0xGcnVJdVNpYk1SOE1sWElVcmNXcDdKOGlkVW11
eC9CT0IrYjBSUjlnOC9zeHdqZ2E0M0p3a2Nld3NGamFFb3IxUThKYk5iUWpVMXZqb3hSTnJrRHVXNmxDbmpGU0ZacVFVSG4wbVVY
UTcxd29pTGtIakdTMUI4R1g1bWY5eDZpZUh2VXkzRXdVNHNqT0VUMUd4bitRVWxadU9Ta2tiYm1haFJmUlBqVFFZS1Q2TmZwbzA5
eXQrTjZRSTdUTG0wVmFEaWpkZmZDZEtscXVWSEhzcEgySmRlaXpNN1ZzZ2Z1R3JDSW9IRlBEOXBuMXRGU1Bac0s1b2FiVy9ueFN1
OE8zN0ROTDM2eFo1dTBSZHY1R1ByK3QraXlKeGRUM0lTaGs5Um1FSkh2Ly9WSHJRVUlkTTFWR0QyMm9yWElQYUxsMTJwekdSVVJz
aUkreS9jZldUcXY3RFpvTTdhUGY0UXJGV05tMTl2QkZad1NQN2JkZkRGTXZUVUFTUHBLOVVyNy9qdjZSOTJmNXVWVW9NZU53QVNZ
R20vNjBRbXpZTEdQdFhDTnFiL1MyVGdxdHB0K0ZET2l1Y0N4TXNiYVFUazdnbFFCNXJzZnhKNUVRZG5hWldyMW54QzZUWDk1eCtE
VElRazVNQjhFWkczMHZXU3Z0ZUlpTU5wZG9hbnhuWmF3QnBybnpoNWJYdXk0NkRXd0M0UG4xSkY2bElaWUVURy9kanVFdFFSdE8x
ZFBHWHJUK21mSkVoR2ZscVR2a1ZsM1lzVXZSU0JKYU5uNllMblJ4K0tLOVNPOEtna211enlnY2YvRkE2ZXBHQ3RmSlVuOUVuazNs
TGdVSVF0T0RJVGQ2QjMxYm5WVkJGTTFnZlhIeFd3WG5xOXlSc00vakE3VUg1Ym10RmlpV2JiTXhnbm9OQWgzYnVFL285dDVBK3da
Y2wybnhYVmYyM3FwamhvQmxNeHRRSmY5WUtpeWIvVjJ2VGo4MXJYaTVyMXRoV1RlQ0RTNzRWK0ZrdTZFalNEcUFYWEtVTTFrMTh4
VTdSMk5qd2lXVkkydnFhOGIzSFBpOWl1RWo0eVNLZVFVYzVJTWJmdy9kQXBPMEVxT1JlRWdzek1BVVE1cFhkTlQ0THlJNGFiZG5X
S2c1dHZ5OGpQemtjNGtWUHBZUElVZXM5SENhd0pyL3J5TTZueUhock1xNlRNMDZwYVVQbWpPeUVUaW5nemJEVFpTVlp4Y3VESk0v
UG0rdlEvZFVBbHBMQlc1WllwRXExVFM4c2xXUVRsRkNoUmNhdmRaclVLQlYxQ1pxTW5VYy9xUEhRR2lxYW9NMkMwQXZaenlaaXJl
eENGUTRZVkF6cnhCN3RjTmdMSHU2UEw3M1NtNWJZaStmZ3A3RGl0RVF5N0RFNFBUZXZpY1lJWTRNNjBFZWhUTS9uWnJrOU5VWnRD
UG10VHl5OVdDTElZeStQaUhiRTV0dWJGLzBsTjE3bVJGU1pYK2lDejZWT1ltK1hRbEZXS0ZhWWlsTXJiRkczK0hWY0J1TUhwR09N
aHFpOXNxaTMrWCthNVo5ZFVQcUloV1FIVkNCeGx0SStGajVSQnNhUDl1Sm53R05BYlI5bjBlREt6eFhkQ3M0elYzYkdzRmgwT2lE
U1E2ckJ3eG03enEyd2tIRlA3NnlENXUvMm9CQVRlQUh6RXViMm0rNU9VN1kwdmVTd3VOYVZwYmREeHBVdWk5RW1aU09qQXE2RTc5
Z1Vrc3VBR1BYdHk4N2RxSXludjJZR0phdGJrOEQwSml0MUp2R0N3aGVqNW1Ha1FLZWsxcWowdWg1RzNnckRreGNacGNqTkNvcDJE
SUw5ajZWYWlhN21BTWQ1MDdRckd4R0tEczI4ZW56QjlPcWp6VWlzb2VKTzBCbGJveXFYV1Q0SE1Wa2hxQ01xYWlkb2k5eWg2UENE
UkFqTW5FYWNJTUprblR3SFB4eElTS0Y3Vi8xMGhHeFN2NFNPd3R5ZTV6dFNsbjQxQVd6dzZHWkhyV2NyclRla3FYMnl3SGE4cnRV
WWxFdjY1L2VzOFJyanAxZnN2cjFWclVoTUJIc3RjUkZYamxDM2lTamZJTnNqeFh6RVVmQXNHMVBoR1c2azg3amM5RUlGL2lyU1Bw
NHNBWjd1WFZyWlIzd3NobG93MkYvRi9uaGhhTHcwMTV4RzlINWhIaTdGYUFmUWgyWUNiZENBbnhwNThIZnlhMStUSjA4ZjlDSmx4
MWd4ZzZmVUNxT0NZbjFNSHVnV3didENIcWE0SkhiYjI3bndnSW1jLy8weFVxUFJERlVoQ2NaOU1EUm9LVi9IUG9NQ2lMZWFMb2VS
SkthWHpHZXRrNU05a0J0SkhIWk10b0VDVldsbkduZjVWZVVERlJRUVRpN1NPcDhDQ2RrMmNydDBZWHpKdElEbUN2c0Y5WEduaWpP
UGFqc2xySlJmemkwSjJMdy9KdjYxdFVuOGFVLzVxTHZuUDROS2V5eFVoME1NLzNtYVdjcDdnKzdMVFFsbmpMek8wVDNSbUUzTGs4
YXFiRVdiTFBDR0hsWTBHNVBEWWZ4VDZtdXhxcFhQS2RnNVVkMHJONDhmQ3ZCbXNheHlEYmtlYy9OaGN5ellFSHdzY0lML3Q5SmlK
V2JJTjZpV29xQmlKVThOREtnMzU3T2lITWRZY05jWGJGeFRFMS93blB2eUJwN2FMbEdldkg0RDUvRlVORHFGbzFNYlc5clVDU2VX
VUtIYnlwVEtLNlBVMkFCNkQrZVM2UWtCRHRFT2dCTTRLelRsVlBIQU5yb3hPWTRvdTNRNnFGcW1QcTBPc0ZFVGZHWXNVZ3NDaEsw
dnNjOHYyNDJVZUFZM05LVWxvbmFKNTJXY1Z3RnZEWEh2WUVGdng3T3hveDZNYXVPU0ZtUnl4ZVU4ZU9sSG1EZWt5cUUwdXYyMXJG
N0ZQVFFJRHJmSm1JODIyNEY5YXF3Uit4c0krRnJrN2h5eUtlT21OYms0UlVXVURMSDBHcGw4MWdnb2IvRmY1VHFkNlFMa1dqbE9S
cCsrUmwxd0x5QTFKL2FodnE5TGdQRlhhRWEyYkxSVDBpQkoxMmNlRGwweXVuSUtKbUtrRGxvUE1Hc25NSkl4WUVsWHUycldVeEx3
QTQrTkVxYXdEVFpCbEhGK1EwRm9jQ0JFNUpIampuNnZudDZZdWlBMjdhOHdScVkxL1RZc3NkbVQ0cGIwbjlLUDAraXloQ2NDUXpo
RkhyYmZDeWppNEx1blRDVGpkOVM3UHlCMnlaZ1MxU1BSbktPWHNiS0liNk5wMGc0ZHBsaGtwWU1aWEZONmJPZVRwclNDVTRqWkxQ
SGgxODgvWm1oTjNqcklhdmNNVnRRQkxpMGpISlJZbEVReUFtUC9YM0U2QmhZTDdOcEsxL0Z0NHVYa0pRcjgwRUZyd1ZxclV6R1Vh
QU5zNUQvQ1hmMTVSL2RKNm51Ry9CanhONDVQZGNnMk8xNFJkRFBRYjhhcnZWUGtaZUhlZW1YSGcrUmlCRmJuQTBzN1RxaDdqajVv
elBVWFZiRHcvNy9EYllubHpjZThXazB1S3dvbXFHYnI4ZXA5QXFSajhVY0tRNUJPT0pKWi9MTXpSK3c4V3lFbkZIaGlxSW1CcHdT
c0NOUFRITzBQei8rYnBvazNiemltYWt4RzNxclo4bjdicHNhVkExRnFuTUNPdGpwYjBkNHovQzN5QnZnN3N3Y2pSd2J4L2M0OUFF
STdURSsyNzkxSGhDcG1pb3Bzb3U3YVg3VjJhdHRuK0NnMktaYk44Ujl2WWFxUWZBamlWS1g3L2ZjVGRoOEdLQytoSGlldkE2ZVhw
UkNnT2ZHUlpaRDhxejJteHgyampiM1ZjTEtWdEo4amNyTGZ0UG5DQmxkQmo3Q011dFhFb1l6UkYzOVU3b1R3dDM5TFNpRXZuL0o1
ZUlCUGdDdnF6REVOczh4T1JsYlM4bW41UUJHcnNzMGwveXNJc2laZW1vQnZtbUVFR1d5NTlsb3I1ZHpheHArR2tkZHRnQzlyNzE0
V29tNWdUMTJBV0Q0N1EzYzdRRG1FaXFJRXhmUXNIcjhSY3UvWWwwNXFRUGs5QWpONlFpTHV0cDhady9HWDV6ekpabzI0djdJMzVL
emZodHlabS9HakMzN2Y1NHhMamoxZWNMZ2xpMmI2aG5ZWnlpMmtBQmZHREFZcVdjZzFobmRlSVVIdzREaUFHMS9jVG1BUE9lWXQ4
aHlyUFAzdmI3Y0thZi85YXNRMS94b2V2THFTYkJ5V3l5by9odVJPK3U2Q1NqYzYrWjF6TGhyejZFRjJQVGVYaDYwR1Ird2dDQW51
VWRBR1ZaSGNXZUJoWTU3RXcvWjlhdFQzbC8wMmpVNHdkcExkaXpuekFiRmQ4ZUNrQ2FyQWt0TWlUS0NvV09RWDFHYlVacHJBRW9p
SVhpTC9WaDdGbUNwOGdjSytaaGRpTkdkT3ZYc2Y0QUdsL3d6UzdzSnFuSjQzUkpsVDA4UDR2bUQzalY0UkN2TUZnQ2hkUHZ4QU1u
NVhFRHc1NVV1dkM1R2ZDV2JldmhXdmYyM1pTWkdQUlZ4RndRNEpmeHdVajVsYWZvTDN1eXZHaXhBMDBWSlM5VXl2b0w3VjZoa3ZF
WmFuQWhXcHpDa3FPVkNvVm05WWxqd1JYeXg5L0RTMWtXUVpUNXVEWlJhMzgrejhIeVV6NlQwTm1mNnR3QkZZSjlNWUNLSWtsVERB
NFpld0ZMYkkrcHlvcTZYUG1DRzRvajh4YXFzUVJxc1FuMVN1ejJhMmgvakdVL00rdFo5TGUyd0FRRWJiUnhzQWdBUkVicnh0Vzk5
b3AwYnZEbEVUK2RxTHdKVkFqb0VsdE10VFRsd2NCRWw1RG9kSkxJZGVGMlZBY2wwVWdDTi9uK3BNc0x2OW51VWNteStTSzBNcWhT
UEliSHhzY1BhNFhTZXVJK1hxbTRpUGFPSHZMNU9oSzFCaXhabko3ZEdFeGhpK043NDc0VHFwZjJscTI2NWZtdkVpUGZRcFl1Vi9h
WGt2OWl5LzJ0YjAzZ252K1lIRVc3bTlIMzZlelBPRG96U3hVTUVVNTBUaC9EYmdRb1hhVkErN3BIbWVpMWUxOXpKVXFLV0J1T1V4
R3dHMS85aDlUM3RSMzNZSzlua082ZVlHYXJrZHZkMlVqQlgvK2daRk9HU0JkTXhFOVgrczFvanhiaVF1V0ZDYVM2cUFuWXc4a3pW
OERvZlArUGZtdE5QeFF6NEtiMmk4bFBpTGlWMDQ0YmI2alF1MFhscFVtWlJrOXBlWldLZnExQzErYXQvR0xNVWVXem5ZeklETW9Z
NlU4K1VMV0Y1RW9Dd3UyN2lraDhkdTJ6cjFicWRoUXUzejhwT0VXNFRJcmZSRGVWd2s5Vm9WVHNSd1crdG0wSU5oaGRieWZvblZN
b0RpYU9pRkNyNjJUbkt2TVBpSVFCTlc2Mi94d3BBTm0rbndYT3NwaXJCQnI5Z01RZGNXcEp1R0VnRVRrL2k1T1BVTk1hTjV1R0I5
ZC92VmxrRDB1WUJocmhjbGs3NC9JZDN6WWtDTzNnSXZkTHNwNkR6NHRLMFFaOWkxVW5XZ1pRNjlsRWpBalhzc1hNVlJMSDRSU0V0
b2JSbVE2S2tyZXJZdTNjWWQ2SncrSGcrbm9jeXZDVjNTTWt2Nk5LNlQ5TlZXS3lIMGNyVGFpK2YwMmRHWW90bzVPaXN5S0VXRUFQ
RmdUZ2JtbXh1UDFYNE8wN0J3R3hCRU96Qkp6TUVibjNCR3NUM0ZqWDljTVVNd3Q4RENWZTJOM0pEdUp6VC83TnR3U2hPMVk5MkNN
bjIyeEFTSGxlS2NkYXVvK3V5YndsWnNuYmhhT0Q2VTRzSUl5Y1lKWkNJd290V1BwOG45WEYzSHRhdExmNzBpdnAweFE2Z1N3R01W
S2ZsdHJnUVZ2Z3IxWnFDRnpnU0Z5U3BkcDRLb2U5NW5tSEhDVzZ2MEVCMnF0My9wMkYxNTRoc01rSFprUTRZbG9QNjAyRTJsNE5w
Mnp1MEtnb2xZNGZwVDF2c0xVSVpMRFh6cjZGc3Z5cDh3emluWDBrbXhiU2k3TitKaFpTRDhEcHRDdEIrbGR2UllpRjJkc2REVFp2
SEZFSlo4ekxwZE1IR0h4TzlOQ3hBcC9oemJsdm9ncy9uNHV0TzRURmdaVnNGTjdJZDRNTDZCTEdHZGpwVi9ieEVBOWE3K281ZXhu
WkZzb2NYQ1NHenV6Q1JDa1NRczlsSmg2RVEzd3FFNXlzdUJycjJibldtQndBK3dhMHFjNEx6eXpCQTl6bE11NmpSTW1rYktRVjh6
KzY4N1JmOTRTNHhLQS9CZGdsN1RQK3ROK21nNHk4eWRieGZyb2Fvek1yNUZKU2NCWWR3RS9ETWRTcnJrNWVIQU90SE1kMlVDTGRJ
SEtHejVSSzJzRXlpYTIzQmFsa01RRmovaFB4YW9POFp1ay9yOTQ2UHE0RUVpZjNBTHRLVUtVY1ZKUEsrVFRwZHFTQU9WdllMNDUr
aDRRSnJUU29BT0tsOSt2Y2xBS21sQ0ZCYk9xL3RLQlJRemxxb2t3anpsNE5nc0kvUmdxVWRZYUMvc3ZCOXk1SDNMaW5qcmVPb3Zo
WFRKSkh6aVMvMno4TnZUSTRKTmdhRXVWQ1hvdXlzK3JkSDhtbVpsTkhaM1lqbU56NVowcW1xVGFiR1JyMWZjWDdId3Fyek9sU0Ix
Rm5jRVJXV1N2eHBsdE5Fd3JwU3dCdUZvUngxVmJwM0kzNmJJNU8wb2JCN1RpTG53S3lqUlJESG9XbmlZVFYvL0lwUE9ueEVxMHVK
MnArZmxuVW1NcjhTdGdlQjQ2eitkOENnQXNzajJDZERwL1d0WnFwUUVuckFScmRWNnlDQWJIbmoxRlRkUi9UQVM3K2hJVVFMVk1a
NFhJdnp0VDV1dVVoWEgrOW5jMHBQaEdyMnFNdm5kdU9VZGdOMXB2YkQ2OVhQTUpMSnpiSnd5UFpXT3ZEd0VUR3hjdnAvajJmeklE
OURyNFJWRU84RmovUFBiVGN3WGNOb213TXkyV1MxZEs0SjN1Z2twMllDajdId0txWkN5Tm9vZmFOSFlTSXdMNjVJcng4NmJaZGNX
SnZQMDY2TWxhOE1HNWs1YzFtbWJXbm1aRU1ESXQzTVJEREVoc0N0ei84ZGtuaEFIVGRmck5TeHFLV2QxUVJZdGQ5N2ZXK0oyUkJE
VjlRVVNvdjlVZVVOTngrQlVFOGNsRzBnZGlPeGlFWEtJNVppT2lpTWdzTGtmaWluMldjUkZZQWJYSTg4SzNEZVZCb0lKd1F1VXB2
bzZvYzlDaENmMzR3YWVWSVBSSHdpVE5SQnFWRmNia0RHTCtyVEVjSXRmUjNDUXNhYWpTRFBiTndnLytKQUdsZndNNlpNMnFkY29Q
SWhXZHVTREY2aXNXcWNoUUpqSzRYQzREMFBQUG5TQTg3clR2ZjZiWnMvRkdRQUtJeEVHY2JzWU85c2NyZnF2OXo0Rm1yZnRHWHVS
bXA3VVU2OVJLeXhzYW42RzQ0THN4UHRlUm5TM2RldkpQeTZlK25COFhSUlI4SXJlMjAyekRLOEJUNTZpR0JiWnFhazdqSmRkQWJn
d0Nrbmc1Rkw0T3FtWUtnbGxvOHJDb0tZZGVzaTVBcEhOYmVmSWVBUTdHUzhRVkV6RXhNNTAzUzRsNWlhcGV1cFlPS2lzNmFGalQ5
ZEY0eUdIWUZQbzNhYXYzMHZsTEtiSnh2ZVR0VHNPSmUzbW5VejBIQjVXSXZ6OVFpM280RGlRQTdYSE1Lem5YWFEyZ0FkTmFieHFr
UmZTMFgrWVpEdlVWQmU1V0pycXd5UzN5ZGkrQjM5d21XN1pRN0JwM3QyNUhKc09XM0RnWG4wSXNvQ1NBNERhZEVNOXBXZ3JSSnJl
eDQ3M1JIYWhJb2RpbTZDKy9iaHRsQSs2WnFpOU1vcUoxV3M4VkxwRU5wUWpTTFJzamlJZmxGbmliSUkrTUNZSkFLeGlvUWFWQThT
V0lod2RjaDBkTHdMZEtDa2U5UDhPL3N2RjhwQzFTTUZzZzdWbHlFQjdzVkYyM2pad3kzZnFDTGs3TXREazZXMU56MHJreFRqcDkr
Zi9KMmk5d09KR2NBOHYwQjQ0SE1JOWRmSS9hY0d1bW4xbGJaa2Jua1hjaWR3RCtkRjRyUnZvbEtqRE56YkIwVnlPNGpmRjVUZVRS
WXJNWXpUNHNkWXl2ck1BcUQwLy9DOGJJVnZnOXFTNHJ1T1hycW1XTEc4SG5zR081MUlRK0laT3FBN2UyRS8rVmZsLzR6a2lXMmpE
S2dZTGwweDVHdnZxWXNzVm5TQTFHV1R0QmNGc2RZU0IweHArdXNIb2NPYWhTYkdXTWQ4U1pUajZGbWRHbS9CVnEvdlE1dE9SbkNB
OE1sUy83TXZ3SlMwVHVvL3dxclNnRjRmZzNQZ1IyWjVDTGRNVG9MOGlKeWtTWVEwTmhjR3NnamhvQ1FONUtwRTV2eTVnc3RjeWJ4
ams0QTJJYVhocFVyek5HL3pQSTRqYXNqTGJUSC9HaHN5dGZydkxNdDRpeFJ5bXZPM2YyWWxhbWkxSXlNS285WXNRU1FWaG50T2dZ
UG0rb2lLZ09JbjNBbytMQSsvZDZvTm0vaEhKeXVTZ3RhTEFDaWtXaVV1QW1CS1JUQkhrQW84TWs2SnRycDY2ZHA4djM0NXI3dGpI
MkdMcmRINHF0SG1RL3ZjSHdQU1pTbnlxWnRPS20xcE5ZSkxqZWNNRlA2dXVaRXpKN1FQOWZBakR3cUZPZytJVWVlNVdNN2x2U0pj
aVAzVDRLaFNWaGpnNEgwcVZtNEdSelI1RXpPUzZIb1R3bjR2bEpCb1Y1bTROS0hiQk9YL2ViSEYvSWMyRlkxRHpEb1RqRGl3SHZs
UUhBamp2dWxYVkEwV1hQaEkrNVVvQTdwRWpWTU1OZlZoVSt3eXY1WVp2Nk9GREpYYWxrSld2ekVtSG9SUkhMTkFqUDh4aVVNMWFF
blBEWUxpbjJkVURoRE9OeHVlSDJaSUpWeUpQSWJBdjRMTGxxUkI4YldnY21OUWZ5bGg4MXJGZVhndDJJa2JmQ2s3K0E2dnJmR0FQ
OXlhK2FQNFQybzFKR2NQbFUvR3ppK0lIQkZvT25HdHpxOXl0cDdkVVhrUXFIVU5jdjBoZFF5cTJtSjRSVDVsT1U2eEhYSjNuYjcv
RmQrbXBtNWlOZ20zSmdNSVFJamxpNFZ4cUVLMjltR1VVQk5WalFlRjNPV2hkUDBBVDBidFdDcnJCakUvZE54U0JLL1BOd0I4ZzVU
TjZqdWxJbTFUN0UxbUkvRndLL09zRGFBWGNwZFQ1VnNLdzBPRWZqa0FnU3p6S1NJZEczcDZFWENtQ0dEMGVhbG44ZW5PbjdLTzRV
L1dXNmpDcHFqQTRHcTRoTUJ1cW5KSkx4TDNSSUdqNGhyKzJGclQ2V0VEbGt5TFFBV3ljZDFqOWZGQkMvSHRUTFFRTEhJaVE4cTBr
dXpRUEUwdVZjTDNlNWxyeUJCNE05Tlhiai9iYU56bzlTQ1VNUW1yZGJ5dDUyNnJSNWtucVh2TGIzSUJGMjl3QTFndEpuTUd1aEpK
Z2NhRHFTaXBONC9YdnZTVkpmdkpPbW9kVHF1dUJsWUdEMHpRVHhsNHdROVY4RFRQMG5SaktsdVN2dHpobFF3N21Ic3ZYdHVnL2VU
a241WC9IbTJhZ3BGTWluSzFtRk9jcHRZSmV6YzY2QW5MYlVwNWlLTG5DZUFCR1ZhQ2xUV1QwakV2M2JjQUZmSE90SG9FNk5RYkQ5
SG5sc3dyQVFEeWxiQ09nWGc4ZjNOZjdQSHMwQW1qWFZLN2tvdlR6dlJlMWxUWk5aaXYvL0t3aDdBblMrNldXOFVJZ0R1Z2dRUHpY
WXhaRHU4VGJ5NW9qVDQwdEo2YklkSTZ2c1RUS1YwZmg2bkhiamRyUHpBOVpXb2FpNDJRdHhNNDIvaFVnOTdVUWgybEk5TnFCM3JQ
UFE3dndJRGduRlc2aGpLUW1KTXltajRUbUg3N2U3QXlCak0wVVFvTDhyclRFNFdKWUtTQ0Y3SW1zbWJRUVRFZ2l0L0pPcHlmNEJt
ZXA2RkhlRlBSYVM1Z3VWeGQrZXdNWGsySjlnMC9SS09iMzRtaTQ1V0F6cldpTDNVWjRhNm0yeGs1MllUUEp0L05YOVoxQ0EzZG15
SUJyaHRGN1NqOGlmem1mVDNoNlFITWUrUEpoYnFVK2t6c2lHNk1GenZ1Ryt2UHNZVlRvejFEVmFpOGpyL3AzTE0yU2xub2tuSno1
ek4xWE1veWJ2MFI3RFJSTlFYejRwM0NqN1JoN21PTUk3eXozUnhoY3laYWxsTi9HSkU0d2NMWEh4T3d0bnNEQU4wYUhuUjFDbEdq
NVFYQWdOa3MzdFFOa3RrYjcvTGdGenkrczZuNVo0bWg0K1hCdi92ZUxRSU5DcnR3dWZHZ1JUVTVYNktib2hzVzJqZjFJOFhnQVk3
Q2xZb05KeFgxWERsQ1IyalR1Tzd5MTFCRkxTTXkzdU96cUgvLzdoSnhFZ1JSeWJpazdVdFVOMFVuRjNVREtORmtSUUh0Lzk3UzNR
Ymt3SjlCZWY5aE5SUXdEL2hQV3NwZHVEYXFlUTQ0L0VKbDVaUm9IeSsvbkFwSW40RzFDZVArOTNHNytDVEdZQURoTStWUTNKUXJs
N244Y0JhU2NZd0JreVFMNG43bjVtYzVJbnNHdlZVOTZwa1FZcGhrMzRabzloejBRL1NJSXY3TEM0MzV0WjZhNit0a05OWVAxbkdt
K1Vxa0R2RXEyNWhvM1ZSTW1zM29ObGNmd1U2d3IrNmxENmErcVVhME40b0drdHFLeWs5dXhJa0ttMWM0cnRuR2lMVlI0SjJYK2ps
emREN0Z1ZXloU0JzMWd1aW15TGVLWExlaWhRRWxGcXQ4Q1BheXZ5TjNQcHdNcDdQemtrcjlwVUx4QytnTnNGTXlWK3RBVlhSTEdN
R3Z2cjRIblhkZlM3bWFIdFlzelZBR2RvbS83LzJFUVQvMlN3NHR0OTJkRG01SDQzVTY3ai9vQ3g4elpqNStMeVhUbzlpcEMvMFlm
Z1JzV3cyVEx6dmNmT29VeDBLWUtMZVExWml3dWttZGhseTdxSFdCS3JHbWlBbnRNbEJlZ1lScU53cEJaZEVMN2FQd3d2M2RaZWNR
UWZSTko0STdQRG1pTGM2SjVaTU4vYlVodlY5ZDJXaWJ2ZEhQVGsrMVkyVmhQa2ZRREt3WVdUWnFDa2RoTE9BYU5DTEpJV3JXZDFL
N0FhaHlMZWtKYVhZc1FwSllVbDVVc3hZTWVRd3lyOFFIVHc0L3pKRURWZTdVd0k0VHkrQVl4V1VmbGdGNk9DcUtRMEJiT3pCRlNn
TXZuL1JrUXNmdG5mVWRZU1ZlS29OSDNwRHZJQTV5WWtOcGRnUGpoeGhuTGtMVUtMaE9oZG8yUFM0bXFWb1BrdUJSTmFtSklHZXZo
OU1tR2ZYMm1qRlNva0dIS1NTdnREc1RzN3MrNXhJWXpSQWd6VTZKZk1iOFlJWnhGVEZkOHR1Rk1BVnpEY3ZveTdQbWFBM3RZWHNJ
NWl6T09iOGFJOVhGS2g0WC91MEtvcUlVSXJFR2piREhNWmdBR1FXSkl1MzFQa2VFbzE1TCs0S0p6T0Y4WXdXT0pKbUd0Skw4OFlE
OVJmT1NBZVptdXM5QzhCTDVSaGJEWENFTFNRUHE5OUV4RWlsaVFVaVI3ZjVsc0hMNkNwRmk0bXRQc2QxZW5INDlhTldLSjBXbGxI
N1FxelJ5dEJhTkFwbDFRSy9XM3YzWm9TL2p5UW41dkRQZ2NnUTZLL3JUb0drWk5jSkFKVjArR1hvd1hyWmRERXg1N1BJUFBseDNG
N25PK3Bla2F6OWwvYnFKTWp6SXdNejRUTjh5cUxVWTNqWDFHSTNCaXU4R2RTVGdHZFlKM0wvbmNVYnJodDdic0Y0TURieDVmSzhH
NVBzd0xKVTJTYk1ydjlKMkE5ZzYwdVV0Z2Z6Y1ErallURmc2dG8zSWh3Wm1pOEtEeDBvV1hnR2kzMWhSYjY0VUVJV1dreWIwOHNU
SHRvKzB3OGRzUkN6dEhPQzBkNW40ay9BZGZXc1VxQ1NkQzZadnNHYjIwVGhDK2lmRkV3aGsweDcvancrMmNwNU83MzZVNW1QVElV
elp2bUJ1VmlYYzU4SmFycnNiaEFWcEZheVZwL0h6RVpoRG9pZ2F2N3dCOTgxOUpsVUF6WXIvZ1BhblptZXNsZjdMSjloZldwcW5W
LzI1cDJXcUhEWVF3Q3l1QlVScVlVTSsrZEhYQ3Y5WVh5Vnl5R3hFT00yajRlcVR1NGFBenBtUFNjREZSZ3ArT0RnNCs4dEdwakJC
ZlhqOFZITEVySnhTVnZubHh0TGs0RXFGZmk4b1UrQlBFd1l2UkZISzdGZE02U1FZV2tPc2xLSkFXSWZ1dXFWQVRwSS9UT1FZQmJV
UzlmVjRSSzA3RGVzUHpEeTFKNFBkVXBGMXByNW9uK1ZnRmRnRm8yTDVmeUcvaGxUVjE1R2MvdkJZTGJ5aWhkN1lqZWFodU5iZ2tY
M3NxeHZDVkc1VFRxUW4rVDlacXdITlZiSGFrT3AzMjRlSmg3UThQMFhxUDExeStGdjVsVnoySnp6ditIVkZVVCtZc1ZUNlcrNG5s
cXNPOGR1TVhFK1FxQkd0aHhqOEtPSmpMcFpONXJXeldJRm4rS3J4U2ExUG9mYmU1VnluL1cyVzZZUmVIU2xlZXBiMDB6bFZ5RUpL
ZVQ0bXBoNTJCZ2cwLzlPNXRKeGFWUmhSZEdNY245dUh6RjNDNWtUTFBPU0kwNUc3RlJGK04zT3RxQTFiODFsaHIyVTNsMDJPYzZU
b0FDaUcwRE10aHo2cU0zdGk2MWJOT3k0bVRoUndPbFlzS295d1YzOTc4eGtjRjZQTy9BS0dTWW91aWNPU3VOUjl4Ti93STVjK0F5
UEVqTUhOcEZYVjhUWWpLV0xqaStGU1BFV2dJbFhsQlZPbEw4cU12MjJJaGdROW1HeXlxVk82NTArUURqMTFRV0pudUFLb1dxc25t
TkpFWWZWekI4MitacERzZDVxOEpFVG5Cb1NsMnpFUHVuS2NXMHF1ZlZjeFkxT004akxGOURrT3RHUU9oM1hxemxOcWlRczNaemVT
SUlKeUI4MVZNZ3dUdHMyeWQxeFBtMnNIOVl0Z0xQVHZSeE5vaDYwaFV1ZHlzUFl1dXJpL0ZMcHgvRVhVSzc1SFIydVRCYm5nNkdX
d3pMdkw3SFVWSGVUQ29yRWRnREJwaVZwZFFUUWs5NUFmTm05UTdQMlNyWktQV1pqSXRGSGs4c0JPcmE0UHgvZlFHR0NVV2VxbHBL
L3hSVGM1NFJxTkh4L0ZSZDhVTUNmTzk1R01zQzE1MTRhV0gva3J6Q2dlN0FLUGpVVEp5V2hweHRLa3FnWTBVTDh0ZnArQWVidVo2
Visxcjg1NVR3Qlo0MWJzRzNDbFdWdXJkZ2U2UE1aT09GRWJwTW8wQjk2c2kxUUxoMWpxVlRsREttZjZwV0dTUWlQY1NZVC84WndY
RFJSY2pianB1V0RvZitTeExwdjBQcU5vck45SkZ6SXU1Z2xWTzdXb0EyTXkrRDFvZ3hTRUdERllxNjB3ckVqVmw0TDhrUk4wNVdN
MjRySnBVU002QzFXdW9KREx6MUtGTmtlb3ZxU0MvZ3NzZUFLSnBKM3lmT1ZIQ3pNUlRvMEVGQWFZZE5UWFVmM1d5dm9BcHpXR1lh
MGhORTBIaFJteURjZ1M5TzkvRUZGTmUrWFh0L3FVT3RTbENIbmZGY3ZhbytpNjZvanN1YmRUOWNieVIvQy94T1lVT3VoeGdLelEx
SWQrUWVNS2J3cCtETDQrcTRpamFHeDhQbnA0ZDkxaGFlNEJOVEo3bHcxRk9wOWE4aWp3RmMwemhQa3Z1NjJEVzFudWJsQ2h6Tzhp
NG9WL25PdmVZSlZSdmhsRm5sNVJqakQ3akZIbFV6d05sMDNFSzF3K1hqZW1hb1MxNldHUjFDb2UvMXJ1U2QrSkFrYlVESWJDRXFu
ZHVwQ053Ry9IYWdWWGZzUXlMUDRKOERtRXJMcy82RmFhblhOZ0J6Zkx5M2F5NHZKZ20xRE5pdTgyM1djQVlia2VLNjF2dzJqaXh1
NEdzUWo2SUYzTmFxYk1CUWRtcHh3SVZRcHlaNjh5RjlqMFBBR2JQc3hBdzd4aGtJVUFDNkd0N05rckJxVStPU0pFNlZoWDJGcVhC
dis5N005ajFrWm1oaFNGUGRNd0RmYjBJRFRKWXZiRDNrdFJEUWN4ZTVOb1ZRTmNSdWZYQTloeStFanMxOHhHSld5Qm55MjI0WllY
YVFmWnNXOVgrVmdyUGFDb2g1R0F5YklPWmVad1pOQ0t1K3ZmY0VhSld0eTVqb2ZFdjNDQ3JXclZvWFA3Y2NmVlpHb0c4Nmx4MTBD
eFpCci9yRFVpcWZjditUOFdrNlJuUXQ0QjYrTENLMENrbDVqRUFwc21ZOFJFYlBnakxNYTg3Vlc3WkFiV01LQmZLZnVNdXYzNGZ6
SDFkT1FlZTVTTytHaXJHUGRwRFRjZnhlZkhYTGRKR3JYUTZiZVVVUmxWdndPRmF1QnVyZDhPZEdzbTNyY3JhNlBoUjQyOTZ5aStS
ZkxNemErUGNTZjg3QWhibWZkMk5FNjRUdTkwNFNYOHBUSjBtVzZtb2F5Y20zUjFBYWU1U0R2aEs0NnZQdkpFQ3JrZ3Z6eUNjQmlB
Vy8zM1VCQ29BZjE4YmsrY2d2dGljTnBva1ltVUNWUG1WUVRENy81cGlLS1BoSEdpcGVab1JqNGVoWVBmeUZBQk9KWkUxWTJGUVFl
ZEZVOFJ5Z2hpMWY0TUZwckFINWVFZWMxdkduTG1UNGxPM2NDS1JhZHVmSWVremNVUXRrcm1BUTdqcnNwaERHSkZMREVWeDZKcjAw
bE16d2l4anR3ekpQSTZYKzFrZmZWZi9aSHZkN1ByTE54eHB0bkFMd1c5cXZpaTA0b09saDZTS3Q5REdPYVhydEVTQWtLQzExVndR
THBna3owNDljU1Zid3lRMWphU2VrbnkvTkFmMW9hWlNTS044SGl6MUR1Q1dLRmVNcXBlTWRjSmNvcGRJWEpZNkVZU01XUkZpN1I1
dDRqeDFYVjhxWUhkdGNZVkZSMWRzeGNEWVNha3lHaGlFL3YwVkFTNFB1NGtjYlJ6WTQvQzNKdGpPcnhueFFFMVRubFF3cS8xZUNE
bkpPZytuV0xESDNBV1Y4dVlka0lTaXgzYTlhQ1BoRE5PRVhNUkF5aVI3TEJYSnFydDBMQTV2akxXeTR0OWNGckFmaE5CdWovbzM4
eEFWVWNlY09WU3l0TnAvWE1FL2JINmRNVVg4OGRTaHQ1M2hKUURwZTZTWDBEMFR1NDFSbFVDZTd4MXVpRkdFT2psK0s3WVJiTURk
bTJtbWtHazZsbzVLbnRNMnpTRXNIQ3N1TjdPNUp1akRHZTROVlVxWkNaK2ttWksvRno2S1NwdDVHU3JyQ05QTlU2MnkrZXl2ZnM0
ME1ITUNoWlpJbzJGZVpkeU9jRDdLa1luamtpUi9DT1ZaOXZZbWhHWHF6YVNwRVlYZ3g4UFMzMkYwb3ZiYXdaMmFqVE1uejM3cUdr
MEJoNmdqYW1rY2NCN1pNc2JiWVBMcHc3SEUzdEFMTmJUUFJmTXlneVR1TEF0UDlEOUw1aG54N2VLRTlsc0xCeTg0Vmo3NkNBSE1y
dHIxTExkd2tKdm5XOGVYSDBhdWFhTGYxeTNhV1IxRElHbmZJYmFoSnF6L1hTeFRzU1o0cVovRjl5N1JuSHF5dUtlQWdXZGhsNEQ0
OFNPWU5xK3FpWksrdWR3M0U4b1IxRUdBUVpwMGhKYlFjaG56SmVNdERNQkxPYVBnSUZYbzJCaDFXcXBzTEhyTkd4RnRMSllJMGVt
Y3lGWVRyZGJRZm5TdGUzZGc4bXVTY1dKZjRqN09kVWp3NG1LUDNpYnFPNjZ4YW9qdk5ab3ZsVVQvTThuTkhDZ3ltY2lUYzhNaWdE
bjR3QmRMWnkzY2lyZ0c1eS9UWWJ3TUdYZHN1VFBkeXAwTi9tR0wwV0k1U2Z2Z2ZxYnVFVll2TVZCeDRmODIyRnZIcGtHSlhtdjNk
SkJxUDQ0bUh4YzhwZmFoSnZVMVVnLzMrUTU0bVdlTGxXYnRibkRmYU81bmwxcUx0K1dMY1AvVkZPZVpEblUrWDF0Z254QXUzYUZM
dUdTYlpQVHJmOVliOUVmRy9KQ1QreElVMFRZNnZTaVJvaGJCT1c1MU0rR094cUVPQnUvSGNpZllwUER2bEU2ZHNJa0I2OHdDeit4
S3NQYWxSdEd1MXIyVFd5R2Q4WmRpTjJOUmd6T3JDdFZ3andobDdMa0FZTm52YS9JWEQ3d0s5RzNCZ2xLdXVtTFlzbk5pdmpjc0xE
R2FMMHFRdU4zUjMwa2FwTWwwV1k1K2JOVlo4cExWbTUwRi93d1gwaGhuWVdYRXU3bjBmUzVrV1RFamxzQ2puNzZwMnpXY3RSS2N3
RkthcFFGT1NFOVltZ0JLQnVXYUttek96THRIRWdvNzZ2ZndpdW5sYUxxTnc0bklLSVJsb05vc0FRVXFZbmpuVEI5M0R2STdiUTNq
NDJ1UldWQjNxdHArS3Z1a2xSNGJVU1k0TjVtMmYrL0NZMWhQTnRkMnhVeDlXcCtsZlJUbzJvZDQzY09hdm5wV0hXT2VGaWJBWHFY
SXZ4NzluRm5nWnJyeXJJdzk3UEtocmsyYWJ5Q28vNDRKVWN6YldvN0ZrNHRPcVFoSVRiUCtibU1kYU9XakJJdE9FSTQ4VnhBNURk
b1QrMS85YTh4d0NVcGdzc0tjUUVXZEkvSklBY1J3TzZUcWZZSWVuZUJsWDlrRnhLZHpRV1Y3SlNQSXFXdEZKTm1QeldXQUFnZGtK
OEJHN2paOU9yUEhHVDFqU0YzM3BvK2lLcFZoMjhZTTFtYmxCVkRvdzA3bDRQbXZBTW5rbk5uREJ6c1owVnFueDZ3WDlKeW9leGVr
eDJ0cUY5K0RVMHVrZW45c1JpYjRmRGJwV0t3cUlYYTJYUTF3dUZmVXduQmJON1poSlRkeFJ1TFNrZVducTgyN1pPbmNwaDJ1V1Za
T2RnYzYzTngyZ0crM0pCUlQzd2s4UXRubGUyZzA3c2Fxa3VyNHpsT3BoVlJMdTZremg5MFc4Rld5ZDRnOVBXdVJBOU01MEN2cDFS
bDFsTWVuaDZyRDJIWmovOHRTR3RmRWlMaUZlMVRGMldkN1NsSWJGd2QxWUxBRmFUMTVjbTZtRDVGbWg3djFkUkFpTEJPTlpJdmVk
ZWtUaWVHTmhNaTFvaGV5anpxUVRzOTF0VTB6WFRzRDVsVEFmRDJEcmJDWlpZdWNoZmRaM21qek91VVRTYWhoa0hrN3F5dDNuT1lJ
VzlOeWcybUt4TVNvMTY2RExjMm1Bb2UxZmkrMmY5b2ZWdjhxZ2JaN1FVSFQrdmMyT1RxbS9KTUI4WFZHdEYxM0VJb3piWlplRTFH
aWtucDFMVFZsWldXWjNFVFY2TDdEeFVicjBDdVIwUjE3UHZzL0V0RlZZRW5RZERLNk1LQnZwdW9YZGVhS0NPcUxjM25nNVF1K2NS
OUowRWdkYVVDcHN1SmsrVk5YazIwdmdwek8vd3YvRE14eXgyYVhBazgxV2tpOUdYamU4NEEwVGZQNGIyU1pYeUptSlNlQSt1Mk03
R0JJSldGUnJ4SHBWV2xqVzZZc0NHbzBFME53TWdwNEN3OFU5R0JrdWhHcERIcWxMWHlJMDUrbEFRQW9XRi9aSE93TmpSaEZFS291
N1c1S3FLWHJyeVVQSWdhSWNqSGhpQktEWHh1UmNGMlIxN2pIdXFXYXB0NGxMTko5bncrKyszdjI3aWU1WmZJdVFUNlFpN2dBcVNB
c3FDWXlTd3VEdkMxcHVFS0x0WlFkYUswQmhEWXVnM2l6b1dtMW8xTkVId1NaUnNZbnRHdWhCYVo5eTkwTGpoOWF0MVc1YmhCdFZC
MEJiVmRZYTlBTmxENzMxbWcwalFYR3lGTTNaT0tZSkFmNXE5a3pnQ1NJNjFPQ1RtUzZUdTc1VnpjMVVQaXl6OUtTV1IxUVFpYkpL
bGtXNFc1aWI1NlZkMmpxcWJOenFGd3phczYrWmVWNkVYNmZuQnVJYko5Rnl2SUZBMlZHZFg5ekQzdzBSZEpGaDlTNll1clE1NCt1
OWcxZ2pWZ0U2WUdYMHQ0R09HWUdrR0lnU3EyUlRrWkFEUDFueGtIZFRseERYby9UN2pEM09JWmVBSzRWZm9YOUZUQktxNzF2MlJX
cWp3UGpSN2g5Wk5aVy9idkUrNXV3MWJJa2pLNzRGUkhJdVBHd2FyTlo3bnpPVzlqYzZOR3FtQ2w0eVpCRzBTQnd1WFA1c05YeTZY
YWNOMXB2MnBZMW9kWWYrZUNFdFprdDJSa3duS3VKU1NwdmNPU1pyRlJNZXFpelprWXhXaEZwdkJkYmNqTTVOSk9QdzREczNVbDlr
TU9tbmhVRzdNKzhsTEwzcitnNE1iMnpUT3BXQU1lVnVtU2s4ZkswUDFCdnZvVEFHTTljQUxYNUNDbWhnVWNrNGE3d3ovNHUxT3FY
Zm5KL1Jod09qNEZ5THVuTElsaGswaEFwT1Rvd0xqTFJ6emJib1JEeTBoSGwzNTZESGx4c2FMWmlidXhtQzBoR2NoWGp5TkQ2VFdU
ajlPbUdmUDBXU2VoYjJhbDNMcEJiNmdKMzI4ZVdiODhOUDZXTHlILzg2M0JsaTU3SktiaXE5T2cyZGVSSlhLcDdlSGdxbkFGb3lt
VGt5b2h6TkNuRURZdnRnZWdDeUhrYmZGcDMvNUJuaFNXVitMSjBIenpTbWIrZjZRTjVXZC9UTHFlYWtqODZlOHNWV2ltTUdoT1h2
YlBJMDg2azI5YWpJeTVMMDd5VWVoaWJhZytxNldnU2dMM2ZwdHBTZFN0SG9RSmJZOWxsYTI3ZTV3QUFPZXNpcTRqTVdIY2RDSzIz
VTEwbCtSTFRveFBQcGUxcXRUQ3YyeVc5L1pIRGpPTk1GaEVnQ2hRd0FOZXBoMXJyUVExT0ZFVTVsRyt2L2lEaDU0UjRiWjZxdzdh
VEI0bFBxdkpDY25FMFd4MFJWSWFrWmppcUdob2MyUVpLZDBmNWtXN00wams4WTB5SUdHdmtUM3ZPUnllOXBsampBR3ZYcE54VFd4
M3hwY0tkMitoOEc2cDYwWVRUUVl5RVBDN2crOUxGQUxvRjlOKys3TFQ3L3ZGVW1rMjdvYXFnVFdnY1hCYWpyUkFyZ2FXNEJXWjFo
ci9YTytlUzZKQmhTUzg1cXpQaFhLeWQwV29za25GMDdLZVc2WjFEQkZJMHR0cWRCdGh6cXdrUFlpTW4zYjRTUW1VaGtYa1FTRkNN
VFFadlZ5aUpab1dSeDdtc21WVlVhL0hBTjV5M2k3UWlJNGs0S2tpcXZWa044SkN3bFBJM1g5SnlqTVVJUE85TEQ4UU44T2lyZzYw
VGVZKzdXa1dpWmRXRGhqanhoRFFXaVBDN01pYUxqa0F6YmxncjlHZkEzZVJjUDd3NFA5SUdzQ2ZqanhIRkwvT0FYV29NQ24waFAz
MTQ1QWk1STRveXZtVERHbGlvcy8wRnJiY0c1R1FWMmFSVTB4RmRHc1VNdzNGN2RpcDhlQ0lzU0tqdXdqYnNXVVl0L0wvQ0pEM3Zq
dFkwbmJuTHRUMmlJQWFIeEoxMGFjTDRlWmhBTExQb3QrSytzamJlZ3Q2RFV2V2w5dTFmMUdtdkd5TkdBcmRUVzJOTEswVlRLdGFz
ZEM2SUw2MWplVHdGUlI4TVo3NWM3NTV1cDg4U04zUWpZNnBSQ013RDd3RnBiS2VJT0g2WStqZVJ0WFlPblh5R0sxVGtYYnRPUVI3
NG1PWWJaZUtLZWtMMGlqQnR3UE1rVHdQR3RUamlUWXdwOVJGS1k3TnRsODYrTzQ5cVN6Y3F0UUkrOFJtRmUyZlJaNGtvMFJ5dGxD
MDkxR0JTRDZtTmh2dDFtQ01qckVmTVFta2lSVWlkcGs3aVR0QjJxbnprU09sUU5SQzBjRWpzeU5QUkVGTzFpZjNLT2ZBS0MxODVV
UGhhOU00OFBvbUpmWE9aLzJEdllCZmJ0eWU5VXAyb09lWjJYQjFSanY2K2RjN1JzZmM0d28yS1RiZm1CREhTLzhoem1UeklUcjJn
SGtjNTV2L0x3V0NhUEEvOTR0aTk1T3hSY056ZzlkeFRPRjN3Y2V1TlJORkVvc3dBOUhFK2tBeEtkWnk0ak5jVHFCWEVBaWhzbWdh
dlluTUc0K20xWmZ1Z0xVOGV0VnlhVHBxa2tkQWlsOUh5TmxyQURCV3FsdHA0MEpaWml6M2hWVWgzZTFFelZtUm1vUlBlOUg0THVy
NkhoZ2ZEalkvQklNQ0JNMkhTUGh0NEszWXBQTENCTTBGRDdMRkpYeUdaT21wVkNweWY1VzErays2VUpFUE51Z0FYbHVUR2FFeVE1
cDIzR3V3aWdYbTlqTTFQZTc1R1o1a09CbFg1ZU1IaWJsa1dSWUp6Z1BZOVNhTGNRK3hLRkFEQ3dKUEdndCt6NUFCNmF1NDRuVWVO
UFJUTTAwdVhPNStHM0htbG1rOC92SHg4dXc3SkUxVGxyNmdhaDkrSExKQk9IeEpPc1BGZGxWSVRvME5OOENOR2V3aENIbWRYNjNE
bTBDU1JGVUhqb0JCdUdsRmQzcjRSZVlWUVFFdVpBRkxiT0NiVFVUMkJNdklaS1pxQk96Y09aOFJRaWpCYk5rZ3FkUk5DZlR1OXBz
Uk1tbWo5cG9Gd25EdzR2aTB4TkUzTjNpQ3FqZGc2bUUyMVIxVzJrVmQvVzhsRHpLUHRaOFVTdC80VXR1dExWbHN2blBxS2xlMFhS
cjlOYW9IY1NTNElEbzZiS1RMcmdCTmQvd0RBdVYvbFI2Q3JSODlIOFF1c0krYnJjTHRMdS83SktTbk1UYTBodnlibHpCOVd2aUR2
dS9CYWF5NTdWWG1SU2c0WWdUeUlVV0h2VGF2MFhsdjNPRnQvZUkrRGF5TzNIMTlGVmNmbkZzelk1a2t1MnVESXVSRjVzL25qdit2
OFhRbDFpWVlXMGVZaFBVMFJlSEJvZ3VMUHZURTdYbFZNWWd6cmVIOW45SUNOUmUwZ09ydWJobzRPdHpQZGliV2JaRXFhdU9hK09N
VDlOTFYxUGdVWEd5ZGNOWm9Mc3k2WThIbklqUXdHMUNLd292SytaalBtTm50bEVubFJZSzlUY0pKS2oxZnRIR3Irak9vUkk0citY
NkFESVoyZjFIUFRKa0MvTWtSK2lOKzVqQkp4TUhVd2FvT21yNTF2WGhRRTdERzJ4ZEdxdTNqRjFTUUJndnFCZ2FxZDI0Ylg3TlN0
dTdxR2tOREhsQTBIa3VJNWxzMGNrMjZGUzdDcG5LUGtyNy9IRnVua1BucVViNUIxNUNLMzhLdkFIZDFURUliazBhQlBEQnlvNWJq
S2pKQVhmRFRDU0p3d0NYZFRDWDRwSUsvSUtSNDAyZTNrVnNEUzVhN25tcEU2QUVEKzBpa3VzSmVEcDVwNVhreGdFd2RPN053Zytj
VGhvQXY3b2txemNnNkQ1bVNIQ1MwM0Ixb1V1cmMxZFBWUnB5MW5Ed1hCL3FhbVMzMlVQSzNjY2o1VkdZSSt6R0tQMGU2d1YzbWFa
WE52dHBLTk5GT09zVEtzS1Nla0MzRk1sRWFOdFBLVk1ka2hSc2JEYTJidGVNRGUzcTBKeUNuc0NyRHRLWnNIenU4cUhmWlI0aXp4
N1dRL1hxcVRDaFNtQlJUSmcyMGJHV1FUWFgrQWhGK08waStTNWhjNi9KcDhvZnpTYlM1QjJHM01kb1M2b3N6VVVKcE1sd2hxRlNw
ZVhuUjgxU0lLZzcvK0d6MkRMRFRYbmVUM3NvVWdvTEtCbC9GMUxjNzJkcHdlK2NTSU9MdEtQS0ZEd0tMUkpuNklRR2lORVpDU3Rk
NisycDhRRnp2RjRCS2xlT1pDSC9Kd0RPT29DemZXSmd0QnFsbW80c05NUENoNXZwTXdabFNZNWJ6THZ0SjNTa0l2c05PVHdSc2Rt
eWRRRE9hbWcxVCtXT0tjSXR5ckQ3TkJRajJwdkdOZjF2bEp5K2c4ZXk4dGNkaEVuc0Jrc0tQTnMzWnlPeVpxd0NQWWJBd3krbVFM
SE5RaW91cElTMGtvNHZjOWVZSnJHTEM4R3NGdlByNHA2aVhjd1lwbWVaYU91UldsL29KRysvQXByRUExaUMxdCtqZ2JuNVZvOWVP
bXNabm53ZXY4RTBIU3EzVkVsNVZZTWsxbUlEN3ExSVVWZW9oRm8yZFZZN1JPWEl2L3lDM1FvNXZoL0MvS2ZXamg0a3pNN0JYbzhm
VmtLTDcxTXNTeFpOTllyb3YzTDg4M2xxWi9xVTNhU1k3NnpmWVVqRHl3OGwyNXVPN0tlc29hbXByVlozUTl4VUYzMzc1Zmo4OURP
NVdYSzg0K3dYQm83TnFZVEk1WGdDYzRFTHB3Y1ZLbFErSjhqUVV2Q2YzU0thbzBuQWVLWEp1eVNvMmh1b3hhb0d1Um5BRjRSZ2Ri
blg0d0lJMUQ4U2paQ0htRlhlT1Vld0N6cld2QmFnZUFqTjY0cjAyMlRReXdvY2ErbXZBamRNZmFyd1BnWG9KWFhpRFQ0LzlLMlNH
Vk12NWZWdmZrRS95Tk1xZ0N2NVdXemMwbklnSXlCNXBHREphY3pBRkg2MG14TldidzI3ZHYxWjQwM3RDY2JCSFRBQUgwdWduVHg0
TXNmRERENTRGL29IdUx6d25Ic1VQVW9Pb0ZUMEtoQjFuNnU1dHF3UHFqSTlwRVVOM2IzTXJLcHJSVFhkNkhtOWVUSkIxQ2ZWaXBX
K0FlUzB5L3R6V3A3V3NXRHlSK3NWSm1yYVpPcitVOGZjUVl1aytNMVVGUmpsUituMnpIallkOUZab0hQNEdvbUpkZnRUWmhWUk5I
RVdYTm9FRUgzUWlSbHl2Q2FIUTdQUlNybittQmpzS08wOG1VQVZaVnRCckJScFI2czdYc1Q5ZitWV25lSXpwdnZiUWtrSnZtWUlj
elJrY1Nxc3dLRTM4RVN0ZVRFSFA3elJhTGVMQkN5MlpibFBRYzhKUzRPeUZ0T2FjU1o4Y084cnNMVGlhdHZlRHRrTFRQNnM1UzJW
YkVCVUxlR0loK2ZZYmNNYUc3a0ovVWh0YTdiOFBsWERSNW9NV3p1NGhSREJJZDl1UVpQK2RTY0JtOXdhUCs3V0xjY3VNVDUxbGI5
SGxqTnpsUVVNeGluSFpxWkczeGZzdVlVTWkrWTdDeTQ2M3NCNHBYeEMvYzdzQ0R5UDVlOVVOdmpRRUcrY1NkSWtsVWpGcFQxZU9F
MVBQRG1jQW9OWTV3REZVM2VUNXF5TlYyM2RtZlBqdEpJS0pKWEc3Z2xjdjFISC9WQlB6NlFnQjhmK2hrTytPdE05WUZlTWd5eXdp
Z2I4cDFXVC9EbUtEdExZOENXWEc1Y1NLbkxlTXlWTlFCQ0hnSlMwR0FMNXpJODFiNVE2TWNEbUp4TmZxWnpJRlliMm9NWGtjOE5I
K0NabkNWeWVKakpHZkNvb1ZOd3U4ellZYU1RbXg3aEJwLzU3d3NjZVpzd0s5bTlRM3p3UmIzajdzSXkvMzVubElxRlcydVRGZ1NP
WUIyN2FCRVBHQjlwekNrb09CQ3IzYWhpcm4vSisvSzJwZHo2VDFmMXVoVEdseDVmeDBuZkd3NFlhcnpYOUM1c1dFVmVuNllVcHVr
TU9hckYrNExDYTlHRVprL2pVM0p4V0RuRjdpeEhHNVBWaUFuZXBkTHY2TWdQV1Y1WHhQZWhldGZsSngvR3BOMWVBaUI5UmNlZ1ZB
TytCTTRCRHpjR05XQlJ3ZVozZjRsSG5ZNUN4aEkwUzhiQk1BMnluem11b0RxQmEyV0ErTlAxR0tlWlRvZzhYcFFFYk9WRS9Wcloy
QjFyZUgvS2pMcFFqVSs2ekdsS2N0VVBxZVRGRW1lamtLUThZbytKUFZ3UkdPOStUM25YTDUySDdyTXJSTmlNQ1JxeExETXgvY2NU
NlpFSkdDY0o3cnB1NmNieXhLSnNRaVRGdVlCanVEbzF6bWZaL0dKdnlkSkYranlWUmZrdmVhT1hGRXdXdXA4dkk0MXRLUnV1YlVW
Y0t0bzl1ZVovMHNPdi8zZk9FZnhoUHlJbHN0Um1NWllnNHdGa0YzRFFMc05YQWdXYzN4R0FWMTRHRWYwdnMyS0ZPemhoWGNTYUtY
S0Q1bkJaR3BjUWJJcmQzQ2xkaE5YdkwyRnFRRTFiNDlnN0kyb0ttYURsTFVmWFFGU2FHN04vK3NkRjdPZkJpclpNOE9GblhDMDdG
ZG9xQUlkNFJsNjd6R0pFMVBSdGhab0RlNSs3Y2dlT0djQ3Q5bXYxanpsMno3RGdrZm5UM2tRc2d2TGxBTUhGOWpSbXhmNVppVkNv
SSsxYUpUMTdlRVZpK3ozcjR5WW5tUHdkWFVNQkxOc1F1b0RRRUFkM2pvRTQ3REFLRmgxaVRTMEpiSkt2YmF0WmI0MlR4bE9tU09y
aHo5ZWJNdUd5S21lYWg1VzV4Wms4bzlvOWdJZlNCV0lzVHhSbkdQMlY5MjUrdzFMZjRpOXhBbkEzcmlGdkFreUZtVlVaQTM1aGw3
ZVl3eXIrV0VDQWg0Q2M2VnZOQ3NGdnlFZEE0NGlvK0o3S2VxaEFyNFFmTm8rZHU5NlJRcjFCbFV0NHlmVXBBdWFzRmx2MU8vY0kw
Y1B2ZGxtd1piaXpRNFV5WmJMNENtL2p5UEd2TnhEaWFCQS9YZ0tPcEZxSUJ6SzFDcEhpSk1ENnhCWDRxR3NwSUNLdWErbURqRldS
Mm8zNDBoSHdYcjZ2L25wbjZNb2ZRaEZjSUlQTXoycWZMZVdhSmk1MU16RnZJL3g2WGpNdGdVd1NKTHgrR1hKTmloMkdmNXl0Z3FH
L0dtdFIyMXZwbGg4ZHo1Z2wwQ2N3SHVSa1JZcWdETlpyc2llSzZXK1pycEgxdklCQ2cvQlVvelR4dHNWL1pDTElqVEFic1hmVFpo
S0lKNmNwdWNqdlg4L0hZWHFhNkU1T0VDdHNRNWhkSmU5Z01PV0JPTkFkL1p3dG9wWUFnL2ZCMmpQVStUUjJwZTdZdTNoWnZlY2I3
YmFxdTYyVU9rOVJLc1ZrbmFGLzZRT2ZxNXhKM2VZa2ZnVkRhOVVBR1ROalVWc0xCRjlhUTlvV3ZUWU1aQkpxbGJaZURvMEFhaHVR
UmZVVnphc1JoRGQrWGJ4M1B1TmlaWUVSV0dqUW5hcHQrMTV0MVFEM2VReEk1VmN1dnR4anhBU3RDVVM4NDVobzFOQmM0c040UU1l
SXRuZzBGUnpCNHRxYzZTS3BxQXc1bisyQlpid3BuS2NSYThaYk9GUVNaQndNSENpYmVPbHZKM0MxbEJQY1BTaXBYN2ZoUTBoM3hG
eUt6ZlI1TWtlREFyUTEwTGE4YnVXUEo5MXdoUGNSaGhjQ3VMNUhoazlsSUNOSXJvZEg3OFo0RlZnTzFkLzhwV2tkc0cvNXg5RG1N
RHRNSXFJWkhnZlNsUmw1bW1wRjVIZmVSZzN6ZW4rR1ppdFdYdW1CMkhDNmYxZjlScjVZWHUxV0hESVNLaHB5bUFxZCtOZ1QzTlZ4
b0Y1TW5McUFJYnpQT1lRR2plUW5wMytyYjlPQ2VUWEpmQUUweVZ0WW80WnhMSlNudG9McGR6d0RHN3Ayck1nOGRFOU0ydEVzZTUy
Um1DTnVvT1VrVkk1WUNJRmVxZXdBWW0zb2VlZ0pYS1BVTC9zNHczWWVpUS80QWVwSC9ZVEtXTXhLeFRMTkpMRkIwcytiQU1TRzVz
SlFNQXZRamZ0M3dZcGphc1hlVWhyWHlyT2NOa3YyV0IvZm1OQnM0eFNoenhuNkxNWGE1WUc1dmNLU2Z2L2N1SmdtZ2xKRElUY1ov
YzN2RytnOU5yVGRjSjl6YzZzbHBGa2VoMlFuSnFlYlJVRExueFdNOTFUdno4YjIyUnlDcEQ4S0thQnArRnlpWU05V3ZmY25uS1ZG
L3NXSU9xOFovMVV4bnU1d2h4WEF0SGRZMEVPbEtUZ2x0bkV3d01hRkZuSUVwTnNjb0UxUVhCQ250elhTRUZHQ1NPMWdHQ2VTNU9W
cVFkNVBtVUpZMHhLaFRaV1ZjMHdoa29sOFdpSXJtUnhyTGN5SEJUVi9jczZwaGpFMkltTVJjaFNMSEJPZlFWRHhzTzRtYjdCcUVP
QzRXME9XSkRqWnZjL1QybVpXZmEvTDh0V2IvSVdMYitNbitaUUdJbjREbnlYbWZJQ3BDTHlCVnhzWTFJYnFhSHdRbmJ5ZGk4b0xP
cnljTmZRRHZ3Z0I3NXlrUWpuSklIOGJ4U3pvQzhRMi8xZjQ2MXIvbjE5SHpUQVp6b2cvT2o1MzhZcDBqYUVoaG5MMVZQak9QWnR0
bEUxVk5wOGpJcWZDSnBlcExnamc0UmpjMEFqR0VSSHhMNjYxblhKWUFiNFZrcTc5eDJySFozNnBMRXNyQ2paYnZneFY2VEppZk94
MGJ3cVpjWWVJaWRUa2NFcmJtTS9QaDFzOFFXaTZQSCtkWGlLQ1FFeURVZzBRV0RiL1J1K2ZNOTRZVVM4Ullha3NXVURLZDloTUdj
MDVDbk5UYVFSY3dtUHNoRGU2Qmd5MUNvZjNzU1RPdDM5QnBXRCtLVkxraSs5TW9RcmlHRjV2ZzhsVE0wNHl6TDZkUzIxYnIrOEV5
K1NrbGk1UUxNTXFlUWdpbXNHL2Jrd01yQVRZYjgvV1daMUdYMTQxelFRSisvNEx6UVlpSkJNZmdlY0JJLzFacVFpWXU3YWJFNlpQ
MkE1NmswdDBORU5mMVNtMVA3ZlhITEpHSGJheEVPYTcrcUdTTEhxNy9XYXU5UGdNSm05S3hBR0JkWnV0elRpMnFFWVJqZGl2MU85
TEpsWWxoL3BYSnpLdFI5RVIzT3ZySXNpbnlCeVg3eWtYWDBkRlRjdXE0bmxpcjVTaDZIeHRZODNhRWl1MFIzZldJY0NHam80Q1Aw
MFk5dlZ5MVRwQWlyTkZ6a3N6YU9HMlo4eWY5dGJKU0pLRGVaMUxjamFTbG5yRDZzWEZIakVBVm1MMmU1c0FFZXhlVlREMU94N2dH
cVZEditWK3VkWnJnL0w5MlRoVHF2TFdveWVsSmN2VysvdHNyUXE1MmU0ZjRDaDhBNm5heEFYUVFWRTJwTmZVa1p3UzlrSysrejBX
OHFoSnZuZ1VYUFd3V0ZNZU5yU1YyVTlobk0wUFdCNU5xbURZWHNDeTNtRWp1Q0wwa3ZFSzkxZnV6U04wMWZDdjJOUTJqQkhMOVBY
WkpYL0xlbWx6L3c1a25ZZVluMG1PVnc5SkJUVEozcU10SVFTblFIcDVhUjZ0SWtyQjY2UEZoYUR1a3FLMWtWTXlLODRSMllJRlVQ
Y1o2TFZFQ0NTZzloZklXem1nYWg4RHdPRDUwNzZ4cHpYSEk5UlhwYmt1R3FHYXNaN3FxNk1OMUl5Smx3RDRzYm0xRk1PcHo4WUFo
Qml0N1BuZWt6QjJVak1tbTVEL0FpdFBTMCszS1NpclJNVXRDejliSTNiME1tclRRR00xMWRNYi9DN0pLK1N0c3h1am5RNi9QeDdS
UWdnYkZ3c1lhZnNhaEV6ZTBCOXNhRmlUcUphTjdnRjRBZjkyUGdQZHJIUmdPVFpPS1I3NzdCZjdzUG1zTVdQeWNpZm9uQ2htcU04
R1pYWWF5ajh5b3JMeVFHVzcyRE9vUnQxSnNHTTVCYlhnWmx1NFNQanFLb0VqWjZXazVvY0tUK09wQ01ONHp2VjU5eGVrTmxvdEhX
WTh1OXd5Sy94RVhDRk5ldlZ4QTc4dzRaQWVwaW9uam9ETWhFbWI4T0N6Mkp2VkVSYjROb2ZmV1NrTjFvbXd1YUI5VENCTHM3Njdl
SEZic21SV1pvZzZuRjYwVXVGaDkyTWdMWnVlcGNTRFo4Wi9qb0szZkZqUnJnRnllQ3ppdWxLY2lXWU0xaE5hOEFOY3JCc1hjUlBs
ZmRvMUFSeW0zS2dHbDFoZHg2SUhWWkRMajlnMFlPMnpENWN2Q3VvUExsT0dyNmM1RHdjM2FaMGxBZkQ0cTcrc1NRaU0wV0VuUVNV
WmdBczdWb2laN3MwbTN4ZVQ4a3BMbmx6ZGIvNHgvZ0pHL1p3dWdwK29DSHRZUXYySFltOW1nWGpBakNVOExjajJlNWJHcWJ2aGs5
R0ttMmF4ZzMzbzBUTnRDelNtekNrWVBMYytuc0F6WEJ0TmpuN0hNUm5JUkEyeXRPbHBYU3dBSGRMZzdVSXNaQVFVUDlVZnV2NmxM
QkZxVDVKRENSTGcrTmxEdUhVUE5YcTN3VWlSUUtRM2kwRFpHWlVKa1M2OEk0cERTK1FaU0svSXNlS0FDNGJ4L09VSTZXMGRJSUpl
bU5HM2l5b2RCQUJ1UGxtd0hOQUJ5b0tvYUVkMkF6YmgzQ3lEbDA3VEpqM09vWUp5RmZ4RDJJamlsRGlxL2d2M1hjclEvYk5xTU13
bWFNdEkzNnhwdGNhb1ppdmhXUmZHRnAybnpjTFdUSUxlNVRKL0JkVGNuSEkra2V4cUxSUndzdzNwOU9tTXRha2sxR3lYYXd5aFJm
N0dpMndRQnZTakxhUE16RDc3MStOdVhCUGtrbSs5Q1dxVEpjaHFHWTVLb25oV2p4OU1SUDVuWTVld2RocVVKcHJiaVMvR0NINXRW
LzJ5TFhhWU9mUm1udHpmdlJ0YjF3bDFJUGNlVnhJSllsU3NhcWVGdFZnMUdkdzJyN2Y5cWNXdXgxUlQwNjc4TFNYR2piTmxRRzFs
OUZmTWM5Z3JWWkh1eUpSL0p3YVVVZmhMa1JTYUExRXFJV211ME9wV2pvbmJFU1dLbkdBMzFFaVV6TnBJSk1lSXRCUCsrbFNsUEtJ
TEQvSnRtdGhWZURjalBBY0NNZVJXNEUzKzB0RTR1WlQxNi9EVFdGSE51MkFnZStTL2NsRVNQVFc0ZFhLSEZvT2hjY0V5cFVHUGFJ
UCsreFg5UWljUVhWWFJWVlFDdTFFR3pKSkhUMGZSMW1KUEFTM3hhYlhFa1BsaTAzU016Y0d4NGxwbmJhcU9WOSt3RzFoYy9IL0dM
UXR6OTNqZzFieUU2d1FPYkdMS1orWVpmQml1V3F5YTR5OTF2YTcrVmw2akxGdTArSVV4WjlLUVBDaG9GeENpRnBxd1hlaFJOSHRI
bEtjUklKd3F6UFUyY05mMmVkcTY1NEtvdzhlUmFUbWU0QjNsTEMrcUxYMWJaQktseXpnaS9PK2FkY1BFWXN5UkhDalVqKzQ5M3VX
K1Bmcm9yNWtpcjRTWjNuTUxlVkxEVGVySHpzWERPclN1K0JKU2R2cFptdFJUS3I3a1FLaUQ3emk4Zy84K3J6UGhQcUdzVnhVTVVK
STJJMFdlbUpIcHRibFU4UW9aVG9sZ2tva0NNU0VGZUZGSHUvMUJ3RWNIK3lEVFptcmVNSUV6Smh4eTBXT0F4ZlBFK3ByM2VGS3pm
d0JIU2JxdHZKaDZOVitSb3ovUVZkaUxpZWhtZmdrVWNBQ2lNU2ZJeHF4QjBrR1hZbmlZejN6RkY1T0JRdlBZa1dXd2lYS3NRQ3Zz
ZnVGUnUxaDZHUmlabzVCOFRtcTlRNVpkcHlHdXp6ZHJLdW42S2tpcHZHNWcyQWJCbjF1L05vT09Ka09MMnV6U1krQ2k3aFBrQzd5
dXlaYmVWRGw2eW5GMEJjMTkzTHZyQ1FjZnE5blNIb1h4eXNza0NqeHk5dEhFb1pKZUNlbG8yMlJIMXFubnlXS1IvZ3N1aUpJTzVn
ZWxidUFLREloamhqMGMyZnJXZnh6RmpKektCTEFCYVpBalJOTFc3Z1RZNTlTWUhQNVkrejgrTVltbmU1bU4xa3dLQUxmQ0ZXeHQz
dGxaMGhvU3I4emltZG1vL2JyNUR3VFc1b3NJUUJkSFR6a2RZOVVtWVNNVW9TNUcrQkh5WlcweUlXRHBjbTRUSTNHQmkwanY5Qy9L
STQvcWMvUC9JWENKdWJNT0V5dXU4bldsdXhqNXBtRGVFNllVbmMrY3dLaUFWOWxTK01SNnRic0EwY3Vxbzd1R1BBVG85NnR1NE1s
RjcxcDJjQmtISy9ObWk1WEsrbENlejVyTytsVU5memVnR1FpeWxSTUlJbU9zWHBvSHZtWGo5Y04reU9OMUwvVWdEUkpJRHlFT2lB
azVsckJFdUIzWWsrNWtlaXNoTFBRclc5VWgyeUcxNEh4dTdTNmJJUjEvUlFzVkxOWnZNMlh2V0JQdWhSeVg0SUEzdldmRS9NcWp0
TWE4aHp4SHVmSkl6MXdXbjVIc21TZXpJKy93cHhhWkFCYjk3QkV5cERRWFFsdnBqSHhzbXFWRG1ZamRoNVA5aVpUYlRwMGFaMUhN
Smo5bFh2b09ULy9naGtCR0UyVGp2dUhPLzVjL0FZUDI2UU9HS1g1eUZ3QytmKzhKYmo2TkdjaFM0YWd4NFo1YnVPOEI5M3NtbkVx
TlJ3amg2eHFkelZhcE9GMHdtL1Z5NTFiQ2N3ODR6aElEMEEvWjVkK2ZHUVBqRklzQ20rK1lkWThZR1ZxT2pGbUIwNkNDbjZEQXdH
bk03K1YvMFp1ZUpUOUVxSlRraklQbVlkNnhUMWw4Mmdaa1JGZjhTN2lzVEhoTE5HMVlTSjk5eHY2RzEyNWpFaTdWREJIVDdZRXJx
Qmp6RlNZK0pkZEJVOTdjUVNHN0FoSFZwMUdqMUlleEtjYzh4S0FIQm00emkyNWQxUEJRRjh2c1YvR0EwTlRoM2pKMVQvUFJXR2Zj
Um9yV24wUm5oUG1uR2JVc1hSekdXZXYxb1NvYXQyQ2xyekJzcG1YZjZHNzZRZVFxeWhxTTJJWjNFV205UkRnQkMzWWJ2a0dqb3VL
N1drOWRGcHRtN0xzanNjM2ZrS0Vhek11aGtzMkNESVhYa0RvdThuTjRoZ0N2QzZocmJkemlPQ1Z2QUM0YzJQNW9IZXkzWCtLQ1Ex
SHFoRjBxNnRER2YwMzBUczlieEc4Q25UZERoYVJGUmwvcUFZSFBBSk5TaXRSNVpRWVZPeU1KVWpLKzFORXl3RzR2UUk1Mit3Rm9F
VlYya3BWRCtTbmp2eTduV0g2ZWtSKytKanByUDFLWXIrZEEza1E1U0s5OW1pMWV5Z00rbjlmckJPdW10VG9YZDc1L0FEa2pUY0dZ
RkM5MW9ROERtQi9MdTM0eGNVejlsQmxlcUhTMlhtcjJPNHZnMzFxNWtNeHNpZUxLcHp5Rlc5WStqRHVNSzlWN0h1ZzB3Y3FzeUpX
S3VyUURaM0Nqc0gxNWsxM2VCSVBlSTg4dE1yRlYwSmM5eFZ0cnEyamxaQ1dHbXBZRHBNRDlJVEVjUGUxWXV2cncySkhzeFZaUHor
cjB6V0FSYlNINVY5TkxPMWpOTkl1eTk5RHdzbWVMR2ZFRlppRkRMMi9zU2dKNElydGdqNzl5bXNqakc5YmovSFNiWWZwVkZEQ0pq
RlVDeldtWlJ1NFZzQzQrMlJUZ0RUYkJkSEFQT3hkbGRaQ1c2WXNuaFdqRXJGMm5UWnBCK0RBdGpvWUF4aWJEUCtWWm1XZVJMWW0v
QTJ2b0E4TytVcnc5Y0xibFVEWnJYa1hSZW13elJnTWZRWEgvdGRjc2hXd2xrdXc3Y2grclhrK0h6b0Q0cVZGSGpQTHBpaGhkWFZa
YTZ0Nko2b1ZLNFRLaUt3SHpWOG4zMTlMeEtIVmkxRGFtMkdacGxKbU9pcU1XNzNmWGpad0xFMFQwTjZMNUhIUDNVcFBwNjE5QS8y
c2dhcEc4NzU3VGY3VXNTamlSM0pUQUFRR053akxseXEwY29BOVp3QTlzSlpmQ1hLWEhhcE9Ma2NYNlJ6UUtySzdyUE9TOTFGbWFm
SS9Va0xHUzZwWFMxRStmTXp0eDdVeEo5dDh6VGtCMlFld0kxaXl2MGhmU0p1ODFuYzRJMVB4VThLaldjSFJCWHl5TzRQS0R6SlRr
d3JubWhwM3JqZGZqaWhTVzJPWlN5d3BJYjB1ZVFyZVdoSVhPNGczaHVFWUYySk5heWVYZ29LWEx1WncvSDNOanE1UmRqSEdTeHJ2
U2FwcThWNkw5SGNaaGNvbWNWNlZGUERjQ1AvUWljeHk5ZFhHdU8zVkg1M0J4bmp2SWZYQkxKYkpDWGt4czlQM2Vyd0dMd203YXFD
eVN5SVdzU3NqNVZISm01QzlCc20wc280NU9JQjFrWENZc0lnRGI2anoxRHpsVEZ4dGxucElEVVk0NnVETGRtZE1VaVd3TVEvbzJS
NnljZ1FWNmRpTEdxQS9xckorTjFmUlhDd3Fya1AyQU44azZId0FGTTZYWXpGYnphM29hUTR1dXQ3dWc5N2ZPRWc3citQM1o0VzNw
RVZlaW5mSVVJVTZTb2xWL09oNTFmWXh4TVlXRmdhZUJKY0ZXNS9RcVBkYzQyNVhiZmxhUWx4ZGlmN0haQldDN3BWNUpuYVpmbVFI
dEZoVEFqZEVzeFdoYW1qOGxJZ2hxaVUvY1NFdXd2NXNaYXJJVnVNTEhJaDk4MldTc0p0d2o1OWxxN3ZTWGlaSDQrejFoK0Q2ZVRD
eTVHam1FZHBsZTJkTm16SlUvQXp3bXRidXppWFIzVzN4V0M2clNPamgySWJzeGVVY2ZTTjdGMmFaQktGbEVHRXZwdTFVR1V4alNP
ODZ4MTYvMlpzL3B4QnFMSWIvWjlobXA4NGdHM2FMdEZ5TURXLzhOQlFOOGk5YkdLSFd5dzR2RUFRNUtXc0VqaVZjN04xelBqczR2
RzJwenJDZFh2Rkg3Sk4zbmFXc3Nld3ZBa2Y4T2swcUx0WG84b25EdjJhWC8yTG1uOWMzNXRPdUdVZlFPYlVZbGQvblM4Y09zMGlR
M1VweDJlcWNubGRMNWRNdzRmZWhlRXZBVnBEa2FKS2Z5R1pXKzJYWTVzcHdFRTRzUzhMd2ZKOEpodWhvbHJxSWJmNTVmWVo3OXNH
QXBDYzBDc3BkOHpBRyttdlhTZjBRL2N5U1pEbnY2VmxrNk5qRkR4UU5jK1hzdXRVVDdEVVJUZWdmbjdsZm0wMkFKckRNa3BrMXpw
aUpxMmJOUWljdE5tM1hhOTV3ODZNWXBxUWV6L01TNTNxNFAwWG1JSGpJMmxwbDUvZHpwRnMwd3h1Wisyb2xmbFUrcnNHSTA0WTRV
enRocnNXVmFVdWJ6R2o1MGVmalhvN01ISFdFODNkQ1R2WDFsNE9qVXRiL3RhRHVvaXduS01ZdkRCRGpKY0I5ZEV1OExUUVl5d1Aw
OHp1eDFnaXNnL1Nibkx5b2hJeFhGNmRUamxjQTJKU200NjNBdytqOURjeUQydE9NaFB1Q0FEU2hiejAwOXFVN3RXc1hhV1NjeS9P
RHlaQUY4NVl4WEtDSlZ1YnRXeGlPKzIyVkF2dnVpNm1kUUs2M1ZLVzJOWDBENzJ2NjFlTjJyeGpxNVgwQ2w3cVltMGtXU3AyT2pT
WEhFWEhGTUF5aW1DV2ZxWUM4NUlJbUhyY1llVGoycWprOVBRbnBTZGJVTnFuN3BTenMrZ2lDWjdnK1dCaDZuWDNNRG95bERaRFow
RXZ5SC8rNVhKam05bHdCRHJ0SlBaOXcvNzdtWml4Qk1jZVZOTzMvZi9pOHVCLzl2TURNUy9pK2lxU1NTb1ZNSzhsMDJlaVFhdnNQ
U2xzeG9WY29XeEgya2lmd0RoY1ZveUFpN3FPUEQ1Y01HOXpsQ1RiVjIraVJNZlc3N3pMbVh1RGRIcjQ2UWl3TDY4OGl3T082VEh2
TEpZdmRYK04wTjBoOVlaSi9lRE0veFFRaWhGMDVpUE1tZW5lTGZWMzdsUlZ2L0NvMmRFZG40RkhsV2xZUGZhenBieHlwWkUwRE90
V2NMMmtvL2t6dXd0RWJMcWpXU1pxb3VmU3kzRFVHVXA2NHIwdXRmVFpZRXdBaW1oZWNjVXBYN25DRzIzWjM5TkFmRm16emw0S0dn
REI3QlhRWXVMSnViZjA5VUFvNXZabnRyTXRNNE9scjB1allBWnBESmwrcU1DdFVPN0ZYdmdQNEFCSFlEeUg2R1RsQ0ZJT0lBTks2
OVE2KzI4bkZQMC9YKzVsajRKcXhBWHJNdTRPOFphVmdmWnZrNFdZcEJHREtxSkswU0JoeXFMWXJrU1hSWG1RQ3FTVFMxV0NSeVUv
Yk5DOEdvZDVsb29SaERNaDNmaW1VVHRDc0QxNWNaZVA3cklRWWExNVBGdFpJdktHQ1lLMk5FQlFwR1QyU3lGL0Fhd0x0b1BOdHJU
bEx2V0gvUlYrREx1YS9lSzNrSG5vcFBYcGZQUFBFN0lyRmRnM29WRHhlUXk3RHdOb0RWcFlMRDdtcGkyRnZrOUk2WTFJK0ZGeWZh
b241dTRmUHNSNHg0eFRuQVNpSGIzMnhoSC9PYkowdUkvOUtna1AxWVF0RVU3SmxicEc1NjlPaDRxL1A3bC9QNXpEZnh5cjJjVnQ2
d1h0YlZiM0hySmdTb2Z0NEM3NkhyQWhuZWcreHdEVWtEWjBpN1RhUk1pQlhUOG4vcXdpNENwcnhDb0pkc1VLZzQ1YW41WGxHOXNs
cWpoTzk3N2E2NTY1Rm8xWDE5dXNoa2E0emJhcEk1RHZ0eS9NR1VNZVZhdmlPbTZkbTN3SGpmVk1VK001bFNUZ0dPaTBlYzZFVnZO
ak1MWERDQVM1MmNvZzk3NXFzeHJhSkg2QzhCZ01Xa3lsckE5eHdMYWdTQktmN2N1MzJYL3E5ay9QTWFWVVg1SUo0NHJqWFVIRkFj
L2duNHYrQjZiTXZaYzg4TC80eXQ3eno4Y25aM2pDS056M2pOT3M2UUhpRGdmL3FNZEJzZ0YvcWxOT3dnWTN6YmVScHFYN2lZOUUv
ZHdVNWxPdlM3VGowZml6ZlJkL2FOMVBTZURZY1YxZXBJd3FIZkZhZ3NyUWtaWDgyeG9UL080L1NFMGJrVmJHYjl3UXV6emJwK1RC
S0IzSnVPbmUyN1UxREdsRXRLSjZYbGJmRllpd0k4ZlN3OWZEakJJS1hHZ0VDakovczZvbXlYY1JlSkdtVXRXYVZDS2h2SndETndN
TGJkeEprZEdzTmJPQ29Rdmh0NjlOUk0wc1JSYUQrUlIrQ1dGcWk3R0ZGVzNaT1N0Q2praGdPdk5hOVp2VTYzUksvWVFaV24xMFY1
ZUhya3Z4Qkhhc0RYZW0rMVFMczluUndkZnRUTmJKWm41TC83T2xBbU5xbit4TzlsTWRVSFdzd1Y2SmgxcGk1SmE4KzdyYmplYWQ0
ditucmJVczE5MDM3VE1teG1HNnRrQWxJRnp3c0NMc21FVmxPOTdUZ2dSMmxJK0R3OEJCQ0E4ZWlENnNxU0NwVFBsMmVwQ3RMVXhL
UlNBUFRDaittaGlmbDVjcTJKeXNudlRqUjNadmZrMGFzVERpVkFPM0N3dlhEWGo4NmdYWCtKMnNDODE3aE1Sb09aeUYydTFSQVJE
Tkh6MzZ3Y0pBNUhUMGdhTkpLYmk4Y2JRc0Iwbk5sOHVkbnlaTzBGRmtCZm1uQ2hPS2ZwckgwVlJHdllzUGpUYkhUU1ZRQ2ttVHV4
MDg2dCtYY1JvZm9jSWVXOHB3T3BuVkdUM1QzRFdRZDR2SHhqRUN2Zkd5OERiYVh6UERDVFVtdHkrTUxIamU5bHozckUzS3NteTAy
SHBMbXFBZVFHSGFyU05wa20walRLWEFEZDBwQXRGOFZSTEtOYmRLWmlBZzVQMkhEQWJFMjF5UmkrNGFTQzdJS1FQSGdMRGJMTjM1
dkFVVVFGbjVjSDVTZ0o3N3liMGZwSk1sUHlPaUdJM1QzUWNPazIyTnlqOFVxaW1nMGRTYXpDSHhGSmtJZFJhclRzNzhGem92REZp
RXZGVnN0eFlnUXRORU11c1VyK2JxVG4zbDVjMzJCK1kvckRWbnBwd0pDTUZhTi9aeFpjZ2lPbFB3QU1UcEVWWVpEMHVGTjZmdkcx
Tno5eHp0RnlyRGl2VmRXTmo4ZzZlM1QwZnZxaXlYUFVlRlhrMkh0WGRQOEJyamVIYmVFZmJTVlBId3RYMHNjMUN6NEpuVnE5c011
dUVUNFEzcElyWnRyai9naVJwcnhuNVdSY09CZFFZWXc3R3dNWE8xNDJLY2NBTzAzR3RPcXB0M2pOV0RTbkhtSllXT2l3elVhdjZm
T2kzMm1uUi9ETCszVU55NDJzTjdXRVpLUXRGWWR2MTlmc0ttM1p3RitJQ3ZYTW9Jd2RPVlR0Q0tXdnlxakptM0lvOGRwdGhBbFF4
VHdpRFVYdWEwelliNlhtTitlSDh4SHVZVGdPTE9oQi8wRUhiSDBkSkFIS0dPS2ZNVFdvYVBBRHR2MnVKVXR4dlN0YlRaL0RDYXlZ
akpiZ2lSRTJyNStUYjIrV2UxZ3JYTm1KRFBUR2RDOHJhMjVjOW1TcmN5amlQbTh3Q1V1WlE4SlFXamlFb09KTzd1dmVCYXFFL204
NGZKVHd4UzVTWFJmTC9zZFgwaFJDM1c0dHE3R3VsYWZTUHB2V0p0WnRnM0pRaG5YbVpaK1VseGdtOXpPRU9JbGxKQW5SNGhPc1kz
Q3NyRnp4azNsQWV4emNTWWJKNFJncnhoa3RZUE5ydGR4VDlkSlFSeHB1aG53UjZ6ckhheXFSS1EwODhTcTRGZW1URVlZRmc2UXVh
OTBPTnJyN1p5aXlRem1SeUJvZEF2VWtBNUZBdVorK3ZiUHF1MFBQc25vSEdEYnc4VkVhN25ENkhnQXZ5THN5Sys2SUM2OFJhTDRt
ajIvam9raU9zUTJpOGpabTJKakk0WkR0VllZeXd2MzhIazUwY1Y0MWxrdkRMOFc4R3JSM2NVZkp0LzVEU0hVK09OeUpUajc4MWdF
bXhReFVZUXhxZ1hoRlRUU09JY0ZMZUpkaDhDRHZ3YWZyamswVEl1Q1FmMUlpQXJ4QmFlc2hSVkhLR090MzhuL2RyTTl4TGRnMmFX
bnUwYXFLcHNQRmFOOHU3alowTVgrcU1kcVk1UnNaNTE0N3N2WWo5emVrSjF2V3NOTzBCaHpZY3UyZ0s3VHhhV002bU5ndFUvb3FM
eUhHbkpNM0I0UmZ6dnVsS3NDL0xsNyt0RmNsdmh1TGE3dG8yNEEzaC9BVXdyVHpkR0Z3MTVLTzdDa0pEaDROSVdJcWRpa0F6V25I
bUJZL2MwS3hqTXA1UnRMWlIrUnY0eHlyR29vMTJNWGpCdHRRa2pYdk1WUndvNHVrZ3lxQ1RSdGJpVXowQ051L0xuVE5yODhZZ3Vv
U0lUczgrQWJoRkkvdWFSeUZ5THdSVCtGWVdXR1lvc0E2TW9QL0h4KzNQNWlyNlhHcVphQ1h3aENGcStyMC9maEJ1Um5mTE9wRis1
T0hmcnVYTW1QZjlpSFZoSk5mR2hJRDQyUlhPckhKLzVQMUNSdnRmWjdtSC9Tdndncm5XWm0wMjJYZ2dkNld4MngwTFlQekJyVkJx
UXA0d0JUQ0QyL0lZR2dCZWtXbUxHaGJoWG8xemd6eU9DMWo5REJiTzZCNUlkUFRDeER2SXF6d29MSGt0eHg0VStGNWFJSGQxZC95
THE5K1JBL3M2WXZPcWE2K2pIN1B2RWRwTHJqN2I0T0FwS0RNMHJZRElLS2lRQU9VQUpZbkVyc1hSdDl1Z3BDRmpFQW50djE2TTgr
ZE14Ryt0eGVpdWlTNGFlZXpRY1hacnhha1Mvbm9TZC81YlROSzZsckw2NmphY1M3VC9ndlc4dEtyRlcyYndscWk3bHh6c01pVEcx
L1NBRVhxdmVNVng2M0drUjdNOWZ6Z0tDdXlhSCtIZTBZZU5MT3VxQVZlUWFodStHOWRhYzFMNHNjWDNyRmYvTE5kUUxkazY1WWQz
czhSK2h3UzZhRWxRdU53NFU4ZzIydmFHQlVsa2toVE5ka1pFeExWL2FlVG5JY2QrcEpxR3ZtRnYyVHpudlBTdkdiRmx6Z0QrMkdL
bkxGY204Tlp4MUo2MnlSTGJmdUtLMEFaTG9LWDA4ZEVycmIzcFoxaW9iamNmNnpNVmY1UmJ6a3c4S3AvTDNIMlNONEQ0TVNzWmdZ
SW91TWh5bUk5VXZWN0FsZVJLVTBhaXV3bkcxRXlMak42K3d1bTN6OTNRVkFVakZmUU5ydHhKR1M4ZEh4U1ZUN0cyNTVkNFFDTlRB
TnVLOE9rck1RMEtPcFF0MElzVHh5d1pHOTVMbXFaYXBFK0M3NTRJUmRkK29naUtkV3Vyam04YWw3NElLempleXNyNmRIV0dMaUVR
eCtlVVdzd3hKUkU0dkVsNU9sOFJaRlN4ZFhyN0JlOXlrRlFkelNSdkRvSUFPSzZFMjFKR25IM085cUFFL0VGeERxeXY0RlA4QUdJ
V0xlaEM3b1l3QnFaRCtyTWNNdTZEK3VkOXFwSHJoN0dLRk1EM3ZlK0I5emZtNytNbmJBL0JpcmJLTHptRVhDbVBPdXdsV0ZKdXZv
Y1duaTJ1N1RmZURwdkZPWE1BcU92ZE03cmgrVGtPYjB2TDBQNVZyazYwaHlFS3dJUVdWN3FoL0UvK2xteGlwYTRQYThMaktOSnJX
OEt1SFJCdXVNNTE2NnF1VTcwU0Q3bXViamx5enBVZEdjeEdSNkdKelRTNWszUTUzQlUrRWQxeWw5QWNHTzhjSlVnamk2K3E1UmVG
cjNNbzMxbktLNDNHdVBDSEt1Mk16K1BYOFEyMWlkakxybkhBQi94ck5JcEo5c1FqbTBBVTFhaGdzcCtwNXNMU05yY3hyUFVqbjdn
NXVCdVRUMU1OYXJqclZxakZmR2J3NXlLcFlrVkpoVTJNWHp2bzhKb0xpRndRUEdjSkxWdXcxMnBVVGNRTCtNTGVjcUtkakkvMTBQ
NDhXbktob0EweHpBVnVBVEVGdHh0SVZ3SU9xTVdZTW5XY0prVlpxMHMrOU9Pek1Fc1hBSi9vYWJzamF1aEM1VlZzTUsxM1doSVdq
S3pvdWpSWFNySGFOd0g2YzZFenlMckk0bFROMThEVXdORWtXWnowN1RrNEN6RFR5M1VyWVRmbTJRMm9yUUVReisxYjQraGdySDNZ
MzYvRHR2d1RGKzJ1Y0xNbi9JOHBKQWZNMGZXbTFkM0ZhK1RnRkcxSDBsWGZOMDlGS2s4dlliRXVNVEFNTmxodTc0ajJTc1RMTWxH
U3M2b2ZMS3p3V0I4Njd5MnFKMXdaMXc4MUwzVlBKVGl3aVNtT1l2UUt4b2JuM01zbnloUjQ1eTFNWStYK3J5YnIyVUFoTTh4UlA2
N29WUXBSQ3Jac1lueWpGVXUwdGs3aGZaRkdObmN1N2FaRXM5d1I4cFlTZEwvNzg0UDNFTHdMQW1iZmJoYVNtRm8wQm5NWE1zd3N3
SzlFUmlFSXVsK0FUdTBRMWdoV0VjRVBBRDlrMGNSc3kzMUZPUis1aU8yTHdZU3lSM1VlUW5KY3kraEt3MElvSWliZU9oMmx6dFFm
T2ZKMzAvSmpXZWNVdElVdmtyZHNWcm1lL2VzbmNZaTlRQ3JiZDAvcW0xT3dJdTFvOWdwMkF5SmxSMUV2NC9EUFRRMVBKRXJHekZI
VXFBd25IZHZSc1UwM0Q1L3JZWjhEQ1g0YjV2amhyVlFLYmE5VHdhSGZBd1NjZld3d2RzYjRlcTRHU0pQM0ZDMHczb1M1L1Yvd01t
VFR5SXI1NXhzN1lYNGdtdlBRT01POHF4a3kzdGwrVkQ4UUZ4R1BtMk9aYlpmVU1SQU9QVU4rQkJ0WGd3UW53aVA2aVFoOHhqK1JR
aTRiNkZMRG1zWFRsL1Q5cHN6UU01TnJQZGlqUVdmdzhmRDZZZDNOMkxwbTJPUVlwbHhSMnkrTExYV2NWSUI3Qk1TRFRsT1NYeGFF
NmN2UFBEaDc5REw1SnRyRHgzTXdwODFlS1dZNDJ1QmRGeURxKy95RmNqclU3S20zSlJ2c1RLRDNuTVNzM3BZOERONi9RcWZZbHpY
MjFORE9WNnNJZkZycWQzT2xDekFoZkJnTmtwblUwQ3l2b0tLdExVL3MwTHY1RVlCcTZHMk9ld1YxMERYdFl0ZGYvanZFeE5Vc05Z
dHhCOStJTmZmNTZEMzNsQ01HYVVFYWx2ZjQ2ZXpsbEFwcDBoMzg5ZW9saTNrK0VBQW95ZGNlcG5yTXJYVS9xZUFwMW04MlorekR2
djZFMWRxWitwdVcrNUVkdWFyM0YrMmEwRml0eEFMQVlUL05wOUo5a3VtOU5VYnp4MC9JQTlTditFc091WldNbTZrRklWNXZMUkNt
MkRoOXpqLzV3dy9ha0dSOEo5SGFPQ1R2dE10YUJPMW9DclNaVkNPZ1ZOWFFST05jdHFTdWRQOTdOK1h5VVF6QXprM256V05hL2hV
R1NJWFF1cGpwWWtrK0JPU2xhZEtwY0lTSGs5M1BSWDR0b2xRalZ3UWNMTDVLQlk2Uk5RVHoxN3FHS3E1bUZhRGdEOGpTbGM4bSta
akRvc3g2WjNNcmVMSnNxYzdQOFpURmNTZyszL3RhbWFtb21VR1llSVBicFJyemMzNjBHaUJYSlVRNmQ3djJhTjlEOHBzU0p4aE5r
dnhqRWZZcHBlYTMzYXlNeGlUUzhmZHR4WmNVZUl3M2tIVGY4eTlKbXRwK29oNlBTc3pWL2JXR2dlY2Fzc1UxSGgwTnFXay9uTEsx
cG5DeFdxRVdUR3BpM2hCY0VjRk1WV0V4M00vM3Zsc2dsYmJXMmNHSW9CWW82MVR4d09VM1RBQTRWOS9Jc1pldWJTSDE1SFIwU3lQ
NGxFb1hYQzJQQUhtMklFcVV4Sk9qMmhJUkpuTWZ3YXhBYW41bEp0SEkxUjJndnkzYUpwS0loR1dHbmFJdXpnM0dQVDNrOEJmSy9r
KzZJQjB2aUhrYWpYeW9Ya0JCMHBpb1psalpwenc4TndmcUprZ1UrcnRJdDQ1T1Y1RWFIeVVQUmsrV2FibkhZU010cEtRMUdOQzBL
c2NoQlNMNmZUQVRVU1Y5V2FoWWVOWkZ2NE5FcjZXdWc4RVNOVlk2WDdkbmkxb2RjRVl1blp0N0pvSWl0eXcrOFllSU9QUlRjZ2Qy
VGw5KzlvMWhyQ0hJK2pZeUh0UTk2akFjUTdiZVNkL3d3T1VEYVNOVUV4L3lhTHIvVHpKK2sxT2FXNW9Xb1RET0lHUGRtYlAvbDdm
QTVYTm1PNjVkQUJTV1M5N2hYdU1oY0Z1N08yOFNCZnRiMjlxZ0wrUXVZYU9tVEp6b2pSdDg0ZWFjTmdCenV0NGlOUFI5WkNqRllN
dzR1dTJQMUZ5MExzWEZxMVIzSU9MekQvc2Q4TE8rVTF2WEJsblpHWUN3QVpaNzlqUFBKWXRaUFhUQkFneFlwZkVQYXYwS1VvK1RB
YkNuRk45c21QM1UxaFptdm1JejdQdGg5TmRHb2lpYnhmSmgyZnpyRk1UK1BHZVNXSVIxWW1LbGxNK3dIYkxjMlZFUnkzSzhyT0FC
aHJHN285UTFzZUpvTGU4M1ltem16Q2pDai9QNkVldHNRTC9Eb1hGdnBlZUNSVmMrVDBKTHQrZVZyOFhEOHMra0t3c3VwMmFydDVa
ZVFqUjBTRHBlNEljNGVvdmRFbGZlYXB2R2JPV2lEWndjd2pybU1USjBIa1JKMmxrUnEzMitOMkJ4bHl4YlJEMlFDSG8vbWFFREFw
RDV1citKaHFlL1RZazdtcnU3Tkl4amZYc05YbVR5aWJqODdFR3BGQ0VtRytGUEdCeEZSWERza0g1bExQOVFseDBKTWJqU0h0T1FS
NEQrNXZvOEZjR3JZRTlrelZGMXQ1RXNJeFA5ZXJNc0twTWl3VUU1NXRId0ZKV0ZtVnEydXd6MDdEK1JiSDN3T2VkSFYyVDRhRkxj
elF6bmViQlJTTjRSWXRNSERMMGtScEovL3ZzRHVlMHltTXBtZnc5TGh2SzJoejlEaWdKdEJURXJaL3NRaGhsNGtNbG5jTTRzU2Z6
V1FtMXlJNGdraGU5THZ1cmVjbXBoZlV1eVpiNzRIaWg5bWpGK3N6ajJhOVFGQ2FuRXp2TzlUZG9wM1lsZG00N0w4ZFREcnVlZEtJ
dTJJQjlDempMaW9mZHAxU3FYVnBCd0Zsa1o3NnJqbitLeTd6M0pvTVJ3U1lrKy9qaFpSSExzQXYwTlNwZXd6aVBrcVEvZ3h4ckpJ
OTkzUDNodHEvVEZNckdFT05LQlBLbDdrelJRVDg0c29haGFVcWtkajNCaHVneWFSckFCZ09ia1JjQ0JnMXVkQ0srZGkvWkF4bnJB
WGh0K2FkenFyNTRoaVdBTEJYclJSYjhJUnMzUHpBNUh4TktzRDU0clo0Q3JCeW52OU5UaEpFa1BnZ0Zvb2ZLTzU1dWpaVTg1bjMx
VFdZSnRnMzM0TTBzcVVRNjBtMG5ram9qd1kzSmtGd0wwYUZxcHV1Q0JPLzB4M2c5K0NETlY1S0JNVHVxWEpnMTdWREVzNXR6dXBw
Y3YvTmFROGVUbk80Q29Ma0E0SEE2UEt5R09lZXoyVHRpTnFqd1l5ZE5uNUkxVlIyU21CbzQ0eDh5YndBRVZKRlFDYWJpMUplNWFo
T2h4a1JWYzJyaGhxRUlGUjhnQ0Z6Wk9wVlpVQ3VzVW9wQnlNZXpUK0FaWStDbGZtN2lIQlA0Ri9pMDc5YXpZeWk4VDJmbTBySDcx
Y0wraVczc3A0T2pVZFFWR2k4VDZhbWpHU1Erc2IwQUoxZHdBcERlQ1hxVEtqWlowWG1KTFlWalBwUFJMSWI3WVd4RndmMlBYTHJY
b2FNQUVkQUxSOHlGcHI5c2tRTDR3ZUkxNTVIRmt3eE1MMHJnWnc0MS9yRk9jVXIvZm5MS1ZMZ3BEWDRyOUt2V2hDa3BiTEkvc0h2
bnEwNzU2VndpNC9xZzdxc3h3WXdwQ3NZdGt3SW5JaUU0SSs5RWU2bmhDTEdoL3ROOXl4OG1WQnZYUjhJTUxtcFN2czBFTlBWa0F1
T3VtRGlmRmZnRFdQdGhPQmhOcUZqZUJaZ25VTktDNEJsTm1wdWYxR3k2SFNJYWFKUVlIQlVTekIvVFJQV1hLV2JJWHhzU1lPSTZX
ZC81TmdRcURlRGZyMTF1QUFqTkVMcmZNZ3EwMUpHOUN6VHpOWWxnNDlLS0FRQ0RtTzB1d0Q2M3N2MGN1cHhKNmpzajhVVkZzUk0v
ZFkvcHNVUnNHS3d4STQrVDdla0xWNlZxN2psc1lLSTdNQlhtTFVnMGZseno0K0dXU2poTW8xRk9hSU1lNWc3ZjczYTZmNWtCVjdU
V1pldjN2VERGcVU0S2pML2hnNUlldmNHK01kWDBkYzhUNGgxenZHc093OG80U3h4T0lNdkZ4K09tUitwQnFUOWhaeUV3YkRqejda
VXZiQkt0czZPUG1IV3REcHp4NVAvTHJkanFkaWJ2cGUzQzhYN1c5N21vNDRFdHZuSGdOWWVqalFXUWQwY1c2R3RNS2FUZHJ0Y2hw
L01nR1JRTk53RG9qcDZqNjlHV21GdExkRHpGcWtkUDZNbWFCdWIrT3FWQnNTZlgwM0h6MmxlZEI3TFd1WTgvcHE2cy9nRzlnamQx
SmdrOFVrWVI5ekEyK1U3ak5lN0VxRUZjUGxQSEU4RGdNRGxJZUhDM0hOTTFQN0lINnpnbUZRZ3ZIUFpTUkozUU9MUVlHelRQMnRl
WHdoRy9VMTE0cUNHeHNSOHNjdXQ0Ni93ZVVRQW9aM0lKUm15eVhRaU01YmRXa1c1dStRcjJ6cFJZRjVKQ1VyUEhJRTg5RXgyc1ho
T0g1cFdzR0RIVE4wSjZpZEJWc1dOc21SOEpCTXNtK3JEZmFmSlFqRE1FcGs2VFhkM1ZJU2dhWUVBTnAycTNSK2UvVmlpaWhnbDZ1
cXdoYi84WkZFY051RFBmbHpyV1kzQy9YQkdOM2RJVUVqN3FWZEJBbm9yWll6cHMvYUJVRWx0ZXpyRkRIK0huZXFJOGdWVlZLbGZN
Y05mVW1oMWpJVHY4NitxM3kvSytxMjl4dzRyNDV0MDNqSkNRci9uMk9OT1ZZbVZZQytkRDZCTUU3eVZGaU9JRnNncTlQNVplM245
WEZvT0RycVJsTEduU3hFS1QrUXl0M2JnU3pPYzVFNjBZYjlVQ202ZytadFkzaFhtTXdaVVYwNWwwNmt4cUIyTWhRQkZFRjFqaCtR
U3RJc05xcEtRcHl0OTFZWlcyTG9KdWRYSGw1MXRuNWJVd2JDUnVEV2lVTDBzdUZuZmVxY0h3Qmd5ek9BSlRmL3dHL1VFZnV2OU5V
S3pZU2pwUXV3dGhIUXRsYW5iNHVINXJSK2xpMWVFRnVTeG1uNHlidnB5RnhKOXhETmhOTURBTEhldk5iajdIS0dXeEJCVUVtWjBH
cjcxUU92b3Q3K0NYUHluaUlERkZyQzVia0R5dklNR1M3ZVZTd09OeGFGcndBTG9oRnl5V0VuVVhTanpacytJREVPVE9yZU5zOVN3
dEt5eDBsenQ4ejkwR2k2bGtGUnB2VlFWc2JMbEdENU5QVHZlS2pBVklDOStYeHdhbHdzWjZkU3ZESzhRVDdRWTlteUo1eUR4eUlu
U3lsYzdxTlIvdDZPWlpRN2tYdHo0TThVZ05tT2RMU095QUhpWUxCMWlmMlpUNkRCV1dDeVBiZ3VKa3VXeGJ3ajdFMkkzOFRqQUhW
NWx0d0ZBTEsrR0FqU0MxQW9vMGszakJSSHRMb3kzWWlqMkFKdTRRUUxmT3h1L1lNTFRhTVQ2aXkxTjRsZjg0WEpiRnJwQXpuTEdL
ZVRlck93M20xZzVBbzFPVXFrMkFuRDlrT2tjMHNvb3MxWmZYV2Z0S1JHSFVFQmJaL05ZYlpadFNIZFNNdFJ2bVMwaXB6aDlBNnRx
b2ltQXhCUS9YcEkwYnZwa3JuS2RqSFhEbUlEMDhCckRydnVYY0dJL215OTJLeXh2bmVVbUY4WlJCd011YmFCK0h4Y3JlTjBMYXlI
SFZTbGJOSmhzV1VLWVFLRm9rSEpDZjFYdnVLZGd1NGREYnRYazJJWWk4SWJocHd0K3RONUZiZGI1QVhOVFVkYUttdFVtTWU5TExV
UUtqbnZMZ3BWNlY1bmZ6N09ETzFpQTc0aTIzTGdiK3RnR3hzK2NxeWs5c00zY0g2WFEydzFuMFRWNmF5UzJOTzl0QlhId3dXMUFn
aVo2ZEt4d3B6bXYzcnorVi9ZaDc0a3F4dDZiNjl5dFMzdGZ4YkRZR1ZVZzJqN1JhdmpmdGcxUS90MGVSUkR0RXVGQzBwN1FzRUxE
eU9KYlpTeE9pS0llYnFmNlhVaVZtbUllOWxCREpiZlpSeVBDU2lFNEIwck5jNXRUUXZ5SGMyMnRZL0ZyZ0V2Y2xOc080ZmVEckdT
ZFZrVkZHd1dLTVY5YTFmSDNCaWZWN3ZNZGFtbmNEK3dzMDRGNnV6M21pUVZnUU1ZSVhtSGVOQkJWWXV5ekU2WDFPNEF5ZDFpN1JP
b1BoMmVJS1d0MzVGc0MxWjBkYmp0UEY5NHZFWXdLTFp1ejB6bkE4ckt0TWw1YWFOV2tCdzF5R2R5VWRmUkd2K0xoYXhJaEYrRDhh
L3lnU01SUHltTGRXV25nU3B3QnNvMjgyYytDODlFZ0tWVzBhdFBiZkVjcHdyYldtdFFYbllHVnpQcjZFSjVwd2VVdm9waUpyRXN0
YnpxYzVCMDZtUWV4SDBtVjYrUkhPU293Ly9FVFZWZkdxc1VHL0hCckpWRXB5K2RSR2pPZlJxS2x5bHRCYVB4K29GcGI2YTVPTTBi
VzVLRS9EMWNydDkyZ21RSFhIbGdEUUZIdjRQdjRrMmlQZVNlVjlROG40WmVQWUJVMThvYkd4K0lrczNIUFk0MUxFT2ovV003bGpR
NjBYYjB3ZUxSSmkvYmJWcDg2Z0hpZDNLY1I3Z0F1ZHlvWm1XQnV6eFVwSWxQdHFjTEUxazBFaUpSS1A4UndIVm45cmJVN2JTanM2
NEVSUnY5Wk9weGk3Q1BLaEExSmZmZm1CNW5mUTRKS2J2dHNvVVdwRG52Vm11Mm9YWDBDUGZkZ2w0RlhUa3pkejFsTk9BL3VBdjBX
Rmo5N3JsOTR4akhIVkZiUGVZeEtjUldpMTJNWkMvYmplRU5ZTU1xVUY5LytvNndON3hTcWx3NTJ0SUloZFdJMEUwZ0k2UHh2cjhQ
R0g2aDNyWWNwUlJrRmNHLzJIb09NNGg1YklSL0laN1lramk2ZTZ5b3BEUGdCZ3JQTTdKTXVFdW9IZmJWZ2lzeGZTN0tmQk1tLzRB
cEE3bmpPK1VBdEZublVheTQyWWh4MXhyWFI5Tmd4b21hekVLUXptMTVucWs0MzJrK0w1SU9TRTJJK29EejJNSDZVQ0VMK2lIenkv
UEpZbzJpOXNIUGJDM25hTVhFTFpYVzYySkI3b0swL1BZcW80WVpFc0pwZEV5SkRyRElkbHJDZjBVQXhpY2QxVy81MGhUa3ZoQld6
MlhKUlUzMzUveWZvN2d6d3RlUTBuWS9seG9kVDZnYklPTDk1SlR4K0txcVhSbW0veVRGb1JNQkxsZEhBS2I5Q01TSXpRMVhaTEth
QyticE55STg0UE1WNHVUTWFGVGdpVWYrY01nbGxBanZxV3owTkZIZHFlanprQnhRbUVKVEpPRXg4TnRkZXB0cy9CWkFnMVhUVXV2
YXd5NUdCaU9UZ1NDaHFsbE5EY0c5SWl0NHZVd2VoQ2JYUGVwV3VYcXV1YVN1SW5KS3d4T1FXZWpxSTBCK2xNZzNUdGJudEkweXgw
ZXhLQmFldU1aY0VvOGJFcVYxUHE2K1pZVVpXTDMrUE5VTC9rUkgrdE1pOGNEb1JOTW5PK2NqYU91MFByQlROOXVOQ2RucHpadWpy
K0NFdU5uclQ3OWZYK0VoMS9wRVVPUXhsQWFuZkVjSnNBTUlSVVJUVHc1dnB4UlpBK1VTeHJvRDM5d1E1ekZ6QkJWQjYybERZVzRX
c0FPVmxpaDhYV3gybno4YjRKV1lwWkl3Y2lra2t2L3RDeHJLT0swS1phREIxdHprblUwdktYZlBoSjZGbTRVMHc2T09QNlc1UVBG
VVl5NUFiNVZVSnpJa25Gamh5OG84dDk4K0NLeHdQK29kSm1LZXd6TThzbjZSTW9SQmNQaW9CbXVJRGY2Y1d0eXNnd29IcGUzVWh6
SjE1bVNxY2VsamtPRmlJRk5IVmJiUDd4TUJLTEdMaDRqWFgyVGMzcU5jZmk0M2FEK29rcHp1Z3N6dU1HTEhkblZBSVB6RzRtZ09H
K3BFTFBWczFrVjNzeTB4dytHc0o4MCtYMS9rcnN6TWJ3cUlxT1cvVll0dEI0cFpCQmNDNkhMaU94cXRmLzhuajhkTndQR3RtelMx
UThBSVMya000VHBaaGhrWWJaMENYS0tBNlZoNmRnZnNObWE4Q1k1eSswWWtYbzMvRUhvM0xXL3FzZ3VtamJFY1BrY2ptdlBzTnZE
QS9MQUN0NlFoRzNaN3lEU05pcE5nYnh0S09ZNmlRaU51TDA0N2JHdy8yVVlabkZLZnVSekttZTFFdlVldjdrSnhSZVJVUVREK0FE
RnRzMnRZMUNtbnc3SHV1VGZzV25YUmVSMnloamU1bEVzWlRqTXVvR0E1SmhvSmF3aWwxcUNSZUZOTTZDcG5mL0RUa05GeXRaQUJs
eFNCeGJVMlRBQUlkWjRlZHIyZkVmZGRTcmJXbHlPVUhtQkszUVN6enQxREo2NTk0TVBDb0swYk9KUDJ4dVBsa2JHZFNUL1JZa3Rs
eHllYThTWENwRFpuWFk5eUFRdHlvR2V6Z3ZWYURjVit4dlg4QWFNMmdlTFJKeElyMDFDV0kvaDF5eDRDVFlmTlkyYWNpcGRwMzY5
RE9meThoaEdpc2x6bmJlYllmUVRjb3owUjkrWnZkb0luSmFYOVNQbjY5ZjJMZFROVHJzejUrZVBiTVc1VWNCcVFyNWNLT3BFNEN1
Ry9VOE9NNzYrWndkdGIydW5pQ1dBWktyOGwzenZwWTQ1dTd1R0kwV0l3UEN0ZlMrSUFJNVZrRXlLNk5pTmZXUDZncFdVdkd1UVVH
di9nSWRKL1d0NW1YZmxwb3lSbS9BeVZZUG1YYzc5Rll1Qm1KRWEySDUzaUtrR1hjUjR6VjZHYnBSckdvV3U1dFE1ZVNIcmNlZ3ha
YTZoci9nMm1sZjR5cXNhdXBwdk1JcGpZUzZYTWNaTzNyN2pvdWxYaEE5eFlTaVcycnk5anhTSVZ4cWpYYjFxR1gxWGpZVW9TOC85
UzBhOGdIRzVPZ2JhdzRaM1pYUUtUT2hsR05SejJxRG9Vak5rbDl5dFZSZ2JZeDZ3ZjdrdTZidHNBYnRnclgrbDBHMU1Kb0Q2ZXc0
RDYxKzNVM2NqWU0rWllkUzg2bWViODJkNzR0ZndPWDd5UUZaY0dKSStSTklZZTNmNXdFczRMUW1tak9EbjJnTW9wajdubEp5U3lI
V2I3VDdPL2pVUHlqcDVuRXd4cDZXQzIzOFNkeFk3bDhYMERtbkgwS1FaVDhyZGxBeDNVKzJnQmYwNmtwUHRxdXBJakZUeHZPaEl1
SmltSmdFczR0ZmJzalBoRmhEQ01xekxJbm9GaFBhS1ppd2RFNHBpcjZlaUpnbWxxNWJHZ3BZQ1NHT0VocGJnSmx0WUhLZVBNbnFo
WGVJOGJVZGdGd2JrdnoxTlpqYkdNSVNjVHJDOWttUDFuajJ3ekNIYlRQT1RPNFZvR3QrVjlmNEhJditkZC83N2h1dHp1b1hPcDNS
MkRMYnFJK054QjJ2azIvcmtna2kva3JzSllvK1lPeFhWbTNCZUNHNXF3K0c4dDVOQllWQXlGdnArYmxzdnhlS24wNGhUSEg5czBK
bGVBVWFydCt0U1RHN2ovdGpjMENlYWV0akgzME5ZYkpNY3kzSEhpQWk5U21YMXlyQUxaN2JzcEVlMXg5YUh4R1haVm14ZytUZyt3
ZE5iblFKSFdWU3dhZkE2UTBGa3Y2Y0dVd2Y1dkowV1VOaW51VjJ2OHpGTDVKVERKcm4xNlE3M3o1aDBMNEdkTUkvdEp0RUZRT2gv
N2tKZTQ4UWVIenUxQ2RCb3YvN1paQkw5cWNjS1o0S2ZYMG1scUpjUkpzdnYxMkVXOFJrc1VPcXFXQTNxNmVCNjBGekxpWk9lWXE1
NEd5aG1SblpEd2l6MGZLNkhlWG11SDAwaC9PK2t1SFZ6WGZnclJuVzBueGFKMEx3K1pWeEVoSmVHekt6VHJjdWlXR3FybUJsU3Uy
aGFLNFRrUjRTbDdiUmZ3N1c2UmxISVJzYzVVMjIxeTRNVW44QmJKYSs2c0Foc2JjM2lXRkJJWDZVZG4wWHVLMUEwaGtLZWdLbU5J
M2lEalVWVlhqR2laaFJDaFJhYzlreHBXZ1ljQVpmOERmL3dGbXpFSmlDT0t5RUhLMzJjR2FaL2FtMVhCNW84aEdvb09FWjZyTHJX
Q3JXWVlvbVkwVHN1K294ZTVrMEZDZWd6WUV4bDY3NTBETzdFV3hwMDZ6TmU1cUlDQkpLbHFtd2pFVmJQTjlXMWVGTE5lK3JFMGZp
SnNXbzZtZlVseWlNQ1RVNzZLOTk4VEhLNTZOdkRHcmx5UFY4NWkrOVNlby9rU1I2T1dOdXBXYWZjK3JRbjF0a3I3cEJpVmpyeGhP
eGp1M1NVTmhmc1dMeWZJY0lnZkk5NXdGb3FHeVdTZVhNSytRdzh5ZzlNVVYvdlZBT2N3L0VPc2ExVGoxSUJlZ1pLcWlIT3B6d0FE
R3lURGdGWDFqaHd6bGdyOHltUnJoWG9JNjBMMThwNEk2NEtNU2kyUU1PVFY0ZnFMRk55Y3c5T0RpRmM5Sjc5OEU4QXFUa252bkRp
WDF1QzZUcUdUYS93R21RNWdJQS81bnRGdlAxdURqamcyUjUrSi9ib0xiNUhIQWR3ZUhUZWkrYzVMUytpVW5OTDd2bVJkdnpjRG9G
aWVsYTFVclFucGNWZTNvb1ZGdlZKMG1JeWdaalZMdVFqVUNCY2ZIaDdKcld3cHVkRUtTNkloelBNY0U5NEhvb3k1ak1xT1dYNG92
eUFqWjFvZEpuUGJvc3FPY1dVZnZUUmVSeWFwSXJKMUV2Z2hPenUvVGllZ2lpMTVDNzQ4QVhaOXlRdlpadDdLMTVUZGtFcVdrVytu
Y08rbHJZcnd2dTFpL09iMzlWT0NkNWFhRFQwR0YrcVhCYzlGRVZaUmE0TGl5UThJMXZmZi82Q2xoeVFNcHRZZTlVd2t3b1lrc3VT
SHV3MzY2MXpIa3JIcFU1bU5PMjE2enpDcnVuUWRyT2p2eXdLU2JUelpYb25pTitha2dnVVdHVzJLaUVnLzJnbjVhWTlFaXh6KzdZ
Nkd2S3hVL0FKb24rekRGbFR3dXRBTm9TUG9EeEJCZmxEK3UwN3BTMm91R1lBM2xGa3Q4cmE1U1hkdmJid01vZlhMeTFUZHhGWUZX
dVpPQ0JSZi96MDNwdnRTVmxPKzBkdEVUTFVDQW4xVUkyV0xoSmxZU01haFFjQUdOZUlUZVliSDQyTC9rd1hkUFFjbExYUUtHQld6
NVF0VHM3Y0lmUHZBMko1amdjVlRZSm1JZ1daaDB4YzdBUT09
"""


import hid

try:
    from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
except ImportError:
    Cipher = None


# ============================================================
# Version / debug
# ============================================================

VERSION = "1.21"
DEBUG = "--debug" in [arg.lower() for arg in sys.argv[1:]]

SHUTDOWN_REQUESTED = threading.Event()


def _handle_sigint(signum, frame):
    """Request a clean shutdown without raising KeyboardInterrupt.

    PyInstaller/macOS can otherwise raise repeated KeyboardInterrupt exceptions
    during cleanup, which may abort before settings are saved.
    """
    SHUTDOWN_REQUESTED.set()


# ============================================================
# Paths / config
# ============================================================

CONFIG_FILE = os.path.join(SCRIPT_DIR, "psx_winctrl_pfp.ini")
FONT_FILE = os.path.join(SCRIPT_DIR, "Boeing.dat")


# ============================================================
# HID / timing
# ============================================================

READ_SIZE = 64
BYTE_LIMIT = 17

# Active CDU can be changed at runtime from the scratchpad:
#   CDU-L = Left CDU
#   CDU-C = Center CDU
#   CDU-R = Right CDU
DEFAULT_CDU = "L"

CDU_CONFIGS = {
    "L": {
        "label": "Left",
        "key_qh": "Qh401",
        "screen_qs_lines": list(range(62, 76)),
        "lights_qi": 86,
        "blank_qi": 89,
        "lcd_qi248_bit": 1 << 19,
    },
    "C": {
        "label": "Center",
        "key_qh": "Qh402",
        "screen_qs_lines": list(range(76, 90)),
        "lights_qi": 87,
        "blank_qi": 90,
        "lcd_qi248_bit": 1 << 21,
    },
    "R": {
        "label": "Right",
        "key_qh": "Qh403",
        "screen_qs_lines": list(range(90, 104)),
        "lights_qi": 88,
        "blank_qi": 91,
        "lcd_qi248_bit": 1 << 20,
    },
}

MIN_SEND_INTERVAL = 0.02
STABLE_FRAMES = 2
RISING_COOLDOWN = 0.10

# ============================================================
# Display / runtime defaults
# ============================================================

# Display font file. Must be next to psx_pfp7.py or psx_pfp7.exe.
# Example:
#   psx_winctrl_pfp.py / psx_winctrl_pfp.exe
#   psx_winctrl_pfp.ini
#   Boeing.dat

DEFAULT_CDU_COLOR = "w"
DEFAULT_CDU_ATC_ALTN = 1  # 1 = replace ATC key, 0 = keep original ATC key
CDU_ATC_ALTN_SEQUENCE = [65, 42] #Key sequence FMC COMM + LSK2 Left > opens ALTN Page

CDU_SWITCH_CLEAR_SEQUENCE = [39, -1]

# Bridge scratchpad commands are removed by holding CLR briefly.
# PSX treats a held CLR key as "clear scratchpad".
CDU_COMMAND_CLEAR_HOLD_SECONDS = 1.00


class RuntimeConfig:
    def __init__(self):
        self.lock = threading.Lock()
        self.active_cdu = DEFAULT_CDU
        self.active_cdu_dirty = False
        self.brightness_step = 16
        self.brightness_dirty = False
        self.cdu_color = DEFAULT_CDU_COLOR
        self.cdu_atc_altn = DEFAULT_CDU_ATC_ALTN
        self.cdu_atc_altn_user = DEFAULT_CDU_ATC_ALTN
        self.nextgen_fmc = True
        self.mode = "DEFAULT"

    def set_ng(self):
        with self.lock:
            self.cdu_color = "w"
            self.nextgen_fmc = True
            self.cdu_atc_altn = self.cdu_atc_altn_user
            self.mode = "FMC_NG"

    def set_legacy(self):
        with self.lock:
            self.cdu_color = "g"
            self.nextgen_fmc = False
            self.cdu_atc_altn = 0
            self.mode = "FMC_LEGACY"

    def set_active_cdu(self, cdu, mark_dirty=True):
        cdu = cdu.upper()

        if cdu not in CDU_CONFIGS:
            return False

        with self.lock:
            if self.active_cdu != cdu:
                self.active_cdu = cdu
                if mark_dirty:
                    self.active_cdu_dirty = True

        return True

    def get_active_cdu(self):
        with self.lock:
            return self.active_cdu

    def is_active_cdu_dirty(self):
        with self.lock:
            return self.active_cdu_dirty

    def set_brightness_step(self, step, mark_dirty=True):
        step = max(0, min(PFP7_SCREEN_BRIGHTNESSS - 1, int(step)))

        with self.lock:
            if self.brightness_step != step:
                self.brightness_step = step
                if mark_dirty:
                    self.brightness_dirty = True

        return step

    def get_brightness_step(self):
        with self.lock:
            return self.brightness_step

    def is_brightness_dirty(self):
        with self.lock:
            return self.brightness_dirty

    def get_active_cdu_config(self):
        with self.lock:
            return CDU_CONFIGS[self.active_cdu]

    def set_from_qi248(self, nextgen_fmc, cdu_lcd):
        with self.lock:
            self.cdu_color = "w" if cdu_lcd else "g"
            self.nextgen_fmc = bool(nextgen_fmc)

            # ATC/ALTN behavior is user-configurable when NG FMC is active.
            # When Legacy FMC is active, force the original ATC key at runtime only.
            # Do not save this forced runtime change to psx_winctrl_pfp.ini.
            self.cdu_atc_altn = self.cdu_atc_altn_user if self.nextgen_fmc else 0

            active_cdu = self.active_cdu

            if nextgen_fmc and cdu_lcd:
                self.mode = f"QI248_{active_cdu}_NG_LCD"
            elif nextgen_fmc:
                self.mode = f"QI248_{active_cdu}_NG_CRT"
            elif cdu_lcd:
                self.mode = f"QI248_{active_cdu}_LEGACY_LCD"
            else:
                self.mode = f"QI248_{active_cdu}_LEGACY_CRT"

    def get_cdu_color(self):
        with self.lock:
            return self.cdu_color

    def set_cdu_atc_altn(self, atc_altn):
        with self.lock:
            self.cdu_atc_altn_user = 1 if int(atc_altn) == 1 else 0
            self.cdu_atc_altn = self.cdu_atc_altn_user if self.nextgen_fmc else 0


    def get_cdu_atc_altn(self):
        with self.lock:
            return self.cdu_atc_altn

    def get_cdu_atc_altn_user(self):
        with self.lock:
            return self.cdu_atc_altn_user


    def get_mode(self):
        with self.lock:
            return self.mode


RUNTIME_CONFIG = RuntimeConfig()

FMC_WIDTH = 24
FMC_HEIGHT = 14

# PSX CDU LCD color strings. Each CDU has 14 Qs lines:
#   Ti, 1s, 1b, 2s, 2b, ... 6s, 6b, Sp
# These map directly to the 14 displayed CDU rows.
CDU_COLOR_QS_START = {
    "L": 500,
    "C": 514,
    "R": 528,
}
CDU_COLOR_QS_RANGE = range(500, 542)

# PSX LCD color codes -> MobiFlight color codes.
# PSX b=blue maps to MobiFlight o=blue.
# PSX y is used as grey background; MobiFlight e is grey.
PSX_TO_MOBIFLIGHT_COLOR = {
    "a": "a",  # amber
    "b": "o",  # blue
    "c": "c",  # cyan
    "g": "g",  # green
    "m": "m",  # magenta
    "r": "r",  # red
    "w": "w",  # white
    "y": "e",  # grey / grey background
}

# PSX CDU light bitmask:
# Left CDU / Captain = Qi86
# Center CDU        = Qi87
# Right CDU / FO    = Qi88
#
# PSX FMC/CDU options bitmask:
# Qi248 bit 13 = Next Gen FMC
# Qi248 bit 19 = Left CDU LCD
# Qi248 bit 21 = Center CDU LCD
# Qi248 bit 20 = Right CDU LCD
PSX_FMC_CONFIG_QI = 248
QI248_NEXTGEN_FMC_BIT = 1 << 13

# PSX CDU blanking timers:
# Qi89 = BlankTimeCduL, Qi90 = BlankTimeCduC, Qi91 = BlankTimeCduR.
# The CDU screen must be blanked whenever the related value is non-zero.
CDU_BLANK_QI = {
    "L": 89,
    "C": 90,
    "R": 91,
}
CDU_BLANK_QI_TO_CDU = {qi: cdu for cdu, qi in CDU_BLANK_QI.items()}

MDT_ALL_LIGHTS_BIT = 0x2000  # 8192

PSX_LIGHT_BITS_TO_PFP7 = {
    0x0001: "EXEC",
    0x0002: "DSPY",
    0x0004: "FAIL",
    0x0008: "MSG",
    0x0010: "OFST",
}

NEED_RELEASE = {39, 60}  # CLR, ATC require explicit release on hardware key release

# MobiFlight Connector path
# Used for automatic MobiFlight startup and version reporting.
# LED/backlight control is direct HID and no longer uses MobiFlightWwFcu.dll.
MOBIFLIGHT_PATH = None

# WINCTRL USB Vendor ID
WINCTRL_VENDOR_ID = 0x4098

# PFP7 captain defaults
PFP7_PRODUCT_ID = 0xBB37
PFP7_DEST = bytes([0x33, 0xBB])

# PFP7 LED channels discovered by testing:
# 0x03 = DSPY
# 0x04 = FAIL
# 0x05 = MSG
# 0x06 = OFST
# 0x07 = EXEC
PFP7_LEDS = {
    "DSPY": 0x03,
    "FAIL": 0x04,
    "MSG":  0x05,
    "OFST": 0x06,
    "EXEC": 0x07,
}

PFP7_LED_INTENSITY = 255

# PFP7 screen backlight brightness
# Channel 0x01 controls the screen backlight.
# Brightness uses 22 steps mapped from 10 to 255.
PFP7_SCREEN_BACKLIGHT_CHANNEL = 0x01
PFP_KEY_BACKLIGHT_CHANNEL = 0x00
PFP7_SCREEN_BRIGHTNESS_MIN = 10
PFP7_SCREEN_BRIGHTNESS_MAX = 255
PFP7_SCREEN_BRIGHTNESSS = 22
PFP7_SCREEN_BRIGHTNESS_DEFAULT_STEP = 16

# Hold behavior for BRT+/BRT-
# One step is applied immediately on press.
# After 0.5s hold, brightness repeats. Full 22-step range takes ~3 seconds.
PFP7_BRT_HOLD_DELAY = 0.5
PFP7_BRT_FULL_RANGE_SECONDS = 3.0
PFP7_BRT_REPEAT_INTERVAL = PFP7_BRT_FULL_RANGE_SECONDS / (PFP7_SCREEN_BRIGHTNESSS - 1)


def brightness_value_from_step(step):
    step = max(0, min(PFP7_SCREEN_BRIGHTNESSS - 1, step))

    span = PFP7_SCREEN_BRIGHTNESS_MAX - PFP7_SCREEN_BRIGHTNESS_MIN
    value = PFP7_SCREEN_BRIGHTNESS_MIN + round(
        span * step / (PFP7_SCREEN_BRIGHTNESSS - 1)
    )

    return max(0, min(255, value))

PSX_NAME_TO_CODE = {
    "LSKL1": 41, "LSKL2": 42, "LSKL3": 43, "LSKL4": 44, "LSKL5": 45, "LSKL6": 46,
    "LSKR1": 51, "LSKR2": 52, "LSKR3": 53, "LSKR4": 54, "LSKR5": 55, "LSKR6": 56,
    "A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "G": 16, "H": 17, "I": 18, "J": 19,
    "K": 20, "L": 21, "M": 22, "N": 23, "O": 24, "P": 25, "Q": 26, "R": 27, "S": 28, "T": 29,
    "U": 30, "V": 31, "W": 32, "X": 33, "Y": 34, "Z": 35,
    "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
    "SP": 36, "DEL": 37, "/": 38, "CLR": 39,
    "+/-": 68, "+": 68, ".": 67,
    "INIT": 57, "INITREF": 57, "INIT REF": 57,
    "ROUTE": 58, "DEPARR": 59, "DEP/ARR": 59, "ATC": 60, "VNAV": 61, "FIX": 62,
    "LEGS": 63, "HOLD": 64, "FMC": 65, "PROG": 66,
    "MENU": 47, "NAVRAD": 48, "NAV/RAD": 48, "PREV": 49, "NEXT": 50,
    "EXEC": 40,
}

os.system("cls" if os.name == "nt" else "clear")

class StatusLog:
    def __init__(self):
        self.lock = threading.Lock()

    def header(self):
        print(f"""
===============================================================
            PSX ↔ WinCTRL PFPx Bridge  v{VERSION}
---------------------------------------------------------------
                   Jamie Janssen © 2026
===============================================================
""", flush=True)

    def start(self):
        self.header()
        self.log("Starting...")

    def log(self, message):
        with self.lock:
            if DEBUG:
                timestamp = time.strftime("%H:%M:%S")
                print(f"{timestamp}  {message}", flush=True)
            else:
                print(message, flush=True)


STATUS = StatusLog()


def log(message):
    STATUS.log(message)


def log_debug(message):
    if DEBUG:
        log(message)


ANSI_HIGHLIGHT = "\033[92m"  # Bright green. Change to 97=white, 96=cyan, 93=yellow if desired.
ANSI_RESET = "\033[0m"


def log_highlight(message):
    with STATUS.lock:
        if DEBUG:
            timestamp = time.strftime("%H:%M:%S")
            print(f"{timestamp}  {ANSI_HIGHLIGHT}{message}{ANSI_RESET}", flush=True)
        else:
            print(f"{ANSI_HIGHLIGHT}{message}{ANSI_RESET}", flush=True)


def mobiflight_compatibility_error(reason):
    return (
        f"{reason}\n\n"
        "Unsupported MobiFlight Connector installation.\n"
        "Please install MobiFlight Connector v11.1.0 or newer.\n"
        "If MobiFlight is already up to date, uninstall and reinstall "
        "MobiFlight Connector."
    )


def save_ini_value(section, key, value):
    """Update one value in psx_winctrl_pfp.ini while preserving comments and layout."""
    section_header = f"[{section}]"
    key_lower = str(key).strip().lower()
    value = str(value)

    try:
        with open(CONFIG_FILE, "r", encoding="utf-8") as f:
            lines = f.readlines()
    except FileNotFoundError:
        cfg = configparser.ConfigParser()
        cfg.add_section(section)
        cfg.set(section, key, value)

        with open(CONFIG_FILE, "w", encoding="utf-8") as f:
            cfg.write(f)

        return

    in_section = False
    section_found = False
    key_found = False
    insert_index = None

    for i, line in enumerate(lines):
        stripped = line.strip()

        # Section header
        if stripped.startswith("[") and stripped.endswith("]"):
            if in_section and not key_found:
                insert_index = i

            in_section = stripped.lower() == section_header.lower()

            if in_section:
                section_found = True
                insert_index = i + 1

            continue

        if in_section:
            insert_index = i + 1

            # Preserve empty/comment lines
            if not stripped or stripped.startswith(("#", ";")):
                continue

            if "=" in line:
                existing_key = line.split("=", 1)[0].strip().lower()

                if existing_key == key_lower:
                    newline = "\n" if line.endswith("\n") else ""
                    lines[i] = f"{key} = {value}{newline}"
                    key_found = True
                    break

    if not section_found:
        if lines and not lines[-1].endswith("\n"):
            lines[-1] += "\n"

        lines.append(f"\n[{section}]\n")
        lines.append(f"{key} = {value}\n")

    elif not key_found:
        if insert_index is None:
            insert_index = len(lines)

        lines.insert(insert_index, f"{key} = {value}\n")

    with open(CONFIG_FILE, "w", encoding="utf-8") as f:
        f.writelines(lines)


def atc_key_value_to_altn(value):
    """Return 1 for ALTN mode and 0 for original ATC mode."""
    value = str(value or "").strip().upper()

    if value == "ALTN":
        return 1

    return 0


def atc_altn_to_ini_value(atc_altn):
    return "ALTN" if int(atc_altn) == 1 else "ATC"


def connect_with_retry(host, port, name, stop_evt=None, retry_delay=5.0):
    while stop_evt is None or not stop_evt.is_set():
        sock = None

        try:
            log_debug(f"[{name}] connecting {host}:{port}...")

            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.connect((host, port))
            sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
            sock.settimeout(1.0)

            log(f"[{name}] connected")
            return sock

        except KeyboardInterrupt:
            log(f"[{name}] stopped during connection retry")

            try:
                if sock:
                    sock.close()
            except Exception:
                pass

            raise

        except (ConnectionRefusedError, TimeoutError, OSError) as e:
            log(f"[{name}] not available: {e}")
            log(f"[{name}] retrying in {retry_delay:.0f} seconds...")

            try:
                if sock:
                    sock.close()
            except Exception:
                pass

            end_time = time.time() + retry_delay

            while time.time() < end_time:
                if stop_evt is not None and stop_evt.is_set():
                    return None

                time.sleep(0.1)

    return None


class Pfp7LedController:
    """Direct HID LED/backlight controller for WINCTRL PFPx/PFP4 family devices.

    This replaces the previous MobiFlightWwFcu.dll LED route.

    MobiFlight-style light control command:
      02 dest0 dest1 00 00 03 49 light_type value 00 00 00 00 00

    For PFP7:
      dest = 33 BB
      light_type: backlight=01, DSPY=03, FAIL=04, MSG=05, OFST=06, EXEC=07
    """

    def __init__(self, hid_device, hid_lock=None, dest=None):
        self.dev = hid_device
        self.hid_lock = hid_lock or threading.Lock()
        self.dest = bytes(dest or PFP7_DEST)
        self.lock = threading.Lock()
        self.last_states = {}
        self.screen_brightness_step = RUNTIME_CONFIG.get_brightness_step()
        self.connected = False

    def start(self):
        with self.lock:
            self.connected = True
            log_debug("[PFP7 LED] direct HID connected")

            self._set_screen_brightness_step_unlocked(
                self.screen_brightness_step,
                force=True
            )

            for led_name in PFP7_LEDS:
                self._set_led_unlocked(led_name, False, force=True)

    def force_blackout(self):
        """Force all PFP lighting to black while the HID handle is still open."""
        with self.lock:
            # Backlights to black
            self._write_light_control_message(PFP_KEY_BACKLIGHT_CHANNEL, 0)
            self._write_light_control_message(PFP7_SCREEN_BACKLIGHT_CHANNEL, 0)

            # Annunciator LEDs off
            for led_name in PFP7_LEDS:
                self._set_led_unlocked(led_name, False, force=True)

    def stop(self):
        """Switch annunciators and backlights off during shutdown.

        CTRL+C can close the HID handle while shutdown is already in progress.
        ValueError('not open') is harmless in that case and is ignored.
        """
        try:
            self.force_blackout()

        except ValueError as e:
            if "not open" not in str(e).lower():
                log(f"[PFP LED] shutdown error: {repr(e)}")

        except KeyboardInterrupt:
            pass

        except Exception as e:
            log(f"[PFP LED] shutdown error: {repr(e)}")

    def _write_light_control_message(self, light_type, value):
        value = int(value) & 0xFF

        msg = bytes([
            0x02, self.dest[0], self.dest[1],
            0x00, 0x00,
            0x03, 0x49,
            int(light_type) & 0xFF,
            value,
            0x00, 0x00, 0x00, 0x00, 0x00,
        ])

        with self.hid_lock:
            return self.dev.write(msg)

    def set_led(self, name, on, intensity=PFP7_LED_INTENSITY):
        name = name.upper()

        if name not in PFP7_LEDS:
            log_debug(f"[PFP7 LED] unknown LED: {name}")
            return

        with self.lock:
            self._set_led_unlocked(name, on, intensity=intensity)

    def change_screen_brightness_step(self, delta):
        with self.lock:
            new_step = self.screen_brightness_step + delta
            self._set_screen_brightness_step_unlocked(new_step)

    def get_screen_brightness_step(self):
        with self.lock:
            return self.screen_brightness_step

    def _set_screen_brightness_step_unlocked(self, step, force=False):
        step = max(0, min(PFP7_SCREEN_BRIGHTNESSS - 1, step))
        value = brightness_value_from_step(step)

        if not force and step == self.screen_brightness_step:
            return

        self.screen_brightness_step = step
        RUNTIME_CONFIG.set_brightness_step(step, mark_dirty=not force)

        self._write_light_control_message(
            PFP7_SCREEN_BACKLIGHT_CHANNEL,
            value
        )
        self._write_light_control_message(
            PFP_KEY_BACKLIGHT_CHANNEL,
            value
        )

        log_debug(
            f"[PFP BRT] screen/key backlight "
            f"step {step + 1}/{PFP7_SCREEN_BRIGHTNESSS} value={value}"
        )

    def apply_psx_cdu_lights_bitmask(self, state):
        md_t_all = bool(state & MDT_ALL_LIGHTS_BIT)

        with self.lock:
            for bit, led_name in PSX_LIGHT_BITS_TO_PFP7.items():
                on = md_t_all or bool(state & bit)
                self._set_led_unlocked(led_name, on)

    def _set_led_unlocked(self, name, on, intensity=PFP7_LED_INTENSITY, force=False):
        name = name.upper()

        value = 1 if on else 0

        if not force and self.last_states.get(name) == value:
            return

        self.last_states[name] = value

        self._write_light_control_message(
            PFP7_LEDS[name],
            value
        )

        log_debug(f"[PFP7 LED] {name} {'ON' if on else 'OFF'}")


def is_mobiflight_websocket_available(host="127.0.0.1", port=8320, timeout=0.25):
    """Check whether the MobiFlight websocket TCP port is already reachable."""
    try:
        with socket.create_connection((host, port), timeout=timeout):
            return True
    except OSError:
        return False


def load_config():
    cfg = configparser.ConfigParser()
    cfg.read(CONFIG_FILE, encoding="utf-8")

    host = cfg.get("PSX", "host", fallback="127.0.0.1").strip()
    port = cfg.getint("PSX", "port", fallback=10747)
    vid = WINCTRL_VENDOR_ID
    pid = int(cfg.get("FMC", "PID", fallback="0xBB37"), 16)
    did = cfg.get("FMC", "DID", fallback="33BB").strip().upper().replace("0X", "")

    if len(did) != 4:
        log(f"[CONFIG] invalid FMC DID={did!r}; using 33BB")
        did = "33BB"

    global PFP7_PRODUCT_ID, PFP7_DEST
    PFP7_PRODUCT_ID = pid
    PFP7_DEST = bytes([int(did[0:2], 16), int(did[2:4], 16)])

    atc_key = cfg.get("FMC", "ATC_KEY", fallback="ALTN").strip().upper()
    if atc_key not in ("ATC", "ALTN"):
        log(f"[CONFIG] invalid FMC ATC_KEY={atc_key!r}; using ALTN")
        atc_key = "ALTN"

    RUNTIME_CONFIG.set_cdu_atc_altn(atc_key_value_to_altn(atc_key))

    active_cdu = cfg.get("FMC", "ACTIVE_CDU", fallback=DEFAULT_CDU).strip().upper()
    if active_cdu not in CDU_CONFIGS:
        log(f"[CONFIG] invalid FMC ACTIVE_CDU={active_cdu!r}; using {DEFAULT_CDU}")
        active_cdu = DEFAULT_CDU

    RUNTIME_CONFIG.set_active_cdu(active_cdu, mark_dirty=False)

    brightness_step = cfg.getint(
        "FMC",
        "BRIGHTNESS",
        fallback=PFP7_SCREEN_BRIGHTNESS_DEFAULT_STEP
    )
    brightness_step = max(0, min(PFP7_SCREEN_BRIGHTNESSS - 1, brightness_step))
    RUNTIME_CONFIG.set_brightness_step(brightness_step, mark_dirty=False)

    log_debug(f"[CONFIG] PSX {host}:{port}")
    log_debug(f"[CONFIG] FMC VID={hex(vid)} PID={hex(pid)} DID={did}")
    log_debug(f"[CONFIG] FMC ATC_KEY={atc_altn_to_ini_value(RUNTIME_CONFIG.get_cdu_atc_altn_user())}")
    log_debug(f"[CONFIG] FMC ACTIVE_CDU={RUNTIME_CONFIG.get_active_cdu()}")
    log_debug(f"[CONFIG] FMC BRIGHTNESS={RUNTIME_CONFIG.get_brightness_step()}")
    log_debug("[CONFIG] Display control: direct HID")
    log_debug("[CONFIG] LED/backlight control: direct HID")

    return host, port, vid, pid


BUILTIN_MAP = {
    "2,4": "INIT REF",
    "2,5": "ROUTE",
    "2,6": "DEPARR",
    "2,7": "ATC",
    "3,0": "VNAV",
    "3,3": "FIX",
    "3,4": "LEGS",
    "3,5": "HOLD",
    "3,7": "PROG",
    "4,0": "EXEC",
    "4,1": "MENU",
    "4,3": "PREV",
    "4,4": "NEXT",
    "6,1": "A",
    "6,2": "B",
    "6,3": "C",
    "6,4": "D",
    "6,5": "E",
    "6,6": "F",
    "6,7": "G",
    "7,0": "H",
    "7,1": "I",
    "7,2": "J",
    "7,3": "K",
    "7,4": "L",
    "7,5": "M",
    "7,6": "N",
    "7,7": "O",
    "4,6": "2",
    "4,7": "3",
    "5,0": "4",
    "5,1": "5",
    "5,2": "6",
    "5,3": "7",
    "5,4": "8",
    "5,5": "9",
    "5,6": ".",
    "5,7": "0",
    "8,0": "P",
    "8,1": "Q",
    "8,2": "R",
    "8,3": "S",
    "8,4": "T",
    "8,5": "U",
    "8,6": "V",
    "8,7": "W",
    "9,0": "X",
    "9,1": "Y",
    "9,2": "Z",
    "9,3": "SP",
    "9,4": "DEL",
    "9,5": "/",
    "9,6": "CLR",
    "6,0": "+",
    "1,0": "LSKL1",
    "1,1": "LSKL2",
    "1,2": "LSKL3",
    "1,3": "LSKL4",
    "1,4": "LSKL5",
    "1,5": "LSKL6",
    "1,6": "LSKR1",
    "1,7": "LSKR2",
    "2,0": "LSKR3",
    "2,1": "LSKR4",
    "2,2": "LSKR5",
    "2,3": "LSKR6",
    "3,6": "FMC",
    "4,5": "1",
    "4,2": "NAVRAD",
    "3,2": "BRT+",
    "3,1": "BRT-"
}


def load_map():
    mapping = {}

    for k, v in BUILTIN_MAP.items():
        by, bi = map(int, k.split(","))

        if by < BYTE_LIMIT:
            mapping[(by, bi)] = str(v).strip()

    log_debug(f"[MAP] loaded {len(mapping)} built-in bitpos (<{BYTE_LIMIT})")
    return mapping


def pressed_from_mapping(frame, mapped_bps):
    pressed = set()
    flen = min(len(frame), BYTE_LIMIT)

    for by, bi in mapped_bps:
        if by < flen and (frame[by] & (1 << bi)):
            pressed.add((by, bi))

    return pressed


# Direct HID display timing.
# These small delays make font preload more reliable after quit/restart cycles.
DISPLAY_STARTUP_SETTLE_SECONDS = 0.30
DISPLAY_FONT_HEAD_DELAY_SECONDS = 0.05
DISPLAY_FONT_DATA_DELAY_SECONDS = 0.20
DISPLAY_INIT_DELAY_SECONDS = 0.10
DISPLAY_CLEAR_DELAY_SECONDS = 0.10
DISPLAY_SHUTDOWN_CLEAR_DELAY_SECONDS = 0.05

# Display command headers from MobiFlight WINCTRL CDU/PFP implementation.
DISPLAY_CMD_HEADERS = {
    "0301": bytes([0x03, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x00, 0, 0, 0]),
    "0401": bytes([0x04, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0]),
    "0601": bytes([0x06, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x19, 0, 0, 0]),
    "0701": bytes([0x07, 0x01, 0, 0, 0, 0, 0, 0, 0]),
    "1001": bytes([0x10, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0, 0]),
    "1201": bytes([0x12, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x04, 0, 0, 0]),
    "1301": bytes([0x13, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x04, 0, 0, 0]),
    "1801": bytes([0x18, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0, 0]),
    "1901": bytes([0x19, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x0E, 0, 0, 0]),
    "1A01": bytes([0x1A, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0]),
    "1C01": bytes([0x1C, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x00, 0, 0, 0]),
    "1E01": bytes([0x1E, 0x01, 0, 0, 0, 0, 0, 0, 0, 0x00, 0, 0, 0]),
}

# MobiFlight AES values for encrypted font .dat files.
FONT_KEY_B64 = "MY6JFI/baxXX0dyOV1c8Bw=="
FONT_NONCE_B64 = "CcwLDBJBtVe2JUHDnMhWtw=="

# Direct HID display text format.
COLOR_STEP = 0x21
COLOR_INVERT_OFFSET = 0x1B
COLOR_SMALL_OFFSET = 0x16B
FORMAT_TABLE = {
    "a": 0x00,                    # amber/base
    "w": 0x00 + COLOR_STEP * 2,   # white
    "c": 0x00 + COLOR_STEP * 3,   # cyan
    "g": 0x00 + COLOR_STEP * 4,   # green
    "m": 0x00 + COLOR_STEP * 5,   # magenta
    "r": 0x00 + COLOR_STEP * 6,   # red
    "y": 0x00 + COLOR_STEP * 7,   # yellow
    "o": 0x00 + COLOR_STEP * 8,   # blue/orange naming differs in older code
    "e": 0x00 + COLOR_STEP * 9,   # grey
    "k": 0x00 + COLOR_STEP * 10,  # khaki
}


class DirectHidDisplaySender:
    """Direct HID display controller.

    This replaces the previous MobiFlight websocket JSON route.

    It loads Boeing.dat from SCRIPT_DIR, preloads the font, initializes/clears
    the display, and writes CDU display data using 0xF2 HID reports.
    """

    def __init__(self, hid_device, hid_lock, dest=None, font_file=None):
        self.dev = hid_device
        self.hid_lock = hid_lock
        self.dest = bytes(dest or PFP7_DEST)
        self.font_file = font_file or FONT_FILE
        self.counter = 0
        self.stop_evt = threading.Event()
        self.started = False

    def start(self):
        # Give the device a brief moment after opening/restarting before font preload.
        time.sleep(DISPLAY_STARTUP_SETTLE_SECONDS)

        log("[CDU] loading Font to PFP")
        font_json = self.load_font_dat(self.font_file)
        commands = self.font_json_to_commands(font_json)

        self.send_display_commands(commands["large_head"])
        time.sleep(DISPLAY_FONT_HEAD_DELAY_SECONDS)

        self.send_display_commands(commands["large_data"])
        time.sleep(DISPLAY_FONT_DATA_DELAY_SECONDS)

        self.send_display_commands(commands["small_head"])
        time.sleep(DISPLAY_FONT_HEAD_DELAY_SECONDS)

        self.send_display_commands(commands["small_data"])
        time.sleep(DISPLAY_FONT_DATA_DELAY_SECONDS)

        self.send_display_commands(self.pfp_init_commands())
        time.sleep(DISPLAY_INIT_DELAY_SECONDS)

        self.send_display_commands(self.clear_commands())
        time.sleep(DISPLAY_CLEAR_DELAY_SECONDS)

        self.started = True
        log("[CDU] ready")

    def show_welcome_screen(self, version, seconds=3.0):
        """Show a centered startup splash screen with fresh alternating colors."""
        if not self.started:
            return

        display = self.make_blank_display()

        title = "PSX WINCTRL PFPx"
        subtitle = f"BRIDGE v{version}"
        name = "Jamie  Janssen"

        self._put_centered_colored_text(display, 4, title, ["c", "g", "y", "w", "m"])
        self._put_centered_colored_text(display, 6, subtitle, ["g", "c", "w", "y"])
        self._put_centered_colored_text(display, 9, name, ["y", "w", "c", "g", "m"])

        self.send_cdu_display_bytes(self.display_to_bytes(display))
        time.sleep(seconds)

    def make_blank_display(self):
        return [[" ", "w", 0, False] for _ in range(FMC_WIDTH * FMC_HEIGHT)]

    def _put_centered_colored_text(self, display, row, text, colors):
        col = max(0, (FMC_WIDTH - len(text)) // 2)
        for i, ch in enumerate(text[:FMC_WIDTH]):
            idx = row * FMC_WIDTH + col + i
            if 0 <= idx < len(display):
                color = colors[i % len(colors)] if ch != " " else "w"
                display[idx] = [ch, color, 0, False]


    def force_blank_display(self):
        """Blank the CDU text while the HID handle is still open.

        Shutdown must be quick and robust. Do not send the heavier clear_commands()
        sequence here; the screen/key backlights are switched off separately.
        """
        self.send_cdu_display_bytes(self.display_to_bytes(self.make_blank_display()))

    def stop(self):
        self.stop_evt.set()
        try:
            self.force_blank_display()
        except ValueError as e:
            if "not open" not in str(e).lower():
                log_debug(f"[CDU] shutdown error: {repr(e)}")
        except KeyboardInterrupt:
            pass
        except Exception as e:
            log_debug(f"[CDU] shutdown error: {repr(e)}")

    def send_lines(self, lines, color_lines=None):
        if not self.started:
            return

        display = self._lines_to_display_cells((lines, color_lines))
        byte_data = self.display_to_bytes(display)
        self.send_cdu_display_bytes(byte_data)
        log_debug("[CDU] direct HID frame sent")

    def _new_message(self):
        msg = bytearray(64)
        msg[0] = 0xF0
        self.counter = (self.counter + 1) & 0xFF
        msg[2] = self.counter
        return msg

    @staticmethod
    def _time_bytes():
        now = time.localtime()
        ms_byte = int((time.time() % 1) * 1000 / 4) & 0xFF
        sec_byte = (now.tm_sec * 3) & 0xFF
        min_byte = now.tm_min & 0xFF
        return bytes([ms_byte, sec_byte, min_byte])

    def _write_report(self, report):
        if len(report) != 64:
            raise ValueError(f"HID report must be 64 bytes, got {len(report)}")

        with self.hid_lock:
            written = self.dev.write(report)

        if written <= 0:
            raise OSError("hid.write returned 0 bytes")

    def send_display_commands(self, commands):
        commands = list(commands)
        if not commands:
            return

        index_header_end = 3
        time_id = self._time_bytes()
        msg = self._new_message()
        current_index = index_header_end

        for cmd_index, command in enumerate(commands):
            for i, b in enumerate(command):
                current_index += 1

                # MobiFlight replaces bytes 8,9,10 in each command with timestamp-ish bytes.
                if i == 8:
                    msg[current_index] = time_id[0]
                elif i == 9:
                    msg[current_index] = time_id[1]
                elif i == 10:
                    msg[current_index] = time_id[2]
                else:
                    msg[current_index] = b

                is_last = cmd_index == len(commands) - 1 and i == len(command) - 1
                if current_index == 59 or is_last:
                    msg[index_header_end] = current_index - index_header_end
                    self._write_report(bytes(msg))
                    msg = self._new_message()
                    current_index = index_header_end

    def _full_command(self, header_name, payload=b""):
        return self.dest + b"\x00\x00" + DISPLAY_CMD_HEADERS[header_name] + payload

    @staticmethod
    def _aes_ctr_mobiflight_decrypt(data):
        if Cipher is None:
            raise RuntimeError(
                "Encrypted font detected, but cryptography is not installed.\n"
                "Install with: python -m pip install cryptography"
            )

        key = base64.b64decode(FONT_KEY_B64)
        nonce = base64.b64decode(FONT_NONCE_B64)
        cipher = Cipher(algorithms.AES(key), modes.ECB())
        encryptor = cipher.encryptor()

        counter = bytearray(nonce)
        out = bytearray()

        for pos in range(0, len(data), 16):
            keystream = encryptor.update(bytes(counter))
            block = data[pos:pos + 16]
            out.extend(bytes(a ^ b for a, b in zip(block, keystream)))

            for j in range(len(counter) - 1, -1, -1):
                counter[j] = (counter[j] + 1) & 0xFF
                if counter[j] != 0:
                    break

        return bytes(out)

    def _load_font_text(self, font_path):
        """Load font text from loose file, bundled resource, or embedded fallback."""
        path = Path(font_path)

        if path.exists():
            log_debug(f"[CDU] using font file: {path}")
            return path.read_text(encoding="utf-8", errors="replace").strip()

        log_debug("[CDU] using embedded Boeing.dat")
        try:
            return base64.b64decode(EMBEDDED_BOEING_DAT_B64).decode("utf-8", errors="replace").strip()
        except Exception as e:
            raise RuntimeError(f"Embedded font could not be loaded: {e!r}")


    def load_font_dat(self, font_path):
        text = self._load_font_text(font_path)

        if "{" in text:
            return json.loads(text)

        encrypted_bytes = base64.b64decode(text)
        plain = self._aes_ctr_mobiflight_decrypt(encrypted_bytes).decode("utf-8")
        return json.loads(plain)

    @staticmethod
    def _chunks(data, size):
        for i in range(0, len(data), size):
            yield i, data[i:i + size]

    def _font_head_command(self, head):
        payload = b"".join([
            struct.pack("<i", int(head["id"])),
            struct.pack("<h", int(head["matrixW"])),
            struct.pack("<h", int(head["matrixH"])),
            struct.pack("<i", int(head["glyphSize"])),
            struct.pack("<i", int(head["charSize"])),
            struct.pack("<i", int(head["version"])),
            struct.pack("<i", int(head["size"])),
            struct.pack("<B", int(head["isWriteFlash"])),
        ])
        return self._full_command("0601", payload)

    def _font_data_commands(self, font_config):
        head = font_config["headConfig"]
        pixel_data = bytes(int(x) & 0xFF for x in font_config["pixelUint8Array"])

        commands = []
        for offset, chunk in self._chunks(pixel_data, 512):
            font_data = b"".join([
                struct.pack("<i", int(head["id"])),
                struct.pack("<i", int(offset)),
                struct.pack("<i", len(chunk)),
                chunk,
            ])
            payload = struct.pack("<i", len(font_data)) + font_data
            commands.append(self._full_command("0701", payload))

        return commands

    def font_json_to_commands(self, font_json):
        large = font_json["largeFontConfig"]
        small = font_json["smallFontConfig"]
        return {
            "large_head": [self._font_head_command(large["headConfig"])],
            "large_data": self._font_data_commands(large),
            "small_head": [self._font_head_command(small["headConfig"])],
            "small_data": self._font_data_commands(small),
        }

    def pfp_init_commands(self):
        init = []

        init.append(self._full_command("1E01"))
        init.append(self._full_command("1801", bytes([
            0x32, 0x00, 0x13, 0x00, 0x0E, 0x00, 0x18, 0x00
        ])))
        init.append(self._full_command("1901", bytes([
            0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        ])))
        init.append(self._full_command("1901", bytes([
            0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        ])))

        color_commands = [
            [0x02, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x04, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0x00, 0xA5, 0xFF, 0xFF, 0x05, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x07, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0x3D, 0xFF, 0x00, 0xFF, 0x08, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0xFF, 0x63, 0xFF, 0xFF, 0x09, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x0A, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x0B, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0xFF, 0x99, 0x00, 0xFF, 0x0C, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0x77, 0x77, 0x77, 0xFF, 0x0D, 0x00, 0, 0, 0, 0, 0, 0],
            [0x02, 0x00, 0x5E, 0x73, 0x79, 0xFF, 0x0E, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0x00, 0xA5, 0xFF, 0xFF, 0x10, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x11, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x12, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0x3D, 0xFF, 0x00, 0xFF, 0x13, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0xFF, 0x63, 0xFF, 0xFF, 0x14, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x15, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x16, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0xFF, 0x99, 0x00, 0xFF, 0x17, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0x77, 0x77, 0x77, 0xFF, 0x18, 0x00, 0, 0, 0, 0, 0, 0],
            [0x03, 0x00, 0x5E, 0x73, 0x79, 0xFF, 0x19, 0x00, 0, 0, 0, 0, 0, 0],
            [0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A, 0x00, 0, 0, 0, 0, 0, 0],
            [0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1B, 0x00, 0, 0, 0, 0, 0, 0],
            [0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1C, 0x00, 0, 0, 0, 0, 0, 0],
        ]

        for c in color_commands:
            init.append(self._full_command("1901", bytes(c)))

        init.append(self._full_command("1A01", bytes([0x02])))
        init.append(self._full_command("1C01"))
        return init

    def clear_commands(self):
        return [
            self._full_command("0401", bytes([0x0E])),
            self._full_command("0301"),
            self._full_command("1201", bytes([0xFF, 0x06, 0x07, 0x0D])),
            self._full_command("1301", bytes([0xFF, 0x06, 0x07, 0x0D])),
            self._full_command("1001", bytes([0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0xE0, 0x01])),
            self._full_command("0301"),
        ]

    def send_cdu_display_bytes(self, byte_data):
        pos = 0
        while pos < len(byte_data):
            chunk = byte_data[pos:pos + 63]
            report = bytes([0xF2]) + chunk
            report = report.ljust(64, b"\x00")
            self._write_report(report)
            pos += 63

    def _lines_to_display_cells(self, item):
        display = []
        default_cdu_color = RUNTIME_CONFIG.get_cdu_color()

        if isinstance(item, tuple):
            lines, color_lines = item
        else:
            lines = item
            color_lines = None

        clean_lines = list(lines)[:FMC_HEIGHT]
        while len(clean_lines) < FMC_HEIGHT:
            clean_lines.append("")

        clean_color_lines = list(color_lines or [])[:FMC_HEIGHT]
        while len(clean_color_lines) < FMC_HEIGHT:
            clean_color_lines.append("")

        for row_index, line in enumerate(clean_lines):
            line = line.rstrip("\r\n")

            text_part = line[:FMC_WIDTH]
            text_part = text_part.ljust(FMC_WIDTH)

            size_part = line[FMC_WIDTH:FMC_WIDTH * 2]

            if size_part:
                last_size = size_part[-1]
                size_part = size_part.ljust(FMC_WIDTH, last_size)
            else:
                if row_index in (0, 2, 4, 6, 8, 10, 12, 13):
                    size_part = "+" * FMC_WIDTH
                else:
                    size_part = "-" * FMC_WIDTH

            color_part = clean_color_lines[row_index].strip()

            if color_part:
                last_color = color_part[-1]
                color_part = color_part.ljust(FMC_WIDTH, last_color)
            else:
                color_part = default_cdu_color * FMC_WIDTH

            for ch, size_symbol, psx_color in zip(text_part, size_part, color_part):
                # Direct HID display uses the Boeing.dat Unicode glyphs.
                # PSX placeholders are converted before UTF-8 encoding:
                #   o -> degree symbol
                #   b -> box
                #   l -> left arrow
                #   r -> right arrow
                ch = normalize_psx_display_char(ch)

                if ch in ("_", " "):
                    display.append([" ", default_cdu_color, 0, False])
                else:
                    small = 0 if size_symbol == "+" else 1
                    cdu_color = PSX_TO_MOBIFLIGHT_COLOR.get(
                        psx_color.lower(),
                        default_cdu_color
                    )
                    display.append([ch, cdu_color, small, False])

        while len(display) < FMC_WIDTH * FMC_HEIGHT:
            display.append([" ", default_cdu_color, 0, False])

        return display[:FMC_WIDTH * FMC_HEIGHT]

    @staticmethod
    def cell_to_bytes(cell, index, total):
        current_char = " "
        color_value = FORMAT_TABLE["w"]

        if cell and cell[0] is not None:
            current_char = str(cell[0])[:1] or " "
            fmt = cell[1] if len(cell) > 1 else "w"
            small = bool(cell[2]) if len(cell) > 2 else False
            inverted = bool(cell[3]) if len(cell) > 3 else False

            color_value = FORMAT_TABLE.get(str(fmt).lower(), FORMAT_TABLE["e"])
            if inverted:
                color_value += COLOR_INVERT_OFFSET
            if small:
                color_value += COLOR_SMALL_OFFSET

        low = color_value & 0xFF
        high = (color_value >> 8) & 0xFF

        if index == 0:
            low = (low + 0x01) & 0xFF
        elif index == total - 1:
            low = (low + 0x02) & 0xFF

        try:
            char_bytes = current_char.encode("utf-8")
        except UnicodeEncodeError:
            char_bytes = b"?"

        return bytes([low, high]) + char_bytes

    def display_to_bytes(self, display):
        out = bytearray()
        total = len(display)
        for i, cell in enumerate(display):
            out.extend(self.cell_to_bytes(cell, i, total))
        return bytes(out)


PSX_CHAR_MAP = {
    "o": "\u00b0",
    "b": "\u2610",
    "l": "\u2190",
    "r": "\u2192",
}

def normalize_psx_display_char(ch):
    return PSX_CHAR_MAP.get(ch, ch)

class PsxSender:
    def __init__(self, host, port, mobiflight, pfp7_leds, min_interval_s=0.03):
        self.host = host
        self.port = port
        self.mobiflight = mobiflight
        self.pfp7_leds = pfp7_leds
        self.min_interval = float(min_interval_s)

        self.q = queue.Queue()
        self.stop_evt = threading.Event()
        self.sock = None
        self.sock_lock = threading.Lock()
        self.connect_lock = threading.Lock()

        self.tx_thread = threading.Thread(target=self._tx_loop, daemon=True)
        self.rx_thread = threading.Thread(target=self._rx_drain, daemon=True)

        self.last_send = 0.0
        self.tx_count = 0

        self.rx_buffer = ""

        # Cache all three PSX CDU screens.
        # PSX normally sends Qs62-Qs103 on connect; keeping these values
        # lets us switch CDU screens without using a reload key sequence.
        self.all_fmc_lines = {q: "" for q in range(62, 104)}
        self.all_fmc_color_lines = {q: "" for q in CDU_COLOR_QS_RANGE}
        self.fmc_lines = self.all_fmc_lines
        self.fmc_dirty = False
        self.fmc_timer = None
        self.fmc_lock = threading.Lock()

        self.cdu_lights_state = {}
        self.cdu_blank_state = {"L": 0, "C": 0, "R": 0}
        self.qi248_state = None

    def _active_config(self):
        return RUNTIME_CONFIG.get_active_cdu_config()

    def _active_qs_lines(self):
        return self._active_config()["screen_qs_lines"]

    def _active_color_qs_lines(self):
        active_cdu = RUNTIME_CONFIG.get_active_cdu()
        start = CDU_COLOR_QS_START[active_cdu]
        return list(range(start, start + FMC_HEIGHT))

    def _active_qh_name(self):
        return self._active_config()["key_qh"]

    def _active_lights_qi(self):
        return self._active_config()["lights_qi"]

    def _active_blank_qi(self):
        return self._active_config()["blank_qi"]

    def _reset_fmc_lines_for_active_cdu(self):
        # Kept for compatibility, but no longer clears the screen.
        # The active CDU display is now selected from self.all_fmc_lines.
        self.fmc_lines = self.all_fmc_lines

    def _request_active_cdu_data(self):
        with self.sock_lock:
            s = self.sock

        if not s:
            return

        cfg = self._active_config()

        try:
            for q in cfg["screen_qs_lines"]:
                s.sendall(f"Qs{q}\n".encode("ascii"))

            for q in self._active_color_qs_lines():
                s.sendall(f"Qs{q}\n".encode("ascii"))

            s.sendall(f"Qi{cfg['lights_qi']}\n".encode("ascii"))
            s.sendall(f"Qi{cfg['blank_qi']}\n".encode("ascii"))
            s.sendall(f"Qi{PSX_FMC_CONFIG_QI}\n".encode("ascii"))

            log_debug(
                f"[CONFIG] Active CDU {cfg['label']}: "
                f"{cfg['key_qh']}, Qs{cfg['screen_qs_lines'][0]}-Qs{cfg['screen_qs_lines'][-1]}, "
                f"Qi{cfg['lights_qi']}, Qi{cfg['blank_qi']}"
            )

        except Exception as e:
            log(f"[PSX] failed to request active CDU data: {repr(e)}")
            self._close()

    def set_active_cdu(self, cdu):
        cdu = cdu.upper()

        if not RUNTIME_CONFIG.set_active_cdu(cdu):
            return False

        self.cdu_lights_state = {}
        self._request_active_cdu_data()

        # Re-apply the last known Qi248 value for the newly selected CDU.
        # Qi248 itself may not change when switching CDU, but the relevant
        # LCD bit does change:
        #   Left   = bit 19
        #   Center = bit 21
        #   Right  = bit 20
        if self.qi248_state is not None:
            self._apply_qi248_state(self.qi248_state, force_log=True)

        # Immediately draw the newly selected CDU from the cached Qs lines.
        with self.fmc_lock:
            self.fmc_dirty = True

        self._send_fmc_frame()

        return True


    def clear_command_from_source_cdu(self, source_qh_name):
        for code in CDU_SWITCH_CLEAR_SEQUENCE:
            self.send_raw_psx_line(f"{source_qh_name}={code}")
            time.sleep(0.03)

    def clear_scratchpad_command(self, source_qh_name):
        # Hold CLR briefly to clear the complete scratchpad command.
        # This is used after bridge commands such as CDU-L, CDU-C, CDU-R,
        # CDU-ATC, and CDU-ALTN.
        self.send_raw_psx_line(f"{source_qh_name}=39")
        time.sleep(CDU_COMMAND_CLEAR_HOLD_SECONDS)
        self.send_raw_psx_line(f"{source_qh_name}=-1")

    def clear_scratchpad_command_async(self, source_qh_name):
        # Do not block the CDU switch or display redraw while CLR is held.
        # The command is cleared on the source CDU while the bridge can already
        # switch to/render the selected CDU.
        t = threading.Thread(
            target=self.clear_scratchpad_command,
            args=(source_qh_name,),
            daemon=True
        )
        t.start()

    def set_atc_key_mode(self, mode):
        mode = str(mode or "").strip().upper()

        if mode not in ("ATC", "ALTN"):
            return False

        atc_altn = atc_key_value_to_altn(mode)
        RUNTIME_CONFIG.set_cdu_atc_altn(atc_altn)
        save_ini_value("FMC", "ATC_KEY", atc_altn_to_ini_value(atc_altn))

        log(f"[CONFIG] FMC ATC_KEY={atc_altn_to_ini_value(atc_altn)} saved to psx_winctrl_pfp.ini")
        return True

    def start(self):
        self.rx_thread.start()
        self.tx_thread.start()

    def stop(self):
        self.stop_evt.set()
        self.q.put(None)
        self.tx_thread.join(timeout=1.0)
        self.rx_thread.join(timeout=1.0)
        self._close()

    def send_code(self, code):
        self.q.put(code)

    def send_codes(self, codes):
        for code in codes:
            self.q.put(code)

    def send_raw_psx_line(self, line):
        with self.sock_lock:
            s = self.sock

        if not s:
            return False

        if not line.endswith("\n"):
            line += "\n"

        try:
            s.sendall(line.encode("ascii", errors="ignore"))
            return True
        except Exception:
            self._close()
            return False

    def _connect(self):
        with self.sock_lock:
            if self.sock:
                return True

        with self.connect_lock:
            with self.sock_lock:
                if self.sock:
                    return True

            s = connect_with_retry(
                self.host,
                self.port,
                "PSX",
                stop_evt=self.stop_evt,
                retry_delay=5.0
            )

            if s is None:
                return False

            try:
                s.sendall(b"clientName=PSX WinCTRL PFPx Bridge\n")

                # Request all CDU screen and LCD color lines on connect.
                # PSX sends these values immediately, so the bridge starts with
                # a filled cache for left, center, and right CDU.
                for q in range(62, 104):
                    s.sendall(f"Qs{q}\n".encode("ascii"))

                for q in CDU_COLOR_QS_RANGE:
                    s.sendall(f"Qs{q}\n".encode("ascii"))

                for qi in (86, 87, 88, 89, 90, 91, PSX_FMC_CONFIG_QI):
                    s.sendall(f"Qi{qi}\n".encode("ascii"))

                log_debug(
                    "[PSX] requested all CDU screen Qs62-Qs103, "
                    "LCD color Qs500-Qs541, lights Qi86-Qi88, blanking Qi89-Qi91, and Qi248"
                )

            except Exception as e:
                log(f"[PSX] setup failed after connect: {repr(e)}")
                try:
                    s.close()
                except Exception:
                    pass
                return False

            with self.sock_lock:
                if self.sock:
                    try:
                        s.close()
                    except Exception:
                        pass
                    return True

                self.sock = s

            return True

    def _close(self):
        with self.sock_lock:
            try:
                if self.sock:
                    self.sock.close()
            except Exception:
                pass
            self.sock = None

    def _rx_drain(self):
        while not self.stop_evt.is_set():
            try:
                if not self._connect():
                    continue

                with self.sock_lock:
                    s = self.sock

                if not s:
                    time.sleep(0.1)
                    continue

                data = s.recv(4096)

                if not data:
                    # Debug: PSX disconnect without exception
                    log_debug("[PSX RX] disconnected")
                    self._close()
                    continue

                text = data.decode("utf-8", errors="replace")
                self._handle_psx_text(text)

            except socket.timeout:
                continue

            except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError, OSError) as e:
                if not self.stop_evt.is_set():
                    log(f"[PSX RX] connection lost: {repr(e)}")
                self._close()
                time.sleep(1.0)

            except Exception as e:
                if not self.stop_evt.is_set():
                    log(f"[PSX RX] error: {repr(e)}")
                self._close()
                time.sleep(1.0)

    def _handle_psx_text(self, text):
        self.rx_buffer += text

        while "\n" in self.rx_buffer:
            line, self.rx_buffer = self.rx_buffer.split("\n", 1)
            line = line.rstrip("\r")

            if not line:
                continue

            if line.startswith(f"Qi{self._active_lights_qi()}="):
                self._handle_cdu_lights(line)
                continue

            if line.startswith("Qi") and "=" in line:
                try:
                    qi_num = int(line[2:].split("=", 1)[0])
                except ValueError:
                    qi_num = None

                if qi_num in CDU_BLANK_QI_TO_CDU:
                    self._handle_cdu_blank(line, qi_num)
                    continue

            if line.startswith(f"Qi{PSX_FMC_CONFIG_QI}="):
                self._handle_qi248(line)
                continue

            if line.startswith("Qs") and "=" in line:
                self._handle_fmc_line(line)

    def _handle_cdu_lights(self, line):
        _, value = line.split("=", 1)

        try:
            state = int(value.strip())
        except ValueError:
            return

        lights_qi = self._active_lights_qi()

        if state == self.cdu_lights_state.get(lights_qi):
            return

        self.cdu_lights_state[lights_qi] = state

        log_debug(f"[CDU LIGHTS] Qi{lights_qi}={state} / 0x{state:04X}")
        self.pfp7_leds.apply_psx_cdu_lights_bitmask(state)

    def _handle_cdu_blank(self, line, qi_num):
        _, value = line.split("=", 1)

        try:
            state = int(value.strip())
        except ValueError:
            return

        cdu = CDU_BLANK_QI_TO_CDU.get(qi_num)
        if not cdu:
            return

        if state == self.cdu_blank_state.get(cdu, 0):
            return

        self.cdu_blank_state[cdu] = state

        log_debug(f"[CDU BLANK] Qi{qi_num} CDU {cdu}={state}")

        if cdu == RUNTIME_CONFIG.get_active_cdu():
            with self.fmc_lock:
                self.fmc_dirty = True

            self._send_fmc_frame()

    def _apply_qi248_state(self, state, force_log=False):
        cfg = self._active_config()

        nextgen_fmc = bool(state & QI248_NEXTGEN_FMC_BIT)
        cdu_lcd = bool(state & cfg["lcd_qi248_bit"])

        RUNTIME_CONFIG.set_from_qi248(nextgen_fmc, cdu_lcd)

        color = "w" if cdu_lcd else "g"
        atc_altn = RUNTIME_CONFIG.get_cdu_atc_altn()

        if force_log:
            log_debug(
                f"[CONFIG] Qi248={state} / 0x{state:08X} -> "
                f"CDU {cfg['label']}, CDU_COLOR={color}, CDU_ATC_ALTN={atc_altn}"
            )
        else:
            log_debug(
                f"[CONFIG] Qi248 reapplied: CDU {cfg['label']}, "
                f"CDU_COLOR={color}, CDU_ATC_ALTN={atc_altn}"
            )

    def _handle_qi248(self, line):
        _, value = line.split("=", 1)

        try:
            state = int(value.strip())
        except ValueError:
            return

        if state == self.qi248_state:
            return

        self.qi248_state = state
        self._apply_qi248_state(state, force_log=True)

        # Redraw because Qi248 can switch the active CDU between CRT and LCD.
        # That changes the default color and whether PSX LCD color strings matter.
        with self.fmc_lock:
            self.fmc_dirty = True

        self._send_fmc_frame()

    def _send_fmc_frame(self):
        with self.fmc_lock:
            if not self.fmc_dirty:
                return

            self.fmc_dirty = False

        active_cdu = RUNTIME_CONFIG.get_active_cdu()

        if self.cdu_blank_state.get(active_cdu, 0) != 0:
            # PSX BlankTimeCdu* is active: keep caching incoming CDU text,
            # but render the active hardware CDU as blank until the timer is 0.
            ordered_lines = [""] * FMC_HEIGHT
            ordered_color_lines = None
            log_debug(
                f"[CDU BLANK] CDU {active_cdu} screen blanked "
                f"value={self.cdu_blank_state.get(active_cdu, 0)}"
            )
        else:
            ordered_lines = [self.fmc_lines.get(q, "") for q in self._active_qs_lines()]
            if RUNTIME_CONFIG.get_cdu_color() == "w":
                # LCD mode: use PSX per-character LCD color strings.
                ordered_color_lines = [
                    self.all_fmc_color_lines.get(q, "")
                    for q in self._active_color_qs_lines()
                ]
            else:
                # CRT/legacy mode: keep the existing all-green behavior.
                ordered_color_lines = None

        # Debug: FMC frame queued for MobiFlight
        log_debug("[FMC] frame queued")
        self.mobiflight.send_lines(ordered_lines, ordered_color_lines)

    def _handle_fmc_line(self, line):
        left, value = line.split("=", 1)

        try:
            qnum = int(left[2:])
        except ValueError:
            return

        if qnum in CDU_COLOR_QS_RANGE:
            self.all_fmc_color_lines[qnum] = value

            # Only redraw MobiFlight when the color update belongs to active CDU.
            if qnum in self._active_color_qs_lines():
                with self.fmc_lock:
                    self.fmc_dirty = True

                    if self.fmc_timer:
                        self.fmc_timer.cancel()

                    self.fmc_timer = threading.Timer(0.05, self._send_fmc_frame)
                    self.fmc_timer.daemon = True
                    self.fmc_timer.start()

            return

        if qnum < 62 or qnum > 103:
            return

        # Scratchpad command line for active CDU selection:
        #   CDU L -> Left CDU
        #   CDU C -> Center CDU
        #   CDU R -> Right CDU
        if qnum == self._active_qs_lines()[-1]:
            command = value.strip().upper()

            target_cdu = None

            if command in ("CDU-L", "CDU LEFT"):
                target_cdu = "L"

            elif command in ("CDU-C", "CDU CENTER", "CDU CENTRE"):
                target_cdu = "C"

            elif command in ("CDU-R", "CDU RIGHT"):
                target_cdu = "R"

            if target_cdu:
                source_qh_name = self._active_qh_name()
                self.set_active_cdu(target_cdu)
                self.clear_scratchpad_command_async(source_qh_name)
                return

            if command in ("CDU-ATC", "CDU ATC"):
                source_qh_name = self._active_qh_name()

                # Start clearing immediately, before saving the ini setting.
                # This keeps scratchpad cleanup independent from ATC/ALTN mode changes.
                self.clear_scratchpad_command_async(source_qh_name)

                # Also clear the local display cache immediately so MobiFlight
                # does not keep showing the command while PSX processes CLR.
                self.all_fmc_lines[qnum] = ""
                with self.fmc_lock:
                    self.fmc_dirty = True
                self._send_fmc_frame()

                self.set_atc_key_mode("ATC")
                return

            if command in ("CDU-ALTN", "CDU ALTN"):
                source_qh_name = self._active_qh_name()

                # Start clearing immediately, before saving the ini setting.
                # This keeps scratchpad cleanup independent from ATC/ALTN mode changes.
                self.clear_scratchpad_command_async(source_qh_name)

                # Also clear the local display cache immediately so MobiFlight
                # does not keep showing the command while PSX processes CLR.
                self.all_fmc_lines[qnum] = ""
                with self.fmc_lock:
                    self.fmc_dirty = True
                self._send_fmc_frame()

                self.set_atc_key_mode("ALTN")
                return

        # Store every CDU line, even when it is not the currently displayed CDU.
        self.all_fmc_lines[qnum] = value

        # Only redraw MobiFlight when the updated line belongs to the active CDU.
        if qnum in self._active_qs_lines():
            with self.fmc_lock:
                self.fmc_dirty = True

                if self.fmc_timer:
                    self.fmc_timer.cancel()

                self.fmc_timer = threading.Timer(0.05, self._send_fmc_frame)
                self.fmc_timer.daemon = True
                self.fmc_timer.start()

    def _tx_loop(self):
        while not self.stop_evt.is_set():
            code = self.q.get()
            if code is None:
                break

            now = time.monotonic()
            dt = now - self.last_send
            if dt < self.min_interval:
                time.sleep(self.min_interval - dt)

            line = f"{self._active_qh_name()}={code}\n".encode("ascii", errors="ignore")

            try:
                if not self._connect():
                    continue

                with self.sock_lock:
                    s = self.sock

                if not s:
                    continue

                self.tx_count += 1
                # Debug: raw PSX keyboard output
                log_debug(f"[PSX] TX#{self.tx_count} -> {line!r}")
                s.sendall(line)
                self.last_send = time.monotonic()

            except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError, OSError) as e:
                if not self.stop_evt.is_set():
                    log(f"[PSX] send connection lost: {repr(e)} -> reconnect")
                self._close()

            except Exception as e:
                if not self.stop_evt.is_set():
                    log(f"[PSX] send error: {repr(e)} -> reconnect")
                self._close()


def main():
    try:
        signal.signal(signal.SIGINT, _handle_sigint)
    except Exception:
        pass

    STATUS.start()

    if DEBUG:
        log("[CONFIG] Debug logging enabled")

    psx_host, psx_port, VID, PID = load_config()
    mapping = load_map()

    lsk_bps = {bp for bp, name in mapping.items() if name.upper().startswith("LSK")}
    log_debug(f"[MAP] LSK bitpos: {sorted(lsk_bps)}")

    bp_to_code = {}
    for bp, name in mapping.items():
        code = PSX_NAME_TO_CODE.get(name.upper())
        if code is not None:
            bp_to_code[bp] = code

    log_debug(f"[MAP] resolvable to PSX codes: {len(bp_to_code)}")
    # Use all mapped HID buttons, including BRT+/BRT- which have no PSX code
    mapped_bps = set(mapping.keys())

    devs = hid.enumerate(VID, PID)
    if not devs:
        log("")
        log("[ERROR] WINCTRL CDU not found.")
        log(f"[ERROR] Expected VID={VID:04X} PID={PID:04X}")
        log("")
        log("[ERROR] Check the [FMC] pid setting in psx_winctrl_pfp.ini.")
        log("[ERROR] Also check that the CDU is connected and visible in Windows.")
        log("")

        input("Press ENTER to exit...")
        return

    d = devs[0]
    # Debug: selected HID device details
    log_debug(
        f"[HID] Using '{d.get('product_string')}' "
        f"if={d.get('interface_number')} "
        f"usage_page={d.get('usage_page')} "
        f"usage={d.get('usage')}"
    )

    h = hid.device()
    h.open_path(d["path"])

    try:
        h.set_nonblocking(True)
    except Exception:
        try:
            h.nonblocking = True
        except Exception:
            pass

    hid_lock = threading.Lock()

    pfp7_leds = Pfp7LedController(h, hid_lock, PFP7_DEST)
    pfp7_leds.start()

    display = DirectHidDisplaySender(h, hid_lock, PFP7_DEST, FONT_FILE)
    try:
        display.start()
    except RuntimeError as e:
        log("")
        log(f"[ERROR] {e}")
        log("")
        input("Press ENTER to exit...")
        return

    display.show_welcome_screen(VERSION, seconds=3.0)

    psx = PsxSender(psx_host, psx_port, display, pfp7_leds, MIN_SEND_INTERVAL)
    psx.start()

    log_debug("[RUN] HID keys -> active PSX CDU, active PSX CDU screen -> direct HID display, active PSX CDU lights -> direct HID LEDs.")
    log_highlight("Press CTRL+C to quit.")
    log_highlight("")
    log_highlight("+-----------------------------+")
    log_highlight("| Scratchpad commands         |")
    log_highlight("+-----------------------------+")
    log_highlight("| CDU-L     Left CDU          |")
    log_highlight("| CDU-C     Center CDU        |")
    log_highlight("| CDU-R     Right CDU         |")
    log_highlight("| CDU-ATC   ATC key mode      |")
    log_highlight("| CDU-ALTN  ALTN page mode    |")
    log_highlight("+-----------------------------+")
    
    prev_pressed = set()
    stable_count = defaultdict(int)
    last_rise_time = {}

    brt_hold_direction = 0
    brt_hold_start_time = None
    brt_last_repeat_time = 0.0

    try:
        while not SHUTDOWN_REQUESTED.is_set():
            with hid_lock:
                data = h.read(READ_SIZE)

            if not data:
                if SHUTDOWN_REQUESTED.wait(0.001):
                    break
                continue

            frame = bytes(data)

            if len(frame) < 1 or frame[0] != 0x01:
                continue

            cur_pressed_raw = pressed_from_mapping(frame, mapped_bps)

            cur_pressed = set()
            for bp in cur_pressed_raw:
                if bp in lsk_bps:
                    cur_pressed.add(bp)
                    continue

                stable_count[bp] += 1
                if stable_count[bp] >= STABLE_FRAMES:
                    cur_pressed.add(bp)

            for bp in list(stable_count):
                if bp not in cur_pressed_raw:
                    stable_count.pop(bp, None)

            rising = cur_pressed - prev_pressed
            falling = prev_pressed - cur_pressed
            prev_pressed = cur_pressed

            now = time.monotonic()

            if (
                brt_hold_direction != 0
                and brt_hold_start_time is not None
                and now - brt_hold_start_time >= PFP7_BRT_HOLD_DELAY
                and now - brt_last_repeat_time >= PFP7_BRT_REPEAT_INTERVAL
            ):
                pfp7_leds.change_screen_brightness_step(brt_hold_direction)
                brt_last_repeat_time = now

            # Hardware key release handling.
            # PSX automatically releases most CDU keys internally, but CLR (39)
            # and ATC (60) must be explicitly released by sending -1 when the
            # physical key is released.
            for bp in falling:
                name = mapping.get(bp, "").upper()

                if name in ("BRT+", "BRT-"):
                    brt_hold_direction = 0
                    brt_hold_start_time = None
                    brt_last_repeat_time = 0.0
                    continue

                code = bp_to_code.get(bp)

                if code in NEED_RELEASE:
                    # Debug: HID release for keys requiring explicit PSX release
                    log_debug(f"[HID] release {mapping.get(bp)} -> -1")
                    psx.send_code(-1)

            # Hardware key press handling.
            for bp in rising:
                if (now - last_rise_time.get(bp, 0.0)) < RISING_COOLDOWN:
                    continue

                last_rise_time[bp] = now

                name = mapping.get(bp, "").upper()

                if name == "BRT+":
                    pfp7_leds.change_screen_brightness_step(+1)
                    brt_hold_direction = +1
                    brt_hold_start_time = now
                    brt_last_repeat_time = now
                    continue

                if name == "BRT-":
                    pfp7_leds.change_screen_brightness_step(-1)
                    brt_hold_direction = -1
                    brt_hold_start_time = now
                    brt_last_repeat_time = now
                    continue

                code = bp_to_code.get(bp)
                if code is None:
                    # Debug: mapped HID key has no PSX keycode
                    log_debug(f"[HID] {bp} {mapping.get(bp)} -> NO PSX CODE")
                    continue

                # Debug: keyboard output to PSX
                log_debug(f"[HID] {bp} {mapping.get(bp)} -> {code}")

                if code == 60 and RUNTIME_CONFIG.get_cdu_atc_altn() == 1:
                    # Debug: ATC alternate translation
                    log_debug("[ATC ALTN] ATC key replaced by FMC COMM, LSKL2")
                    psx.send_codes(CDU_ATC_ALTN_SEQUENCE)
                else:
                    psx.send_code(code)

    except KeyboardInterrupt:
        SHUTDOWN_REQUESTED.set()

    finally:
        # Ignore further CTRL+C during cleanup. One CTRL+C is enough.
        try:
            signal.signal(signal.SIGINT, signal.SIG_IGN)
        except Exception:
            pass

        # Save runtime choices first. This must happen before any HID cleanup,
        # because CTRL+C during HID cleanup may interrupt shutdown on macOS/PyInstaller.
        try:
            save_ini_value("FMC", "ACTIVE_CDU", RUNTIME_CONFIG.get_active_cdu())
            save_ini_value("FMC", "BRIGHTNESS", pfp7_leds.get_screen_brightness_step())
            log_debug(
                f"[CONFIG] saved ACTIVE_CDU={RUNTIME_CONFIG.get_active_cdu()} "
                f"BRIGHTNESS={pfp7_leds.get_screen_brightness_step()}"
            )
        except BaseException as e:
            # Do not let a shutdown-save problem cause a PyInstaller crash.
            # KeyboardInterrupt is also covered here.
            if not isinstance(e, KeyboardInterrupt):
                log(f"[CONFIG] failed to save runtime settings: {repr(e)}")

        # Hardware blackout while HID is still open. Keep this simple and fast:
        # backlights/annunciators first, optional display blank after.
        try:
            pfp7_leds.force_blackout()
        except BaseException as e:
            if not isinstance(e, KeyboardInterrupt):
                if "not open" not in str(e).lower():
                    log_debug(f"[PFP LED] shutdown error: {repr(e)}")

        try:
            display.force_blank_display()
        except BaseException as e:
            if not isinstance(e, KeyboardInterrupt):
                if "not open" not in str(e).lower():
                    log_debug(f"[CDU] shutdown error: {repr(e)}")

        # Stop threads and close handles. These are intentionally best-effort.
        try:
            psx.stop()
        except BaseException:
            pass

        try:
            display.stop()
        except BaseException:
            pass

        try:
            pfp7_leds.stop()
        except BaseException:
            pass

        try:
            h.close()
        except BaseException:
            pass

        log("[END]")



if __name__ == "__main__":
    main()
