From 12c4ec4687eb88cdd31e132d2dd4222df768964d Mon Sep 17 00:00:00 2001 From: Aleksey Filippov Date: Fri, 29 Dec 2023 11:36:45 +0300 Subject: [PATCH] =?utf8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- docker/php/Dockerfile | 4 +- erp24/forms/EmployeePaymentSearch.php | 73 +++++ erp24/forms/MultipleUploadForm.php | 36 +++ erp24/forms/UploadImageForm.php | 38 +++ erp24/forms/device/AddDeviceForm.php | 91 +++++++ erp24/forms/device/SelectDeviceForm.php | 49 ++++ erp24/forms/infoTable/ChartManagementForm.php | 46 ++++ erp24/forms/infoTable/Charts.php | 39 +++ erp24/forms/infoTable/YearWeekSearchForm.php | 40 +++ erp24/forms/lesson/LessonForm.php | 36 +++ erp24/forms/log/ErrorLogSearchModel.php | 29 ++ erp24/forms/payroll/YearMonthSearchForm.php | 46 ++++ erp24/forms/planStore/AddPlanStore.php | 52 ++++ erp24/forms/support/TaskSupportCreateForm.php | 30 +++ erp24/forms/timetable/AddForm.php | 146 ++++++++++ erp24/forms/timetable/HolidaySearch.php | 35 +++ erp24/forms/timetable/IndexForm.php | 49 ++++ erp24/forms/timetable/StartForm.php | 251 ++++++++++++++++++ erp24/forms/timetable/TabelSearchForm.php | 147 ++++++++++ erp24/forms/timetable/TabelSearchFormFact.php | 124 +++++++++ erp24/forms/writeOffsErp/WriteOffsForm.php | 34 +++ .../writeOffsErp/WriteOffsProductsForm.php | 111 ++++++++ erp24/models/LoginForm.php | 3 +- erp24/tests/functional/PageListCest.php | 13 + erp24/tests/unit/models/UserTest.php | 5 +- erp24/views/layouts/api2_menu.php | 2 +- erp24/web/favicon.ico | Bin 318 -> 38049 bytes 27 files changed, 1523 insertions(+), 6 deletions(-) create mode 100755 erp24/forms/EmployeePaymentSearch.php create mode 100644 erp24/forms/MultipleUploadForm.php create mode 100644 erp24/forms/UploadImageForm.php create mode 100755 erp24/forms/device/AddDeviceForm.php create mode 100755 erp24/forms/device/SelectDeviceForm.php create mode 100644 erp24/forms/infoTable/ChartManagementForm.php create mode 100644 erp24/forms/infoTable/Charts.php create mode 100644 erp24/forms/infoTable/YearWeekSearchForm.php create mode 100755 erp24/forms/lesson/LessonForm.php create mode 100755 erp24/forms/log/ErrorLogSearchModel.php create mode 100755 erp24/forms/payroll/YearMonthSearchForm.php create mode 100644 erp24/forms/planStore/AddPlanStore.php create mode 100755 erp24/forms/support/TaskSupportCreateForm.php create mode 100755 erp24/forms/timetable/AddForm.php create mode 100755 erp24/forms/timetable/HolidaySearch.php create mode 100755 erp24/forms/timetable/IndexForm.php create mode 100755 erp24/forms/timetable/StartForm.php create mode 100755 erp24/forms/timetable/TabelSearchForm.php create mode 100755 erp24/forms/timetable/TabelSearchFormFact.php create mode 100644 erp24/forms/writeOffsErp/WriteOffsForm.php create mode 100644 erp24/forms/writeOffsErp/WriteOffsProductsForm.php create mode 100644 erp24/tests/functional/PageListCest.php diff --git a/docker/php/Dockerfile b/docker/php/Dockerfile index d9d401bc..050409b8 100644 --- a/docker/php/Dockerfile +++ b/docker/php/Dockerfile @@ -6,7 +6,7 @@ RUN apk add --update --no-cache \ RUN apk add --no-cache zlib libpng icu \ && apk add --no-cache --virtual .deps zlib-dev libpng-dev icu-dev \ - && docker-php-ext-install -j$(nproc) gd mysqli pdo pdo_mysql intl calendar opcache \ + && docker-php-ext-install -j$(nproc) gd mysqli pdo pdo_mysql intl calendar mbstring opcache \ && apk del .deps RUN apk --no-cache --update --repository http://dl-cdn.alpinelinux.org/alpine/v$ALPINE_VERSION/main/ add \ @@ -21,7 +21,7 @@ RUN wget https://getcomposer.org/installer \ #add xdebug RUN apk add --no-cache $PHPIZE_DEPS \ - && pecl install xdebug \ + && pecl install xdebug-3.1.6 \ && docker-php-ext-enable xdebug \ && apk del $PHPIZE_DEPS WORKDIR /www diff --git a/erp24/forms/EmployeePaymentSearch.php b/erp24/forms/EmployeePaymentSearch.php new file mode 100755 index 00000000..36e96c10 --- /dev/null +++ b/erp24/forms/EmployeePaymentSearch.php @@ -0,0 +1,73 @@ + $query, + ]); + + $this->load($params); + + if (!$this->validate()) { + // uncomment the following line if you do not want to return any records when validation fails + // $query->where('0=1'); + return $dataProvider; + } + + // grid filtering conditions + $query->andFilterWhere([ + 'id' => $this->id, + 'admin_id' => $this->admin_id, + 'admin_group_id' => $this->admin_group_id, + 'date' => $this->date, + 'monthly_salary' => $this->monthly_salary, + 'daily_payment' => $this->daily_payment, + 'creator_id' => $this->creator_id, + ]); + + return $dataProvider; + } +} diff --git a/erp24/forms/MultipleUploadForm.php b/erp24/forms/MultipleUploadForm.php new file mode 100644 index 00000000..04075602 --- /dev/null +++ b/erp24/forms/MultipleUploadForm.php @@ -0,0 +1,36 @@ + 'png, jpg', 'maxFiles' => 10, 'skipOnEmpty' => false], + ]; + } + + public function upload() + { + if ($this->validate()) { + foreach ($this->imageFiles as $file) { + + $test = 33; +// $file->saveAs('uploads/' . $file->baseName . '.' . $file->extension); + } + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/erp24/forms/UploadImageForm.php b/erp24/forms/UploadImageForm.php new file mode 100644 index 00000000..c80ae72e --- /dev/null +++ b/erp24/forms/UploadImageForm.php @@ -0,0 +1,38 @@ + false, 'extensions' => 'jpg, png'], + ]; + } + public function upload($entity, $entity_id) { + if ($this->validate()) { + $target_dir = 'uploads/' . Yii::$app->user->id . '/' . date("Y") . "/" . date("m") . "/" . date("d"); + if (!is_dir($target_dir)) { + mkdir($target_dir, 0777, true); + } + $targetFile = $target_dir . "/" . rand(1000, 9999) . $this->image->baseName . '.' . $this->image->extension; + $this->image->saveAs($targetFile); + + $fileRecord = new Files; + $fileRecord->created_at = date("Y-m-d H:i:s"); + $fileRecord->entity_id = $entity_id; + $fileRecord->entity = $entity; + $fileRecord->file_type = 'image'; + $fileRecord->url = '/' . $targetFile; + $fileRecord->save(); + + return true; + } else { + return false; + } + } +} \ No newline at end of file diff --git a/erp24/forms/device/AddDeviceForm.php b/erp24/forms/device/AddDeviceForm.php new file mode 100755 index 00000000..03035f3f --- /dev/null +++ b/erp24/forms/device/AddDeviceForm.php @@ -0,0 +1,91 @@ +device = new AdminDesktop(); + } + public function rules(): array + { + return [ + [['storeId'], 'integer'], + [['name'], 'string'], + [['name'], 'default', 'value' => 'Рабочий ПК'], + [['storeId'], 'in', 'range' => array_keys(self::stores())], + [['typeId'], 'in', 'range' => array_keys(AdminDesktop::deviceTypes())], + ]; + } + + public function attributeLabels() + { + return [ + 'storeId' => 'Магазин', + 'typeId' => 'Тип устройства', + 'name' => 'Название устройства', + ]; + } + public static function stores() : array + { + return CityStore::find() + ->select(['name', 'id']) + ->indexBy('id') + ->cache(3600) + ->column(); + } + public static function devices() + { + return AdminDesktop::deviceTypes(); + } + + public function getStoreName() + { + return self::stores()[$this->storeId] ?? 'вне магазинов'; + } + + public function save(): bool + { + if (!$this->validate()) { + return false; + } + $this->device->name = $this->name; + $this->device->store_id = $this->storeId; + $this->device->date_add = date('Y-m-d H:i:s'); + $this->device->type_id = $this->typeId; + $this->device->device_info = \Yii::$app->getRequest()->getUserAgent(); + $this->device->lasttime = date('Y-m-d H:i:s'); + $this->device->keygen = \Yii::$app->getSecurity()->generateRandomString(); + $this->device->ip = \Yii::$app->getRequest()->getRemoteIP(); + $this->device->admin_id = $_SESSION['admin_id']; + if (!$this->device->save()) { + $this->addErrors($this->device->getErrors()); + return false; + } + return true; + } + + /** + * @return AdminDesktop + */ + public function getDevice() + { + return $this->device; + } +} \ No newline at end of file diff --git a/erp24/forms/device/SelectDeviceForm.php b/erp24/forms/device/SelectDeviceForm.php new file mode 100755 index 00000000..67f88413 --- /dev/null +++ b/erp24/forms/device/SelectDeviceForm.php @@ -0,0 +1,49 @@ + array_keys(self::devices())], + ]; + } + + public static function devices() + { + static $all = []; + if ($all) { + return $all; + } + return $all = AdminDesktop::find()->indexBy('id')->all(); + } + + public function attributeLabels() + { + return [ + 'id' => 'Устройство', + ]; + } + + /** + * @return array|\yii\db\ActiveRecord|null + */ + public function getDevice() + { + return AdminDesktop::find()->andWhere(['id' => $this->id])->one(); + } +} \ No newline at end of file diff --git a/erp24/forms/infoTable/ChartManagementForm.php b/erp24/forms/infoTable/ChartManagementForm.php new file mode 100644 index 00000000..76feb8ec --- /dev/null +++ b/erp24/forms/infoTable/ChartManagementForm.php @@ -0,0 +1,46 @@ + date("Y-m-d", strtotime('today -14 day'))], + ['date_end', 'default', 'value' => date("Y-m-d", strtotime('now'))], + ['mode_select_matrix_category', 'default', 'value' => 0], + ['mode_group', 'default', 'value' => 0], + ['date_start', 'validateDate'], + ]; + } + + public function attributeLabels() + { + return [ + 'date_start' => 'Дата начала', + 'date_end' => 'Дата окончания', + 'mode_select_matrix_category' => 'Определить категории матрицы' + ]; + } + + public function validateDate() + { + if (strtotime($this->date_start) > strtotime($this->date_end)) { + $this->addError('date_start', 'Дата начала не может быть больше даты окончания'); + $this->addError('date_end', 'Дата окончания не может быть меньше даты начала'); + } + } +} \ No newline at end of file diff --git a/erp24/forms/infoTable/Charts.php b/erp24/forms/infoTable/Charts.php new file mode 100644 index 00000000..fc80bd09 --- /dev/null +++ b/erp24/forms/infoTable/Charts.php @@ -0,0 +1,39 @@ + date("Y-m-d", strtotime('first day of this month'))], + ['date_end', 'default', 'value' => date("Y-m-d", strtotime('last day of this month'))], + ['date_start', 'validateDate'], + ]; + } + + public function attributeLabels() + { + return [ + 'date_start' => 'Дата начала', + 'date_end' => 'Дата окончания' + ]; + } + + public function validateDate() + { + if (strtotime($this->date_start) > strtotime($this->date_end)) { + $this->addError('date_start', 'Дата начала не может быть больше даты окончания'); + $this->addError('date_end', 'Дата окончания не может быть меньше даты начала'); + } + } +} \ No newline at end of file diff --git a/erp24/forms/infoTable/YearWeekSearchForm.php b/erp24/forms/infoTable/YearWeekSearchForm.php new file mode 100644 index 00000000..34e54316 --- /dev/null +++ b/erp24/forms/infoTable/YearWeekSearchForm.php @@ -0,0 +1,40 @@ +year = date("Y", strtotime(date("Y-m-d",time()))); + + $this->week = date("W", strtotime(date("Y-m-d",time()))); + } + + + public function attributeLabels() + { + return [ + 'year' => 'Год', + 'week' => 'Неделя', + 'store_id' => 'Магазин', + ]; + } + +} \ No newline at end of file diff --git a/erp24/forms/lesson/LessonForm.php b/erp24/forms/lesson/LessonForm.php new file mode 100755 index 00000000..6ba21beb --- /dev/null +++ b/erp24/forms/lesson/LessonForm.php @@ -0,0 +1,36 @@ +year = date("Y", strtotime(date("Y-m-d",time()) . $modifier)); + + $this->month = date("m", strtotime(date("Y-m-d",time()) . $modifier)); + } + + + public function attributeLabels() + { + return [ + 'year' => 'Год', + 'month' => 'Месяц', + 'dateFrom' => 'dateFrom', + 'store_id' => 'Магазин', + ]; + } + +} \ No newline at end of file diff --git a/erp24/forms/planStore/AddPlanStore.php b/erp24/forms/planStore/AddPlanStore.php new file mode 100644 index 00000000..d6c8e353 --- /dev/null +++ b/erp24/forms/planStore/AddPlanStore.php @@ -0,0 +1,52 @@ + 'Январь', + 'Февраль', + 'Март', + 'Апрель', + 'Май', + 'Июнь', + 'Июль', + 'Август', + 'Сентябрь', + 'Октябрь', + 'Ноябрь', + 'Декабрь' + ]; + public function rules() + { + return [ + [['store_id', 'year', 'month'], 'required'], + [['store_id', 'year', 'month'], 'integer'], + ['date_str', 'string'] + ]; + } + + public function attributeLabels() + { + return [ + 'store_id' => 'Магазин', + 'date_str' => 'Дата' + ]; + } + + public function updateDate () { + $this->year = intval(date('Y', strtotime($this->date_str))); + $this->month = intval(date('m', strtotime($this->date_str))); + } +} \ No newline at end of file diff --git a/erp24/forms/support/TaskSupportCreateForm.php b/erp24/forms/support/TaskSupportCreateForm.php new file mode 100755 index 00000000..9855cd1f --- /dev/null +++ b/erp24/forms/support/TaskSupportCreateForm.php @@ -0,0 +1,30 @@ + 255], + [['name'], 'string', 'min' => 3], + [['entity_id', 'function_entity_id'], 'string', 'max' => 36], + [['files'], 'file', 'skipOnEmpty' => true, 'maxFiles' => 20], + ]; + } + + public function attributeLabels() + { + return [ + 'description' => 'Описание', + 'entity_type' => 'Тип сущности', + 'entity_id' => 'Магазин', + 'name' => 'Название' + ]; + } +} \ No newline at end of file diff --git a/erp24/forms/timetable/AddForm.php b/erp24/forms/timetable/AddForm.php new file mode 100755 index 00000000..8ce1dcf4 --- /dev/null +++ b/erp24/forms/timetable/AddForm.php @@ -0,0 +1,146 @@ + array_keys(self::stores())], + [['date'], 'date', 'format' => 'php:Y-m-d'], + [['timeStart', 'timeEnd', 'adminIds'], 'required'], + [['timeStart', 'timeEnd'], 'date', 'format' => 'php:H:i:s'], + [['shiftId'], 'in', 'range' => array_keys(Shift::all())], + [['adminIds'], 'each', 'rule' => ['in', 'range' => array_keys(self::admins())]], + [['slotTypeId'], 'in', 'range' => array_keys(Timetable::slotTypeName())], + ]; + } + + public function attributeLabels() + { + return [ + 'adminIds' => 'Пользователи', + 'storeId' => 'Магазин', + 'timeStart' => 'Время начала', + 'timeEnd' => 'Время конца', + 'shiftId' => 'Смена', + 'slotTypeId' => 'Тип занятости', + ]; + } + public static function stores() : array + { + return CityStore::find() + ->select(['name', 'id']) + ->andWhere(['visible' => 1]) + ->indexBy('id') + ->cache(3600) + ->column(); + } + + public function getShift(): Shift + { + return Shift::all()[$this->shiftId]; + } + + public static function admins() + { + return Admin::find() + ->with('adminGroup') + ->andWhere([ + 'group_id' => array_keys(AdminGroup::groupsWithShift()), + ]) + ->orderBy([ + 'group_id' => SORT_ASC, + 'name' => SORT_ASC + ]) + ->indexBy('id') + ->all() + ; + } + + public static function minutes(): array + { + return [0, 10, 20, 30, 40, 50]; + } + + public function getStoreName() + { + return self::stores()[$this->storeId] ?? 'вне магазинов'; + } + + public function save(): bool + { + if (!$this->validate()) { + return false; + } + $start = new \DateTime($this->date . ' ' .$this->timeStart); + $end = new \DateTime($this->date . ' ' .$this->timeEnd); + $minStart = new \DateTime($this->date . ' ' .$this->shift->start_time); + // shift crosses midnight + if ($start < $minStart) { + $start->modify('+1 day'); + } + if ($end < $minStart) { + $end->modify('+1 day'); + } + + /** @var Admin[] $admins */ + $admins = Admin::find() + ->with('adminGroup') + ->andWhere(['id' => $this->adminIds]) + ->indexBy('id') + ->all(); + + $trx = TimetablePlan::getDb()->beginTransaction(); + foreach ($this->adminIds as $adminId) { + $timeTable = new TimetablePlan([ + 'shift_id' => $this->shiftId, + 'store_id' => $this->storeId, + 'date' => $this->date, + 'admin_id' => $adminId, + 'd_id' => $admins[$adminId]->adminGroup->id, + 'admin_id_add' => $_SESSION['admin_id'], + 'time_start' => $this->timeStart, + 'time_end' => $this->timeEnd, + 'datetime_start' => $start->format('Y-m-d H:i:s'), + 'datetime_end' => $end->format('Y-m-d H:i:s'), + 'slot_type_id' => $this->slotTypeId, + 'comment' => $this->comment, + 'status' => 0, + ]); + if (!$timeTable->save()) { + $this->addError('adminIds', implode("\n", $timeTable->getFirstErrors())); + $trx->rollBack(); + return false; + } + } + $trx->commit(); + return true; + } +} \ No newline at end of file diff --git a/erp24/forms/timetable/HolidaySearch.php b/erp24/forms/timetable/HolidaySearch.php new file mode 100755 index 00000000..6b225e10 --- /dev/null +++ b/erp24/forms/timetable/HolidaySearch.php @@ -0,0 +1,35 @@ + 'php:Y-m-d'], + [['dateFrom'], 'default', 'value' => function () { + return date('Y-01-01'); + }], + [['dateTo'], 'default', 'value' => function () { + return date('Y-12-31'); + }], + ]; + } + + public function attributeLabels() + { + return [ + 'dateFrom' => 'Дата начала', + 'dateTo' => 'Дата конца', + ]; + } + +} \ No newline at end of file diff --git a/erp24/forms/timetable/IndexForm.php b/erp24/forms/timetable/IndexForm.php new file mode 100755 index 00000000..d5dfbaac --- /dev/null +++ b/erp24/forms/timetable/IndexForm.php @@ -0,0 +1,49 @@ + array_keys(self::stores())], + [['start', 'end'], 'date', 'format' => 'php:Y-m-d'], + [['start'], 'default', 'value' => date('Y-m-d', strtotime('-1 day'))], + [['end'], 'default', 'value' => date('Y-m-d', strtotime('+7 day'))], + ]; + } + + public function attributeLabels() + { + return [ + 'store_id' => 'Магазин', + 'start' => 'Дата начала', + 'end' => 'Дата конца', + ]; + } + public static function stores() : array + { + return CityStore::find() + ->select(['name', 'id']) + ->andWhere(['visible' => 1]) + ->indexBy('id') + ->cache(3600) + ->column(); + } + + public function getStoreName() + { + return self::stores()[$this->store_id] ?? 'вне магазинов'; + } + +} \ No newline at end of file diff --git a/erp24/forms/timetable/StartForm.php b/erp24/forms/timetable/StartForm.php new file mode 100755 index 00000000..3345973a --- /dev/null +++ b/erp24/forms/timetable/StartForm.php @@ -0,0 +1,251 @@ +type_id == AdminCheckin::TYPE_START; + } + + public function isEnd() + { + return $this->type_id == AdminCheckin::TYPE_END; + } + + public function isAppear() + { + return $this->type_id == AdminCheckin::TYPE_APPEAR; + } + + public static function ratings() + { + return [ + 2 => 'Неудовлетворительно', + 3 => 'Удовлетворительно', + 4 => 'Хорошо', + 5 => 'Отлично', + ]; + } + + public function attributeLabels() + { + return [ + 'id' => 'ID', + 'admin_id' => 'ID пользователя', + 'type_id' => 'Открытие/закрытие смены', + 'date' => 'Дата смены', + 'time' => 'Время', + 'store_id' => 'Место', + 'checkin_id' => 'ID отметки / открытия / закрытия смены', + 'ball' => 'Оценка', + 'comment' => 'Комментарий', + 'photo' => 'Селфи', + 'd_id' => 'Должность', + 'status' => 'Статус проверки', + 'replaced_admin_id' => 'Заменяемый сотрудник', + 'gps' => 'Координаты', + ]; + } + + public function init() + { + $this->checkinModel = new AdminCheckin(); + } + + public function rules(): array + { + return [ + [['id', 'admin_id', 'replaced_admin_id', 'plan_id', 'checkin_id', 'store_id', 'type_id', 'd_id', 'ball', 'status'], 'integer'], + [['comment', 'date'], 'string'], + [['lat', 'lon'], 'number'], + [['admin_id', 'replaced_admin_id'], 'exist', 'targetClass' => Admin::class, 'targetAttribute' => 'id'], + [['admin_id', 'store_id', 'device_id', 'type_id', 'd_id', 'ball', 'date'], 'required'], + [['d_id'], 'exist', 'targetClass' => AdminGroup::class, 'targetAttribute' => 'id'], + [['store_id'], function() { + $targetAdminId = $this->replaced_admin_id ?: $this->admin_id; + /** @var Admin $targetAdmin */ + $targetAdmin = Admin::find()->andWhere(['id' => $targetAdminId])->one(); + if (!in_array($this->store_id, $targetAdmin->getStoreIds())) { + $this->addError('store_id', 'У пользователя нет доступа к этому магазину'); + } + }], + [['status'], 'required', 'requiredValue' => AdminCheckin::STATUS_PENDING], + [['photo'], 'required', 'message' => 'Смена не может быть открыта без селфи'], + [['photo'], 'file', 'mimeTypes' => ['image/jpeg'], 'message' => 'Неправильный формат файла'], + [['store_id'], 'required', 'message' => 'Смена не может быть открыта без указания магазина'], + [['time'], function () { + $maxShiftDuration = max(ArrayHelper::getColumn(Shift::all(), 'duration')); + /** @var AdminCheckin $lastCheckin */ + $lastCheckin = AdminCheckin::find() + ->andWhere(['admin_id' => $this->admin_id]) + ->andWhere(['>', 'time', date('Y-m-d H:i:s', strtotime("-$maxShiftDuration hour"))]) + ->orderBy(['time' => SORT_DESC]) + ->limit(1) + ->one(); + if (!$lastCheckin) { + return; + } + if ($lastCheckin->type_id == $this->type_id) { + if ($this->isStart()) { + $this->addError('time', 'Смена уже открывалась'); + } else { + $this->addError('time', 'Смена уже закрывалась'); + } + } + }], + [['admin_id'], function () { + /** @TODO check for power admins */ + if ($this->admin_id != $_SESSION['admin_id']) { + $this->addError('admin_id', 'Неправильный пользователь'); + } + }], + [['device_id'], function () { + /** @var AdminDesktop $device */ + $device = AdminDesktop::find()->andWhere(['id' => $this->device_id])->one(); + if (!$device) { + $this->addError('device_id', 'Неправильный идентификатор устройства'); + } + if ($device->keygen != $_COOKIE['device_key']) { + $this->addError('device_id', 'Переданный идентификатор не совпадает с привязанным устройством'); + } + }], + [['plan_id'], function () { + if (!$this->plan_id) { + return; + } + /** @var TimetablePlan $plan */ + $plan = TimetablePlan::find()->andWhere(['id' => $this->plan_id])->one(); + if (!$plan) { + $this->addError('plan_id', 'Неправильный номер записи плана'); + } + if (!$plan->isWorkSlot()) { + $this->addError('plan_id', 'Нерабочий день по плану'); + } + if ($this->date != $plan->date) { + $this->addError('date', 'Дата открытия не совпадает с планом'); + } + $targetAdminId = $this->replaced_admin_id ?: $this->admin_id; + if ($targetAdminId != $plan->admin_id) { + $this->addError($this->replaced_admin_id ? 'replaced_admin_id' : 'admin_id', 'Выбран неправильный пользователь в плане'); + } + if ($this->d_id != $plan->d_id) { + $this->addError('d_id', 'Выбранная должность не совпадает с планом'); + } + if ($this->date != $plan->date) { + $this->addError('date', 'Дата не совпадает с планом'); + } + }], + ]; + } + + public function beforeValidate() + { + $this->time = date('Y-m-d H:i:s'); + return parent::beforeValidate(); + } + + public function save() + { + if (!$this->validate()) { + return false; + } + $filePath = $this->generateFilePath(); + if ($this->hasErrors()) { + parent::afterValidate(); + return false; + } + + if (!$this->photo->saveAs($filePath)) { + $this->addError('photo', 'Невозможно загрузить файл фотографии'); + parent::afterValidate(); + return false; + } + + $attributes = ['photo' => $filePath] + $this->getAttributes(); + $this->checkinModel->setAttributes($attributes); + if (!$this->checkinModel->save()) { + $this->addErrors($this->checkinModel->getErrors()); + return false; + } + return true; + } + + private function generateFilePath(): string + { + $Y = date("Y"); + $m = date("m"); + if (!is_dir("data/admin/$Y/$m")) { + mkdir("data/admin/$Y/$m", 0777, true); + } + $fileName = $_SESSION["admin_id"] . '-' . date("YmdHis") . '.jpg'; + return "data/admin/$Y/$m/$fileName"; + } + + public function getStore() + { + return CityStore::find() + ->andWhere(['id' => $this->store_id]) + ->one() + ; + } + + /** + * @return TimetablePlan + */ + public function getPlanSlot() + { + if (!$this->planSlotModel) { + $this->planSlotModel = TimetablePlan::find()->andWhere(['id' => $this->plan_id])->one(); + } + return $this->planSlotModel; + } + +} \ No newline at end of file diff --git a/erp24/forms/timetable/TabelSearchForm.php b/erp24/forms/timetable/TabelSearchForm.php new file mode 100755 index 00000000..cd303466 --- /dev/null +++ b/erp24/forms/timetable/TabelSearchForm.php @@ -0,0 +1,147 @@ + array_keys(self::stores())], + [['adminGroupId'], 'in', 'range' => array_keys(AdminGroup::groupsWithShift())], + [['start', 'end'], 'date', 'format' => 'php:Y-m-d'], + [['status'], 'in' ,'range' => array_keys(Timetable::statuses())], + [['start'], 'default', 'value' => date('Y-m-01', strtotime('next month midnight'))], + [['end'], 'default', 'value' => date('Y-m-t', strtotime('next month midnight'))], + ]; + } + + public function attributeLabels() + { + return [ + 'storeId' => 'Магазин', + 'start' => 'Дата начала', + 'end' => 'Дата конца', + 'adminGroupId' => 'Группа работников', + ]; + } + + public static function stores() : array + { + $stores = CityStore::find() + ->select(['name', 'id']) + ->andWhere(['id' => $_SESSION["store_arr_dostup"]]) + ->indexBy('id') + ->cache(3600) + ->column(); + natsort($stores); + return $stores; + } + + public static function adminGroups(): array + { + static $groups; + if (isset($groups)) { + return $groups; + } + return \Yii::$app->getCache()->getOrSet('admin_groups_with_shifts', function () { + return AdminGroup::find() + ->with(['shift']) + ->andWhere(['NOT IN', 'id', [1, 2, -1]]) + ->indexBy('id') + ->all(); + }); + } + + /** + * @return Admin[] + */ + public function admins() + { + $adminQuery = Admin::find() + ->select(['id', 'name', 'group_id', 'store_arr', 'avatarka']) + ->with(['adminGroup' => function (ActiveQuery $q) { + return $q->select(['id', 'name']); + }]) + ->with('adminGroup.shift') + ->andWhere([ + 'group_id' => array_keys(AdminGroup::groupsWithShift()) + ]) + ->andFilterWhere(['group_id' => $this->adminGroupId]) + ->orderBy(['group_id' => SORT_ASC, 'name' => SORT_ASC]) + ->indexBy('id'); + if ($this->storeId) { + $adminQuery + ->andWhere(new Expression('FIND_IN_SET(:store_id, store_arr)', ['store_id' => (int) $this->storeId])); + } + return $adminQuery->all(); + } + + public function search($tabel) + { + $classes = [ + Timetable::TABLE_PLAN => TimetablePlan::class, + Timetable::TABLE_FACT => TimetableFact::class, + ]; + if (!isset($classes[$tabel])) { + throw new \Exception('Unknown type'); + } + /** @var TimetablePlan | TimetableFact $class */ + $class = $classes[$tabel]; + return $class::find() + ->andWhere([ + 'admin_group_id' => array_keys(AdminGroup::groupsWithShift()), + 'store_id' => array_keys(self::stores()), + ]) + ->andFilterWhere([ + 'admin_group_id' => $this->adminGroupId, + 'store_id' => $this->storeId, + 'status' => $this->status, + ]) + ->andFilterWhere(['>=', 'date', $this->start]) + ->andFilterWhere(['<=', 'date', $this->end]) + ; + } + + public function holidays() + { + return $this->validate(['start', 'end'], false) ? Holiday::find() + ->andFilterWhere(['>=', 'date', $this->start]) + ->andFilterWhere(['<=', 'date', $this->end]) + ->all() : [] + ; + } + + public function getDates(): array + { + $startDatetime = new \DateTime($this->start); + $endDatetime = new \DateTime($this->end); + + $dates = []; + for ($date = clone $startDatetime; $date <= $endDatetime; $date->modify('+1 day')) { + $dates[] = clone $date; + } + + return $dates; + } +} \ No newline at end of file diff --git a/erp24/forms/timetable/TabelSearchFormFact.php b/erp24/forms/timetable/TabelSearchFormFact.php new file mode 100755 index 00000000..40be10f7 --- /dev/null +++ b/erp24/forms/timetable/TabelSearchFormFact.php @@ -0,0 +1,124 @@ + array_keys(self::stores())], + [['adminGroupId'], 'in', 'range' => array_keys(AdminGroup::groupsWithShift())], + [['start', 'end'], 'date', 'format' => 'php:Y-m-d'], + [['status'], 'in' ,'range' => array_keys(Timetable::statuses())], + [['status'], 'default' ,'value' => Timetable::STATUS_PENDING], + [['start'], 'default', 'value' => date('Y-m-d', strtotime('-7 day'))], + [['end'], 'default', 'value' => date('Y-m-d', strtotime('+1 day'))], + ]; + } + + public function attributeLabels() + { + return [ + 'storeId' => 'Магазин', + 'start' => 'Дата начала', + 'end' => 'Дата конца', + 'adminGroupId' => 'Группа работников', + 'status' => 'Статус проверки', + ]; + } + + public static function stores() : array + { + return CityStore::find() + ->select(['name', 'id']) + ->andWhere(['id' => $_SESSION["store_arr_dostup"]]) + ->indexBy('id') + ->cache(3600) + ->column(); + } + + public static function adminGroups(): array + { + static $groups; + if (isset($groups)) { + return $groups; + } + return \Yii::$app->getCache()->getOrSet('admin_groups_with_shifts', function () { + return AdminGroup::find() + ->with(['shift']) + ->andWhere(['NOT IN', 'id', [1, 2, -1]]) + ->indexBy('id') + ->all(); + }); + } + + /** + * @return Admin[] + */ + public function admins() + { + $adminQuery = Admin::find() + ->select(['id', 'name', 'group_id', 'store_arr']) + ->with(['adminGroup' => function (ActiveQuery $q) { + return $q->select(['id', 'name']); + }]) + ->with('adminGroup.shift') + ->andWhere([ + 'group_id' => array_keys(AdminGroup::groupsWithShift()) + ]) + ->andFilterWhere(['group_id' => $this->adminGroupId]) + ->orderBy(['group_id' => SORT_ASC, 'name' => SORT_ASC]) + ->indexBy('id'); + if ($this->storeId) { + $adminQuery + ->andWhere(new Expression('FIND_IN_SET(:store_id, store_arr)', ['store_id' => (int) $this->storeId])); + } + return $adminQuery->all(); + } + + public function search($tabel) + { + $classes = [ + Timetable::TABLE_PLAN => TimetablePlan::class, + Timetable::TABLE_FACT => TimetableFact::class, + ]; + if (!isset($classes[$tabel])) { + throw new \Exception('Unknown type'); + } + /** @var TimetablePlan | TimetableFact $class */ + $class = $classes[$tabel]; + return $class::find() + ->andWhere([ + 'admin_group_id' => array_keys(AdminGroup::groupsWithShift()), + 'store_id' => array_keys(self::stores()), + ]) + ->andFilterWhere([ + 'admin_group_id' => $this->adminGroupId, + 'store_id' => $this->storeId, + 'status' => $this->status, + ]) + ->andFilterWhere(['>=', 'date', $this->start]) + ->andFilterWhere(['<=', 'date', $this->end]) + ; + } +} \ No newline at end of file diff --git a/erp24/forms/writeOffsErp/WriteOffsForm.php b/erp24/forms/writeOffsErp/WriteOffsForm.php new file mode 100644 index 00000000..346e49f1 --- /dev/null +++ b/erp24/forms/writeOffsErp/WriteOffsForm.php @@ -0,0 +1,34 @@ + 'Магазин', + ]; + } + +} \ No newline at end of file diff --git a/erp24/forms/writeOffsErp/WriteOffsProductsForm.php b/erp24/forms/writeOffsErp/WriteOffsProductsForm.php new file mode 100644 index 00000000..43d0818c --- /dev/null +++ b/erp24/forms/writeOffsErp/WriteOffsProductsForm.php @@ -0,0 +1,111 @@ +select('quantity') + ->andWhere([ + 'product_id' => $productGuid, + 'store_id' => $storeGuid, //'quantity' + ])->asArray() + + ->scalar(); + + + return $productCount; + } + + /** + * {@inheritdoc} + */ + public function rules() + { + return [ + [['product_id', 'quantity'], 'required'], + [['store_id', 'cause_id'], 'integer'], + [['quantity'], 'number'], + [['product_id'], 'string', 'max' => 36], + ['quantity', 'compare', 'compareValue' => 0, 'operator' => '>'], + ['product_id', 'custom_function_validation'], + ]; + } + public function custom_function_validation($attribute, $params) + { + if (empty($this->quantity) || empty($this->store_id)) { + $errorText = 'Проверка по наличию товара под списание в магазине не пройдена'; + $this->addError($attribute, $errorText); + } else { + $resultCheck = self::checkProductBalance($this->$attribute, $this->store_id, $this->quantity); + + if (!empty($resultCheck)) { + $this->addError($attribute, $resultCheck); + } + } + + } + + +/** + * {@inheritdoc} + */ + public function attributeLabels() + { + return [ + 'product_id' => 'Товар', + 'cause_id' => 'Причина списания', + 'quantity' => 'Количество', + ]; + } + +} \ No newline at end of file diff --git a/erp24/models/LoginForm.php b/erp24/models/LoginForm.php index e86786f6..f68ba61a 100644 --- a/erp24/models/LoginForm.php +++ b/erp24/models/LoginForm.php @@ -103,6 +103,8 @@ class LoginForm extends Model $_SESSION['dostup_area'] = []; $group = AdminGroup::findOne($user->group_id); $_SESSION['admin_group_name'] = $group->name ?? "Какая-то..."; + $_SESSION['name_group_admin'] = $group->name ?? "Какая-то..."; + $_SESSION['status_dostup_arr'] = []; $_SESSION['admin_group_add_arr'] = []; @@ -123,7 +125,6 @@ class LoginForm extends Model $_SESSION['manager_id'] = $user->manager_id ?? null; $_SESSION['content_dostup'] = $user->content_dostup ?? null; - $_SESSION['name_group_admin'] = "Пользователь"; } /** diff --git a/erp24/tests/functional/PageListCest.php b/erp24/tests/functional/PageListCest.php new file mode 100644 index 00000000..c9a1e607 --- /dev/null +++ b/erp24/tests/functional/PageListCest.php @@ -0,0 +1,13 @@ +amLoggedInAs(\app\models\User::findByUsername('admin')); + $I->amOnPage('/info-table/shift-sales'); + $I->see('Login', 'h1'); + } + +} \ No newline at end of file diff --git a/erp24/tests/unit/models/UserTest.php b/erp24/tests/unit/models/UserTest.php index 28986cbb..697e1459 100644 --- a/erp24/tests/unit/models/UserTest.php +++ b/erp24/tests/unit/models/UserTest.php @@ -3,13 +3,14 @@ namespace tests\unit\models; use app\models\User; +use yii_app\records\Admin; class UserTest extends \Codeception\Test\Unit { public function testFindUserById() { - verify($user = User::findIdentity(100))->notEmpty(); - verify($user->username)->equals('admin'); + verify($user = Admin::findIdentity(1))->notEmpty(); + verify($user->login_user)->equals('root'); verify(User::findIdentity(999))->empty(); } diff --git a/erp24/views/layouts/api2_menu.php b/erp24/views/layouts/api2_menu.php index 2f5389a3..18e16f09 100644 --- a/erp24/views/layouts/api2_menu.php +++ b/erp24/views/layouts/api2_menu.php @@ -4,4 +4,4 @@ $this->registerJS(" var ADMIN_ID = " . (Yii::$app->user->id ?? 0) . "; ", \yii\web\View::POS_BEGIN, 'api2_menu_init_global_vars'); -//$this->registerJsFile('/js/site/get_menu.js', ['position' => \yii\web\View::POS_END]); +$this->registerJsFile('/js/site/get_menu.js', ['position' => \yii\web\View::POS_END]); diff --git a/erp24/web/favicon.ico b/erp24/web/favicon.ico index 580ed732e86556ec57f3f3395a210246d679c076..a62770a944c96b41c38842479068edc54b737ede 100644 GIT binary patch literal 38049 zcmX_H1yEaEm`!kZX>lp8MT=X3;_gt~DN>x`Ufi`varfZv#WlE=;_jMk{@I<4OkU>A zBzNxp^qlhn06^IDzXuRN1&B@o0El4MKUI}wG0{lSV3(M3Up}kSH^W5`G;aya0=?V3NY#{-EGt=>k-RXn`4KS#_j?J4>edb(2-mzG8@-NIzBg1 zZGF)=?iuia?Vmu}miXVR&{{VwHI{z=0xE?|r)Y<)B~k@zt{=Z3-VykdV= zU-v@wMu1mL%{47+e1TQ1@#~}qZ^y!^TBFJ&kXK6k66I+6_UOXx$b8|%oPGY_@pImd zhaaZwiT&;>L~1f%f+-aCi+hM~lnbwvyd!1aRhz%_)NfpQb;|Xs!{&vM77kC3j~(o7 zY-~6ORe}KN zNdY@;9|XU;mX?+t5UAMl?{Ly{o9h9O-}N7cRF2L|-=l9W8~W~7L&SVJF2hIeBNRW} z?jSE01|26gLM@IxZyp#(!xBZcg<>9PI&5D+s>)`Y500xSqOCB3m-7w zelsP+$MXAZ)uAyD3vyd3M)7zRAMmNHC$bKiQwK?0VyZrU(Ag?ly@0*>Li;Ihfy*-P3{+7G(+4I-71JVUy%@LySj#7@k zrHD}D#dYOLRJ-n~w<99i)t8qSJA3==g*g4%(5~w!7WPV^<1$*i6leFhW1XH;^?v?9 z00}Uj=GQee5Bh4Iwz|Sbm!J0B4VvUL&=Wf49A33dx;4LlFv+_Oc>+9>z%F1ef&t0-4`g};6Jsc}k z=zr1mVAqeaB;=DHc*WgcuIPrlNgMZRUGQdNOF!M%zubN8TZ?YI$bH$}7)z}#rT=5l z-J*`MzU%%(JsKKX)xYs{y-Jr^0jyU=p1ElH+jb8h9Enw5FeTI z4B2Wd-vV*Z>uAzF8App~V<cYZ8``H5N*myC>$Z=<9^6^N_O0yJd zU!czRlbD!O*IgPI=2F%Y6!^N^_&i#rCFIyIcc%USAE{MPGF*5WC}-m#5bB zs3OXYik?LWofS>a+l&`*-U#IV&#$@7AMyO3pmVT z&lo2=5tI$rH#e3er)OtMCY6|aez79jp576Q_1%kh2D26*)`}JqYq0K}@wcQcSyIB< zs+P1I-g$jN$8gYX%X~FmX}Pz2x0ds+rv2YMZS0QXnWZI$2VwJJHw8TzaI1^8e#b?3 zWh=%G7$^p{QPsmTI?m*~bWo6wGDs;ltwRxh!CrW+&Jvqo3WhCS1Dd`{Nmsj3t@P?h zH;AcY#9QtWFXG{}<-onx>4`3aZt(O1E>8by2J>v=s>Mnjy_}pJIrJHE*&fhN_djsd z&4KRtbS7PJ=U$Vq{nelOsv+}IJ$GY=sOPuqbnwqQj;U;`09h4(o!4zN7M^z`YD+=Z z^&V&XCzJe8=4qQPzlXHb5QF!J)`E4g9cog^;;GNI-rU@@s)AFEcD?I((wgEOjdeqZ zdXU_=&jE}Uu)sB;ZR{KugC%S&>jfkB!;Z}>D*pwZf%d(m=<1eDpLu3xW_gG7cq@P# zwr&_dYXh3{jN~bi#hvS2M6p_r@tucU=p`v)9b}3QY%(pbU(@(auMl(uqN()u&sj8> zw+wqWAK~zlu}g2+{BdFALik0)jMqD_)@Q$q;g_@FJWFk-VdbWDHcNCMs%yFo)qaY& zW6_7lwMy^2EYhY-FODu@iAK|NQkQX{^dZ3V(GLid;<=V^HGzMazTJAWvaLSOyr& z<%oHH3oqB&WqxD|QDP>Kgo+8Uh~nZ;^w9Sm3t_dDZnLXk*5@Vyt!bD zc`x09rjG*&lQ z#plQeQ!8~WD>ztsQpZ@NT<%OX|4P!4n_!U4+v(MZ=7E-P;+!NOzz1Vipbbv@{jJOD))GS8wY{@r_y5^$!nawHM;=smcI9_q5Xj0_@KM3@gmv0AXTAw z=XMOYKTElE?GH|?2@fNDhOaAiHnRm*o4+Beg1k=G3e@{D%9qf*tb_8l(dJvJknwa5 zr?&m9N)pCM7Y>Q6(iC`^bzq{1M)zz%TUqV*?32@>W1y5Js#v^RC;lBw zMP*7yT5EQ-%o;zcU}>YgDtHuJ4oeqc_?)yC=7v~{xgYa`33UwFF9uI2F3(jr$9(K( zYb3t({6)VNnq~^VXuE_qX317Oh5gwfCL{!H_?)m|3Y|5Xhi+dqud#zM`3*UGe{F73 zup}4CphnihsrDFnj+@!%bH5{8R$HbCCZf(q$zKHtEtQrmpr{jVfEFH}C%lPdpR%7e zSM7=Qs}bv6P!X_*+4OBTd~cM%=N%VBzfru>Th_n3&OhIsDAv{K^xPD79rmw3LQbE} z-D10{>Q+}*<3=c<=JT}yUFm@y>%l5<`b>!SD-Ff8a4oUc3w~{X#FFAE1Mc7|dw7>) zkPtqj&0f4HOlPpqzN7?-eScjEA_4#<==&u8q9GvC=|CK77Q0L6x^K%G?iU@MHe5!| z)JwO^ntrqU z9g6tiv0}+^Qj+c1l*VpkhS`?1@{z=PAreYP{Yl;ir^Y5o*wn;lxd&j<`u3i z*(L;*=lCleYy3C!01ua(=o;_J7hnrkV}@bepD|e@4uXPqBssLr7~GE@`={3B9S~Xm5z6V zd|*cV(j89m$B>mGn-V8I z(!+U8>zDnipo`o~XiHX)js^}FtUSnx7ru6GT;1sqiI$`p-}1cyEzZxITi)0huQ;%g zUR;cXV4bp}5oH9`0PWA*qv4b;R{vPa8S6Ot#e<&5oc#QJrx@Nx1&v}zFAaO(x*4~8 zW@_I@ypuD=zeqCKdA$0|T6{XN3omrhY5p*PEw)ev4wdsuu}?~aPQf;3xTYsPD_QSh zj0Zz0o3Hxr@ozl7>(-=?>#}KtzEkH__~QDyLu~l0-a38oIq9fIR1lA0{?BzGo9Z5O zITNDa*VVgwY{}BAT&R(cIz2tJI>4q{M=T7*BxOZjc2jFieS}o+$DIf?_4zvpa=g&_ zGGFmyIrqDTUzi$ALm7=oGUb=hj{6gNw}jdgn1$PEmzYor^;%_TqFiBtb38XqQ&UoO z3vF*T-St@5Gw@r@n?J97>_gesL1qe!N?$4#5wYEu|Cj6RSQT^6JE^Urlzs|%WoImF zJHGzXLY=Cn-#**^u-Wl%ql2yYta+{Ep{C>9p}f5OBe++lD;z>wiXgL8(^G6Y?|7H6 zkoVDCX6#0$FF)?Pv=K2w=y(iSQWn1mPF~=r|obMXs^SxvfyI3HO2(S`cNdI(&@)-2bdRiU@@F6p@)5HWPpFTMBsN(k} z%?DCa(yG#2AN9F#NBcnDLa;Kr{g(i@psxl3bP2`%@tGc}#Z0ZRa%$fDeg$99A99l? z&@GykTafg0b6`;DH|qG~#4G?Y-=DaV<}xSAglhI%^iV%Q5rMU(r;VSvX_<-Zxk*@e zc|*_8arsl3<}vmwPB=O-dlS9lCk1e%9!FJ9;}pqO zv(KF!e5}Pcqa0V%29?L1%mAQktoT+6Q?kMRn$wo!k0ofi%`MCT)FRnPNl2}ySMJqob-N%{VOBAUCEzaR)R8&0{UcHiOaQs>gb_Evy6RaARNWs8d%JM79Iw!- zozC404&A!^x5L8tV;F9*Px|-qJ=0~LR?QBy zp?#!bj}Whnm4ldDgW^h$MDM2F;k&6S{WZwG9s2cpRQ}`Q->EN#9h{t0ZO>y*aC?b@ z0r8?ipAhoaiPNeKiCfW=kRYtKD4&UaYH@YS72BBn4N+k6p(##a-)6k4@3igUT!b>< z)ult3umIzH!JfMmAzbb8i0kD;!}`+F5_H{lx;gHBq zimRvPtHh@-!oH?|lr6-ztbpyCRzSGIKt!2@hSN+?pHS2D*G~3GV?`R0b%8HT-!B&Q zyo|6vk#n>kO6r-jZzohqfQXRYoG<0NWL)J<-i78NCDocQgIZc1wp^!;stp{jqJj8j zeLC>7OUujefIq6C-;)VO5sJIgaz9Eqmb(JNx$5Ja5`% zx}s$EU7jkoADjF^wlg$5JbbgVCTpSoX+K+_uN&rwn?5^X2i3nfaY@)pCw{2wdMp~A zmOYF`rx;v1%B_B%9>_)0M9=xf7b}Wm0ijgs-gMfgz)fUG&nwH@;AtGz4>(X)YnU^p z(ykGU0~G7hjG09a+v7yaK31(`eUTB6E!R#`nEr+Pvt&VAV|GI!Oqgz>;qa*btIv@% zXx{?`9ZMP3A%%d-#qR6BHo_t<(hhR)Q`lqY;^GFep)*CoW&*CiO`+J+p7|Dm@x~T2 zUUYcj2WNCg-4AUyvxh_89X9v=wo0r7(5Tzf^{i zAUTsCw-OL0=>WJTFXzkf+m(c~qceP-SS@R^>eh~F2zL%EP)qzx#wdvveSc#1;ivST z^jB=~;P8l!?4UFX7KP7YU)m3)I8sk5Yj5w&pC6P#!VZINi5ZtF+yW2{6>?JgR~Yu! z1cLP*haFj5(ZxaGo)R%2;@}JPhfDBJgM8oh**$+d7GL`;f z?K=HCnfmhNMM`N*2RdSz$|f)LQR+bCCmMyj-;ZiUeIMCRdk%~tDzhJGVnz)#TZIP> z^NduOwiJTiNl4L)DO{?)#ZF)9bq{z7AdMW?9KJ&%!74(TIyy}Mi|bGY{ZZVBJoV?P zeOxdJZ4l1=-tr4tpr8iEzjV0auzVt#3Hg+}20 z2PxvOK(SW_^g%-Gxi=HjQ#EWph~ecflF&@@!K6|E%UQ)2>@jpo(g=h6xBr&pmU$3n10eAeOw0XRoW^upc z!U_z%{}{?uyZnb`p(eSo*}76Dy%R>B%W@fcfBPd`WF`I+qPN93r{N}G7o4FOrYW}BzivIhaud&k!^n3pg5epz6B)R4}=4Jl}$@0}C8VRdG zMOONRbOTNLrRq(ef7BAQAV)iOt&-^z4e5w$YilzThE*+6+q*juU$N+T zP^Htvz+HPwU5{yLiToYT!PTCOxJ*w=qbE$b4k^D5P&CFrItbJFNU!zX{Kou(sugi8 z{aaSHe+vLd-pQ{;^I8ky9`d<*<+t?mq9cZf|3KIH=k2mOd*hW4!7;Yqjvw3dg6{pF zL^_Cr*gfQNyvbTD{c~8I>Aix9?mD#Z_^;1%wU*CZ-=OWPSB)T?z2%7YcZ1BExncsr)Iy zI#)y?l!le2%A=Pzd4I%GS#Two!5Lj&119UP9hTQ+m$j?GX*ZX(X#}=Bsbk8^6o@lp}?@mdAfZJb;Ik!+ zcYI_L-sJs=ZS1L{5$`ggIp5=;`PFm#^=A64rndHC-sE@bdfm=N$0am+`2L}}xfx3l z7O%5^Rj?FfB}`vrQ&e2sTUSh?Ulg%`;8bdV%G({0en|Pg#4Go2MlQWC9{U54CS`D> zndD)a7F9TK1{pD^c-CN^t!Du7x5VM<2~kv_!mqy;#NE)(IgUbqO2fPgKyVDomJy>mD_v$o>;35gOrUn4m(*!%KtTdfUii{2pa)qN>8&lHh5`D9(w zq?KrnfhhLkO9%_fa$Pq!EMa)?PG!h7T&;U3x<9!#-ee{^1*$j>}Ng*k@iwmyu9ZHxhThV7{G(T%k<6;A%lMUjy8c?kbkQmyaHT<=})ohfygh*0r_n!}L^ z72gW5l@UWX666P4s>l6()O2LeRmVjR%QmjRU3sO1w#d!Id=9J(K}X(1@1@bs6-$%= zMj6kdT5)u|Q?n3*s`@OHhed6-d1k{I)yTiM?R@nvN?h)elL&5;wQ=UZEL@pg7SUUO z+$sXK)@ZE~a`yA>2It18i&K{!L`e^bEcmHWvxhLkyT>mWii;?VCr)3njNr285>Y=qp zEMXxg?$_^%?jAp`&wFEsFtmm6x<3NDk|K1XZ_d z`YQvuhqzK)Pvh}WxYElGP&A{!WU^T)MjRw_g*v1wduz_<8N4jrpn7Nne{ag~kO8Uz zcLrh9f*US3wBfWrMC1Yd_9wH~x(;$Xgy_1QK_QLGKL&L(Gae_@-n*?IQPYJYbgtw2 z7aT8ArpSv4O{`@EZDn{O7?Eg1a8k&@}3WK&X(|uE@Y2 zic`^Efm*7V$trDcm8@akty1lWpZ_Q`KIo}~>O}+LI24!Lnw6zou|CXTI`V^22H~+C z*h-YVL#1p$GvER)LNTGabiMb}>G_GH0S!HS4O|ez_ov6a$Ge5=WMfj!MD*I-G?c7jr;L}$D`f5yJm$uU+WAV2DbifK{=4(@|x6l|nhY%IM|4y$S#TU$;W0Z>1YV~I~kqRZM@ zStJo!+~!m0sU84NqbKx}q$yybA*U&#qmXIZB~BpI_P=Bba~*u{Eek^B+_daXMf9K! zg?+S5@%)zK6;oc|-frf#L-|g+PtZH9AoY`g;h0`7#-T{QEXrpk85DEutd@f=YI}+MXwi~8#;im;INk*-;cEk9JyKPxYKO51& z7>B1ERe-iv;gn8m2aHdAIBVGwg|`u>|JELv6t_TSvZp|hX6Ej>PQs0BwcpNCbsG4}fY zotXcx`6l>Hf1C6-Ux9*Cgx%hx0dmSpZl!g{KtZfqEeS_J81>cZvs(*Yg~}oseML~K zx_D#m_E!1RfXqq`J5UO@rrr0ewgJMfLZvn87x_`aMeY(W)UQBzJt7U!DBkUb=MIIQ zKNyTBz1YyaQ}INCjgARom0%&stR)f1>w%cU_L>FKl%TyY2Uo#gV0xULPOtk_5B;_Z z!R_w|$c#N4)jCfs@%C5jn_?EhVr^1pTPAk3ED9TkS&?zyH32$q@wKNjq+b!j?hEA7 zPj`U^%XdLL!Hni=!QA<2{+U0It=oEHvDbMjSC5&T(uLcc(AdTafN>I!voy+?Osuw>`C0E%d3bcj5f8n{)*cEE%KUDcy^lD<$kjl&W zxDi!-9-lhY0I=^sop>1(3U0D%Up$sgWBxwO`;-?H2%jSIPFI5__l2>)rNj|6nxnEP zM9Bvh;Pif)y5jwy8!C{WFFPi+7@Szq!d)^hIao_u7irZ}`$PX;_RbxZwcqIuJ0Y(D zN&iPxR61HA_Xo?^aW17?-f6OAk|aF*OLN%+a_Q*5x8>7o|K^6|@XLl-)t}qd!I4{y z$hF%Z0*B&m{iq`XR{#qHy^ohbHmO2cR4+xSeSHicjQwIyQT~Us}q+;@!?-OP@ouW zuU1$Xx*^}Xl7?^;sKzg(I1!FBL)P)_0pF)znZ5ZtX}Q?d;6vYjo6>Ot_blg=RPN5) z#fM6M6#o8+$+c4vBw^JGTn{>tNoCn?U-n~+r~l{qa@KO+X5cm-w1|2C+tBl=t#LOh z>E;@^SR`0P6Ek$J?eaNfwC+~fvQ+E(P<{=&%k?M06;5hNR;4E2*+|LHqw&+#8v+$u z4U$4Ow4_;9FO|(ZkLK^I86A(PS zW}KJQv?7io1m3mOmLR+z!k;um$c@UI#!~s3=a#4oUxyr-T# zrm*1K1V~YI=skUYo9x0%`In=1mab@?sL86Jn-G>J98Sl=V_u_fX#uywSp(p@`Il~- zk#l6urm<3qAY1~a+x}QlQIT>Kpx7hl{vQVPAFpn>=<~lJ`~(kWifwM~iWidipEwmGwK7tj79OF8Ybq`D#+5 z5tHgDpFMY0u1+&sl>Q?(tH$&kVUTa7qa$-7llDX6@52-}Xm$QQ8ktCJf&6~%6_{=T zf*oM%#}r9(u<&K?Tig*e+W2+d=lQ6#U%@T44oySl>nC&jMFYCvT$)8%8}>YXC$WDf zm;aguwS>&L@OMO37OyS^uCET^(!kkH--@E!`SUh4Bq+j+z!3ZUkWn#tgKi`T z4l9|~qK`NG&V_>HBR>e;b-Jutb-@LANip}R*`-k4DQw;@-l*~K^=}5wL`I6c@YzVc z5%=U3ksglP1Ze1xvEdD@mj8uH2<|jCo6d zzOzZ>ghK;iNS6KUb04nUFX3 zNz1M~aCSE~!MAt!RDh>f$8*)ABK2?^X{VULS9Wo#8BInM9B+TafZ!8o9Zw09^@Kl; zeu8@MZo^f4Wsh;cmv7$R@qXx+kfh1Evar)we0++b>$PjX$~UJhWtcbk`FbIsI(V@GtR%|04SWkI@M zwZ~q0yE1|$+h2>T$Hvt|=chv@==lTKo&gn;@grDgC3;D47{x1BI&WVwW>;)x{ZSu( zuJmYn_{U8?$(WlYfv18@#@ z)Y5al!$gNGI{**4d_zG>##!*3F-meYR2Wgur>-bvZ7VL8wm{LFGt3OB)UNJF6IWPI zP($3t^Y_Uo4%Yuqt3=j%0i$KC{~f4A>ubWBV+FGTE8j2nr5eu2ZFPTcUwhQYuO*UZ z1pEZDqL!SLQfa6Qgh>20{^48Ev%Tg+$8z=m8V?_DN>CawX$LoiRR=Y1 zQWM*zh;Y2ibh(N|6+ay#F=0d4L0JB5wto*&0APhFv1+#`W+dy`o9Lg?@Ix;Yv-uWD zxUGbc>3#pkEsKLqGBCmW@p@b)l9H06*hD@hxVr?Yx zc*AsOndrtG3vi4X+mn9FCDZHI#OT}f1tZdXxv0qWO4KBu1Nu;jy@v?Xu`{CAzqJ@u zNk{uM=xUaZf#`-p&fvWr4uWvdwYj^KjgS723y!v4>IbC#-XLCeO=lMkQw zE2w+ybfcpaieVbC6*+X}UtUAvPPGn>1Vavaa){29Iv;=BR{<@rg~b zbs*H338gAj{9l3TK;3an^8tgB)M7_^Kf7gfBfT!E1mb7kVJ7Nye|WweT}`ZDx5am5 z2LUJ5{036zcNsIk1YBbRH-rk%dg)%*%Jo9&+h4C0kQMXcSZ|^T$0H6T7&USv2|av+ z*>Hp2Z=kK_$dgG@+{Rjy9BbYxOq$&WvtQ zSX4gWj=&5#l)$2-3J8X?54KjX0)OdIac5*_AuKBSt9o`oXlq^`Wlg0~q72X**ad5g zC#DT0s{QA?9hgr!_{}d{-Us9ZBPYxGbaT~Sirnpj3`czdQ4E9=4YFq+2JdFaxj zwC5SfEB>_cW2NZdc{jQMV=>NkfiUqVJ&)6-aAA-mB`(Y_A#4kVa(mF@%G&Q9P?39+ z2jh>d*n#<|Jf?jcCZ+Pc8T?9&kH?w3>XhQ`@tO+xD(PqaVw*$|Rj&TpZjBc?TW2ie zi&vW0G3hUdk20v5F`_8-tuc0Nb=|r`Nfes)VZ8V$5@QRx-M(!Jha@c9S@ty)Grxc= zi?9Fcn1L#L0eJGZSGz+Y9j6V+jW1i@$0rANUmDHfA5ryN;c(PTvW+{~)gx4;q}DJW z0K9AJb1!~)kX(OT?{7;ygUe6Jxc(}*xEua5sg{UZOYq}EN*1wo+Pd5lwg-xs7AO1J zPT#8nVJ0fj5=9nYUya_y zRpjSc)mFdo2<%w%*ZSB?VdRO4-Q{elpgK6r{~OehO-)6_#ej%ms0x#URp}=okqh2V zwMn3Ha<}d7mve4iL&F%vnQBW{UBcd;iYFlP^=acY#yg*j|HRWc3IikvN90W~`6NOE zx<8e+0)t%@>ZLg8&iL2;Pw<3P>?PVALf^59!KlOA`wKd)C@WN-D&C z-DL!;AS?q0d)tCQAj|mLq6t3d6C1ZtVl|4ohq&e(G20!d3&K9E(7N{P*Lrn7wi~;_ zuuDYvp%biit|&9OW5J-K1}lA{#c`6PM{%MyxY5;C7d~5*8<+-#)WIQzroG*i8poX} z5LsZ{I?qqgMleg<_!edzR;l4tFP)MT{5by9lZUiIJ2rR_75U_?CtQdPRi4K6&|oau zwOXUM2gs;RM(#|*z6vtzSWc!WgZjn9IYk$)itrLxl><|cC@W?W#NQAy78kiU`-u3 zKiY^NRIU+Z-|Ld`I{yo9FV7!vx(&zed{P1xfHAa4^>&LDeH$KYLvn8$KQ2V{Zd4W9 z6Y|sR;ITvT4hSadF43Kgm_?zsYIY>U%E@D5%z%(MmAZNt{bJ1edtB|Y;&R}ZVZ1{o z`}FNI8*fUSpLOB73RO&C?bQy{u+!XN@pU0IgW^V>kI3b!u{$2?o?BhY^3D$%o|x5N zyL?pf!+&KuA_7(pgnr$Ym*$f3ARr2zw|0U4(@LoUa5w`~Xs5B)&^w_)N3~T1kk~({ z0jv%^xy33~4VBMG!9OM1QxoRQ6y~aCkB>={T#*qNoL?9L=(gYWq87KKEtKk;L-%OO zXMHX80DNX4%$+WYpxu4}^%c2^pqp(UT%q4CN~$F=3H1|Ahzv!Z_r5KBke|W0!>R|A zoT(!spNiw+1H&V~X}_MfwY9Z2ikKcSN}cgIzXDwq`7@TD(=+J~loN3$fVTNE`e}2S zeBKwC9b=oZ%Cn%BOOM2YybrI{!fQfOzgFY z+k6!QMfe@*cIo{G>vhpjJMqo$+-=RK;1uQSTz|mxZ5cxO5H@?u0ppLCIT$tKuA)J^uE zMv%B7S+g7^T@R+-FC=}Jmj5qPLVxccsC#-{Y+$V%z_hTIu#%XLX_WeE>Erxti49*Q z?zY~A?h>=2XvPIq1CE8)3p1p1)6V$FxOVd4V|v+~Vs`W&EOOef2TnJg(w8C_qM3N|R-T-kR2RmJ za#>8ovedM$&xN5hhimxbEvnOuW(y)}#IA&5OXDD($-Y5KdI)}Qg;46bO>_PJ9Q;Hq ziS$abqoUKDzHr#V*c-NMA0{?LtVH$rTEfp4d0wbu*xb^Vh9z^6ilWJ{w)6A-+0p?Z zG-Nu*d0|tr7$Khoy$Qih9(OLGRX)NmGcpzLap1Zt!1!^up}CA%%U+2jevmMuc|3A{ z_;*g)$)Ju%@ z87oeIj&7_)B0-Ob^}8ZHuqXzEsOL+;twNF&-Q}OqlDX?1?F(WjGz{Y>LMh~oia>S! zri}~(S8oK~?;PAX-vl{hU@QdDWpK{h85nYq`7=rQDCif{{g~MWZB0tz?iJ+^9t$PJ zSP6ZK1RGaXQ-IU;?HvsLQ%k!)(_A4GD8)t_&=6_TCk%*>nP5pdBX>1{eFX^j>PhS+c@_mg4c^^*zNpXINon_EU|*al6CRqwcuB2sif&T> zR(%Q6i#hLk4lzq(fyT319XfG2h?tFbMtx>`Yh7DR49p9s5=v=hVk=)5C)-Dy z;m8Kk95qIYMYALDuL6m|%-=L zP<68cBt$yc^!@YSx4*9IY0t-06d6TN-LcuFllm30^5B~u@a9zNg-C?xrd+(40-1sI zaX2g)k=fMpR8Dq#C7)`i5HTT@qx4)+Rj{Ehzze|Zas{;m_>2xM+h-wr{lk#wmJm<} zAs`|Om)@q8i$i*^rRGa?(!@b z15(L4IF^IjZ7e7qMPK*d&H5Bmjh^A>p;)1VyO2w@=u4YoF6Yhco4Qy$zJi8z?W+Vf zv#XRSWlVwt62fJwTqea4%D=4-iH&E|j4dZ(!W~;x8Fhe7(IvI>{GV-UIXUe0l)WCH zcP~B4Nd5`3WXqPr)XJ-w3H_Hc# zbuv-n`S_YPbH7R+0&4!T0s3)H5>l;CuaK-mZoT%}jBWBehp{{(QbRydc4!L3);+}o zJpXw|{-qvbF$uABtpmGXd4gNJH zmW>m&nN8%b&QWLQH@SvxqS$7@q1fP_+kfq{OEGO(?Iys)Y!E-3GUG|5jk?k;S z**?l2oWV~hmqVd9?W4~DrE*_PQ|PHR23~MJP`{qBkc2JJ{eB=&c{xjzLEdc81sf*E z`Rxq6TZpXt>2<+X?-#D(6@HU#Zij*AMT9~OE~G+g#25fp^4L4U#ueT=RLk#_UYa-&1JQryN>n+DC$5D0 z%ehC02$83_-Iz@M5=iFBpU-%JSp~1q`Q1-u02=Ct*#KDG5|#=9FKEgV@H!XrooUvo zVDkY0A%Aj^hOnq=V|bVEV)qg66&AI@r;zoNFxOK+Cf;bXO=?{DTG7rcdhOs{37qX>9{PZa`1RdKOnDyhhN3-p#L z9>*L)L`X|>T*jrtNT-#h%%CV937|X3|P*qwx!{2^_zABxHz?Ny-+8E7RQ|VScLO>Vq;(G~SZ>I|* zr|;DFp4nvApC!#iisQ&+qtxpMQ4MdqryG0icqeLEc)+x-3Hm^bl|kU{9W)3>-`Mx6 zrOz1h-E{<-$8GJQ7`wQ%OdCsF43y@v?=77zpsF^*I7S-{0xPqpZ=+m=DP}_vNh)WW zi$s~*=;Z^a>533i8XU5|rtbeCy;SSfB4#bb~Xh_W5R z@&R6pyG;>n@i!*xi~Zft#l#CzvR=Zis6cpT$>o*hI)A3XkeY9kS~uTXSjTQ?d(X)m zt*5`ENd1KOy<1F|kurSGjg>EUiA@iMj?!WasSSl-3HDZ0trK`I;7J&{>%9t5NObC2 zpkIqaTjf1uqGDkxF}EMJ6KG-__{L)NtB#zg3V|8@-i<@GD%!A4=koMZsyMUKmzV+r z!&;BQM^6Zxkqhw!_o>ri1D|L+*I!2fJJI31GKfeoxu~tn5ujDw4YY&XE8SD*L{Y`j zX1gQJhoBYcSs{^m9tm&Bl&FT0JNG(~wf!eh-|z|yh?E7sVk;qSLplx%(51v6SJ-U( zu<;7ot}*=gf#e^8h4?%KVK6phAmnqEirYLJu_641#{xFAoO>X`2erAr1hLx(*udWLgTl~lKSH#O5ig$mZi90& z)t^D5FS@8@8#K13B6n}IUqo>rsPxl$4i&YczioOn@gV*|fgwrW;by49&0OZ$fvrHm z>_UyoU>@iQ8IykdTZidUy|6P&!O+-w4^&jv5eA&AqU*_&ux&_xN`nTFW%I|Pc&^$a zBSWFE!2>##Jt^#aZ+AGjpCIlGlPqIyq_PwY4nS5K-lQS{WOORvNw`vkBAK_OT$p2r zN^d;4y$C@w!=LIYV;hK`V}VR|mK6#q5*IaFG|Vl##X9y13iuyHB#Xe=&{DoEFZpUy5J1}CpE_;`Q4F4UnGgF}br%{GH zUx)VqoWT%voL^QfO^=}AY+l}CaGW5~e z(*OJ_!=oBaOTjyAtVF?m9LkE2sK6^_&`T|gTgjyYON2u8>0VFtlZgFW@N7<-Q^k>3 zfmPaHoSqGyLzj_0S8SatHg)g+<&t|(kJrRUB?Lxc|1Rts3R^^pUn@QeY_=Q!rnJ(W z2@s4hZKG>C3JAm!eWa?as2GzU*+!}mV@*Xoe4u*FDS8yH2N1wT1tAgIXp->7c->O& z^jOryX=0a@##7+l1P>}%t4T&DcgBg5vVInfVyX}O5T+6ejrtH8;71ZFHi36I6-n3o zrg^yP3*NuJu|oDB9L5`#4phe&`uO?P^b=2sV39ySuJbTPeNtdoqxY~-!eR)v=nN1+ z1eW)Q^ZW%laSnH(FG+lZ$@EH1>(xDOrV^{8B0=i%(iy}Yc?Z}jICCn3O*n2xB&t~+ zq3;7$yg9OHd()bDXK$H<6!01mKHOyllg`yQ>)Bl=6G8sPW)k~*n&2pGUnPPN5PH6^ znKAtjQ)d|!RUdBgVHmo*M7q0q0qO280YRD}r9&9HyF*G^asWZPI|OOz5DDp$yvMuN zUF&|Dk27=5Kc8ps-yW-ccpLr+JI{!Kk8^>)U7rwHPMq0Y(&I5!758WHF)3NJ^$7|R zcv{T8!gFcfKqF;g+v;Zi@zxF{(MD^&V zZSGTov?);ysI9X~B;@&@6vp;D2#e3$I5(}>5g?jy+)>oDS|r7<^-RekkrqUOiK3En zJ5fB+&=qIU8uZPrR2qU~@!e7AGsW$@oThO01+=H@2q$wOejGXQ`Kjhf zy0St))|H(x;ZpbbtUmsQinJyJPitL-fcpbNXe>t{3vUNt#5Nw!;2D(Uyy< zV*RVZrZ$$3Qa^-$PtcQQ3Bi3pxmh-v3(U~;wk*|za14?NYjBzR6Jtqs$aHKO=wx#o z*ei`k2niqW7yXS(OH0W*$?Q)*=B%9&l<6f|(&Zx*jt+fNvGOMSPoqK=~d{;M7Ormy(< zcbOnpZPejc?oIPcOGz`i!Cy^x=h;``4#41H9AMMM@}h~&9-oT1Ff7i*!aGN zu<*BHw_UI2ufjQ{n6}hskN@?NPE1W3dtP2!Tm5jfD@;yIu@p_$Fik|mfv~`W7R0s} znitLJgx~igWQ`&hX6eBqC7+Vi(xKXU^j`JO-1WBvEZAXDF&k)w%1&@S1 zK~?`@Xa@uDZIK0>!+)ThDl;*H`-|GzY=#V#AQpchSr1;$Y0eIG}LepS%O;?V&)`HlhLIPt>FD zkfHgX#{gcW=;OAA_+MFh7qB4%u6Y|GLI3U+VDA2|f%a%2cf%G;K|JV!MtV~W2`_-c zj|h;vgZkWSaxMg>J{2n-8AQxP^IMWGkT&sXIJ|(#e_vOe>E#oqjm3%kJT3+XjbJgj(5vJ zH$@)4PxsdgobAWE9tioo)*oV|I+FNr3eCY2{4-V}s5^`OjO_Ir%rS*qN6OL1DP{;r zS;>T(-UIlcB!a9AKIQ>>Vf38+`M9_Xm>C*iPkvdDz$@n5TDk1Qj(eH|mnx4t&EM+m6 zCJdjt9)1;faKYVr?q~se9iJf??CeCOCEC-_Rima@B+M??_$BhitP?_Qw6dl|8hqGR zI>Q9bXg=Zy`E0sWywe?>gwmg*#u&;@k`9~eO42R~%Q`eV)GDOu-`+NDNDgT>=Np_1 z&0eza`#dyPsq-l%(8_NxhA86~lJJBELL8E(sP~CUq^|3inn3GGpm|Z9hgb4icLbN( zJimnl8nY?IcRhV4&GWgDX_;Sl^Wh13PC--0U0s>>$58c!X#*tf;8O*@c~P6%O_|X= z56i$)m;_ONpOx2hd}8gy%B`~{f(-^SNS(gHS=j!FbPp}em zmG|~2YwPC(wQ=ELSqOK6I~Qt{IW>;{Qbc1%&}!6M@bNkc17{CzP>O!Ky7V&ZBlgzt zSar~;F5HW_Wz_f@5fQH+pZLfk$|Bpm?k#cU0gq{C^1)+3!>_+R!V*ZX2>K5s?;h3c z<2mwZL(G& z&SgclC?J7{zR6oVqZxc&y5_wx$;xg*VY7hIU-=E;2hHG*M?H%ITqiq+f1dhR<2 zQ4nW`Y@xnaA>K}4P;W6u=I96JmqD^Mi2$kRSmr$oOlf2lg{s3v3(XEa*kjj~IcjUF zALZ;8uQ|@VV3Hz4_5M1a1j`HRV@pjq74eXP@fO`wKMdt;?osPAh!>xL6q|v2wl8sc zgTF0oLm%{4|1!i+)Uak9;ZN_{Cx5$(gT=uWN?ebSkn;hE7&;8Q@8oiZ$PU=C2!W%s z#N!zv$KdQ8lQe=Psa+@F?oAQ-&Jj_AMbT%ZZXffz3nAbGS7_bwoU_zCrJj^>GYdiG zRxYa>WuLQjh|WgL_2x~s>Q9DMOl|tlY6x+D4CVpPct8K5$lmc3D5Rdnf;FM3j78NJ z3)S}TNRXl3fm&IQ^<)>KUM^{fJOb6WTw7RDa)NK8yDKO4a^mB#3_yLETOa;QS_6KH z3hd0(tt%P`Cgbk_>!_0g!g2fQdd3OQYx&7PW`^%?*wIdZ|KM+Dyx2|?^pL>x z`O)|2Ta702oaQOZi(vYfja(Q*CW_UPr|UL_Hdd-FT4+(t;dj|rV+jhq3koG7Cz`EjvPii^w^QT?I)Gs zi&LbLMo^{dM3+qKQG5%&bVzA|sFv^e(uJK_?oT(Jm1mjRI7ypPRDj6+9mf|te=*5= z4V+xq`$qOCNbXK&6P1Bbv)WPMxl!P#aik>Y4m?xsemsrI%cFiI0hg*PEgVENPb|fv zn70(lK|LW6<|L9VIl3mGTC^-E;~FY;HC-hnXMce{W5-+Q&_q|_J*tG)GrWAkO8stl zh1iaDpM=Cb;R6EsqbVpRw8Y8S%m))It-${*s6BJ%dqXFLj?x^<#NKP2Y{d9haSkbp z62jl!zCQ#NXN|WDr#IDHT?Kkri6hY$u)ar{y<6AEDC*5Y_tHR6l$CPd7c=K&J}87c zSxNX@u^q9V>?fnO7>Ka_C^_va;rn$sS`f0NS%iAc@xdHn5(Hs?@ql`BHHw-#*wJnL zqOVtGT^vjqUK7INN=0!b6v8-7XSv5!gYkeVC21wRPHiqr?wa^U5s^3o<&Jnh5{Vhz zgUspP}`{$Xnduh+GjueMRy!aIV*~`0Z7inMb&vqGv&d^=dk)n~J%Y zrz2shjU@5?WitMA#%ryyZ2ku{%}}SMtNpp0N!bzvDs&A*c!WXga&?2fGwNDr;kjnEiO2FNI}7WQEY$m=9|6rzpTuu<#SnU$=;Y{GmBO?yu6W!4 z48aI8xW9W|(b{bVZayAIXvl+t^-GW;yo)miKeKtAnha@KSn;&L*K{S2d*t0Wa_&ez zuK~fJO?cbAy#AerQt+s)W1s`!`C-T2bPbVsZ;FC8RB(L7DxRGB`;bI<3r6Ja2F2>m zePuWrMpJhe4Xup6&kk(^VSQfkPU;0l%u1gZKEW1B z8T1hGyS{~ZoS-KNFZqxfUzsNKj{7yjH8Mset(5^jbG?W+tERckx?+9wif2oDirp4U zu+rAhGzCKjOhi0Gqxzxh5ju1B@Fag%V9Ewgy5gHV4aV*tg@~wmzhBD#mM^Ul!)Zak znayVvk1Q1&ZP{?rU#k~-VCT8f1y>T347Pa?BQUXm$%5e&6qO^W-~SDHRKmMm!$C=S zyMaec5J3i-W*Lrjj5W0+m4w6_mz*G^wEgh3?p99rbgfIR?Dz)3LCH$okerbCS;1vI zn&dd|mduK3(Hh?kUeB6v`vY|`Kof@!5@{x#F8|dZ-|tVE)0S)MJ<3w)c1M;urGnp& zOvI;O(x^V!2(9?g*fzdG>%9+IB!)J&7xy1B!$11C@ZbuA-Z7-wqEsXoR7}f`YbL=z zmn^+uMwX8F7!!Pv!ihr6;gyXuA;fhJN|>yIvrag|$AfJZ&66cJt8|S+_Lmi9E5jNc z^|P;AhP;q`cw8qbZe`w+Yt#~V^O#b`M3|xtSR<%5I!JI*c0sxOUIGsLPG#3@^}DP3Lv^c>{-BnnFeSJ3`RF7jUgoFL|>5mP35X;=bYf2XhwWHVI`OO|y$irO`qT ztl=H=$;eDZu0&((4k3g9+Q3YLSMsCJhk<}iM46)#Vv8{@rI&)8#U4a6Ifil-8OPifq}6}UXbr2x&yVsaQY z5gLS?g|lxk`gU~_bJg-VP`itQDp>D}EZY{cyqI%}?jm*8KXqVkk*V})4LiJzym-v~Pk zq0MS?KO#fIrNhv?oZ)T-RieHazQqke)i__%`Yq3+gO9;uFUt}0@KHUB#ns-uplCg? z;Y`~%u^MB65lVP3(!ft5s~yq+Kq?qrZoLiZTfsm7V0|U`DXX?Pg-uOshWu%vN;BWn zV(FzuXHTF)}v4WZTLyWoar~QW`oeY4ib1% z5T`KI<2{L5(6dGZ%6^5$UznO8oL(2ILe6*uC0MG#a@?C+Ki1YF<#@NzB{6~qRYw0j zimBu@w7RcjU#JS@^y7l+uQi+Eb--!S^+ z*g5xNQu#E=HuhjuW>Cu+(~l;Z7VCW@1yugp)pmvpY}aYbPsCDhLOPtY9J9iGe-zW~ zx%j=VbygOq+Z7RnrV7Nck;D_{UB}}~BF8zlTFayFr-j?ITcpX$1U8SLERK>}#V5~% z=zO0<*nBhLjhzXZ3HiZpZsX#@6)#m?G(=4>&qt2QhQ=Ax^*#86oaR@Al7_2R zQjm7GEOtSKxDcXoQla8b9C;;i7<1Y-vLwMA60D%iM7uDxmK}EY#2k6#X_++5HoGmM z->vhi>$?#uG>2A+$Fo;{zm52OTJ5mz`SOD=X))nc9v;GpUH02l@@-s(vpI69(NZ}y zQVAiKFgU0Zy*qXfnO4UoPhQj89lA>?*=0X#)#TJ~e95Muz=G=eZNGEzqj7%z5VeDo zvL&u{n@Zb%z-JhF4^DeaCCJ2oQo4xPMa#KP6#LhR^xFcfe&#Mj$NjRG3m41}rR_XX zr4*qPs1BGH8f{KVo`0IVy^TZFvRw6Lq1^Rju6JA0irwPYhah!WDWOi7FhU6X%p+kt zos!UIr2fh^=rE#mPFPN#nwa=mtSrcI>TSPGXM4P^@1DWfM))UrfRQL7n}|m58=JG# z%q|-Bqhu!Bq7cPKaN*f5eH9wYk4W{ykim?Fg+0 zP$=abAmdO|=<}7ECbXXF_fYTxU?SY*M|pE&m=h{!lePi$isBO%Qk5%p=}v7B((gPb z4(ON-9Uk(0W!wFOj#grErMa28U60Jc_Qi{hO^_9x%3`I z7EtP;KM&SS;HUH+1(Iv@YXZ>4?u0?jXl(XKcR-9))O3|C~^93JrhP@g|h=oTv#&MwH&9qMOYpdnFmT zur*q~c!cMdO!s zjt0{Z6dj>udWQ#BACd3vN#W^3pZQT?vvj1G$>tV}A_vPT{r?%#?S04YF4*Y7M1jUr!k zuE&E@mt7gLVg)m~G?cV*xQEu)Emuk)UP@e(^SyKps@BcDhZH^TZ$|dtzuWDfE1{HqHltQW>qrU1$3?2=c|wj`UkvMiV5 zK*(rXDOmh(OwLc*0i*D65=-W`*2@iC>Kt1yY58WwKv4c;%K`U`8V6=rvsJa>XTa&N z8V5YH_2dnpqPtO5krX3iDCZTe3F2gs40IL18vuZqd9SvC3c>qu>7uxG+)Z?21}#yw zpeDn!wN|ZQ9CnfdiJVPbc6v%8d9z~TgaHKP2<@m@@E_UsK2<^x>7|?}wpY(0`Zrhg z_iG7F_|)=v$%9d)AaT`3u%iAQgPsVVL#_}_WN?)38<~cB4;{nVDfJ+kwF!^#SgZbe zGQ2O*8R86YL1;=M>`E-$I#7ICoCUiwMA*n7z(qVBIUQx%SJIcnN>Y|czzxg<-vMNy zSERo)AG`kp9falQ=f|z5q1Da>eN#en%-I|f@%#C$i@|2mL|n#Mh<&AwIDeF_kuKB_ zaT2v1lM`ldNlDnmZ^QZbIV>&POHS~K0f8aO8KXyUHn(EgrT8vbjrYPs{aw3lF(?Y5 z!ZwzHc|oH;NOH+ul(m3+;zTAsmfq$Z&a(H=}%WoRa8@d*%>Z4 z7&!&{2lys1a$NAEKR*)CtrPEOdbt}O&LivtAR<@Jd%CR&^$y}w~vcsvIp9#9XfmGA!lha4L;(aWS8}_Sn@MUEgd83 z%{gMXAFrtX*MLW%3P?&F3)+qzo-D{;;C)>I%33^AlEJdE1$#wNBaw z^ucZ@2r9*Fu;AXgtN`wpbh3@E4jNJzqQEK%k$Mu5H+oBqs>;t4zc0U@;{cs{xQrTgzUn&Qor6^NfG%X&o8k_BeD?7D?SP0%C7 z%<{OKs!^?qV}YVAPRzaix?InP+^qOwzjVV?tc)wT7w!c`OjC8vN7&n^8z}4}HFRQvQv=d#0wXl6^^uH5i2TFQo?+F&jtHii4G#Qa|0cVm6BRm$f z-3OF_rVC6oZe(Nl$_n{WeLuDvZ8VPfo#c>6*><3gb!mPN<;C~I&gI-N!TC@YBEQ;>N}L+7)4NYE=Chnvn|4Y2Rwe<9PEwq@+t z;-|I8Y~MT4qw!E<_=3IV+DQ7+JrEkhesov&|Eku6YAY|G@aA&XRj-y5LSj_^pG%OypEckVHw!g1aJQ3mN{5v&hek1rTHHU0SSq#`%!zyrM|pMCnV^s*wPP8 zLXw!!O-3g0P*!e|NGA$27U6gn3Xcu2B0-N4M^ z`qox(kS0zx@#my;4>GJrS*14~il@BhlQQpmyzPpfg#W>dllaV~97FI;$jTvo?uv4V znaK91uM5@=$#8!R#DsJh7CVk*X&%pPm9grk1Hpt{l)B?04)ZBpzYu~w z_(lb;os6lt(k4Y#sBK*yuTg|HLhyyp`I#=)z{KqvT^#_wuG+dVtg#kxMmpni=$aNf z?Rwxu!IjmA9ZQy>JRvSCm5R7>)9d-$|2S?#uW@&Bzp!o)`S3?Gy4{QS-Ni7JBx0V( z9IvEN;dO}WWo(;|qLjocGxL8SW&3tyuNR3r?~vlV8@zMe#Y>@(LGMRavT%ZiiT=kk4S?4tNHZ7(}X(zLH)=#okF^5&Xnf<=W1v%d z+K6W}>5GIG5=i9?UR%p~blk`!9Ec?0?d@&*Xj9n{;<;F2=D?U)+6k>r@}H_x`$U%* zLfo7xWkS=-;X=aD{39~GwJOLzZ8V=%&$Fz2>jcMgOYbG6`}Sto@tz9Z zmABT#f4*L=UpA2|w65vF#1PkMnqLN3UV$`Y&|4bojbQTjdWC&_-0yyO*+-0f$~?2E zE|9%GiKB$yU;WVdFB*YkTq4T9wHoGL(O)!Lc)+V{`maR(iHI?gr+3q^1zARakAh;B zi@gNd7~)pZ#U8_sU2Q#(v2=wB6-N(LXW0 zR|1FB7dY+Q!Sr4#k^56R-;n*B_>B;>&)kPoieeOn2o2CgN5tO?n$sa`qh0)+x2tf! zZvdCGiO!iWSd`~`emPM!c+S4s7>G6yzVHQr1x9LWYLAtwi#LzdTSb8JC>eEAv4jw_ z1GlXn4xg?59>7lPr8UcAh%oEL;^OmYbFh$FD^JPU0+Ul2c#G@2Zuvzn-d@b)i8NB? zZh4ER_lY#q;?n-k;fE&EZtzvJxQtXeQZp&46>G{G)wYKH^ItVR{Sgpm&%>#N?3VXG z;iSaO^6fhvEzm^tri&dx*FTB9X{f~g@BZpm-<NZU&=vq;Pz!r%m`Zj z&5?A|0{|4cC~*Emd|#GpGy|RsP(T%;3}89`kR;EY(ApMXV)852S57uP@HfAtYMQ=L z6-1+e^SE~a>>$n=i*c6{V}$zkoubqOioEm8kGA8~*(+MAADiSeDBP8SNTY44hwoZR zx8A){k5zP#DNFmA9Mt^P(6YMON@uYZs}MO<s*j@TgjY6SFzw)<-3yK74DvGfn*5@g(opX4sT9Td5=dKH&!- zUHt4SlUpDrjgX~#akPo&gNFT1>q6MnTiEzIP!$;Tx%$NlC0u+z&)tjk$y)`ZM3Pf+}>+NoN6H3u(8 z8Y9<;_qS{@tt&udlhnycROBW+ON0CU1|O#xCH6e9fBX=S8>o3OoD-6gFOWXcBNC_o z&O)kFM{y$>|hW%!hxv9|FURKaA1-Mv(r`8>sf7vWJ~RmED_v$g^y zmKT~4ur;IA2d$)~VQuED-@h($Bwv6PDli)|mwYZ+9&sH;_JHL5qNU4z&98g-{v5OX zEcboYw!Q`Wdj(F?qFcqyy7pq71>8<*L!Ic8xmIkR*f~s&)r+zLK@A4?k$je?&SSU= z*6jwb&O-q)(xw&|N7?862g?E=S}Q8*&3y};In=iYF-rePU%pbwrC7fXYp!jYW=(;a zuaV@=&dN}qRJErbceq`*5B621-gLBR)P-;(f3hIPuIS9WG3jTxBVR)N55xC13S4E8 zm-6euA+?&aN8+DjuNZLxHYtOvkT?dBlIuCgx*{ zKd(E#x$!!xZX6Q5h-4S!AGtkhiYqffXiWo*JvhQY_@>1;RxQi!%}r`~Wl<(&%pI)p&S@3-wm&EGM@2kXqHLM5coL-~TWCTEf9O7W_MerB53h6t zV%r9_eSY}#QU54JtNXj1gisn6J~A9x7Y>d`JfOa%Iw~HLyR%%ev1|!YI)X@n;aMKR?&gSFli# z9yW$sMUUi+_Wfh*&tk8_DS{q16q!N4=yzKR&6AtQIb}#fr6qajs~|mkjqbgn3g)=o z-wxN}$1qhs*+x+w=3`mn!_NOWv4u|?%{&<(}RS|%rPm5 zV2xLVz27tBUDY>y_uYTC^9j6GM1wlBPpi&r%Ut#(W*{!w8iszIFA&__j@?W}aX`z4%L3&u5h#OE>!~aD#Uu9z zvX%$HYcA+~i_VeS&-5s+yy?{-YBT-y>qej`O1vxwTu=#aQ)n+_|NEHH=~uE*l$~1o zRye9Lrfd8ka(XllWQK~gk$e6@FeZnwi<<3h(`r5VzmOn(FVrqHUV>dZ@N|y3)6%Dm zSp4-*ksqtt zobglRra1etiPRSaT5T%{+fg;li(_E=o2Qv2HMX?j;-jeIkI0l`tEKwXUmzPqSA5W5 z82_~C<1_!;!h@A3EKwo27r=bTw&|2JCRUI~@JWNsy#_2T{SDyOe`ig)EyEr~%n7jz zIAL-Vy8~{GhAZRS7>ACK$n3Z?4~7`l60)JHvZgdF4D6kskgQ|@zrHWB7qJowi!!J(I#)6CKL2F;DdDs@&;gAKYEg_D3llGS^RaQ{h71jOCPhWLw z{G7wv?(QM;)JA9isfvs>PY$0OwNELWB^%~9+D>Xjva1pPnJXs#i01->NzeW)%rNj8 z4NKgzP|WNBr+s=_zHXN_k0%+@`?SQ%lSQ)@MF87COM$|B^|0~o&+#+x@II$ByG$0G zzP=d=dZla*6K3L_D>L+gjT;QN=g!AfBJ(7efp$QS`Iqs-HwFker%E4Ija=r zpOpPPgdonUb`W?xH8?mk&1asP*7L&E9+=@yto-+bN?nKh`kTORwL84Au~HGsAwg&C`g6+tNhvxqj~3U^9>wCWLU#DAix__lOdUgk%; z^ql27;ROww>cQQo{v+rEAG7IKbNjwf@cw(BXYK+dDOGpiTIfTr;&G!Bjp_| z*KC7Y8q6I2DR{7#Gx?9Hx1>f$F`?qQq^oyciOwg&XXYa8>U){HbZ}L`XXf_bqhQ7b z%F_&Q$5le@{%Gy#_+1~sQ6(3F`RfHhzL{$uV>C@z>jUGp$5&UfPb(0xQaBWcP@$!| z`uh4Vi0=Z)6ki@0C=%lE>q(*$(BeL2bYh53bJCTTX4ElAlH?yI?EZXzB+YKWD1bY9 zDuK$ed?aU-Ero_rT;+|ryTE*#qF^xE{_E4_NuwtCkqE#Qs)qBjD4oo}Gkk$L z341C3wb9xqwC>Yy&yw)V52)-l@^buUMzG5@`)Z%djdhNLhM7V+a)YG)$8Yk1;?II{ zS2k>yJPsZ7I|s=N2U7Rp;3)G>TL1J>WPVt5*R-#5xP8yJS1KEe@?&x76JX8=EMFlu zx<7jN;_&<^!~tC{0*NVaDux`_)Nm|>q1hfZ6~-Gesw7Q@uEEwr*blG0+0#*Ze$g~p z3s!qMEO2^UJgqb4MF`iYG!>smP%48o-4@MlyX_B|nB+@ByCYNbk zN525T;Dr8xkE^S%BqprZ)XWCAN{t)dpmqbUn#LTBpSW8_DR6F~U}>11aBd{3Sg=&H zk0MSo9Wt}_?H=QKX`{dhL;LkS1|(qT&wvW~w8ysE?<}SjB;HU;&ioeyau=^C>!iu) z5O1V0f_350IPo4;fuQT~^*coW$>l7R)YycwqGJ)a>U#%eOn*a$`>Mru^g zC7`k6V*Nl(tNP;op&u45i3uhu^`d4&k19U)+v6gRNcKFt92(YVr~&nywDW*o)oqvd zRj>WU@OW^xNJ3v`pMeEr#OK=2tFw%+*me6;)0It6K02M8BCqZ;* zrO7^ZGq_3hi5f}-Q$Tyn%%O7I18@)7GVj8S+}C~gbABNiNx-lyjbl&mGHF@xEoNzK z21p$URuS-wTZlAou5xyXdQ!i95)U#21CWC;ag3;KmOZ#$M~4~hlk4qyt&go{R11gG zD|Ji+Ma$XZT zaD=qQoD55anid$ld69>$pA9u^_F$vdS$t&%GZgB%IJttoS&Tp$b|jLNUx2pTGTmd2 zU3wW006M$i1fmJX+VP;9^TpNd2Uz5g3GbgyBnsmHq7PCpPZxQwLIGhXFkiao^Cmt4 zel`Q_vgIqDFID7!iN^^I0{-rifE!Bs9DoOqb|eCbG$3{L&ZZXTuDCWd^>>nPTf|}i zWmNDQfx!_etP|h}3cp1REZ-O&5P2Sqs}Q{b2xcK}5u-*|FdI5--^VTOE5D zxoSo`QE?Fw$o~Ro@L$HnToJ!=M}66Nw2?Rh!u|y6rx8qJ;#BHSGQeMmsC3>UqEd)z z$|E6}^xS28aci=G%c|P73|S zZ!B$eVJM!WalG^RM4#6+wGlZvUgB{JAr_OI_p`O_6ThKu~*+c@O9h9t_yYD=35!jhc?KckJ2RZ-B@P%g*q-WiN|96^rqfA!IRSk zEOLdAW0uG$^h!#_MpB>KUA3V#0MD$Fd3@?hfc!#-;T@Gp?ZnPWS`sYlsTJQt{I%N`c?qG3ryLv=hCUZUc4`i^vGvY5AXATULK~|5JTGlEh=JlyS2`T%d0@mahy6;eKJ^(aMu&4c zHm6$e=C80qxXyn_|M}8IVRkqK&zsINs)?oIn^}xMEgW*{4Yvkvjj(|J?ANurCO|ID zW8{~;2)`Rdy`o*PsSk{rSg$qt{{P?MBe_qi=9V`V7~jcr8fym%}VYJ<84{sT6=xQjy1`0u}WESRq=3Oc|Uv zh8!8)hX0at04%EkJ@V#P?AEVJskLdLrg$%{S;_RtXTEWVZ2Nt5ducugN4se3&*C9pMbXdS zEx-9a`p+sc0r>l$`*g&y@8cU6Cdp-xlaM}LeEDGc)J=fiqkv`-p7Ki$0iE|3Sv%LS zzlt+aMUbw)zo5{`99QI>?w6-i^{;)$q*mx%ciS#*y-~ph+CI|rWRnb4>#PlaRqc*) z^$n)z39`(?>J<8LRpoFkMIg}W6FwElxySV_+hc5HVl#b+1S#Clp{;~7bmNlU;uP=x zgcL8(WCGA}h*zDpGZFs=(4Us3{(nyAjScyZ$(VW7sy%m7@&Itp(CO(6{Co``nDS>- z4$4|RKtftxjxC*CUDy47+`Wy5*`U}?&IIjWAgh&GN=j{z(7i`U!7{p!0s}%<4}_S& zvks6$|5LGN<=2IL&11~!FGN)|C|f1|c+4#*t97eBhVQ=4tdx(3puf#zB03$lu#D*T z^|ynwvv&J^w8iN(#n1DHH+`)@u%9sy9aucSlofbI4JB_06L2=!_?JUtC7HP2>=uxP;v|J~l2olV&yKV$I*5^wu7wX6`+s zMm*bhBP#oH*19N=cc;%?x-@dU?Jflgg9qY^Bk)^qm|aP#5Mr0D8qV2SGkR-!ETh z6o{&Xb@_G?gIpm*l-l8nGP;kZ!(vn8@AEq$Vfp^WOmw#+owQd;AIujn+3!SOecZkF z)fWT0D1RC!)sF%bH#Nn92$Z8F8SD=x)6^{>Au#82O3Ga5536rc7rE~61*1#9>VNcd z;%5+pt5`6O>XF3L0a~P76pGxG*WMTr%ip)U+8l4cPTb!gb-(?W8Ou%7d4KpN1z@nh z+eq4^dMSro0=Zvlj$!SDKmLGCK8&7f1GuEk-0m76tI@n=BqTWMiiWXHw}Is)BbrK; z9M2jyFFA%GHP(hqfdGD2Skxwa)VuqSa39<*?o)Mu$Yo9~D4h8A5 z#$1f$lTS@6P^;IU@Sivt=jv8nc$*|(z8c<-Ejr)_?0o|Qsy6izlg*@FRB+9ewu)Ka zvnSkte~PEp+rS{xgTxC(k-I%MW`XId2hR`k2!z1aV~d>$%{D}>a)nGbM7Lek{avOe z2)an6y1$QCo#+GToP16h5&R{FKWPzq1q>!hsu7yWg}TES6?;Ja;VlI3TK z0F2J-{!G8mX~ezPUE|Q&Z>$q7<%3U44Zb|V76F+ncv-%oxWy+@JUEiPpG}03DL?YF z>DQTEzC3mkKEoz@3YK0W*koN5`ntLn+rNiwXzA$CIgNeJ_J~#|sHQ0v!=F@_d7@e7 zVX-Od!~H>3kfkV2Xp;1HAxMXX(16jIx`bFh6qv231qx!(Kn%R zz+XD}5BpY@pUNDESgIO<=n)?HCO|gl6Voj zHh)U*S!srrtO}2W;gB3tjqVq#u}A&$yX52@!Y6jU@4CceBUpZvsWnrp#J?re^;SxI zRYa#3AqfxVq>zwNRK`_&wDU59;8Yw-8gxSzmx3$Pj-ZFhP2`+N?QTcg$arS#s1CpJ z6bZ50dAfI8{#8tEX*U^arC4A4JN2gam@dNdV%}EQ6%lMlO@9R~>#hy2V zsUhJn*yfl-A0CbyTV$t}eH)IQ+YaRIV@qSL-*1aCs^yS2FuMK)1uSPJ)(s4o7g&oO zNH5U!N^R=_Xn^3ppk5>Zye$D;ZcbSL4t+w|@JHJG3<<3I75Vk0XrDD@>B-3GW+R0tpKwDwl zzyA`-v(E5K^32;IP{v7;z>ohIr43K%aVfGpkN4#~!T)1d>x!d&4+0VXrz9(-OV%!I zlnv0iD~8Rw13R03T+|{FK)edZnaO=vZ6|?`*gT@>Nih=24;re-nX#baxLqJCIP{T-;y}^$ zeWFxJV<;-W&)zr}67RSDi@mW&`YP7)gJU()4t@!p#EE(`1AbO%M8Dn}5<@}{V3-bi zU`@95kb8JH7`J&;TBX(#f98>QTB`3Q7dlZ*JS*5tpj2x%i5GM4qbk5((x0@q$#iW; zly8^sM@xeD&RyQSGY+EG4-dBF&s9`beg$qCAJNVoufI3-esndvl zmHdv4aFgqG$dfjwp8vaW{|#evfot0r{NHlHaA`x$3lVqFTf;IVw}Pi2U2j+o;10#sM_O>#vy_b>i-&p?Hl9sx6U zjjAf>GEQ<+(|jZXOGgwJ@?G*vf9s(E&CtvFnVh1&{mPzS3n%x{Wl8h#GfTXyMqx_OJ|3Po(Cojsjw)R9Q^zXsGDjIV^Yo(kNC z4)Df?7`K*$D#eM!{L>;R)}bhs({2h6-Ma3%d1vKZ+|0`eu3$*~YLpZNOVQ=KdV&|z zy)*Y_APW_)vDAEENqKFXLviz7M)$?qpTCqC_W(aSotpmJ(e1iF7dUZh|BNp+oG{dt zeoaZ4P<-%Tz~?q4p)QtCCRj>44d>f&Gj!3I&t@XY5smv$cAJHn2ka0C_C2h$tQi`L zfL$^bB>MuQ$o~l|5!CJ@ECBvbb_Q!M(X{Ssul+^(UAhr|6DMBbCKvfA7w{XN6d^c) zL8AQxX56&{2pd&k(FB2)O)AbT0JHE=ATB0WA5_`r4tJY(5n+~+z9Qvhb}j_vx4%6- z0*Xqn#QF2*C%uqwzWGM$hd=z^Fw6qGCdUn;RU;5a^qQb)eSN+BKT%;KR)X7d>Zzw# z2OV^vJTF*mI5*dT1r@IeO~4G-%P;r-?6c1di}C_HzoENOnIl##4OZk?5~*myfBmJ1upvHi!TJ4)Ce;XUhj^@ zi@)r$OJ#9sY_~Jml{v1LS?Id!u8o^hz;EYa=ch2qyK}M|1?^;1vjKKN=#DtzaPd(= zO#*3!{3IU1#oGA4|NEba+`KtIE)hjn@d@KR5g@NHqD%;=4p+?K#1l`5c!#FSlfTCr zq@Kwhxh+rD9)&&n{rBj#nFIL@vl0L{d>d#{%u>uyYO9TD&VP_svRwr#<6d_@%p%w8>PBI))ZtMiC``Wq}JBf2rPHu!Ua+5H9!}7fjzue z(4Mg>{ZR5`oy_{;S+I8AefJ%6&m79 zg!12@XgfPTd0tX^(cq-F-FB-)rv0M&oQIvBU6lY80Vk>ky#X%1%PyLVA4>of#v1Q+ z7_yQebRoeitQEg&$7PBKsKa89RV;%W!tNexkelPSA(cl$SNwy?BX1Q2j-2+q=^sKr2=( zPsxlWu;}J0be|iVYfUN{F~GeW@>Q?UA^@=l85XYs@x#h<9r1vha7j!DT(6QOqeF}! z7R36vHXn#M8z?g=9rfniYvY-Khsh{c0IUzF% z8axlbd^?s)JVd8-s&U_|&E2?FM25patz!Y4uvDPj3UVoE92-50&>_Ld$nXD50s1 zPI>j!lf?H;HUq$T{P8~qGTp+Y92CIwrX!7@QSKazXoUh7qe#72h6M}ei{J0H0=VDL zKKnGLJA)4%6jva{8|2bVo;*3i`Y=9yDzx6L7b^LP-?&YF+&b5KAz*ZMF4&jdaRC}D z%r`Cp<-G={Z!|hSC;*m3Af-Wrjz*Z4e#kZ>6zst4S}2WV2WdO+PHqGe`YS*8hLq>Q z2Os1cI6UTGDHIz=Yofbt%DYl>W#JM;p83A`Zfu9Lz z9(dpZzW0OW;Z4WJGq4Cb7YfmI>f!jT8QdSR6M8JLJWV@t!k@iL;8&L2U#*+PM!x&l zV~+`g5MvF1NF&9Qs(%iE#V^q278-;!XjhA8fK>>pF5Gq3U4-p;2%GRW5aUH z4je5giW2$V?=FtOGi<;87$rCh92di{sE7Z9#fVm4!MRZ|esK+VP}O}*zW^(W_s%)T2T6 z8S1TQ<~L}{WQbc$8+R00JV-vHu()2_AMg7=?zm$F%b^ts!I~**{yMkoe>W7tf2;X> zHf-K5Wx{}95YC|;zy|eT62b@*&yIpZdF-)A9cn4FlaOy_mqF;4En6DMWtivy-RK6T zBs&q#Xel#sc$IlBm4w1NtL=tXVGrg={1uR{O_1Gu(z5Y6H{XG(tU_Dmthk&i(-cz zwzq!&`)kBcjkR;LxE3v1B%g;^f<;PzakvJ)=|Kk_5QfY5>vI=PNgxEVfG~iB{DcoT z1HmJ>N;ZIiA1Ot@9UP&4^2sOTf;m%^V*o;KSht%G5XHs4qr9WB^19s&09e;wf2~}j z+uY}!LoWwDMEm-^dTs2R+x5TOir~LAbaS=I{nGh`D7{%6=3k0jz=}id6bnRzB0!-$ z^w5J=RaK=moP%;)G7qF60S6gB8UZ2bxBve8S(je=J74H9_qNkcJ4U5CN9m!^{FI1k zsKVcfB}C)#`D^*v+C>*SXL{ONd5MgsfPsw&mh#{ z?2>Mik$+JH?7X-JsepP$VxRXq5Ptze){z333L39)Bt`=Ou`QXaM48|RA zr!m>>Nc*fn<{j`Bd_En66ea1rbIzF{jYPcfg=-+ah&$v$6Bep@lYYlJ!OxATiU8Et z-D*k`IZ}dDh+T8d)eaY&d#ADa01uM@Ad5U1NNT#rn{U1uPzLz8o z-w<&IZc7k>s1e{_{9^O49h}{t`-xTMXWS;3g9$QXIVGAk;TZwSK}iv3A*H$b=0A@x z^LgeFgP>eCY$!6pJx)gdE_|GAbAq26=~M!So*X-Pwk{G88fydtpA+1G*D5eB0{L*1 z0jWB6*`A)^YYf89Ng$7=DD)=)nMewZdI2Kxq}GB4RO7qtwyQ83!39XgA4oZXLHORo zF?bfF{qXA%dMf@vWqOsW&9AVlJnPRs`^;UbhrK^XmxFKN_wI5dH`1vL{#VV@fWpI3 zVd4bf1lW;iFzF`ZbSnd*>!cHb98;~wZd_MaJ1o`#iU8OyWzi@dqT!HoMvGD4ws0Th z-iZgKQo$JQx+oOldZ?tNp$5;y`1Nj~=VzWJ&y;5iHoyhbuG8<}w`%@hPUv%Eq!q!x z>4Fj1HJ9m~$ZBb67E~ZRCxs`5qRgudOrJn@Xc&3{^URyCtaSVsb(wL9z6Jn)|5vuQ|cbjZC`+%%AC<=uIk4wLdCm zD!6;_>u}KHgBv%&jZ)+PMD6+eA%`4nU3lU7f}s2K(A?Cq-Y=Dx6aL)D7KH$^YzH+jQ)W-o*sv@kcmu2(1wvd(n=p)?oF0nu*ANnyvKJvP;L92c{GB$NZ^;9Q)O zb8`(`3)jT8agAIn*UYuM@5L?fOmGUsBzP9MLs$r|(q3++T0cX4`yIWgy_~@3Mz&i9 zaL4Vc=9Oxadn?nm<|0IpiG2R~XR_m+e)?(R2b*?hUZHUdjv>JW>4y?w*F=cGDd2XX zVCYW(_W?ZMJMOrH z(>TSe$h^u7AD=)eeE!@s)(z)%#Uuu_^)y8b{qB~Be=jHaxiMOm!N2Ns;#n|!!HPxQ zi&^<}Cn6F~k3tAQFTVIfwUZtyJ1JIzTLHL%NJGE>p;Mi=*=BZ|Gz5`3~RZ7jX`n&GB-wWdn zEw-tj2OUQ(J-B$X5by+Gsw1%M&iLo<$?y0ZpW(B7hwpL>j>R!KHs|16oReM!-+c3p zTnpF4wRw<_o%$YT>wCIF-{WR}{(Mf@b0cRR*z+GWB^55iF_z6m54Fzc8tGQ$Rt#=Z zlD4*1*>x!g#-$*G0M>wxJzsqBg)}pTL6`z2KuJt~=6C#!&+u8k!*@9b$KseAI{+8Z zsjrEhoi0t!>1#el-@||Fd-_3cm(PvdNM13(PWxjWSUgJ2^E5>HIZb>zQ~T4!8lcps zg|kQJ&--Q(tqpMpY74#ZPUlvppQLMpX)h&?(_7u?4nKi|Hzs1xse+qqY&Kl zpERY_PjofoP8y_in3^Z6IZn;F*q-kHN9F)W`l$eXh8! tD>rf@H!`ObMs(&zZsbO8 -- 2.39.5