From 32ff8bca38650bbf4287474a5f1697a5c561a9e5 Mon Sep 17 00:00:00 2001 From: eleino Date: Wed, 4 Mar 2026 10:16:34 +0200 Subject: [PATCH 1/9] Added types for photo object v2 --- .../src/entities/Gallery/types/gallery.d.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts index a759bcfb4..cf7a3f9f3 100644 --- a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts +++ b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts @@ -64,3 +64,33 @@ export interface PhotoObject { full: PhotoVersion; }; } + +export interface PhotoObjectV2Translations { + id: string; + languages_code: string; + photo_object_id: string; + title?: string; + author?: string; + description?: string; + link?: string; + link2?: string; + image?: string; + image2?: string; + image3?: string; + animation?: string; +} + +export interface PhotoObjectV2 { + title: string; + author: string; + description?: string; + id: string; + category?: Category; + translations: PhotoObjectV2Translations[]; + link?: string; + link2?: string; + image: string; + image2?: string; + image3?: string; + animation?: string; +} From b6aee3079c4a56b5a9968a6a8b94baa8079b0c78 Mon Sep 17 00:00:00 2001 From: eleino Date: Wed, 4 Mar 2026 12:33:19 +0200 Subject: [PATCH 2/9] Added galleryApiV2 --- .../src/entities/Gallery/api/galleryApiV2.ts | 30 +++++++++++++++++++ .../src/entities/Gallery/types/gallery.d.ts | 19 +++++++----- 2 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts diff --git a/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts b/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts new file mode 100644 index 000000000..d8edc5cd7 --- /dev/null +++ b/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts @@ -0,0 +1,30 @@ +import { directusApi } from '@/shared/api'; +import { envHelper } from '@/shared/const/envHelper'; +import { createDirectus, rest, readItems } from '@directus/sdk'; + +const directusBaseUrl = envHelper.directusHost; +const client = createDirectus(directusBaseUrl).with(rest()); + +/** + * API service for fetching gallery data from a Directus backend. + */ +const galleryApiV2 = directusApi.injectEndpoints({ + endpoints: (builder) => ({ + getPhotoObjectsV2: builder.query({ + queryFn: async (_arg: void) => { + const photoObjects = await client.request( + readItems('photo_object', { + fields: ['*', 'category.*', 'translations.*', 'category.translations.*'], + deep: { + category: { translations: true }, + translations: true, + }, + }), + ); + return { data: photoObjects }; + }, + }), + }), +}); + +export const { useGetPhotoObjectsV2Query } = galleryApiV2; diff --git a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts index cf7a3f9f3..af59996d8 100644 --- a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts +++ b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts @@ -70,14 +70,13 @@ export interface PhotoObjectV2Translations { languages_code: string; photo_object_id: string; title?: string; - author?: string; description?: string; - link?: string; - link2?: string; - image?: string; - image2?: string; - image3?: string; - animation?: string; + link_text?: string; + link_2_text?: string; + alt_text_img?: string; + alt_text_img_2?: string; + alt_text_img_3?: string; + alt_text_animation?: string; } export interface PhotoObjectV2 { @@ -88,9 +87,15 @@ export interface PhotoObjectV2 { category?: Category; translations: PhotoObjectV2Translations[]; link?: string; + link_text?: string; link2?: string; + link_2_text?: string; image: string; + alt_text_img?: string; image2?: string; + alt_text_img_2?: string; image3?: string; + alt_text_img_3?: string; animation?: string; + alt_text_animation?: string; } From ea3571a703adf5b3048021e0b887f0a34c7bb2d1 Mon Sep 17 00:00:00 2001 From: eleino Date: Thu, 9 Jul 2026 20:20:07 +0300 Subject: [PATCH 3/9] added types and updated hooks for PhotoObjectV2 --- .../src/entities/Gallery/api/galleryApiV2.ts | 34 ++++-- .../Gallery/api/galleryCategoriesApi.ts | 3 +- .../src/entities/Gallery/api/mappers.ts | 112 ++++++++++++++++++ .../src/entities/Gallery/api/translations.ts | 2 +- .../api/useGetDirectusGalleryImagesV2.ts | 34 ++++++ .../src/entities/Gallery/types/gallery.d.ts | 62 ++++++---- .../ui/PictureGalleryPage.tsx | 8 +- .../ui/SectionGalleryV2/SectionGallery.tsx | 1 + 8 files changed, 217 insertions(+), 39 deletions(-) create mode 100644 frontend-next-migration/src/entities/Gallery/api/mappers.ts create mode 100644 frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImagesV2.ts diff --git a/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts b/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts index d8edc5cd7..4c03fb09a 100644 --- a/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts +++ b/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts @@ -1,6 +1,8 @@ import { directusApi } from '@/shared/api'; import { envHelper } from '@/shared/const/envHelper'; import { createDirectus, rest, readItems } from '@directus/sdk'; +import { DirectusPhotoObjectV2 } from '../types/gallery'; +import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; const directusBaseUrl = envHelper.directusHost; const client = createDirectus(directusBaseUrl).with(rest()); @@ -11,17 +13,29 @@ const client = createDirectus(directusBaseUrl).with(rest()); const galleryApiV2 = directusApi.injectEndpoints({ endpoints: (builder) => ({ getPhotoObjectsV2: builder.query({ - queryFn: async (_arg: void) => { - const photoObjects = await client.request( - readItems('photo_object', { - fields: ['*', 'category.*', 'translations.*', 'category.translations.*'], - deep: { - category: { translations: true }, - translations: true, + queryFn: async ( + _arg: void, + ): Promise<{ data: DirectusPhotoObjectV2[] } | { error: FetchBaseQueryError }> => { + try { + const photoObjects = await client.request( + readItems('photo_object_v2', { + fields: [ + '*', + 'category.*', + 'translations.*', + 'category.translations.*', + ], + }), + ); + return { data: photoObjects as DirectusPhotoObjectV2[] }; + } catch (error: any) { + return { + error: { + status: error.status || 500, + data: { message: error.message || 'Data fetch failed' } as any, }, - }), - ); - return { data: photoObjects }; + }; + } }, }), }), diff --git a/frontend-next-migration/src/entities/Gallery/api/galleryCategoriesApi.ts b/frontend-next-migration/src/entities/Gallery/api/galleryCategoriesApi.ts index b454505de..b1331e4f5 100644 --- a/frontend-next-migration/src/entities/Gallery/api/galleryCategoriesApi.ts +++ b/frontend-next-migration/src/entities/Gallery/api/galleryCategoriesApi.ts @@ -1,6 +1,7 @@ import { directusApi } from '@/shared/api'; import { envHelper } from '@/shared/const/envHelper'; import { createDirectus, rest, readItems } from '@directus/sdk'; +import { Category } from '../types/gallery'; const directusBaseUrl = envHelper.directusHost; const client = createDirectus(directusBaseUrl).with(rest()); @@ -30,7 +31,7 @@ const galleryCategoryApi = directusApi.injectEndpoints({ deep: { translations: true }, }), ); - return { data: categories }; + return { data: categories as Category[] }; }, }), }), diff --git a/frontend-next-migration/src/entities/Gallery/api/mappers.ts b/frontend-next-migration/src/entities/Gallery/api/mappers.ts new file mode 100644 index 000000000..0547f77b7 --- /dev/null +++ b/frontend-next-migration/src/entities/Gallery/api/mappers.ts @@ -0,0 +1,112 @@ +import { envHelper } from '@/shared/const/envHelper'; +import { DirectusPhotoObjectV2, PhotoObjectV2 } from '../types/gallery'; +import { getTranslation } from './translations'; + +// for mapping DirectusPhotoObjectV2 to PhotoObjectV2 +export const mapDirectusToPhotoObjectV2 = ( + directusPhotoObject: DirectusPhotoObjectV2[], + lng: string, +): PhotoObjectV2[] => { + return directusPhotoObject.map((item) => { + const { + id, + category, + translations, + author, + website, + date_created, + github, + linkedin, + instagram, + facebook, + image_1, + image_2, + image_3, + animation, + } = item; + + const mappedCategory = { + id: category?.id || '', + name: getTranslation(category?.translations || [], lng, 'name', ''), + }; + + const mappedTranslations = translations + ? translations.map((t) => ({ + id: t.id, + languages_code: t.languages_code, + photo_object_id: t.photo_object_id, + title: t.title || undefined, + description: t.description || undefined, + })) + : []; + const title = getTranslation(mappedTranslations, lng, 'title', ''); + const description = getTranslation(mappedTranslations, lng, 'description', ''); + + const mappedLinks = { + website: website || undefined, + github: github || undefined, + linkedin: linkedin || undefined, + instagram: instagram || undefined, + facebook: facebook || undefined, + }; + + const mappedFrames = mapFrames(image_1, image_2, image_3, animation); + + return { + id, + category: mappedCategory, + title, + description, + author: author || undefined, + links: mappedLinks, + frames: mappedFrames, + date_created, + }; + }); +}; + +const mapFrames = ( + image_1: string | null, + image_2: string | null, + image_3: string | null, + animation: string | null, +): string[][] => { + const frames: string[][] = []; + const directusBaseUrl = envHelper.directusHost; + + // for managing file sizes/quality to lower bandwidth usage/load times + const imageWidth = 800; + const imageQuality = 80; + + // insert image url, image id, and type (image/animation) into frames + if (image_1) { + frames.push([ + `${directusBaseUrl}/assets/${image_1}?format=auto&width=${imageWidth}&quality=${imageQuality}`, + image_1, + 'image', + ]); + } + if (image_2) { + frames.push([ + `${directusBaseUrl}/assets/${image_2}?format=auto&width=${imageWidth}&quality=${imageQuality}`, + image_2, + 'image', + ]); + } + if (image_3) { + frames.push([ + `${directusBaseUrl}/assets/${image_3}?format=auto&width=${imageWidth}&quality=${imageQuality}`, + image_3, + 'image', + ]); + } + if (animation) { + frames.push([ + `${directusBaseUrl}/assets/${animation}?format=auto&width=${imageWidth}&quality=${imageQuality}`, + animation, + 'animation', + ]); + } + + return frames; +}; diff --git a/frontend-next-migration/src/entities/Gallery/api/translations.ts b/frontend-next-migration/src/entities/Gallery/api/translations.ts index b607ea678..eb025b0dd 100644 --- a/frontend-next-migration/src/entities/Gallery/api/translations.ts +++ b/frontend-next-migration/src/entities/Gallery/api/translations.ts @@ -8,7 +8,7 @@ export const getLanguageCode = (language: string): string => { return language === 'en' ? 'en-US' : language === 'fi' ? 'fi-FI' : 'default'; }; -const getTranslation = ( +export const getTranslation = ( translations: T[], languageCode: string, key: keyof T, diff --git a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImagesV2.ts b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImagesV2.ts new file mode 100644 index 000000000..51e8eda54 --- /dev/null +++ b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImagesV2.ts @@ -0,0 +1,34 @@ +import { useGetPhotoObjectsV2Query } from './galleryApiV2'; +import { useGetGalleryCategoriesQuery } from './galleryCategoriesApi'; +import { mapDirectusToPhotoObjectV2 } from './mappers'; +import { PhotoObjectV2, PhotoCategory } from '../types/gallery'; +import { useMemo } from 'react'; +import { getTranslation } from './translations'; + +export const useGetDirectusGalleryImagesV2 = (lng: string) => { + const { data: poData, error: poError, isLoading: poIsLoading } = useGetPhotoObjectsV2Query(); + const { data: cData, error: cError, isLoading: cIsLoading } = useGetGalleryCategoriesQuery(); + + const isLoading = poIsLoading || cIsLoading; + const error = poError || cError; + + const categories: PhotoCategory[] = useMemo(() => { + if (!cData) return []; + return cData.map((item) => ({ + id: item.id, + name: getTranslation(item.translations || [], lng, 'name', ''), + })); + }, [cData, lng]); + + const photoObjects: PhotoObjectV2[] = useMemo(() => { + if (!poData) return []; + return mapDirectusToPhotoObjectV2(poData, lng); + }, [poData, lng]); + + return { + photoObjects, + categories, + error, + isLoading, + }; +}; diff --git a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts index af59996d8..37b507343 100644 --- a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts +++ b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts @@ -69,33 +69,45 @@ export interface PhotoObjectV2Translations { id: string; languages_code: string; photo_object_id: string; - title?: string; - description?: string; - link_text?: string; - link_2_text?: string; - alt_text_img?: string; - alt_text_img_2?: string; - alt_text_img_3?: string; - alt_text_animation?: string; + title?: string | null; + description?: string | null; +} + +export interface DirectusPhotoObjectV2 { + id: string; + category: Category | null; + translations: PhotoObjectV2Translations[] | null; + author: string | null; + website: string | null; + github: string | null; + linkedin: string | null; + instagram: string | null; + facebook: string | null; + image_1: string | null; + image_2: string | null; + image_3: string | null; + animation: string | null; + date_created: string; +} + +export interface PhotoCategory { + id: string; + name?: string; } export interface PhotoObjectV2 { - title: string; - author: string; - description?: string; + author?: string; id: string; - category?: Category; - translations: PhotoObjectV2Translations[]; - link?: string; - link_text?: string; - link2?: string; - link_2_text?: string; - image: string; - alt_text_img?: string; - image2?: string; - alt_text_img_2?: string; - image3?: string; - alt_text_img_3?: string; - animation?: string; - alt_text_animation?: string; + date_created: string; + category: PhotoCategory; + title?: string; + description?: string; + links: { + website?: string; + github?: string; + linkedin?: string; + instagram?: string; + facebook?: string; + }; + frames?: string[][]; } diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx index 113960eea..325e44eef 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx @@ -63,11 +63,13 @@ const PictureGalleryPage = () => { const categorySlug = params.category as string | undefined; const languageCode = getLanguageCode(lng); + // TODO: switch to V2 hook const { photoObjects, isLoading, error } = useGetDirectusGalleryImages(languageCode); const isBigDevice = isDesktopSize || isWidescreenSize; const allCategory = lng === 'en' ? 'all' : 'kaikki'; + // figma shows the text should be present even on mobile, so this boolean will become unnecessary const showCreativity = useMemo( () => !isMobileSize && searchQuery.length === 0, [isMobileSize, searchQuery], @@ -90,6 +92,8 @@ const PictureGalleryPage = () => { }); }, [photoObjects, categorySlug, allCategory, languageCode]); + // keep this search filtering, see if it there are any new fields to add to the search + // need to update PhotoObject to v2 const filteredImages: PhotoObject[] = useMemo(() => { const query = searchQuery.trim().toLowerCase(); if (!query) return categoryFilteredImages; @@ -150,7 +154,7 @@ const PictureGalleryPage = () => { )} ({ - // Adjust these mappings as needed based on your PhotoObject and FrameSet definitions + // Adjust these mappings to match photo object v2 structure title: photo.title || '', author: photo.author || '', description: photo.description || '', @@ -160,7 +164,7 @@ const PictureGalleryPage = () => { : photo.versions?.preview ? [[photo.versions.preview.image]] : [], - // Add other FrameSet properties if required + // Add animation, and social media links }))} /> diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx index 7ef5d5ac1..dedbf1c42 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx @@ -16,6 +16,7 @@ interface AnimationGalleryProps { animations: FrameSet[]; } +// TODO: update to use V2 photo object export const AnimationGallerySection = ({ animations }: AnimationGalleryProps) => { const { inView } = useInView({ rootMargin: '-150px 0px', From 131e77b55a0c9a300e15a70c17a110c0b0719f60 Mon Sep 17 00:00:00 2001 From: eleino Date: Fri, 10 Jul 2026 19:14:33 +0300 Subject: [PATCH 4/9] confirmed that fetching photo-object-v2 from Directus works, removed old photo object types and hooks --- .../Gallery/api/filterAndTransformImages.ts | 92 ++++++------- .../src/entities/Gallery/api/galleryApi.ts | 84 ++++-------- .../src/entities/Gallery/api/galleryApiV2.ts | 44 ------- .../src/entities/Gallery/api/mappers.ts | 26 +++- .../src/entities/Gallery/api/translations.ts | 37 ------ .../api/useGetDirectusGalleryImages.ts | 121 +++--------------- .../api/useGetDirectusGalleryImagesV2.ts | 34 ----- .../src/entities/Gallery/index.ts | 17 +-- .../src/entities/Gallery/types/gallery.d.ts | 41 +----- .../Gallery/ui/ImageWall/ImageWall.tsx | 92 ++++++------- .../ui/GalleryNavMenuAsDropdown.tsx | 17 +-- .../ui/GalleryNavMenuAsSidebar.tsx | 39 +++--- .../ui/PictureGalleryPage.tsx | 26 +--- .../ui/SectionGalleryV2/SectionGallery.tsx | 41 +++--- 14 files changed, 214 insertions(+), 497 deletions(-) delete mode 100644 frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts delete mode 100644 frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImagesV2.ts diff --git a/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.ts b/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.ts index 3c82e60e5..ab6587b7b 100644 --- a/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.ts +++ b/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.ts @@ -1,51 +1,51 @@ -import { PhotoObject, PhotoVersion } from '../types/gallery'; +// import { PhotoObject, PhotoVersion } from '../types/gallery'; -/** - * Filters and transforms photo objects into an array of photo versions based on the specified version type. - * - * This function processes a list of photo objects and extracts either the "full" or "preview" versions, - * transforming them into a standardized array of photo version objects. If an error occurs, it logs the error - * and returns an empty array. - * - * @param {PhotoObject[]} photoObjects - Array of photo objects to filter and transform. - * Each photo object contains metadata and version details. - * @param {string} version - The version type to extract, either `"full"` or `"preview"`. - * - * @returns {PhotoVersion[]} An array of photo versions filtered and transformed based on the specified type. - * If an error occurs, the function logs it to the console and returns an empty array. - */ +// /** +// * Filters and transforms photo objects into an array of photo versions based on the specified version type. +// * +// * This function processes a list of photo objects and extracts either the "full" or "preview" versions, +// * transforming them into a standardized array of photo version objects. If an error occurs, it logs the error +// * and returns an empty array. +// * +// * @param {PhotoObject[]} photoObjects - Array of photo objects to filter and transform. +// * Each photo object contains metadata and version details. +// * @param {string} version - The version type to extract, either `"full"` or `"preview"`. +// * +// * @returns {PhotoVersion[]} An array of photo versions filtered and transformed based on the specified type. +// * If an error occurs, the function logs it to the console and returns an empty array. +// */ -export const filterAndTransformImages = ( - photoObjects: PhotoObject[], - version: string, -): PhotoVersion[] => { - try { - // Only allow the two supported versions - if (version !== 'full' && version !== 'preview') { - return []; - } +// export const filterAndTransformImages = ( +// photoObjects: PhotoObject[], +// version: string, +// ): PhotoVersion[] => { +// try { +// // Only allow the two supported versions +// if (version !== 'full' && version !== 'preview') { +// return []; +// } - // Filter out entries with missing versions or missing selected version - const valid = photoObjects.filter((po) => { - const v = po.versions; - return !!(v && v[version]); - }); +// // Filter out entries with missing versions or missing selected version +// const valid = photoObjects.filter((po) => { +// const v = po.versions; +// return !!(v && v[version]); +// }); - const images: PhotoVersion[] = valid.map((po) => { - const v = po.versions![version]!; // safe due to filtering above - return { - id: v.id, - image: v.image, - width: v.width, - height: v.height, - altText: v.altText || '', - }; - }); +// const images: PhotoVersion[] = valid.map((po) => { +// const v = po.versions![version]!; // safe due to filtering above +// return { +// id: v.id, +// image: v.image, +// width: v.width, +// height: v.height, +// altText: v.altText || '', +// }; +// }); - return images; - } catch (error) { - console.error('Error transforming and filtering images: ', error); - const images: PhotoVersion[] = []; - return images; - } -}; +// return images; +// } catch (error) { +// console.error('Error transforming and filtering images: ', error); +// const images: PhotoVersion[] = []; +// return images; +// } +// }; diff --git a/frontend-next-migration/src/entities/Gallery/api/galleryApi.ts b/frontend-next-migration/src/entities/Gallery/api/galleryApi.ts index 848eddb40..5d31bd39d 100644 --- a/frontend-next-migration/src/entities/Gallery/api/galleryApi.ts +++ b/frontend-next-migration/src/entities/Gallery/api/galleryApi.ts @@ -1,76 +1,44 @@ import { directusApi } from '@/shared/api'; import { envHelper } from '@/shared/const/envHelper'; import { createDirectus, rest, readItems } from '@directus/sdk'; +import { DirectusPhotoObjectV2 } from '../types/gallery'; +import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; const directusBaseUrl = envHelper.directusHost; const client = createDirectus(directusBaseUrl).with(rest()); /** * API service for fetching gallery data from a Directus backend. - * - * This service utilizes Directus SDK and Redux Toolkit Query to define endpoints for fetching - * `photo_object` and `photo_version` data, including their associated translations and relationships. - * - * @module galleryApi - * - * Has two endpoints for data fetching. - * - * @endpoint getPhotoObjects - * Endpoint to fetch photo objects from the Directus `photo_object` collection. - * Retrieves detailed information about photo objects, including: - * - Associated categories with translations. - * - Preview and full versions of the photos with translations. - * - * @returns {object} Response containing an array of photo objects. - * - * @endpoint getPhotoVersions - * Endpoint to fetch photo versions from the Directus `photo_version` collection. - * Retrieves detailed information about photo versions, including: - * - Image metadata such as dimensions (width, height). - * - Associated translations for each photo version. - * - * @returns {object} Response containing an array of photo versions. */ - const galleryApi = directusApi.injectEndpoints({ endpoints: (builder) => ({ - getPhotoObjects: builder.query({ - queryFn: async (_arg: void) => { - const photoObjects = await client.request( - readItems('photo_object', { - fields: [ - '*', - 'category.*', - 'preview.*', - 'full.*', - 'category.translations.*', - 'full.translations.*', - 'preview.translations.*', - 'translations.*', - ], - deep: { - category: { translations: true }, - preview: { translations: true }, - full: { translations: true }, - translations: true, + getPhotoObjectsV2: builder.query({ + queryFn: async ( + _arg: void, + ): Promise<{ data: DirectusPhotoObjectV2[] } | { error: FetchBaseQueryError }> => { + try { + const photoObjects = await client.request( + readItems('photo_object_v2', { + fields: [ + '*', + 'category.*', + 'translations.*', + 'category.translations.*', + ], + }), + ); + return { data: photoObjects as DirectusPhotoObjectV2[] }; + } catch (error: any) { + return { + error: { + status: error.status || 500, + data: { message: error.message || 'Data fetch failed' } as any, }, - }), - ); - return { data: photoObjects }; - }, - }), - getPhotoVersions: builder.query({ - queryFn: async (_arg: void) => { - const photoVersions = await client.request( - readItems('photo_version', { - fields: ['id', 'image', 'width', 'height', 'translations.*'], - deep: { translations: true }, - }), - ); - return { data: photoVersions }; + }; + } }, }), }), }); -export const { useGetPhotoObjectsQuery, useGetPhotoVersionsQuery } = galleryApi; +export const { useGetPhotoObjectsV2Query } = galleryApi; diff --git a/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts b/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts deleted file mode 100644 index 4c03fb09a..000000000 --- a/frontend-next-migration/src/entities/Gallery/api/galleryApiV2.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { directusApi } from '@/shared/api'; -import { envHelper } from '@/shared/const/envHelper'; -import { createDirectus, rest, readItems } from '@directus/sdk'; -import { DirectusPhotoObjectV2 } from '../types/gallery'; -import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; - -const directusBaseUrl = envHelper.directusHost; -const client = createDirectus(directusBaseUrl).with(rest()); - -/** - * API service for fetching gallery data from a Directus backend. - */ -const galleryApiV2 = directusApi.injectEndpoints({ - endpoints: (builder) => ({ - getPhotoObjectsV2: builder.query({ - queryFn: async ( - _arg: void, - ): Promise<{ data: DirectusPhotoObjectV2[] } | { error: FetchBaseQueryError }> => { - try { - const photoObjects = await client.request( - readItems('photo_object_v2', { - fields: [ - '*', - 'category.*', - 'translations.*', - 'category.translations.*', - ], - }), - ); - return { data: photoObjects as DirectusPhotoObjectV2[] }; - } catch (error: any) { - return { - error: { - status: error.status || 500, - data: { message: error.message || 'Data fetch failed' } as any, - }, - }; - } - }, - }), - }), -}); - -export const { useGetPhotoObjectsV2Query } = galleryApiV2; diff --git a/frontend-next-migration/src/entities/Gallery/api/mappers.ts b/frontend-next-migration/src/entities/Gallery/api/mappers.ts index 0547f77b7..0df604e4e 100644 --- a/frontend-next-migration/src/entities/Gallery/api/mappers.ts +++ b/frontend-next-migration/src/entities/Gallery/api/mappers.ts @@ -19,7 +19,7 @@ export const mapDirectusToPhotoObjectV2 = ( linkedin, instagram, facebook, - image_1, + image, image_2, image_3, animation, @@ -50,13 +50,17 @@ export const mapDirectusToPhotoObjectV2 = ( facebook: facebook || undefined, }; - const mappedFrames = mapFrames(image_1, image_2, image_3, animation); + const mappedFrames = mapFrames(image, image_2, image_3, animation); + + // url-safe anchor id from author's name + const anchorId = mapAnchorId(author); return { id, category: mappedCategory, title, description, + anchorId, author: author || undefined, links: mappedLinks, frames: mappedFrames, @@ -66,7 +70,7 @@ export const mapDirectusToPhotoObjectV2 = ( }; const mapFrames = ( - image_1: string | null, + image: string | null, image_2: string | null, image_3: string | null, animation: string | null, @@ -79,10 +83,10 @@ const mapFrames = ( const imageQuality = 80; // insert image url, image id, and type (image/animation) into frames - if (image_1) { + if (image) { frames.push([ - `${directusBaseUrl}/assets/${image_1}?format=auto&width=${imageWidth}&quality=${imageQuality}`, - image_1, + `${directusBaseUrl}/assets/${image}?format=auto&width=${imageWidth}&quality=${imageQuality}`, + image, 'image', ]); } @@ -110,3 +114,13 @@ const mapFrames = ( return frames; }; + +const mapAnchorId = (author: string | null): string => { + const anchorId = `${author || ''}` + .toLowerCase() + .normalize('NFD') // åäöé etc -> aaoe + diacritics separately + .replace(/[\u0300-\u036f]/g, '') // remove ¨´~ etc after normalization + .replace(/[^a-z0-9]+/g, '-') // replace non-alphanumeric characters with hyphens + .replace(/^-+|-+$/g, ''); // remove leading/trailing hyphens + return anchorId; +}; diff --git a/frontend-next-migration/src/entities/Gallery/api/translations.ts b/frontend-next-migration/src/entities/Gallery/api/translations.ts index eb025b0dd..87ddfe46d 100644 --- a/frontend-next-migration/src/entities/Gallery/api/translations.ts +++ b/frontend-next-migration/src/entities/Gallery/api/translations.ts @@ -1,9 +1,3 @@ -import { - PhotoVersionTranslations, - CategoryTranslations, - PhotoObjectTranslations, -} from '../types/gallery'; - export const getLanguageCode = (language: string): string => { return language === 'en' ? 'en-US' : language === 'fi' ? 'fi-FI' : 'default'; }; @@ -17,34 +11,3 @@ export const getTranslation = ( const translation = translations.find((t) => t.languages_code === languageCode); return translation && key in translation ? (translation[key] as string) : defaultValue; }; - -export const getCategoryTranslation = ( - translations: CategoryTranslations[], - languageCode: string, -) => { - return getTranslation(translations, languageCode, 'name', ''); -}; - -export const getPhotoVersionTranslation = ( - translations: PhotoVersionTranslations[], - languageCode: string, -) => { - return getTranslation(translations, languageCode, 'altText', ''); -}; - -export const getPhotoObjectTexts = ( - translations: PhotoObjectTranslations[] = [], - languageCode: string, -) => { - if (!translations || translations.length === 0) { - return { title: '', author: '', description: '' }; - } - - const tr = translations.find((t) => t.languages_code === languageCode) ?? translations[0]; - - return { - title: tr.title ?? '', - author: tr.author ?? '', - description: tr.description ?? '', - }; -}; diff --git a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.ts b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.ts index 338aa16f1..a6aeb1028 100644 --- a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.ts +++ b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.ts @@ -1,113 +1,34 @@ -import { envHelper } from '@/shared/const/envHelper'; +import { useGetPhotoObjectsV2Query } from './galleryApi'; +import { useGetGalleryCategoriesQuery } from './galleryCategoriesApi'; +import { mapDirectusToPhotoObjectV2 } from './mappers'; +import { PhotoObjectV2, PhotoCategory } from '../types/gallery'; import { useMemo } from 'react'; -import { Category, PhotoObject, PhotoVersion } from '../types/gallery'; -import { getPhotoVersionTranslation, getPhotoObjectTexts } from '../api/translations'; -import { useGetGalleryCategoriesQuery } from '../api/galleryCategoriesApi'; -import { useGetPhotoObjectsQuery, useGetPhotoVersionsQuery } from '../api/galleryApi'; - -/** - * Hook to fetch and process gallery images from Directus. - * - * This function combines data from three Directus queries: photo objects, photo versions, - * and gallery categories. It processes the raw data to generate structured objects - * representing the gallery's images, versions, and categories, and also manages - * loading and error states. - * - * @returns {object} An object containing the following properties: - * @property {PhotoVersion[]} photoVersions - Array of processed photo versions, including dimensions and alt text. - * @property {Category[]} categories - Array of processed gallery categories, including id and name. - * @property {PhotoObject[]} photoObjects - Array of processed photo objects, including category and version information. - * @property {Error | null} error - Any error encountered while fetching data, or `null` if there was no error. - * @property {boolean} isLoading - `true` if any of the data queries are still loading, `false` otherwise. - * - * @throws {Error} Logs any error encountered during data transformation. - * - * @example - * const { photoObjects, error, isLoading } = useGetDirectusGalleryImages(); - * - * if (isLoading) { - * console.log('Loading data...'); - * } - * if (error) { - * console.error('Error:', error); - * } - * console.log('Categories:', categories); - * console.log('Photo Objects:', photoObjects); - */ +import { getTranslation } from './translations'; export const useGetDirectusGalleryImages = (lng: string) => { - const { data: poData, error: poError, isLoading: poIsLoading } = useGetPhotoObjectsQuery(); - const { data: pvData, error: pvError, isLoading: pvIsLoading } = useGetPhotoVersionsQuery(); + const { data: poData, error: poError, isLoading: poIsLoading } = useGetPhotoObjectsV2Query(); const { data: cData, error: cError, isLoading: cIsLoading } = useGetGalleryCategoriesQuery(); - const directusBaseUrl = envHelper.directusHost; - - const isLoading = poIsLoading || pvIsLoading || cIsLoading; - const error = poError || pvError || cError; + const isLoading = poIsLoading || cIsLoading; + const error = poError || cError; - const categories: Category[] = useMemo(() => { + const categories: PhotoCategory[] = useMemo(() => { if (!cData) return []; return cData.map((item) => ({ id: item.id, - translations: item.translations, + name: getTranslation(item.translations || [], lng, 'name', ''), })); - }, [cData]); + }, [cData, lng]); - const photoVersions: PhotoVersion[] = useMemo(() => { - if (!pvData) return []; - return pvData.map((item) => ({ - id: item.id, - image: item.image, - width: item.width, - height: item.height, - altText: getPhotoVersionTranslation(item.translations || [], lng), - })); - }, [pvData, lng]); - - const photoObjects: PhotoObject[] = useMemo(() => { + const photoObjects: PhotoObjectV2[] = useMemo(() => { if (!poData) return []; - return poData.map((item) => { - const texts = getPhotoObjectTexts(item.translations || [], lng); - - return { - id: item.id, - title: texts.title || item.title, - author: texts.author || item.author, - description: texts.description || item.description, - category: item.category - ? { - id: item.category.id, - translations: item.category.translations, - } - : undefined, - versions: - item.preview && item.full - ? { - preview: { - id: item.preview.id, - image: `${directusBaseUrl}/assets/${item.preview.image}`, - width: item.preview.width, - height: item.preview.height, - altText: getPhotoVersionTranslation( - item.preview.translations || [], - lng, - ), - }, - full: { - id: item.full.id, - image: `${directusBaseUrl}/assets/${item.full.image}`, - width: item.full.width, - height: item.full.height, - altText: getPhotoVersionTranslation( - item.full.translations || [], - lng, - ), - }, - } - : undefined, - }; - }); - }, [poData, directusBaseUrl, lng]); - - return { photoVersions, categories, photoObjects, error, isLoading }; + return mapDirectusToPhotoObjectV2(poData, lng); + }, [poData, lng]); + + return { + photoObjects, + categories, + error, + isLoading, + }; }; diff --git a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImagesV2.ts b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImagesV2.ts deleted file mode 100644 index 51e8eda54..000000000 --- a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImagesV2.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useGetPhotoObjectsV2Query } from './galleryApiV2'; -import { useGetGalleryCategoriesQuery } from './galleryCategoriesApi'; -import { mapDirectusToPhotoObjectV2 } from './mappers'; -import { PhotoObjectV2, PhotoCategory } from '../types/gallery'; -import { useMemo } from 'react'; -import { getTranslation } from './translations'; - -export const useGetDirectusGalleryImagesV2 = (lng: string) => { - const { data: poData, error: poError, isLoading: poIsLoading } = useGetPhotoObjectsV2Query(); - const { data: cData, error: cError, isLoading: cIsLoading } = useGetGalleryCategoriesQuery(); - - const isLoading = poIsLoading || cIsLoading; - const error = poError || cError; - - const categories: PhotoCategory[] = useMemo(() => { - if (!cData) return []; - return cData.map((item) => ({ - id: item.id, - name: getTranslation(item.translations || [], lng, 'name', ''), - })); - }, [cData, lng]); - - const photoObjects: PhotoObjectV2[] = useMemo(() => { - if (!poData) return []; - return mapDirectusToPhotoObjectV2(poData, lng); - }, [poData, lng]); - - return { - photoObjects, - categories, - error, - isLoading, - }; -}; diff --git a/frontend-next-migration/src/entities/Gallery/index.ts b/frontend-next-migration/src/entities/Gallery/index.ts index 7937d93f7..176dcbedb 100644 --- a/frontend-next-migration/src/entities/Gallery/index.ts +++ b/frontend-next-migration/src/entities/Gallery/index.ts @@ -2,11 +2,10 @@ export type { IGalleryDirectory, IGalleryPicture, ImageData, - PhotoObject, - PhotoVersion, + PhotoObjectV2, Category, + PhotoCategory, CategoryTranslations, - PhotoVersionTranslations, } from './types/gallery'; export type { ParentDirectory } from './model/galleryApi'; @@ -15,15 +14,11 @@ export { mockImagesFull, mockImagesPreview } from './model/mockImages'; export type { GalleryCategoriesWithModalSliderProps } from './ui/GalleryCategoriesWithModalSlider'; export { GalleryCategoriesWithModalSlider } from './ui/GalleryCategoriesWithModalSlider'; -export { ImageWall } from './ui/ImageWall/ImageWall'; +// export { ImageWall } from './ui/ImageWall/ImageWall'; export { useGetStrapiGalleryImages } from './api/useGetStrapiGalleryImages'; export { useGetDirectusGalleryImages } from './api/useGetDirectusGalleryImages'; -export { filterAndTransformImages } from './api/filterAndTransformImages'; -export { useGetPhotoObjectsQuery, useGetPhotoVersionsQuery } from './api/galleryApi'; +// export { filterAndTransformImages } from './api/filterAndTransformImages'; +// export { useGetPhotoObjectsQuery, useGetPhotoVersionsQuery } from './api/galleryApi'; export { useGetGalleryCategoriesQuery } from './api/galleryCategoriesApi'; -export { - getCategoryTranslation, - getPhotoVersionTranslation, - getLanguageCode, -} from './api/translations'; +export { getLanguageCode } from './api/translations'; diff --git a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts index 37b507343..f498972cf 100644 --- a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts +++ b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts @@ -22,49 +22,11 @@ export interface CategoryTranslations { name: string; } -export interface PhotoVersionTranslations { - id: string; - languages_code: string; - photo_version_id: string; - altText: string; -} - -export interface PhotoObjectTranslations { - id: string; - languages_code: string; - photo_object_id: string; - title?: string; - author?: string; - description?: string; -} - export interface Category { id: string; translations: CategoryTranslations[]; } -export interface PhotoVersion { - id: string; - image: string; - width: number; - height: number; - altText: string; -} - -export interface PhotoObject { - title?: string; - author?: string; - description?: string; - frames?: string[][]; - id?: string; - category?: Category; - translations?: PhotoObjectTranslations[]; - versions?: { - preview: PhotoVersion; - full: PhotoVersion; - }; -} - export interface PhotoObjectV2Translations { id: string; languages_code: string; @@ -83,7 +45,7 @@ export interface DirectusPhotoObjectV2 { linkedin: string | null; instagram: string | null; facebook: string | null; - image_1: string | null; + image: string | null; image_2: string | null; image_3: string | null; animation: string | null; @@ -97,6 +59,7 @@ export interface PhotoCategory { export interface PhotoObjectV2 { author?: string; + anchorId?: string; id: string; date_created: string; category: PhotoCategory; diff --git a/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.tsx b/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.tsx index d7f8a9625..6e6f2c192 100644 --- a/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.tsx +++ b/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.tsx @@ -1,50 +1,50 @@ -'use client'; -import cls from './ImageWall.module.scss'; -import Image from 'next/image'; -import { PhotoObject, PhotoVersion } from '../../types/gallery'; -import { filterAndTransformImages } from '../../api/filterAndTransformImages'; -import Fancybox from '@/shared/ui/Fancybox/Fancybox'; -import { Border } from '../Border/Border'; -import { MasonryWrapper } from '@/shared/ui/MasonryWrapper'; -import { AppLink } from '@/shared/ui/AppLink/AppLink'; -import { useEffect, useState } from 'react'; +// 'use client'; +// import cls from './ImageWall.module.scss'; +// import Image from 'next/image'; +// // import { PhotoObject, PhotoVersion } from '../../types/gallery'; +// // import { filterAndTransformImages } from '../../api/filterAndTransformImages'; +// import Fancybox from '@/shared/ui/Fancybox/Fancybox'; +// import { Border } from '../Border/Border'; +// import { MasonryWrapper } from '@/shared/ui/MasonryWrapper'; +// import { AppLink } from '@/shared/ui/AppLink/AppLink'; +// import { useEffect, useState } from 'react'; -export type ImageWallProps = { - images: PhotoObject[]; - version: string; -}; +// export type ImageWallProps = { +// images: PhotoObject[]; +// version: string; +// }; -export const ImageWall = ({ images, version }: ImageWallProps) => { - const [filteredImages, setFilteredImages] = useState([]); +// export const ImageWall = ({ images, version }: ImageWallProps) => { +// const [filteredImages, setFilteredImages] = useState([]); - useEffect(() => { - const filteredImages = filterAndTransformImages(images, version); - if (filteredImages) setFilteredImages(filteredImages); - }, [images]); +// useEffect(() => { +// const filteredImages = filterAndTransformImages(images, version); +// if (filteredImages) setFilteredImages(filteredImages); +// }, [images]); - return ( - - - {filteredImages.map((image, index) => ( - -
- - {image.altText} - -
-
- ))} -
-
- ); -}; +// return ( +// +// +// {filteredImages.map((image, index) => ( +// +//
+// +// {image.altText} +// +//
+//
+// ))} +//
+//
+// ); +// }; diff --git a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsDropdown.tsx b/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsDropdown.tsx index 3dd702763..117cef62a 100644 --- a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsDropdown.tsx +++ b/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsDropdown.tsx @@ -6,11 +6,7 @@ import { DropDownElementASTextOrLink, } from '@/shared/ui/NavMenuWithDropdownsV2'; import { getRouteGalleryCategoryPage } from '@/shared/appLinks/RoutePaths'; -import { - getLanguageCode, - useGetDirectusGalleryImages, - getCategoryTranslation, -} from '@/entities/Gallery'; +import { getLanguageCode, useGetDirectusGalleryImages } from '@/entities/Gallery'; import { useEffect, useState } from 'react'; import useSizes from '@/shared/lib/hooks/useSizes'; import { useClientTranslation } from '@/shared/i18n'; @@ -40,15 +36,10 @@ const GalleryNavMenuAsDropdown = (props: GalleryNavMenuProps) => { useEffect(() => { if (categories) { - const matchingCategory = categories.find((cat) => - cat.translations.some((t) => t.name === currentCategory), - ); + const matchingCategory = categories.find((cat) => cat.name === currentCategory); if (matchingCategory) { - const translatedName = getCategoryTranslation( - matchingCategory.translations, - language, - ); + const translatedName = matchingCategory.name; if (translatedName && translatedName !== currentCategory) { const newPath = getRouteGalleryCategoryPage(translatedName); @@ -73,7 +64,7 @@ const GalleryNavMenuAsDropdown = (props: GalleryNavMenuProps) => { active: selectedCategory === allCategory, }, ...categories.map((category) => { - const translatedName = getCategoryTranslation(category.translations, language); + const translatedName = category.name || ''; return { link: { isExternal: false, diff --git a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.tsx b/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.tsx index 17f27190e..3a423b0ff 100644 --- a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.tsx +++ b/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.tsx @@ -1,11 +1,6 @@ import { useParams, useRouter } from 'next/navigation'; import { getRouteGalleryCategoryPage } from '@/shared/appLinks/RoutePaths'; -import { - getLanguageCode, - useGetDirectusGalleryImages, - getCategoryTranslation, - Category, -} from '@/entities/Gallery'; +import { getLanguageCode, useGetDirectusGalleryImages, PhotoCategory } from '@/entities/Gallery'; import { useEffect, useState } from 'react'; import { useClientTranslation } from '@/shared/i18n'; import cls from './GalleryNavMenuAsSidebar.module.scss'; @@ -42,7 +37,7 @@ const GalleryNavMenuAsSidebar = (props: SidebarProps) => { const category = findCorrectCategory(categories); if (category) { - const translatedName = getCategoryTranslation(category.translations, language); + const translatedName = category.name; if (translatedName && translatedName !== currentCategory) { handleRouteChange(translatedName); @@ -52,11 +47,9 @@ const GalleryNavMenuAsSidebar = (props: SidebarProps) => { } }, [categories, lng]); - const findCorrectCategory = (categories: Category[]) => { + const findCorrectCategory = (categories: PhotoCategory[]) => { if (!categories) return null; - const category = categories.find((cat) => - cat.translations.some((t) => t.name === currentCategory), - ); + const category = categories.find((cat) => cat.name === currentCategory); return category ? category : null; }; @@ -70,23 +63,23 @@ const GalleryNavMenuAsSidebar = (props: SidebarProps) => { [cls.Hidden]: !sidebarVisible, }; - const getCategory = (category: Category, index: number) => { - const translatedCategory = getCategoryTranslation(category.translations, language); - - if (sidebarVisible) { + const getCategory = (category: PhotoCategory, index: number) => { + if (category && sidebarVisible) { return (
handleRouteChange(translatedCategory)} + onClick={() => handleRouteChange(category.name ? category.name : allCategory)} className={cls.Category} style={ - selectedCategory === translatedCategory + selectedCategory === category.name ? { color: 'var(--secondary-color)' } : {} } > - {translatedCategory.charAt(0).toUpperCase() + - translatedCategory.slice(1).replace('-', ' ')} + {category.name + ? category.name.charAt(0).toUpperCase() + + category.name.slice(1).replace('-', ' ') + : ''}
); } else { @@ -95,13 +88,15 @@ const GalleryNavMenuAsSidebar = (props: SidebarProps) => { key={index} className={cls.Category} style={ - selectedCategory === translatedCategory + selectedCategory === category.name ? { color: 'var(--secondary-color)' } : {} } > - {translatedCategory.charAt(0).toUpperCase() + - translatedCategory.slice(1).replace('-', ' ')} + {category.name + ? category.name.charAt(0).toUpperCase() + + category.name.slice(1).replace('-', ' ') + : ''} ); } diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx index 325e44eef..f66f81e56 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx @@ -1,12 +1,7 @@ 'use client'; import React, { useState, useMemo } from 'react'; import { AnimationGallerySection } from '@/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery'; -import { - getLanguageCode, - PhotoObject, - useGetDirectusGalleryImages, - getCategoryTranslation, -} from '@/entities/Gallery'; +import { getLanguageCode, PhotoObjectV2, useGetDirectusGalleryImages } from '@/entities/Gallery'; import { Container } from '@/shared/ui/Container'; import cls from './PictureGalleryPage.module.scss'; import { useClientTranslation } from '@/shared/i18n'; @@ -63,7 +58,7 @@ const PictureGalleryPage = () => { const categorySlug = params.category as string | undefined; const languageCode = getLanguageCode(lng); - // TODO: switch to V2 hook + // TODO: switch to using the V2 hook const { photoObjects, isLoading, error } = useGetDirectusGalleryImages(languageCode); const isBigDevice = isDesktopSize || isWidescreenSize; @@ -76,7 +71,7 @@ const PictureGalleryPage = () => { ); // filter images by category from URL params - const categoryFilteredImages: PhotoObject[] = useMemo(() => { + const categoryFilteredImages: PhotoObjectV2[] = useMemo(() => { if (!photoObjects) return []; if (!categorySlug || categorySlug === allCategory) { return photoObjects; @@ -84,17 +79,13 @@ const PictureGalleryPage = () => { return photoObjects.filter((photo) => { if (!photo.category) return false; - const translatedCategory = getCategoryTranslation( - photo.category.translations, - languageCode, - ); - return translatedCategory === categorySlug; + return photo.category.name === categorySlug; }); }, [photoObjects, categorySlug, allCategory, languageCode]); // keep this search filtering, see if it there are any new fields to add to the search // need to update PhotoObject to v2 - const filteredImages: PhotoObject[] = useMemo(() => { + const filteredImages: PhotoObjectV2[] = useMemo(() => { const query = searchQuery.trim().toLowerCase(); if (!query) return categoryFilteredImages; return categoryFilteredImages.filter((photo) => { @@ -158,12 +149,7 @@ const PictureGalleryPage = () => { title: photo.title || '', author: photo.author || '', description: photo.description || '', - frames: - photo.frames && photo.frames.length > 0 - ? photo.frames - : photo.versions?.preview - ? [[photo.versions.preview.image]] - : [], + frames: photo.frames && photo.frames.length > 0 ? photo.frames : [], // Add animation, and social media links }))} /> diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx index dedbf1c42..a4fd1ce71 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx @@ -26,6 +26,7 @@ export const AnimationGallerySection = ({ animations }: AnimationGalleryProps) = const mods = { [cls.inView]: inView, }; + // frames will be: [["img src 1", "imgid 1", "image"], ["img src 2", "imgid 2", "image"], ...] return (
@@ -45,30 +46,28 @@ export const AnimationGallerySection = ({ animations }: AnimationGalleryProps) = key={rowIndex} className={cls.frameRow} > - {row.map((imgSrc, imgIndex) => ( -
- {`Frame -
- ))} -
- +
+ {`Frame
))} +
+ +
))} From a07d594220c81c1ec9aca5cb820ef2ec44cb98c9 Mon Sep 17 00:00:00 2001 From: eleino Date: Mon, 13 Jul 2026 14:27:14 +0300 Subject: [PATCH 5/9] added social media icons and tab navigation for gallery page --- .../(helper)/picture-galleries/layout.tsx | 40 ---------- .../src/entities/Gallery/api/mappers.ts | 78 ++++++++++--------- .../src/entities/Gallery/api/translations.ts | 18 +++++ .../src/entities/Gallery/index.ts | 5 +- .../src/entities/Gallery/types/gallery.d.ts | 16 ++-- .../src/features/NavigateGalleryTabs/index.ts | 1 + .../ui/NavigateGalleryTabs.tsx | 66 ++++++++++++++++ .../ui/PictureGalleryPage.module.scss | 6 +- .../ui/PictureGalleryPage.tsx | 59 +++++++++----- .../i18n/locales/en/picture-galleries.json | 3 +- .../i18n/locales/fi/picture-galleries.json | 7 +- .../src/shared/ui/SocialMediaIcons/index.ts | 1 + .../ui/SocialMediaIcons.module.scss | 19 +++++ .../SocialMediaIcons/ui/SocialMediaIcons.tsx | 46 +++++++++++ .../src/shared/ui/TabNavigation/index.ts | 1 + .../ui/TabNavigation.module.scss | 36 +++++++++ .../ui/TabNavigation/ui/TabNavigation.tsx | 48 ++++++++++++ .../ui/SectionGalleryV2/SectionGallery.tsx | 53 ++++++------- .../SectionGallery2.module.scss | 15 +++- frontend-next-migration/tsconfig.json | 1 + 20 files changed, 377 insertions(+), 142 deletions(-) delete mode 100644 frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/layout.tsx create mode 100644 frontend-next-migration/src/features/NavigateGalleryTabs/index.ts create mode 100644 frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx create mode 100644 frontend-next-migration/src/shared/ui/SocialMediaIcons/index.ts create mode 100644 frontend-next-migration/src/shared/ui/SocialMediaIcons/ui/SocialMediaIcons.module.scss create mode 100644 frontend-next-migration/src/shared/ui/SocialMediaIcons/ui/SocialMediaIcons.tsx create mode 100644 frontend-next-migration/src/shared/ui/TabNavigation/index.ts create mode 100644 frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss create mode 100644 frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx diff --git a/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/layout.tsx b/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/layout.tsx deleted file mode 100644 index 96370dcf3..000000000 --- a/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/layout.tsx +++ /dev/null @@ -1,40 +0,0 @@ -'use client'; -import { ReactNode } from 'react'; -import { LayoutWithSidebars } from '@/preparedPages/Layouts'; -import { GalleryNavMenuAsDropdown } from '@/features/NavigateGalleries'; -import useSizes from '@/shared/lib/hooks/useSizes'; -import { useClientTranslation } from '@/shared/i18n'; -import { PageTitle } from '@/shared/ui/PageTitle'; -import { cls } from '@/preparedPages/PictureGalleryPages'; - -export default function PictureGalleryLayout({ children }: { children: ReactNode }) { - const { isMobileSize, isTabletSize } = useSizes(); - const isTouchDevice = isMobileSize || isTabletSize; - const { t } = useClientTranslation('picture-galleries'); - - return ( - - ), - hideOnMobile: true, - }} - > - {isTouchDevice && ( - <> - - - - )} - {children} - - ); -} diff --git a/frontend-next-migration/src/entities/Gallery/api/mappers.ts b/frontend-next-migration/src/entities/Gallery/api/mappers.ts index 0df604e4e..3d95ef5b0 100644 --- a/frontend-next-migration/src/entities/Gallery/api/mappers.ts +++ b/frontend-next-migration/src/entities/Gallery/api/mappers.ts @@ -1,12 +1,12 @@ import { envHelper } from '@/shared/const/envHelper'; -import { DirectusPhotoObjectV2, PhotoObjectV2 } from '../types/gallery'; -import { getTranslation } from './translations'; +import { DirectusPhotoObjectV2, PhotoObject, PhotoObjectLink } from '../types/gallery'; +import { getPhotoObjectTexts, getTranslation } from './translations'; // for mapping DirectusPhotoObjectV2 to PhotoObjectV2 export const mapDirectusToPhotoObjectV2 = ( directusPhotoObject: DirectusPhotoObjectV2[], lng: string, -): PhotoObjectV2[] => { +): PhotoObject[] => { return directusPhotoObject.map((item) => { const { id, @@ -30,27 +30,17 @@ export const mapDirectusToPhotoObjectV2 = ( name: getTranslation(category?.translations || [], lng, 'name', ''), }; - const mappedTranslations = translations - ? translations.map((t) => ({ - id: t.id, - languages_code: t.languages_code, - photo_object_id: t.photo_object_id, - title: t.title || undefined, - description: t.description || undefined, - })) - : []; - const title = getTranslation(mappedTranslations, lng, 'title', ''); - const description = getTranslation(mappedTranslations, lng, 'description', ''); + const { title, description } = getPhotoObjectTexts(translations ? translations : [], lng); + const mappedLinks = [ + { name: 'website', url: sanitizeLink(website) }, + { name: 'github', url: sanitizeLink(github) }, + { name: 'linkedin', url: sanitizeLink(linkedin) }, + { name: 'instagram', url: sanitizeLink(instagram) }, + { name: 'facebook', url: sanitizeLink(facebook) }, + ].filter((link) => link.url !== undefined) as PhotoObjectLink[]; - const mappedLinks = { - website: website || undefined, - github: github || undefined, - linkedin: linkedin || undefined, - instagram: instagram || undefined, - facebook: facebook || undefined, - }; - - const mappedFrames = mapFrames(image, image_2, image_3, animation); + const mappedFrames = mapFrames(image, image_2, image_3); + const mappedAnimation = mapAnimation(animation); // url-safe anchor id from author's name const anchorId = mapAnchorId(author); @@ -64,6 +54,7 @@ export const mapDirectusToPhotoObjectV2 = ( author: author || undefined, links: mappedLinks, frames: mappedFrames, + animation: mappedAnimation, date_created, }; }); @@ -73,7 +64,6 @@ const mapFrames = ( image: string | null, image_2: string | null, image_3: string | null, - animation: string | null, ): string[][] => { const frames: string[][] = []; const directusBaseUrl = envHelper.directusHost; @@ -82,39 +72,42 @@ const mapFrames = ( const imageWidth = 800; const imageQuality = 80; - // insert image url, image id, and type (image/animation) into frames + // insert image url and image id into frames if (image) { frames.push([ `${directusBaseUrl}/assets/${image}?format=auto&width=${imageWidth}&quality=${imageQuality}`, image, - 'image', ]); } if (image_2) { frames.push([ `${directusBaseUrl}/assets/${image_2}?format=auto&width=${imageWidth}&quality=${imageQuality}`, image_2, - 'image', ]); } if (image_3) { frames.push([ `${directusBaseUrl}/assets/${image_3}?format=auto&width=${imageWidth}&quality=${imageQuality}`, image_3, - 'image', - ]); - } - if (animation) { - frames.push([ - `${directusBaseUrl}/assets/${animation}?format=auto&width=${imageWidth}&quality=${imageQuality}`, - animation, - 'animation', ]); } return frames; }; +const mapAnimation = (animation: string | null): string[] | undefined => { + if (!animation) return undefined; + + const directusBaseUrl = envHelper.directusHost; + const imageWidth = 800; + const imageQuality = 80; + + return [ + `${directusBaseUrl}/assets/${animation}?format=auto&width=${imageWidth}&quality=${imageQuality}`, + animation, + ]; +}; + const mapAnchorId = (author: string | null): string => { const anchorId = `${author || ''}` .toLowerCase() @@ -124,3 +117,18 @@ const mapAnchorId = (author: string | null): string => { .replace(/^-+|-+$/g, ''); // remove leading/trailing hyphens return anchorId; }; + +const sanitizeLink = (link: string | null): string | undefined => { + if (!link) return undefined; + // trim whitespace, check http/https prefix, and validate URL + const rawLink = link.trim(); + if (!rawLink) return undefined; + const normalizedLink = /^https?:\/\//i.test(rawLink) ? rawLink : `https://${rawLink}`; + try { + const url = new URL(normalizedLink); + return url.href; + } catch (error) { + console.warn(`Invalid URL: ${link}, error: ${error}`); + return undefined; + } +}; diff --git a/frontend-next-migration/src/entities/Gallery/api/translations.ts b/frontend-next-migration/src/entities/Gallery/api/translations.ts index 87ddfe46d..8bd877a57 100644 --- a/frontend-next-migration/src/entities/Gallery/api/translations.ts +++ b/frontend-next-migration/src/entities/Gallery/api/translations.ts @@ -1,3 +1,5 @@ +import { PhotoObjectV2Translations } from '../types/gallery'; + export const getLanguageCode = (language: string): string => { return language === 'en' ? 'en-US' : language === 'fi' ? 'fi-FI' : 'default'; }; @@ -11,3 +13,19 @@ export const getTranslation = ( const translation = translations.find((t) => t.languages_code === languageCode); return translation && key in translation ? (translation[key] as string) : defaultValue; }; + +export const getPhotoObjectTexts = ( + translations: PhotoObjectV2Translations[] = [], + languageCode: string, +) => { + if (!translations || translations.length === 0) { + return { title: '', description: '' }; + } + + const tr = translations.find((t) => t.languages_code === languageCode) ?? translations[0]; + + return { + title: tr.title ?? '', + description: tr.description ?? '', + }; +}; diff --git a/frontend-next-migration/src/entities/Gallery/index.ts b/frontend-next-migration/src/entities/Gallery/index.ts index 176dcbedb..fc88dd33c 100644 --- a/frontend-next-migration/src/entities/Gallery/index.ts +++ b/frontend-next-migration/src/entities/Gallery/index.ts @@ -2,7 +2,7 @@ export type { IGalleryDirectory, IGalleryPicture, ImageData, - PhotoObjectV2, + PhotoObject, Category, PhotoCategory, CategoryTranslations, @@ -15,10 +15,7 @@ export { mockImagesFull, mockImagesPreview } from './model/mockImages'; export type { GalleryCategoriesWithModalSliderProps } from './ui/GalleryCategoriesWithModalSlider'; export { GalleryCategoriesWithModalSlider } from './ui/GalleryCategoriesWithModalSlider'; // export { ImageWall } from './ui/ImageWall/ImageWall'; - export { useGetStrapiGalleryImages } from './api/useGetStrapiGalleryImages'; export { useGetDirectusGalleryImages } from './api/useGetDirectusGalleryImages'; -// export { filterAndTransformImages } from './api/filterAndTransformImages'; -// export { useGetPhotoObjectsQuery, useGetPhotoVersionsQuery } from './api/galleryApi'; export { useGetGalleryCategoriesQuery } from './api/galleryCategoriesApi'; export { getLanguageCode } from './api/translations'; diff --git a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts index f498972cf..b3c6c50fa 100644 --- a/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts +++ b/frontend-next-migration/src/entities/Gallery/types/gallery.d.ts @@ -57,7 +57,12 @@ export interface PhotoCategory { name?: string; } -export interface PhotoObjectV2 { +export interface PhotoObjectLink { + name: 'github' | 'linkedin' | 'instagram' | 'facebook' | 'website'; + url: string; +} + +export interface PhotoObject { author?: string; anchorId?: string; id: string; @@ -65,12 +70,7 @@ export interface PhotoObjectV2 { category: PhotoCategory; title?: string; description?: string; - links: { - website?: string; - github?: string; - linkedin?: string; - instagram?: string; - facebook?: string; - }; + links: PhotoObjectLink[]; frames?: string[][]; + animation?: string[]; } diff --git a/frontend-next-migration/src/features/NavigateGalleryTabs/index.ts b/frontend-next-migration/src/features/NavigateGalleryTabs/index.ts new file mode 100644 index 000000000..6497f4fa4 --- /dev/null +++ b/frontend-next-migration/src/features/NavigateGalleryTabs/index.ts @@ -0,0 +1 @@ +export { NavigateGalleryTabs } from './ui/NavigateGalleryTabs'; diff --git a/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx b/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx new file mode 100644 index 000000000..169f2e95a --- /dev/null +++ b/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx @@ -0,0 +1,66 @@ +import { useMemo } from 'react'; +import { PhotoCategory } from '@/entities/Gallery'; +import useSizes from '@/shared/lib/hooks/useSizes'; +import { TabNavigation } from '@/shared/ui/TabNavigation'; + +interface NavigateGalleryTabsProps { + categories: PhotoCategory[]; + setBackgroundColor: (color: string) => void; + currentCategory: PhotoCategory; + setCurrentCategory?: (category: PhotoCategory) => void; +} + +export const NavigateGalleryTabs = ({ + categories, + setBackgroundColor, + currentCategory, + setCurrentCategory, +}: NavigateGalleryTabsProps) => { + const { isMobileSize } = useSizes(); + const currentCategoryNumber = useMemo( + () => categories?.findIndex((category) => category.name === currentCategory.name), + [categories, currentCategory.name], + ); + const categoryColors = [ + { tabColor: '#97C459', sectionBG: '#527259' }, + { tabColor: '#5DCAA5', sectionBG: '#0C5450' }, + { tabColor: '#85B7EB', sectionBG: '#2B516A' }, + { tabColor: '#AFA9EC', sectionBG: '#63688B' }, + ]; + const activeTabStyles = { + backgroundColor: + categoryColors[currentCategoryNumber % categoryColors.length]?.tabColor || + categoryColors[0].tabColor, + color: 'black', + }; + const mobileTabStylesList = categories.map((category, index) => ({ + border: `2px solid`, + borderColor: + categoryColors[index % categoryColors.length]?.tabColor || categoryColors[0].tabColor, + })); + + const onActiveTabChange = (tab: string) => { + const selectedCategory = categories.find((category) => category.name === tab); + if (selectedCategory) { + const selectedCategoryNumber = categories.findIndex( + (category) => category.name === selectedCategory.name, + ); + const sectionBGColor = + categoryColors[selectedCategoryNumber % categoryColors.length]?.sectionBG || + categoryColors[0].sectionBG; + setBackgroundColor(sectionBGColor); + setCurrentCategory?.(selectedCategory); + } + }; + + return ( + category.name || category.id)} + tabsTitle="Categories" + activeTab={currentCategory.name || currentCategory.id} + onTabClick={onActiveTabChange} + tabStylesList={isMobileSize ? mobileTabStylesList : undefined} + activeTabStyles={activeTabStyles} + /> + ); +}; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss index 4e5e1eb1f..80eb18d68 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss @@ -4,12 +4,16 @@ flex-direction: column; min-height: 100vh; padding-bottom: 20px; + margin-inline: auto; + padding-inline: 20px; // background-color: rgba(109, 39, 39, 0.322); //@media (max-width: 1200px) { // margin-top: 50px; //} - + @media (min-width: breakpoint(md)) { + width: 60%; + } } .LeftSidebar{ margin-top: 6rem; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx index f66f81e56..df667b4a3 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx @@ -1,7 +1,12 @@ 'use client'; import React, { useState, useMemo } from 'react'; import { AnimationGallerySection } from '@/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery'; -import { getLanguageCode, PhotoObjectV2, useGetDirectusGalleryImages } from '@/entities/Gallery'; +import { + getLanguageCode, + PhotoCategory, + PhotoObject, + useGetDirectusGalleryImages, +} from '@/entities/Gallery'; import { Container } from '@/shared/ui/Container'; import cls from './PictureGalleryPage.module.scss'; import { useClientTranslation } from '@/shared/i18n'; @@ -13,6 +18,7 @@ import { classNames } from '@/shared/lib/classNames/classNames'; // import { SectionGalleryV2 } from '@/widgets/SectionGallery'; import { useParams } from 'next/navigation'; // import { useGetDirectusGalleryImages, getLanguageCode, getCategoryTranslation, } from '@/entities/Gallery'; +import { NavigateGalleryTabs } from '@/features/NavigateGalleryTabs'; export interface Props { title: string; @@ -52,17 +58,21 @@ const PictureGalleryPage = () => { const { t } = useClientTranslation('picture-galleries'); const { isMobileSize, isDesktopSize, isWidescreenSize } = useSizes(); const [searchQuery, setSearchQuery] = useState(''); + const [currentCategory, setCurrentCategory] = useState({ + id: 'all-categories', + name: t('all-categories') ?? 'All', + }); + const [sectionBG, setSectionBG] = useState('#527259'); const params = useParams(); const lng = params.lng as string; - const categorySlug = params.category as string | undefined; + // const categorySlug = params.category as string | undefined; const languageCode = getLanguageCode(lng); - // TODO: switch to using the V2 hook - const { photoObjects, isLoading, error } = useGetDirectusGalleryImages(languageCode); + const { photoObjects, categories, isLoading, error } = + useGetDirectusGalleryImages(languageCode); const isBigDevice = isDesktopSize || isWidescreenSize; - const allCategory = lng === 'en' ? 'all' : 'kaikki'; // figma shows the text should be present even on mobile, so this boolean will become unnecessary const showCreativity = useMemo( @@ -70,22 +80,31 @@ const PictureGalleryPage = () => { [isMobileSize, searchQuery], ); + const allCategories: PhotoCategory[] = useMemo(() => { + if (!categories) return []; + return [ + { + id: 'all-categories', + name: t('all-categories') ?? 'All', + }, + ...categories, + ]; + }, [categories, t]); + // filter images by category from URL params - const categoryFilteredImages: PhotoObjectV2[] = useMemo(() => { + const categoryFilteredImages: PhotoObject[] = useMemo(() => { if (!photoObjects) return []; - if (!categorySlug || categorySlug === allCategory) { + if (!currentCategory || currentCategory.id === 'all-categories') { return photoObjects; } return photoObjects.filter((photo) => { if (!photo.category) return false; - return photo.category.name === categorySlug; + return photo.category.name === currentCategory.name; }); - }, [photoObjects, categorySlug, allCategory, languageCode]); + }, [photoObjects, currentCategory, languageCode]); - // keep this search filtering, see if it there are any new fields to add to the search - // need to update PhotoObject to v2 - const filteredImages: PhotoObjectV2[] = useMemo(() => { + const filteredImages: PhotoObject[] = useMemo(() => { const query = searchQuery.trim().toLowerCase(); if (!query) return categoryFilteredImages; return categoryFilteredImages.filter((photo) => { @@ -143,15 +162,15 @@ const PictureGalleryPage = () => {

{t('info-text')}

)} + ({ - // Adjust these mappings to match photo object v2 structure - title: photo.title || '', - author: photo.author || '', - description: photo.description || '', - frames: photo.frames && photo.frames.length > 0 ? photo.frames : [], - // Add animation, and social media links - }))} + animations={filteredImages} + backgroundColor={sectionBG} /> diff --git a/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json b/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json index c166941dd..4916b5d3b 100644 --- a/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json +++ b/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json @@ -12,5 +12,6 @@ "socials-text": "Also, check out our socials!", "explore": "Explore", "category-menu-title": "Categories", - "picture-galleries-title": "GALLERY" + "all-categories": "All", + "picture-galleries-title": "How We Made the Graphics" } diff --git a/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json b/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json index 704cd56c2..5af3c38c9 100644 --- a/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json +++ b/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json @@ -1,9 +1,9 @@ { - "picture-galleries": "Luovuuden Kulissit", + "picture-galleries": "Luovuuden kulissit", "Chat": "Chat", "Hahmot": "Hahmot", "Huonekalut": "Huonekalut", - "head-title": "Luovuuden Kulissit", + "head-title": "Luovuuden kulissit", "head-description": "Selaa kehittäjien, taiteilijoiden ja suunnittelijoiden töitä ja löydä inspiroivia projekteja.", "head-keywords": "altzone, kuvagalleriat, taide, projektit, kehittäjät, suunnittelijat", "og-title": "ALT Zone Kuvagalleriat — Luovuuden Kulissit", @@ -12,5 +12,6 @@ "socials-text": "Löydä lisää meidän someista!", "explore": "Tutustu", "category-menu-title": "Kategoriat", - "picture-galleries-title": "GALLERIA" + "all-categories": "Kaikki", + "picture-galleries-title": "Näin teimme grafiikan" } diff --git a/frontend-next-migration/src/shared/ui/SocialMediaIcons/index.ts b/frontend-next-migration/src/shared/ui/SocialMediaIcons/index.ts new file mode 100644 index 000000000..cb4efd4dd --- /dev/null +++ b/frontend-next-migration/src/shared/ui/SocialMediaIcons/index.ts @@ -0,0 +1 @@ +export { SocialMediaIcons } from './ui/SocialMediaIcons'; diff --git a/frontend-next-migration/src/shared/ui/SocialMediaIcons/ui/SocialMediaIcons.module.scss b/frontend-next-migration/src/shared/ui/SocialMediaIcons/ui/SocialMediaIcons.module.scss new file mode 100644 index 000000000..5acdcab2e --- /dev/null +++ b/frontend-next-migration/src/shared/ui/SocialMediaIcons/ui/SocialMediaIcons.module.scss @@ -0,0 +1,19 @@ +.socialMediaIcons { + display: flex; + flex-direction: row; + align-items: center; +} + +.iconLink { + display: inline-flex; + align-items: center; + justify-content: center; + font: var(--font-dm-l); + cursor: pointer; + color: var(--primary-color); + @include link-scale-effect('icon'); + + @media (max-width: breakpoint(sm)) { + font: var(--font-dm-m); + } +} \ No newline at end of file diff --git a/frontend-next-migration/src/shared/ui/SocialMediaIcons/ui/SocialMediaIcons.tsx b/frontend-next-migration/src/shared/ui/SocialMediaIcons/ui/SocialMediaIcons.tsx new file mode 100644 index 000000000..f003906e6 --- /dev/null +++ b/frontend-next-migration/src/shared/ui/SocialMediaIcons/ui/SocialMediaIcons.tsx @@ -0,0 +1,46 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faGithub, faLinkedin, faInstagram, faFacebook } from '@fortawesome/free-brands-svg-icons'; +import { faGlobe } from '@fortawesome/free-solid-svg-icons'; +import cls from './SocialMediaIcons.module.scss'; + +const SoMeIcons = { + website: faGlobe, + github: faGithub, + linkedin: faLinkedin, + facebook: faFacebook, + instagram: faInstagram, +}; + +interface SocialMediaIconsProps { + links: { name: 'website' | 'github' | 'linkedin' | 'facebook' | 'instagram'; url: string }[]; +} + +/** + * Component to render social media icons with links. + * @param props - The properties for the `SocialMediaIcons` component. + * @param props.links - An array of objects containing the name of the social media platform and its corresponding URL. + * @returns The rendered social media icons. + */ +export const SocialMediaIcons = ({ links }: SocialMediaIconsProps) => { + return ( +
+ {links.map((link) => { + const icon = SoMeIcons[link.name]; + if (!icon) return null; // skip if the icon is not found + return ( + + + + ); + })} +
+ ); +}; diff --git a/frontend-next-migration/src/shared/ui/TabNavigation/index.ts b/frontend-next-migration/src/shared/ui/TabNavigation/index.ts new file mode 100644 index 000000000..c967785f6 --- /dev/null +++ b/frontend-next-migration/src/shared/ui/TabNavigation/index.ts @@ -0,0 +1 @@ +export { TabNavigation } from './ui/TabNavigation'; diff --git a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss new file mode 100644 index 000000000..e4fc543a1 --- /dev/null +++ b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss @@ -0,0 +1,36 @@ +.tabNavigation { + display: flex; +} + +.tabsContainer { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 100%; + flex-wrap: wrap; + background-color: var(--base-card-background); + border-radius: var(--border-radius-figmadesktop); + +} + +.tab { + padding: 8px; + padding-inline: 60px; + min-width: 150px; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + background-color: var(--base-card-background); + color: var(--primary-color); + font: var(--font-dm-bold-m); + cursor: pointer; + transition: background-color 0.3s ease, color 0.3s ease; + border-radius: var(--border-radius-figmadesktop); + + @media (max-width: breakpoint(sm)) { + border-radius: var(--border-radius-figma); + } +} \ No newline at end of file diff --git a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx new file mode 100644 index 000000000..c2f18a479 --- /dev/null +++ b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx @@ -0,0 +1,48 @@ +import cls from './TabNavigation.module.scss'; +import useSizes from '@/shared/lib/hooks/useSizes'; + +interface TabNavigationProps { + tabs: string[]; + tabsTitle: string; + activeTab: string; + onTabClick: (tab: string) => void; + tabStylesList?: React.CSSProperties[]; + activeTabStyles?: React.CSSProperties; +} + +export const TabNavigation = ({ + tabs, + tabsTitle, + activeTab, + onTabClick, + tabStylesList, + activeTabStyles, +}: TabNavigationProps) => { + const { isMobileSize } = useSizes(); + + const handleTabClick = (tab: string) => { + onTabClick(tab); + }; + + return ( +
+ {isMobileSize &&
{tabsTitle}
} +
+ {tabs.map((tab) => ( +
handleTabClick(tab)} + > + {tab.charAt(0).toUpperCase() + tab.slice(1).replace('-', ' ')} +
+ ))} +
+
+ ); +}; diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx index a4fd1ce71..d1e2e2649 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx @@ -4,20 +4,15 @@ import { classNames } from '@/shared/lib/classNames/classNames'; import { Button, ButtonTheme } from '@/shared/ui/Button'; import cls from './SectionGallery2.module.scss'; import Image from 'next/image'; - -interface FrameSet { - title: string; - author: string; - description: string; - frames: string[][]; // each row is an array of image paths -} +import { SocialMediaIcons } from '@/shared/ui/SocialMediaIcons'; +import { PhotoObject } from '@/entities/Gallery'; interface AnimationGalleryProps { - animations: FrameSet[]; + animations: PhotoObject[]; + backgroundColor?: string; } -// TODO: update to use V2 photo object -export const AnimationGallerySection = ({ animations }: AnimationGalleryProps) => { +export const AnimationGallerySection = ({ animations, backgroundColor }: AnimationGalleryProps) => { const { inView } = useInView({ rootMargin: '-150px 0px', triggerOnce: true, @@ -26,26 +21,29 @@ export const AnimationGallerySection = ({ animations }: AnimationGalleryProps) = const mods = { [cls.inView]: inView, }; - // frames will be: [["img src 1", "imgid 1", "image"], ["img src 2", "imgid 2", "image"], ...] return ( -
+
{animations.map((set, index) => (

{set.title}

{set.author}

{set.description}

+
+ +
- {set.frames.map((row, rowIndex) => ( -
+
+ {set.frames?.map((row, rowIndex) => (
-
- ))} -
- + ))}
+ {set.animation && ( +
+ Animation +
+ )}
))} diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss index ded383548..d10b30ad7 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss @@ -29,7 +29,7 @@ display: flex; flex-direction: column; gap: 2rem; - padding: 2rem 0; + padding: 2rem; } .block { @@ -73,6 +73,9 @@ display: flex; flex-direction: column; gap: 1rem; + justify-content: space-between; + justify-items: center; + align-items: center; } .frameRow { @@ -102,11 +105,15 @@ object-position: center; } -.animateButton { - width: 100%; - height: 100%; +.animationContainer { border-radius: 8px; + overflow: hidden; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); + aspect-ratio: 16 / 9; + min-height: 300px; + display: flex; + justify-content: center; + align-items: center; } @media (max-width: breakpoint(md)) { diff --git a/frontend-next-migration/tsconfig.json b/frontend-next-migration/tsconfig.json index b7f166da3..7c7498ef3 100644 --- a/frontend-next-migration/tsconfig.json +++ b/frontend-next-migration/tsconfig.json @@ -15,6 +15,7 @@ ], "allowJs": true, "skipLibCheck": true, + "ignoreDeprecations": "6.0", "strict": true, "noEmit": true, "esModuleInterop": true, From 3b99d42a289102b14a7be2a8f7cc2e7caf41f398 Mon Sep 17 00:00:00 2001 From: eleino Date: Tue, 14 Jul 2026 19:03:38 +0300 Subject: [PATCH 6/9] updates to styles, smooth scrolling to hashtag element --- .../src/app/_styles/index.scss | 3 + .../ui/NavigateGalleryTabs.tsx | 2 + .../ui/PictureGalleryPage.module.scss | 49 --------------- .../ui/PictureGalleryPage.tsx | 24 ++++++- .../ui/TabNavigation.module.scss | 38 +++++++++--- .../ui/TabNavigation/ui/TabNavigation.tsx | 2 +- .../ui/SectionGalleryV2/SectionGallery.tsx | 9 +-- .../SectionGallery2.module.scss | 62 +++++++------------ 8 files changed, 85 insertions(+), 104 deletions(-) diff --git a/frontend-next-migration/src/app/_styles/index.scss b/frontend-next-migration/src/app/_styles/index.scss index 50da966d4..deffdcd0d 100644 --- a/frontend-next-migration/src/app/_styles/index.scss +++ b/frontend-next-migration/src/app/_styles/index.scss @@ -18,6 +18,9 @@ overflow-x: hidden; } } +html { + scroll-behavior: smooth; +} body { font: 16px/24px; diff --git a/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx b/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx index 169f2e95a..f407f7537 100644 --- a/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx +++ b/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx @@ -37,6 +37,8 @@ export const NavigateGalleryTabs = ({ border: `2px solid`, borderColor: categoryColors[index % categoryColors.length]?.tabColor || categoryColors[0].tabColor, + color: + categoryColors[index % categoryColors.length]?.tabColor || categoryColors[0].tabColor, })); const onActiveTabChange = (tab: string) => { diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss index 80eb18d68..a048b559f 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss @@ -15,28 +15,13 @@ width: 60%; } } -.LeftSidebar{ - margin-top: 6rem; -} -.Maincontainer{ - background-color: white !important; -} .Container{ flex-grow: 1; border-radius: var(--border-radius-custom); // background-color: var(--transparent-bg-dark); //margin-top: 10%; - padding-bottom: 40px; - - .SocialsText { - width: 85%; - margin: auto; - text-align: center; - } - - display: flex; flex-direction: column; gap: 20px; @@ -75,31 +60,10 @@ } @media (min-width: breakpoint(md)) { - .Container { - //margin-top: 10vh; - - .SocialsText { - width: 75%; - } - } - .InfoText { width: 75%; font: var(--font-dm-m); } - -} - -.videoWrapper{ - padding: 0 40px; - margin-bottom: 20px; -} - -.videoWrapper>div { - margin-left: auto; - margin-right: auto; - max-width: 700px; - border-radius: var(--border-radius-custom); } .TitleBar { @@ -123,16 +87,3 @@ margin-inline: 0; } } - - - -@media (max-width: breakpoint(lg)) { - .mainTitle{ - text-align: center; - font: var(--font-sw-xxl); - } - .Maincontainer{ - width: 100%; - } - -} \ No newline at end of file diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx index df667b4a3..115b72f64 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx @@ -1,5 +1,5 @@ 'use client'; -import React, { useState, useMemo } from 'react'; +import React, { useState, useMemo, useEffect } from 'react'; import { AnimationGallerySection } from '@/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery'; import { getLanguageCode, @@ -113,6 +113,28 @@ const PictureGalleryPage = () => { }); }, [searchQuery, categoryFilteredImages]); + // useEffect for smooth scrolling to anchor when hash changes or page loads with hash + useEffect(() => { + if (isLoading || error || filteredImages.length === 0) return; + + const scrollToHash = () => { + const anchorId = window.location.hash.slice(1); + if (!anchorId) return; + + const element = document.getElementById(anchorId.toLowerCase()); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } + }; + + scrollToHash(); + window.addEventListener('hashchange', scrollToHash); + + return () => { + window.removeEventListener('hashchange', scrollToHash); + }; + }, [isLoading, error, filteredImages]); + if (isLoading) { return (
diff --git a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss index e4fc543a1..8e796d8b0 100644 --- a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss +++ b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss @@ -1,5 +1,10 @@ .tabNavigation { display: flex; + background-color: var(--base-card-background); + box-shadow: 0.3rem 0.3rem black; + border: 2px solid black; + border-radius: var(--border-radius-figma); + flex-direction: column; } .tabsContainer { @@ -9,28 +14,41 @@ align-items: center; width: 100%; flex-wrap: wrap; - background-color: var(--base-card-background); - border-radius: var(--border-radius-figmadesktop); - + gap: 0.5rem; + @media (max-width: breakpoint(md)) { + padding: 1rem; + } } .tab { - padding: 8px; - padding-inline: 60px; + padding: 12px; min-width: 150px; - height: 40px; + max-width: 200px; + height: 50px; display: flex; + flex: 1 1 0; justify-content: center; align-items: center; text-align: center; - background-color: var(--base-card-background); color: var(--primary-color); - font: var(--font-dm-bold-m); + font: var(--font-dm-bold-l); cursor: pointer; transition: background-color 0.3s ease, color 0.3s ease; - border-radius: var(--border-radius-figmadesktop); + border-radius: var(--border-radius-figma); - @media (max-width: breakpoint(sm)) { + @media (max-width: breakpoint(md)) { border-radius: var(--border-radius-figma); + font: var(--font-dm-bold-m); } +} + +.tab:hover { + text-decoration: underline; + outline: 2px solid black; +} + +.activeTab { + outline: 2px solid black; + color: black; + background-color: var(--primary-color); } \ No newline at end of file diff --git a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx index c2f18a479..6b5d7541b 100644 --- a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx +++ b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx @@ -31,7 +31,7 @@ export const TabNavigation = ({ {tabs.map((tab) => (

{set.title}

{set.author}

-

{set.description}

-
+
+
+

{set.description}

+
{set.frames?.map((row, rowIndex) => ( @@ -63,8 +65,7 @@ export const AnimationGallerySection = ({ animations, backgroundColor }: Animati Animation
diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss index d10b30ad7..b3a377c76 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss @@ -1,42 +1,15 @@ -.buttonContainer { - text-align: center; -} - -.SeeMore { - margin-top: 3rem; - opacity: 0; - filter: blur(5px); - transform: scale(0.9) rotate(-5deg); - background-color: rgba(0, 0, 0, 0); - transition: opacity .5s ease-out, filter .5s ease-out, transform .5s ease-out, background-color 1.5s ease-out; -} - -.SeeMore.inView { - opacity: 1; - filter: blur(0); - background-color: rgba(0, 0, 0, 0.7); - transform: scale(1) rotate(0deg); -} - -.SeeMore:hover { - filter: blur(0); - background-color: rgba(0, 0, 0, 0.9); - transform: scale(1.05) rotate(0deg); - transition: filter 0.3s ease, background-color 0.3s ease, transform 0.3s ease; -} - .AnimationGallerySection { display: flex; flex-direction: column; gap: 2rem; padding: 2rem; + } .block { display: flex; flex-direction: column; align-items: start; - gap: 2rem; background-color: #1E3544; box-shadow: 0.3rem 0.3rem black; border: 2px solid black; @@ -76,6 +49,7 @@ justify-content: space-between; justify-items: center; align-items: center; + width: 100%; } .frameRow { @@ -86,14 +60,14 @@ gap: 1rem; } -.imageWrapper, -.buttonWrapper { +.imageWrapper { position: relative; border-radius: 8px; overflow: hidden; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); flex: 1 1 0; aspect-ratio: 16 / 9; + width: 300px; min-height: 180px; } @@ -107,13 +81,24 @@ .animationContainer { border-radius: 8px; + position: relative; overflow: hidden; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); aspect-ratio: 16 / 9; - min-height: 300px; + width: 500px; + height: 300px; display: flex; justify-content: center; align-items: center; + flex: 1 1 0; +} + +.animationImage { + width: 100%; + height: 100%; + display: block; + object-fit: contain; + object-position: center; } @media (max-width: breakpoint(md)) { @@ -131,15 +116,19 @@ .imageWrapper { width: 100%; - flex: 0 0 auto; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; aspect-ratio: auto; - min-height: 0; - height: clamp(280px, 55vh, 560px); + height: auto; } .frameImage { object-fit: contain; object-position: center; + width: 100%; + height: 100%; } .buttonWrapper { @@ -149,11 +138,6 @@ min-height: 0; } - .animateButton { - width: 100%; - height: clamp(120px, 18vh, 180px); - } - .textBlock { text-align: center; } .author { text-align: center; } .description { text-align: start; } From cacbfb0e58137a9e451bef0b3ffc4708fe4a12f4 Mon Sep 17 00:00:00 2001 From: eleino Date: Wed, 15 Jul 2026 18:12:25 +0300 Subject: [PATCH 7/9] added gallery view for no results, moved filters into a dedicated hook, style fixes --- .../src/features/NavigateGalleryTabs/index.ts | 1 - .../model/useFilterPhotoObjects.ts | 76 +++++++++++ .../ui/NavigateGalleryTabs.tsx | 16 ++- .../ui/PictureGalleryPage.module.scss | 12 +- .../ui/PictureGalleryPage.tsx | 123 ++++-------------- .../heros/people-pleaser/miellyttaja.png | Bin 0 -> 197219 bytes .../i18n/locales/en/picture-galleries.json | 4 +- .../i18n/locales/fi/picture-galleries.json | 4 +- .../ui/TabNavigation/ui/TabNavigation.tsx | 16 +-- .../ui/SectionGalleryV2/SectionGallery.tsx | 45 ++++--- .../SectionGallery2.module.scss | 72 ++++++++-- 11 files changed, 227 insertions(+), 142 deletions(-) delete mode 100644 frontend-next-migration/src/features/NavigateGalleryTabs/index.ts create mode 100644 frontend-next-migration/src/preparedPages/PictureGalleryPages/model/useFilterPhotoObjects.ts rename frontend-next-migration/src/{features/NavigateGalleryTabs => preparedPages/PictureGalleryPages}/ui/NavigateGalleryTabs.tsx (83%) create mode 100644 frontend-next-migration/src/shared/assets/images/heros/people-pleaser/miellyttaja.png diff --git a/frontend-next-migration/src/features/NavigateGalleryTabs/index.ts b/frontend-next-migration/src/features/NavigateGalleryTabs/index.ts deleted file mode 100644 index 6497f4fa4..000000000 --- a/frontend-next-migration/src/features/NavigateGalleryTabs/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { NavigateGalleryTabs } from './ui/NavigateGalleryTabs'; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/model/useFilterPhotoObjects.ts b/frontend-next-migration/src/preparedPages/PictureGalleryPages/model/useFilterPhotoObjects.ts new file mode 100644 index 000000000..46d3245b2 --- /dev/null +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/model/useFilterPhotoObjects.ts @@ -0,0 +1,76 @@ +import { useMemo, useState } from 'react'; +import { PhotoCategory, PhotoObject } from '@/entities/Gallery'; +import { useClientTranslation } from '@/shared/i18n'; + +export const useFilterPhotoObjects = (photoObjects: PhotoObject[]) => { + const [searchQuery, setSearchQuery] = useState(''); + const { t } = useClientTranslation('picture-galleries'); + const [currentCategory, setCurrentCategory] = useState({ + id: 'all-categories', + name: t('all-categories') ?? 'All', + }); + const [sortBy, setSortBy] = useState<'date_asc' | 'date_desc' | 'title'>('date_desc'); + const [selectedAuthors, setSelectedAuthors] = useState([]); + + const filteredImages: PhotoObject[] = useMemo(() => { + let filtered = photoObjects; + + // filter by search query + if (searchQuery.trim() !== '') { + const query = searchQuery.trim().toLowerCase(); + filtered = filtered.filter( + (photo) => + photo.title?.toLowerCase().includes(query) || + photo.author?.toLowerCase().includes(query) || + photo.description?.toLowerCase().includes(query), + ); + } + + // filter by category + if (currentCategory && currentCategory.id !== 'all-categories') { + filtered = filtered.filter( + (photo) => photo.category && photo.category.id === currentCategory.id, + ); + } + + // filter by selected authors + if (selectedAuthors.length > 0) { + filtered = filtered.filter( + (photo) => photo.author && selectedAuthors.includes(photo.author), + ); + } + + // sort the filtered images + return [...filtered].sort((a, b) => { + switch (sortBy) { + case 'date_asc': + return new Date(a.date_created).getTime() - new Date(b.date_created).getTime(); + + case 'date_desc': + return new Date(b.date_created).getTime() - new Date(a.date_created).getTime(); + + case 'title': + return a.title?.localeCompare(b.title ? b.title : '') || 0; + + default: + return 0; + } + }); + }, [photoObjects, currentCategory, searchQuery, selectedAuthors, sortBy]); + + return { + filteredImages, + filters: { + searchQuery, + currentCategory, + sortBy, + selectedAuthors, + }, + setFilters: { + setSearchQuery, + setCurrentCategory, + setSortBy, + setSelectedAuthors, + }, + }; +}; diff --git a/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx similarity index 83% rename from frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx rename to frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx index f407f7537..86683771c 100644 --- a/frontend-next-migration/src/features/NavigateGalleryTabs/ui/NavigateGalleryTabs.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx @@ -18,8 +18,8 @@ export const NavigateGalleryTabs = ({ }: NavigateGalleryTabsProps) => { const { isMobileSize } = useSizes(); const currentCategoryNumber = useMemo( - () => categories?.findIndex((category) => category.name === currentCategory.name), - [categories, currentCategory.name], + () => categories?.findIndex((category) => category.id === currentCategory.id), + [categories, currentCategory.id], ); const categoryColors = [ { tabColor: '#97C459', sectionBG: '#527259' }, @@ -42,10 +42,10 @@ export const NavigateGalleryTabs = ({ })); const onActiveTabChange = (tab: string) => { - const selectedCategory = categories.find((category) => category.name === tab); + const selectedCategory = categories.find((category) => category.id === tab); if (selectedCategory) { const selectedCategoryNumber = categories.findIndex( - (category) => category.name === selectedCategory.name, + (category) => category.id === selectedCategory.id, ); const sectionBGColor = categoryColors[selectedCategoryNumber % categoryColors.length]?.sectionBG || @@ -54,12 +54,16 @@ export const NavigateGalleryTabs = ({ setCurrentCategory?.(selectedCategory); } }; + const tabs = categories.map((category) => ({ + id: category.id, + label: (category.name || category.id).charAt(0).toUpperCase(), + })); return ( category.name || category.id)} + tabs={tabs} tabsTitle="Categories" - activeTab={currentCategory.name || currentCategory.id} + activeTab={currentCategory.id} onTabClick={onActiveTabChange} tabStylesList={isMobileSize ? mobileTabStylesList : undefined} activeTabStyles={activeTabStyles} diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss index a048b559f..d4132bfce 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss @@ -24,7 +24,7 @@ padding-bottom: 40px; display: flex; flex-direction: column; - gap: 20px; + gap: 0.25rem; } .Header{ @@ -32,7 +32,7 @@ box-shadow: 0.3rem 0.3rem black; border: 2px solid black; border-radius: 5px; - margin-bottom: 20px; + margin-bottom: 2rem; padding: 20px; margin-inline:0; } @@ -47,7 +47,7 @@ margin-top: 10px; display:inline; font: var(--font-dm-m); - color: #faf9f6c0; + color: #faf9f6; } @@ -70,7 +70,11 @@ display: flex; justify-content: space-between; align-items: center; - margin-inline: 1rem; + margin-bottom: 2rem; + @media (max-width: breakpoint(lg)) { + flex-direction: column; + gap: 1rem; + } } .SearchBarDesktop { diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx index 115b72f64..3c3480d28 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx @@ -1,12 +1,7 @@ 'use client'; import React, { useState, useMemo, useEffect } from 'react'; import { AnimationGallerySection } from '@/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery'; -import { - getLanguageCode, - PhotoCategory, - PhotoObject, - useGetDirectusGalleryImages, -} from '@/entities/Gallery'; +import { getLanguageCode, PhotoCategory, useGetDirectusGalleryImages } from '@/entities/Gallery'; import { Container } from '@/shared/ui/Container'; import cls from './PictureGalleryPage.module.scss'; import { useClientTranslation } from '@/shared/i18n'; @@ -17,8 +12,9 @@ import { classNames } from '@/shared/lib/classNames/classNames'; // import buttonImg from '@/shared/assets/images/gallery/Frame 526.png'; // import { SectionGalleryV2 } from '@/widgets/SectionGallery'; import { useParams } from 'next/navigation'; +import { useFilterPhotoObjects } from '../model/useFilterPhotoObjects'; +import { NavigateGalleryTabs } from './NavigateGalleryTabs'; // import { useGetDirectusGalleryImages, getLanguageCode, getCategoryTranslation, } from '@/entities/Gallery'; -import { NavigateGalleryTabs } from '@/features/NavigateGalleryTabs'; export interface Props { title: string; @@ -27,59 +23,24 @@ export interface Props { socialMediaLinks: string[]; videoLink: string; } -//This may be useful later -/* const PictureGalleryPage = (props: Props) => { - const { socialMediaLinks } = props; - const params = useParams(); - const lng = params.lng as string; - const category = params.category as string; - const language = getLanguageCode(lng); - const { photoObjects, isLoading } = useGetDirectusGalleryImages(language); - const [filteredImages, setFilteredImages] = useState(photoObjects); - const allCategory = lng === 'en' ? 'all' : 'kaikki'; - - useEffect(() => { - if (!category || category === allCategory) { - setFilteredImages(photoObjects); - } else { - setFilteredImages( - photoObjects.filter( - (photo) => - getCategoryTranslation(photo.category.translations, language) === category, - ), - ); - } - }, [photoObjects, category]); - - if (isLoading)

Loading...

; - */ const PictureGalleryPage = () => { const { t } = useClientTranslation('picture-galleries'); - const { isMobileSize, isDesktopSize, isWidescreenSize } = useSizes(); - const [searchQuery, setSearchQuery] = useState(''); - const [currentCategory, setCurrentCategory] = useState({ - id: 'all-categories', - name: t('all-categories') ?? 'All', - }); + const { isDesktopSize, isWidescreenSize } = useSizes(); + const isBigDevice = isDesktopSize || isWidescreenSize; const [sectionBG, setSectionBG] = useState('#527259'); const params = useParams(); const lng = params.lng as string; - // const categorySlug = params.category as string | undefined; - const languageCode = getLanguageCode(lng); + const { photoObjects, categories, isLoading, error } = useGetDirectusGalleryImages(languageCode); - const isBigDevice = isDesktopSize || isWidescreenSize; - - // figma shows the text should be present even on mobile, so this boolean will become unnecessary - const showCreativity = useMemo( - () => !isMobileSize && searchQuery.length === 0, - [isMobileSize, searchQuery], - ); + // filters + const { filteredImages, filters, setFilters } = useFilterPhotoObjects(photoObjects); + // add "all categories" to categories const allCategories: PhotoCategory[] = useMemo(() => { if (!categories) return []; return [ @@ -91,28 +52,6 @@ const PictureGalleryPage = () => { ]; }, [categories, t]); - // filter images by category from URL params - const categoryFilteredImages: PhotoObject[] = useMemo(() => { - if (!photoObjects) return []; - if (!currentCategory || currentCategory.id === 'all-categories') { - return photoObjects; - } - - return photoObjects.filter((photo) => { - if (!photo.category) return false; - return photo.category.name === currentCategory.name; - }); - }, [photoObjects, currentCategory, languageCode]); - - const filteredImages: PhotoObject[] = useMemo(() => { - const query = searchQuery.trim().toLowerCase(); - if (!query) return categoryFilteredImages; - return categoryFilteredImages.filter((photo) => { - const fields = [photo.title, photo.author, photo.description]; - return fields.some((find) => (find || '').toLowerCase().includes(query)); - }); - }, [searchQuery, categoryFilteredImages]); - // useEffect for smooth scrolling to anchor when hash changes or page loads with hash useEffect(() => { if (isLoading || error || filteredImages.length === 0) return; @@ -158,37 +97,29 @@ const PictureGalleryPage = () => { return (
- {isBigDevice ? ( -
- - -
- ) : ( +
+ - )} - {showCreativity && ( -
-

{t('picture-galleries')}

-

{t('info-text')}

-
- )} +
+ +
+

{t('picture-galleries')}

+

{t('info-text')}

+
+ 4G#7q(~JJk)j9* z5J04fG?5YrRceru03mtf@4lb!`L6f>cdpDeXG&(y%-Lt1wb$M!$;!frjah&h006L= z7#mmv05sGh4SHa(JO)dXh zuvv6~b=v>C{eL|aKs}Yg0HC8@sjRA|41DuHcm4Oob8r6VPTAD*zlDZ+Uz-1}w7#Z6 zE&cDmRFswfomIcAnkV+Rky;%x%EUm|Hq3eJ?Aa#;6Bsrg1_S4Ru2h?=_M0oHd|$J( z;dgkkTDs|;H(On&>Ni#TXEZ*_d3|chhYlP(@~oOZgO3^?0Gm6n_V!9nHo6P)FUvH6 znx$ICUrbn!%uU?if4Zx+KON!efjM0wB+q`{-wN9Ke5a+Rc4IZPPSexV-NT)_kXE5O z=^|R;2kWC{M*m+GmV)D+vi$dmzQ;yqB#w||i+I%EvAI$aEob{yKi&U*?$UO;GwqLm z)o9_9E2j)LUtY6o?iqf@7M`k;J|);r|K?u}ouTK^T4+i161of>g|;JLM6~9O4+IeZ zUZT~|LHroSLiAYBM}Ham4Ah_rLDZt<(8=g5^i*`WpY(x1v`9T|`2XHX(hdYeu%LH= zFb4c+TJIHr+5#X~9rV5b_|kFZ?Cw7%y(dINYwZHK(vAQYqTk38od|;S$F|Ue_@*z9fTgq+sD$i`haN&1z8JdGg{xR zSH&%KO;_-13}VS89J}&dGR0%PkKcC@Bb|8Q~lpY_tPr6+7GL@(N-3uTykn` zrBH;3Hoc5a>d=^<&CPdp5c}x1Xwh@W+aPTEh!K+ZPbER5vP@L`Umf-Y7VAk*)kP?^ zXb7FNH*W#`gEE^OkOBkRen@FSCfbsw`0+z}v$ZC38eRn-e1upeuSx_1d1ufZc79g6 z>kwkmO73%P`7^5j|9h#u6cfB4UOh!N?|0$-(2au{CgiSo zf+ZqSX7P8K3#Hxz^PZ;EDE-|3F=0`s#&fVD|Cgyl(Yr;q8J`&BR8NMYM;yx0#f>DO zQgbPbb?bv$a*<#h7YOyrA?lTTy6;3A9M~_a`%w<_M4;J2T^elt8n_AFlG-3rJ$&xZ-(LjbbQglXy~Uf zic}Lvw2at%th;)5l~5l2g5_P@8{sw$1*O7;k}ouW6*A7=JKT@*PqA@*w-{gPSb4Y} z$W>PV4>~$-YqV|LLtLUod06jbwsvUuD|j1=M^dYH?tOD+p1P4>FRAc~PU*s1iUz(f zy3O{Xl9E2Der~y#%(b|_#*_#@hah#n41TI&n+_+-F5DOb{!n5G0=u6fw|43m>Phu} z+e`5Ht+Nr8)8k8ftg57)kk?v%HV3T#Aa?$|#*Iv9%#h1i)l=metHah=mRZl_y;)$P z+D)|J9`@=C$=>JBoDx4*fHhKNmQL-5_&gR!N<=5>Ud@n?q3rHCQoy_v(!f{JDKKM? zfSV*AuaO(C9MwkLG*qvD@hgaLrD1QO|P>P zM`Ut6tCyH=!Syaol1qqnD7u}>H(?_EV(`AZe2BP2pQcXHa~%4En zmOb|z;kvz$6R+=MssGOgu-m|0iS7q>6meg zyn-ZT!DQ6F7~HQ`B6H&5igq(gFNe>CPw+E7(ns%-vhZD~XXidr&iBJ1eksJZ`mDLL zWaA@I<9D!gZ&IKYzfSybG!=ehJddXRhwOte%TIN;1vd4M(Co)i#hF`0l-mirFzzOd1Qu9cX6|Y<3}f z!GJwJ$k@_V!~X!fZ!2d=T*Hz|mmO8hg17vkD|E02kz=bW^GxwM1GJ#__1Y$alZ21<`?xanl^t`g9? zM`#gw7=81}$WBZ+!|b|Iz#2TAm<&Op-1JGGui<%rz3J|CA z7(53+)WMxUrG^P_FV+T!J`bgQbhn4md`CI&z>mB;jtp!%Ya$L?wSN2u$gR>Ev<;yZ zla`LYbel|)&Z5dq2HqI@#3GWKm#{A1G+sfsWzl2*0cjA3VXt#h&8tRNsENil2!0o#z$G-0bljrr3dsJ z3n~LB%z&LPQE?I2i9YTETzFYL0}!wOvDolAq-(*g*zJf#*U_P#`Z|1oLEFD)=v@Fz zM_9zo_A%NRA8N!Oxsb7y1{d?&Ms?T03qHWF-2b|vt>wq@KM>`|>?w8tc;x}XemZDb zGk;5Q4qAu+EvqU!6vVsQ;)E}~#CI1uREI-sPcg^A8`Gw7f5zgDlQG`B=2bR`^T={c zm=~?o+(Pyr#T-mHgL*3quQ+JY1r@-^49$E@{EZ?zwg2cbRw zQFI8O&CuY-ewP7$2P*hi9H3P=P_~0sR@F_pgND?CwiMqnY4=_%YI?3y|4oBPhabs< z#;wpJzwfr*$XHAiZ`_dhQK2u&#%Td%P=6MT@cp|NFnmaFYBHMeHW$-;&|NACNw-Bmsq^s=Pla3&* zEx@Y6$-B!$jx4B#ATYH-Do1J1^%wb}>#?D)4PZkK1cStJRCl{Zye?LAsQ|NTp8E>O z3x`Ss@+2jKJV2ZK0t#0Cf4XAY)fTqX1S7fsaog8{^j;8k!2|tOOz1rB?=J0Ujz!gP zJV?%nq>9%T!x3sR&sG!vW+>0d*fM}B;=*$s{J3g;U7L(jg1CL8^_6MhwUr+pv20&U z6r45hIJ!7}(oNiZjg&hmQW+E{L($lj!vlDxkE)?2z&bLbrI(({9(3~3z!aCgHHvgO zu|3>C0>{yLwkrl7(>%2tnGs}XI)!s=)Vsd^Kp$D}1<-c&h}O|OKl?1R(?|@p`*1Im zM59U^8#jW)Y6QHW0?hWd_CPKF4TUxTLBX)-ubfx8WTS~_OA+;cn7O68YjNR`zzE6u zHDN>2^|PfG>Q)|9dKg-IJu=7P{yF|C+cbNxBB`PMUNgrAdSHLw@+;8`*hp4LE0XB) zqOffBIGr-N^^&rg`;67h7b5(z2KnOUqlrr?Ak8E6_BZ7nISuv7sfDZn@3?8^$BBwPeu;vf6 zn@Iz!253>4M<`WOS%v>ODhOzJihGKFpwqP1QKVS|M$|6fK&e9|YVbE&Z_`WbM zGB>=#Ja4EdnOieUU{e9Rtz$v&FjIyq6__-w4t4~?igEv4zdieF;j zcOrpck^GsxG7kia*A|p|`QX;>iw>d8h~Ym;b?FWL0l0=OxI@yKe_?lj_i9zyAE0j^rX`Cy>gQXVR`LmBzQ z!!h%s6NQab_Qsh72mSQJ5*j=L@(;TIo%<<71+(OqK%8Z)CT-rT-spu7ffOaj5~HDuizAX{*wh)i zNQ3tM7X{eX;?=oGHsZ4dREup7=6DQ4d*A#AU!y1uOdYTLMrv4CHE=my<9Vp~aV$`l zoDCw&cTFJ!=cxv(^dI?Zxi*Xju%>=PIo>&aB7@t}S$1Avcl{-iLwjdUl=HimG_mo1 z7s*QcEP(D%yJ243ZVI_5&?*iif~J4Fwc= zA6E#);|blM**2v+hhu^1PJTAO>i2Iuf#-L7xYMKM$d?*UOwp8cLI3?3S z`ExZ;#67vyy6XGTotw+uHCNLtLER5s6;y07*Q<{za{~Qyl_T=Qk2GD#LUHyWCXiMp z6RrhaC+Wu~JGobOJ-boVt7{@RFy@=zGa8X0e^Tyx zJl?oT{b9UCYxG^C-i&ZQcC{^zSt4k$W%3c?n))(%KPH64CG7| z;GNTrt0f93z~c3<#JX>DO5|THrh6Dl>{dx||IWPO#|JeWp2_6#oK1@7J2F2btBBNB zJVW&0-Sw50JPtG=KWJ6lmYw9&V!O6}~K@iF@<4(OZfk!cP)UI&7@(%!csZ)c^_95d>H zTs1g)Xj^e2PB5mu0(&YE%s!ifsrNr~C`w2hJ@eCzz1O{0_JrhAz=X+Z)O22^ha6iR+%hs6<9 za7MD9d>aIy@(M<%XA~}7A-!9(S+WYINs)v5&~A$LGy9+i1&Hjwp-kWT*295`amU&& zu-D4)p38hnoU1pyMKW}mD{pYQo=L!ne6a&q{pJu+MJU6v0ERaeOmswB<}c4*mIu$A z9E--CWMQVke*4(CEzTEO)Sh9!zMRDOHTk6aMh1@I=Xn@=80sx88R$lzfClb;(7Ae( zb$(3>e!hQKR{Zq*IE0CGZNYm4Fx&ATSDn{u1$KsdtY5wL{a1Nsx?>7a@;k`Dh!vAj zzD!#aD^q=hGH54o>t#7lNq!XjhEtUq_%?O({NqjI5HQIwAQuD&&VECZ2Ctgda6NV{ z)SFEV7wo#@`r58uSVEOXojxCtVhdhmjym7J4UaB=a@&#IpM<#Q3@=@byC*bZ^Z@qq z1kYbn=E;~iviTD&UUj6Sk>j=$tjh%vgzR1w`o2K_f}?N`EfNA@prnhFr0`UsZsDjm z)hPTQ$++AKr2TL%vi4f+-9l}9P$*O2D>Txf&0+htXouP7{W}}S!O}k_t~NBMM7UI3 zmd`;#``8pS&37>Aii^qn#vRcEy*J;nWX%UTe)3Fr@Yj!G+wf(ZNp9A$l)sZKT-p3v zvA6M)6g+!R$C|I$CL-!`P*`))GH=Efl`f_RerP4#e6n+E#0xrj*-AIBR&8nPVa=J6 zjc8<=l?W&nAt+RjQ0jq{>YjtmKXS-z6FM?0tByy( zYl7e&1?d%0SnVWXeV!P>!XIfYg`!a{h#_%eP;8{P^K=0bW&iZIuq+%sMnsYrnpXh# zae08H`RivOLerdm(LU~PhJ!G;Mz&!m~y3+wSV$kFJZBdkddmm^gQ@JTYYk0+{86>Djdjs!_WHmX(g`?i`_qbRAgU|!RrnY4yj?2p#7zgq9q-5e{Q}+t zO5`hiSi&zQ_V*GN5_0!?`1)B2Lj`b&bqTyNw@w0?U2dirfe2z>T`^dm68&t3q=Bm^ zHcWq*FWdLpsTT9eGu?hT8pz+ezY)8jBnIQ^Z_XfT;-)5)I(atkPG0@QFA!{-G9hw! zaOrR{$Tk9Hk_SuUQxAO|hK;uuW&=4bjGONz>0=6LRIkFJY$ zS3@f0-NaSObD+tozke=mC;vxb1>*!kq*=WqW}8E-|J`HliWG#?J( z`I^{zP{jymjaEiO#k}vsDt#e|YcKpW{WT4)es=+iF^qrDF$a#03sAD61JNGW3M+D7wKea{Deu|nOm^T zE%r{|yvc<7rg9{koW=z;^wT>x{*O}8p-aU=Jp2AUC1d(%_d`Ja6%3mh=Bj7&{f+Lm zYWAWs?MP>?`8dg;VP4a>4ykjFNENZ+rDP_mi|C#e5zqt5Ji|YZd3|$# zcB}H^(PWo`82QVf&Wm4vmf0VbWNyWt@E~suNYDnkeifD7i6ND$(!OYV?=O?z2jC@*+VW{de=Ysu52$B>3RFrv7!vQ+O{TF-!XDuY7V+@&%O+4ssgmn zFn7%;15V-mlQ1QBLgx`2#~1kk>ElHIOvbht(V3XJ7lpjR0b>-ACas~NH%Za~Yv@!% zDa);~pxzWxT>b@TK+T=)^}vXQIHek@tJWf*E=CM3Fe1!(3`7m){E9NuIyQfrt}FfX zZ-&(l*J?!Eaj*^7tcE@p4_(keEu>@a+Fac@O=e~Yz9eOs?AiA z;V+A~1pYCP){i==c($8VwX2D8C6!ZyBvCSJuZFzFAmZkOlXHKC?IRXh8ua%C>2aq3 z(Win-%uwt1iLSZ=pDlXM0IasQ-}=F z!S1$VZW$8)1Y3hy9^52S6)BOApo=Jhe!ydjKdvOK>7e+2_@;0}1F2)B-#I@WJePFc zU(xwXK+Qb!yzAog%$aw#K;fzGt&oCyz~$>tjhb$GKcjjrwcH zVE+yBpDsAwV^pH6KAxx^>O2w0sM7nk5MoL&u82|e>CuxC>se|YE&H~h{gBT3V<{K7 zioN4z)Ba;y2Iv%Hbe=*{Lomug%e48Jsh2qGxT?mBpXc$jP(+D}A zh>b=i7HN~kgvf5`5R@NTL{!QQmAkHei9CBvN>pz<@NwzUneL}TCJEIKAHG*aq{++g z*`TqFr||X&ib#v7h2Sw&MhRonhzH_V2MI1Vhmc1G6vYgdg1rmXWowuXM0m4#)B*G1 zqG_CWy2Cc8wiXj!%;zoXULYjn)nbTVi4oOsQfxH~aK7w=HIb82Y&JV5=X0#C=STxJ zLA0H#^(=bG29MBv^Ds@K*InSl*@ZlD#Xa$%bPT{Mb_M`v>Q`E%C*TqY)s1hKG0s( zMr{3U;i%gaKdc>QBTQY@^`t~F$#1uViO~x|o!9QV=c>ni{`J|UwD?C!YabtC2iEmG zzjD#=X?<|{ofjfk_!`s;>P$!nxVJ`|q_n{IFxFwop0d`(w!qjMfyW+l!U2_|IPskE zL}=yjQ_dAKFLJ-u%E-}F$6UT)zSDAk2>-Jsqi#-68hbgd>Q68b#!u8o`^)=1h_Z){ zE#K6ss;^@q>ki>%u;+HDl$gEz1Fy94Otng{VeTI-T8Yz~0ve%r-j>%n<&8>WxTdM>G2(JLH-Wp$W(li z&ef1*{Y1HJCeRR_p+-*F4a-_p8b5>fYkpHmfOGd=fm=g2WBJu4bGo^R z@>`N1hSvUwy)2`E9&R>4O>m}iRMHc|RP|AZu~rnj%bWa{(GDXSIL@BcGAjG+w%kbt zy|`!Kb9zti+K(ygc7RIGt??-HcU{!5G0R`3fL$Y!Vd-*)otpC>F#k|_Ht-akJG4Ww zOd-PO&49sQ-cTJq|91igR1?>r_0u`nZ6&y6?~Q1h`zB3JIkoxszQ zf84i~sZj6W^=jY42gwc8aC_`V|40;ze*jmY+dbr3MtI1}jRn~as;86Q;nCqX&j{lb zvP>9=^I0D6RN@V&ET$BUULeoSt?2iOd!y<-qrapG$nx4gNq<8VbW5r=aymxjRkdTT zSU?!Zu$=vyIq40G$J~eV+vrbp)$*mXDGw2Xv$2BhT*0@SH_Oa;+tk@$g+w|u0 zCgT)3V55G#EB}!eauWC!i0Hiv;!IEuyjqaV|(9a$+=F~j0Wp5Vs zZbzL*V!Kud3+nT!qRykAx_(*!^ID(3P;R^V`Bcz0qL@l2M1G`1V{`)dBKV!cLZ9~7 zVYt^X>6`kmjR4^1y9PjI6`mrRr72~k5c6%hTm^8pM>uDNSOkU`qXK4Nw7iEbv9E?| zGYI_-nY&DDY7Nn%{n3pNx8&6d|GE-LGaA~=I5LOUS{LC=4-^&MZ)KWCqZ~MM~a>q?DY?cA48~Dt#4XwObz9+LJQXk+dSn7|0%&_U$_CuQ+MhWp>>Hlb+hq ztjJk!l2)}P(v~pgha1_kFTp}`xl+rN7svg^;t|%(j{JZ&%Y*ekA3ao0S0BH zM@=PJ52P(b17_Wl@uaK!>nN-pLXG+T(V3Mn*kh_Hz3A=lh!-2{UZ%EO{xRdSrG|gF zxh$_fX`Q|MdtM!IljMJE4y#usSz=2sW|y??sD1_Zq*nYwr@BB4R|X$|PN)}j4aA!& z{z&DPFP|i5=^2v7wzad&eN8(>bpCBptc6b00o8-4x7mqIQjQS0m=Q^fI&z?n$B(uX zc;g(T*(K)AOoHjMAttRyoT?|UjmbCAQ4HViB@^_E)2;dtv9t8~ktU{T(jrS#o5q!w#r+ zGw#?lE?ls*vGr^#;VN0`u+3?LWNr-gz)%i8lP4D@IN^^S-$@4ZSFf%TbIYT$zWVD- z`Lj>H)H5If`i(S-#jW*!#fAX}!MV``oev9e>dzH#2-(a~IkR{yL;ob!usHh9kE++~t2v4)w27Q9WL1?x-J7f9p&y^ar7?vhdUnWoor)Ls zR@XC5XN5g=DI9d<5R%$hd`G~q=F2M`^h5pG2P}}UG45_vl?58r^G4+~`L#=t@W!g~>O$EspB|@7yRks{}%|jE21dZi^6gA{2zmM$(!y|DqxhERm@NI2|TH!+a z|JmtvTKt=yT{r}r?taU+iaE(p#!^*;q3T`kuB~TX2mE@$=90j-%1IRBa-;;O$|u8! zug{35PDzwN;NM^j)jv9P;zxYBbsR9*;pctys%qzs7!5er{M#hfs5u1U*P1kN6UnHO z9k-F;u)|raRYgEfT+usZE{Wvdki1Xh@Wiz}wpHQdQ2L8HNSY|tcN*AM0I+<=PPG)* zjNIq(I5u0*4XC6?T`C7>_?UNCG9Z;t3mr zDyQmkh=D?n{Z|^Zo5EvQLsNNp69yu%SHGHRmH!(ueO6bbo{}j}6GU2Io?hj0&pO@f zHvJ<1VIcb`;f2F46^c2jP-#hRwwZ#LV4oDa2f03HT&z1pi~G?n1Ax2>VhPWmteH~d zu#y{RSc#bvx}`Q0OMk)~L%K?W)*H@1{RfY5Bq5@xIN4FmrrnY`=*MOR6RNKcEvVT> zZLHM3OY~xsYEsa)5$huu2gYAKo1VswigvRpJq}x7z980Hl`qUuX|2 zgdY%l#lcjBUmzL(x&1lSk#d`XvMjXHsUP>((d{BC*9srv7uV6W_OxO0piq)sLe4BXH@>GTvPa7Xi{OLW+*N`J&SWiTg?}B( zH(HSvfhPOI3Y+{--riuE@RziMaCUEPHOfEmmhGCqZ3D})XgG2ogmk@4N=}9ALRf#Q>nsncnUSiU=}YC7aupLOrrvF zt1gK4wr|otWL57F&phh9KCv8y!xL__Hyi?xnC7b*gHkIRF3Zt^Bf#YFO1N_ znXLLyjB$+CqOY1Gs9(R<@Lx)*qqq?1^4J?E$28mu~NUL%4p5k*BY>H^%4VQaPnr2cPuKEw$+_qIj`Idw!6b=w+a6b|<9IQ9|- z(A31zCPVm_z&N>oshYzvSw?=;+yJ2M3|tt&OF4lI+=nml=AlTYR4M$nux9^B1bM*Z z7iHXS<;Zg+{s~#Jf0#0c`5W8td+r?v%0esZxr6A&&o;jYm!_u{vyk`d2A(b!`E1=; z*|nMcymPKz%}fhBd*rd}@9~^Zes=ewycEH9Du3BF9(i%;LB*cB&?;7Zo~k1tBKNh3 z{oKLqn!TBPV;RmHseFcGe3#c~IVDSe+rzUvug!Y*q4QN}Mw;^wyuSU|`={`^@9%?! zZ0$-tnZut3e*d;Tx-^uoNDK13VFo3&VK%twbKz@7uE9ix+StmDM(xPek`26!Hrn;S}J2RqXul&zlo~GS(4>(?O-z3z^ zG7d5S@={Mj>V~1B@G1rq5 zrB^Mvfu{L!S4+$vZbt|%J-OrxxP@WEXBqWh#Tqso^5KjWWSHClU4_O!;`Cnd#Z{C} z`rD;9IB@B+4bOyql^sNAxzRgc#-VBlfcvcYmy=gFoo5Y4_+~pCR8%7l!uDO)>><&u z(cunLQ~BBij=S(R(Rs%GvO2!j1*0`>i;M88>)|^$T$}D=!kK*&Yt?CP#$#AuV(yYg z+E1GK%m~X<{0g|@ycbJ-!-(w8mV|JDsxf&y_+@j?2c0Trk(H& za0E3?`tH6c(OgY@>)z8&R*jDoo{fO(;j0VVsdvg6sfm*cA+STPFY=GyF|O>Bmenb4 zuq_ri(Wrat#Gj?nzQfSocAu*%fyGh5f7VL72>xfgwRZGR zMzUf6ci1qAvEz|PtjthK#z*GY$Rc1^MA?l3sy=Ara%v+ARRkFYAJ7~x&&x0#N`eVh z#Kjh_O^)7^g`(aYr-!z?#fasV-NZDXg>UpR1Hs4h_J+&OECr|S^f>=H-q_WHde7T# zXOAWA?&GjuRy_hM$PK4Sh=Fstn_rl4iN-K+E>vYZ1Eg=x%H5!-(6cLUJ2T$+czoYi ztZ|lICUMUzWd23u{>-@VpftnIPVqI4V$JNK`B13@)z!^fi*o>V>Wp_TK!YHOg*eM zyzhjtYT4kAsL+Zn>r?0HLw4v5=pS99MB?3^L(445(yl-gS?fIwBSyTcvs18 zULIV_bDppBk4&rQPD2UyB@?L)&8+ao2ghf;FN-c6hZ5QxM$_DUwSdW1x4u1R{dh$x zg7I%3NZkv3crOW_2c|})4jz6#Ym@lB~NVZ4!}vfUm00 zjWtK(Vu%@VfTPT$iam)Mou9qXYi-G-c3=DY^LQp^&Rh4xYKkOq89piQj;)bn)=YwX zq3pAafnT2EV}Pc2>EpRMc+GDFJh%}1xPpzSig)z59`-#i_R+ogkms0}>-jM)7wl3` zs2SlU8qvT!0G1(A4sR}&uJe_JPieKnA05!_n9Te4iuumc6Wz4i73#-; zjv5!848H%mHx}9i91qe9*17mko}dl`hE1o>Tz>?Ix!*B^r-(@_qKsiXw9A6KKUNT# z7kG78xiQvE4eqZQf-uUG*;7>)!;Cr^WHd9m8P*vTR;{D#ES0tqb zH-GlRss>n>Kx<%ozHVjRk0l;LbhVONj%b0~&1Uq86|!NYd@G2}eq&K$K`UspL`zzFyvf3Kbep2_^$AXM@@S~l_8^FU`Ba^%dUibIve@}7)n0QX6{KDc}h16S(JNC?% z*XCmfrUqpIj*qHTgGnFZx+&4hsGCv5J2mYiToq7yewzGwiJF`k<)*YgdOLd84e}cn zesBebQ4tll?5KgFf3M?oQwmHG$Ej!du#_5~ydA%YBohh3Dw*s4TMPY(SVQ(5qm{(yqtPwcKmF%g;XkR>rc;9JDyso{fjQ zXqbAuoc`O}z@+x{_{#;s@9Kd)Ib;#1t`$LW?i~qL+I*nEl<~n)s%v`OsJAley6EO4>vvTU@9! z&+w_-?-K9raF_QvPSU>DDp_@4kQY#T*_20ud#T(Fns18kS87KVc~c%!!vj`L+H*ff z5d-S@vIyB>I3tRRh<{Bk7ZrUmjB^may$etBrtFU=7Ee7zSG8-GsBjzJRi>@Z87G*F zCcVtxjSepOd+wtZp--Uny{oKWocm@oduIW8c(__Ankd#$<)r=YeurIKq{4I2YfhO- z#KB9K5A`*vew}A@y`xlT(Cag+RVO)`}Wd-K&ni7YoRUSzc$n^drt@Mdzq`+=r zD%$dHo(r?C=9L$SBH1vTga3Wc;N@2uXEQpNJyyFkTSLhZPHDH{7eeL81j}*|xg;r- zpMRas9Um{ADY$wKet2sKTVTQXn(zOZA%a2q5rsWv8Q0>?ey}UX4@G%&QM5eP?NKED! zE&Rxf<~8HOOD~AhKv1(AOH|tFulYs4&M4hJRS*<`*k475CW2375QJB;SS|nFJwBV+ zXB8@E)5c>biY8}Xs(vAMonI%N(`B5#tT1=Y&07-EFC6A(hF7G)8m`t6O)#SE9naz> z)1`4raz%}XK_6hL;+M3B3{I!Mk|z2`E@@N?tLvHFV@2)(`bGN8wY@zMof528IK4|P z5xrK{qMG_m1gVM6T&Bj{2`Mp)CL9h7CK18(x!N&ulSu|n&GZ_2|3b{%HFK6+t4h_e z#ZQm#4vI)V7kiw;H|M(SUwEmp7RM^hc!Vy|=&^>{VVS)AO>EjWM( z3Q!6dH3Rs269<1DzxT3(NT+S{A72P8jOhq}x?4P10%23(lz;25WqC{*Q&p`5!S7k@ z+>Cqku+JlYxi}!@;vcQoi9TC+{dA@5hA-08mMo#BK^g^Qr7t{>K-bl3Y18oNW8;{g z+xwH1D~sCoKA$<-owq_QKmvs!nmG@L$ zPssw~LhiQtkG(Q4s7wGF&nfDB*UC(&^kNWTvyA#a;F~eLXWWq{>V#(7MRO=h96zHP zNJ+wrbC`2rlO!kQU9vpN5h-TGtH?ek6HPiO!j?R8GdQ+#=!O6j<*sAR{FAKH+o1*5y=kNtTndW=!}QH)Py{0>BB@xsP1&jAK8 zu;&twLBa5I7mGY!n{8OqlQo;T<7SWbEFs;?@817to ztCc&zb-l;5t$zS6GCqK^HG$kr-fIc6sQPTqD~N0S6z7{PR%hS}FnhwSw5%Lil_{I^lDtgf=OZfJ(9EQk( z9?>N!jDeh5B56!w16ZlHa^gBc&B$G{rABp-CM3uMi>O_ioy#6?*2^U#_PdZaD$Va; zwXP%fpc(_-beD&V%IzvHw6RF}ehjz= zF+rOfH+yDT&osmKd@qHt{BQxd3MU-~e-r7fgWq`H%DeY!Kn4rSbl6d8JM#KI2bHm? zua;N*91;&T`g_Ho0+fDviqbDx8qZFfktcaOp~~e;&U*(mG2?Bhq=a`xpuE~6U#ajaI>k1yP>0xJHblt-pK%m?q5O69jl8DR+BHs&zg{6NMe}(h z`nS7*o%va<;)W|XIHlr+A9&;PGg1974QD)0A>%b0b!%Uq7r(88)~ws&Mgk?uY-_li zLIh|*zTWD+-`9Tk!QNbW`Eum!9@tB7Z~Q$9*uzEaXUN=&dA1zNbZ--Jz$9%yUHEN9Z;N9^py z*%sv??)BZeMLJI#_n=l=F<#)e;g9d_R@FAr8-^Ps9=`w?>)BK}#VXNGywG$2OMfr0 zzn-&u>aveA3`i`fvnEQ9F&83>#9Ny*yuuFFfihfCDr@b*l0-^M^@(V+ysJOIl&ooC z`0*xZM;-r>R7?cDe3X;=$>Hh3&%jThER02wHj5(vz~f zaP7nCcXK#HUvm741^)M1JulDMmAEZnc^IF17~^c~SmvM5)9ByGWYs{-aq#!K5f$t) z&0(iKI51oZxHrs5OuasF60q0!#|Ruy9po6*HhA$9tUe|mSg7Kyu8E3WR?{4)L( zR1L{3+QRgWcUBCrjUxy8uWB1N99qocKPCu0uMK!lH{Be}KnCMEQov!OPnc}y3fk8B zW2O>b2?=QVss9UVvPE|JkaktpI`;jWf1L@6o1+z1^8I=KUb_kBo;$m07inT@D3@0J z{K)+=#MP&I+YyxV?fOv86#MRDP1G2j-^|?~D<+R_R5qBsu`5+L=8YK<_U6=9NbGuS zkhSc=NEVlZGm?aJ1b)RDnp9<{8PY!D6b0Y+@pP&CXwiMKQNz5!QA8PgEVOb&O$V&6 z`VRen08~M%zOseneVRt3_0Zav_A&%h-?tqATmMe2vjclCVs#=M_t&@)Y^*he-?RWR zsLx1RBD#qnF=(%)K~^`KeaX(@@=Lhl9DZ^S+4_ANP2dK#+D+Jjm{ukHW#I4I?^Bt8 zo&k7mILlDzahu@;qMuvX-WAK#_XEHO%-QcP2Qk9rGQkg2GHn)_N%Q_H7(HnICv?7~ zV;|PBf)miXZ?r!Pg5AmwpU@@}=(%CONbW;0g4e3&RWSgzvqYS3^h|MKR`I!NSkxb^ zTls5+5t~?Ph@ZQJ_&XuH8?rkQr}6nQPBr6Sw55AvGzOps^Xk_W!YMJ(@-3S5yF|kD zCCa_8GQa*Cg!zkz8!Ch3l+Rd=MTOG*v6qpwP#vkgIqzn=t95Rh2{?uuF$S&6B8#kp zF-9{!xWe!F2j!>C);=z+4u^s*h2isR$>HOqWCkwC(TdbOO|nP z`!r^tX9Qjyy05%PkCPaHcL3jQ>i&0IBA++K!aQe1n|O%>H*gw*o|#12CcbB+l1nl0 ztACzQU`RxHMH$wPV@+vKu8BB^h4{^NJC@G(H4*<6&w0}GwBRz)zRfMsk2mR7x;MBL zsFaZBk0Qk*h`%3Xjo4a1K-apl?0+P&HYGqvTWVW7$3GBiLNz6ZBZxCxzDcYqrZ0Sw z`sj9YCFDYSq1;DF#|7Iis55b_6)$Q!%e*H9&dM?K=>c9 z)%d>I!uj3>Bsc1WcuU7pnwZ)~+4?uSCmPN?*W3_k@@wxjxH&?W zASUtSRU&n{QwG2Y(vq~_o~#m1nTVSSvUB{{>1np?R-f)C){aE~n+dahatDcDsU!8w zV!8tj6QRt*as@Z)x8uZL3zz)bPU#Pl6w7D z{pR@O+eN#-x&Eh*XGFI5)@p`C`3*C`~%xMTWmljGR+#$FYPw>4wSf zo{pLNy-oa&byIi$2Dr)76~``WF#w(7?#aj6%VPZLVp9w4)Uq}p*gd>1LNvTWHc@SW z8(cu#K%Fz28rg0+3I4R^5Rez3uG(IbJp*udta^1lZUd~4`Z1gS`+<*}~X4TQ9MA4c$#-8EGjSJb}($B4ZBI5xSrz0uqC zMm^?jB|m3jehu-z)ggb4rX(YTbA&Rdn$4&VuT#&igA9liKtT){F=mA5iP1sO!O`$X zQ7pUP0wMvCfb*68u5nJ80_W!lDWO90YD^bel!F83qwv znpsd&3nxr9Z$SJN;QwdNg3nrtLX%UbK+g!A1;<`{kGDTgApV$r|Nmt+{|7tcBia^> z47AB$>#S4am0If7#cx@ml zov^hfa%*oxb6RCLM1)XkcwcBuq)pvP3t;DV`(_nZ5gaXF@oeqa+v!8euglA77W3_jMmrbibiyxAUaXPm$Q{21_~7UFl8`2i#(@2E5-nWEB)?5o#r zdG(M=NA+-AYyCpVU64J)!~(OM;5@ZQwWxk;i+QrAK?zKm`gY)j2e`{}S8 zm;Pb7d0ofCrTH%P=*qS%BVuW7t0eumVzgU~#mx}^=9!Ka>W@|QA6n;h>X%FwQ5Ef& z_!BF76)On^v4 zT#a)9=W4_SoU8DD3KER*HKs%yV%O-H35W~$ti1Osr-dOplY^O#nAQ@=dbI zgJf&>la24jFNBdAM93{JE1;UFqOR|1}#!&)z< z%_O13Hv}Qn8Fifzs+?d90GN5em<8Pjk*Hb$KSLxm=QeffnM5(>!ORK1n3E6YZ2l~jtvuI|M21)| zv{)%gRbuLNM;9M*gFDD350I@tMmD|^mv0(JdF(Df2k~zc`6=r7G~SjcPIE|a3OEtB z?#t})rpF2fK!D$A#Q)tZ?EN$QpWC^MStzOvP=EW@Cutv@9a8fOLu<2w5RW?r@pfzi*0zxDkv<5QR_+^;9TlP|d`o?-s$vBzNPu z7X6X>Xz@ZCQ$P@^I-@QJRONseQV8J5&miVBsHe1+(`{XH>|IF2`+&T9Z-x8 zDMpq0sd(3z2($vbZ0Y?ZMx#}E)SGq3NBfke-%Z(4EzNz~rnps?Ef;p$(LJ0Ht$yoo z^;5<6UGMkKp`pQON=o@F`;aGsO6_h&&C8PU{(flX3Fs z?(w$43c`;O``>1&|L+IJtz)%qX$Dl?ThvK?F}a#o^pb?l%3-DIP@5zL;}Ft}fc`#y z*%FiiVDa$_ja{`N{#jaKE=_{%8k);azE?WfI^Ima_P=2O+LcF$#&JYidXv`U-3(&1 z1zJo>3T-JricR*5+4dN3bQ-$E-^!ML-+%#FFg6iHRsZ=gIsIA4-|@S=dKl4&(NUK| zxewJ`?e`JQ+!uqRu5)5^cwehzo~~`4Wtj}ZFJPK1yW0Y7reT4TexCwCKkP>87knf6J0<=cpOe}+<0TQZfDxGtKy-}12&Ta3mT?_pi{ny{G5^;crRB-#F@`<`DT zVj`qMU2E8VT|%tIhN!CgL-f?OC)8dW+2UZ77TCTuFGfdQXH@e6^Vx`UKBTUcfjFuC zI{cDaKbkK$+^H#piJGuz844;}RkbMkDx z*j2=zMN`#;kQfYeFGzkE4P%z_G1z9|nIdAj2s-yT;g+YOHO89D(~lTIJmN>V!Fl}f z3T}9}=2ggYGaaRIm4jr2YM=VxNvhq?Qcqtd)+?7=UI)Gx_+b{L{ey+m`ViEQ%$7%w2*|M?%dv>TOLity!`5t;=!I%?=MalQ*xG0`9#Oa*MNvU1VTN9@&H1ul7GY@ zqT{csa>PaQVvaZ^vh7+Hdl9521kZfBMp+JtQI%XL_E9r3Rg(o8Ca9SNgKDBA;9M|g zLDfKL_@LSO?Z3||oG)>%Z2Skx`GBK?bq;pVak#U_bT6kms?BTOUhpYxYd#z6rx<9M z#~6*s`}VfXAS7SJl~`52s_X
6GBQd26+02y2%+jt+@`n&OiEn9|RZvAPOM2OWM z^}*9rJD;Q4|C)XXs~27PUBLgxQk5s%L~Cy^^d0jyM@RiXwv@jA8t~f}#9!!;H{V17 zM6-o9PCCgpYP@5I_(-Ry9V(T~0J@|9mqMv%kI3UxO+BmAgcT8sH+TNH@|*=BUwWraWAvvl zgnaBR^PlpIw;pQuuV$#~f9gOo(?IDk4I!hda=cRltNoJH?&+lg5(q(<9;`Dv7*Ul4 z;v+r_I2R$AaE`rTb9GIoEJ;}e?Z53Wd|X=h1fyc9PW|6zoMT8@t(q*GlMkj0#)ssi zifj~`t)5~e}0Q+i|0y<52eThbiio+X#g#% zTmI3-i3gUTx3PMot^!O1mu({XdEDR%&K0^=K)t6cHHvRJB+9}y$z_Ni;Ihf8+h;b{ zIgJol;6M6f|8slyw#V_V>+!b03dg_iHucz#0hf}a4M-q1vu3gwHoM98O2nLV(hQiD-DYIYjzgcauM_O8zF zXG6E%RF=w3N^27ORLK*%P3Y}+lK#(tZu7OUTksmtrlnq;|BCfYN6i`AcxH$)KXn-? zk6^y9PJfU!j(U%cm5hDTB2s#iS-1o}J+h zwnjuUB@oqQCgv>b3p3rg*1$=97FkH%p>0k{nn1(SJ8$irFc!2pjqwQn9B%LcZu~CX z@LpndsOvWzeuet*tJJe+kdPCjU)m9ln6te23KMnj*;J0iQL47yF z@9v&=+oCnu_jo&C`%@oZMf@KI{yE@B67jc*M+221S|qnh{?XY7mnK)+mc(I2`sCUc z)*GQYcj+95|!+A~4 zP)hs?}utW2toU@JPeeFf$Atw%>u!+1C4gRF|(oBGhJ>; zcmQgo@exi;PQr zyqV4uog|5034IEM>Jt9+p>_AI%tUf6wc~b5TUu|9C&#hmV3?e-Jh&|2d~9r&E;$CJ zX0>l^I99Y&uxQH?mfEz8vrV;&C$^pC%B;O2s=-W7esyJ&d0fn=H{;ybM$<1W?l1PZ zCv7*x3HOgtRnf(UCmY@rCw6lXWrWIob&O2oQkg_EQN{F-t;R%!r@h&#wu&w?FOnq;vd>0xuf9j9MVNg_qpw}cuAUWQp z{l(@I10hyR)GUP%)sfK5UuWrfWuO<`KuTL+iKQ9_w6gP)nZW@F;s!`I0p}1(Rohc7 zoBx)GZ}aeHfL$Mh&I5q>btGFu+z9a_#1A1(iD3^hc~vltWSBvy@Pms;zP2hf@Vp5> zp9cA?-tYG{a&K=A=ox^w6*`i?v*mn$n!dIfNlWcPSYd+Kj z`&d_E)%P#h#JS>lDvajQoru3r#6Q_S7u!;ERy5@Jy*oQAu32^H1p2oU#~6V0-+pUo zpQ^J};#%1CV~mKYUK8!QS#;;%RgZWk+~D5PbVa^!w--G0jA=zEvM&@sE1mVbR^XZ04U~i1n{-A65#E4`U5x<5=hWMgc z5s*+5tLu6nQD!KHJz}WTcOW0zqCv;{WCM5}cpA74uHh1T2H@;(s>fRo=WJ1*?^TBw z8S3;QM78+`qIjZn8q&9r{+lqphWIDg{z6D?m3NWKT9e)qY@&#w<^~gyCDRGc=Zi^h zLHLtc+q&P1s?#0g3CEXDST2jLZRx!3whHa;O218t4P~U72F+Vvo8;ee?pwO&86mAM zY06#;@xKwQeJ&HSkvfkp#i`#y#0b?iFyE_*H4D3Ub30SLH$=7b(ptY`fO1x__sSNt z{Q*9&aG4TqCjqB9cknLYvw+WQvMeA#b(k@|KH%v3kn$)eR<@*Y`ZkQPJ99vkwvP*X zOy5&W@^8vkZI)ZWS9o9QW(yC6+EY$*sv}33+edhYmn|ar+>s5OEz_LZy%;;O((ySz z2$TmkG5Tlv_YMYH^}z1k$p-p$dem zBvdnET_Sih3tT|*`*6iWxZ-{!yNGic#C?cYA?`vvA~FX`%hsEm30oc1pw>CZPr!|F z*@gxr0pdrhybLp9m_ax~OckiL)F49*3v?-K`4TSL|9=d;&^dNnYXW)(;BA2IPkp>g z{2v5<0QhHtJGH2hTB1t*qBeh2t*Rf*3B;dO-&Cupb!>T}(@CaXmOfl#<29tOA^xhC zZ6@5#J++>bZq~vH#R9YZ9Rs1#)?e@SXqZUON>LmAxQ8P0&z zwiuNe^SO|XJ=x&(vHgoE@hJ~#f_bhl219$Src}kL^Ta5>{uf;?hfsMAx3}28zD_;Y z1Wp1jGlBcerhw!RkQ{B(b;e{Rw9Epru8Gy0Snd$(BdBXlnj|BTG2+Ka zHqrln4RPlYe>dXqgY0g^Uj~03aa)KR8=)`l2653D5%cQ^;3l}@lEwH7;tP;W=Z5?Tg$8~Wc**hvH0T+C9&c%^aQyoN!0!j{*LSRTe~=iX zb1^ym1)Wsew*L0-#hlQdvFzC5=fYvBds_1|9kj_?bmcbZ!1-vaqJ?HsZB^XamjCL+ zwYblTxY0TGpes*XRVeyQjr5fs&$OSRRHwCSrc0jc?f(`@~Ri`SKIXp9@-I=Bto@CrChMk;`~4Dl1Fj)>)R zt&0W16cNn{AlaHSBu(87N+bL)17B}{5j_LY<1LGhgtSXkZwB4wtt@MIc{+9z_iSir=NhrF zzkK5HmUj78Lae>jRBg~WEm*2=z?sKoFOKAE-3$ zCaM|mTe$2zl3h{LL4Mid_h+UJs36XXVH=SxTyY1uA>wlDJE!%=N_~{Vp{5f?wEf~h zJTBkDGhK8O=dF0ebgyVz zFg0ngnEvW0P#p%sY_ZOH`+m2K_*+*Uo2y&h-L(H^`i2$f+i#Z(zHp1gF}D~I_2DWH z1LcuAYA+bFZiAxE-7N<|A=$_SF-FQ+&e84~doOQN&Qwj`ygWLD-EN}{!LmoD4o$s( zYL1Bd2sjtcemj;?Jn+ufj=jtEt5w^*p})2+0E^c*K3N&acKVN|p{B@C)dT{NgJ z7cu-dhUV39xhETMkc}_mhj${``icQ%XvUP&Buups=7&@V&rTY%C67fz=us`WM5u=UK zQ_qH!hZ97EY;cIP5W&R-O>+$k=Azk_PCI^)-q*|-=BwcIvoL0Y#Hg&(@H%^|7tbG7k@DTGpU0VEAVn1fTzgUin;W3W7+1=u$~fUmTD0d7|< zK+gcYMbUBm%Ps5GkC^k{NQ5S&T{%Ze4iMpxp>&i1dn6UfOd8T_qGt)$KK3ixOL?X_q>b!{vND{wcsjFK%sq2rK zf}%j}301CNja{VLf_8}7@fWh{eV+(>*2XV@h|f{`{+a4AhQwuvUpJ5Y0?5_T&tmem znI~14dI4hs=1?CJt6gGsUBmgxJz{-8tj$zV&k*L?Mqj9Az>U>Z;3t*@=p2%r2fwcS zeq;%N)b=9k^{9h0)WrHg*9-`y`Xfk&_%UvH2jW``oi1=>egK~VUP*;L1JL6wg^uKZ z&Qe_ckU9PV5Tgan;#@neZzBGSgenQ`BrDi-+n#jWqL3`K2e{TpstNivv=6ePCLdM! zqBg>B*C#@I1}yHs0^Q=&%+{@rp;gu<{>_rRiOAc^e8Cui5R?H>#^Bbf_}f@Di8sW5 zssEP>?Zgur(VViv#B!`a5mD8DG4c2!WyyJcP)!5nVSR!bTAwkMtLom$tZz~;9PO>K zdv%ke-3g(}l=vG5mzV?*@Rnf8`^AcqUNk~r>HbZ}FWS}IPZr}RN#e;Y5UZSeI)W$~ zC6Ldpn)Fq*>uBBY256rzlHOft5@tES7|$oePKa|0=^G>YdBm?1>nX9GDM4*L`^nG- zsg!Qo#RxG}gz|uTcAfg@1;WwSh~+cD)U+zfBmpMvj}X6s%g^ER^Xf3@O&ic?Bdo9O z8e$;U`^vP0`C=||6Wrhuk_|06&=O`w_PGqMy(v22GDIb^l2d{K@^WWR_WK zeEXc%ZnS=KkPW?M{5z@gR}V4g$?~A4I;x44J;JeDwL3+BH(enrVTTCiG-vPHdG@ZJ zBa~^GSX1Muzn4Cfhb)I;;1~{t!N@Tf3VGr1*}|btER<01r!PKrziJU!sNn%8($Xf_ zRlyUgf=~`Ljjz|W?(Jb#JnJgh`JD`$OI|z@kxUu3_83}?bb{vp70HoYz4RrUs31`9 zLMVw*%>`$NwKc{i)qD&`>NGe%B+Pe-~VtJpzYV#MVgy}O808hxBp4vPwM|fJIohp<-KkZmL~4>8kV-! z3EgMw?kAks3ClS4SOR|N@I!O_J6kn3g%~XZ-C=FH{!e+12IlP7ycFH)dCva!CI{Q= z%nu9o(073t)24*l`$%3yhGWNM-Lbai**NFfIG3|=E@N#gW3rJknmCGqBhSIRbkD{< zL?jq{uv(R+>jOk$l~Es!DEHPW57r3tAu%|Wf?XO^r=i_1E6$BV>?|j}qB$#I&l7ft z)yohMaGA$Xu8^%iNH%!@mv1ToPMq+WV1qSj1jLdRgq%_JejGdV%zqOJ&`C zQ~eJ&GF|NFbwVi9igc=V=|18r=u<7i^+4a(;ocT6fBkM|`$ID|MJ4<}U!rpn?^Ws_ zPdtD^hkr$f$Te)TJR;1tiPbfThpHJ7ui<`8`vQ^00tSr%t7*RG0f_YhRQoE> zi&qn5ei=8s)YV`(Q+>Q-SpmP+sE2MtO+e28yv490>)*$W0eGYd{aeKR%fj|AL>wVz z#E_}VzU>1brkc0eMJKJaB(Q1-(lz2DJ}b$FbBf`Ne5BHTvh!=6?$(6aRxhu_>WOM~ zX&bG{Ky0@)38xAcD*R;6H$oqi20*BB|_Rg^CakrB7qo${q2kFynKg;N7>SMA9f(mhm1(28 zPsBfckfsSRX2E<1^!z#_)HyL~GL~DF;v3eR2e};@R?&U@{HCq);5cVVHmG@24hDt5PZt7NhF3~V@Ln1 zTB+N)x{{y(_2Gp1&IaY)gfLGz16pQ=1YU{DK_rI4bN#JuUiEHBqzoJ^;}H@)$V7h_x=gt;0uKL^MqIt8Z9r?)P@=iN$5yW!+&-VlM zbXCm%86dg<&-7rE?HBIg;QBgsm8%&AmHyi=*11SNfYI2ozL_&w&&dmw>Q}q_X6&H&v%RH$Y^fnf$UfB=ZPI#PYx*1a39mjKokA zYg_QAo-R2lDmPlSKWK>Rhp}+asG4v@h~`w7X-J4!VfhMc@kl} z#PpV+A^KhMHyt+uYI9hU_M?UIX((S}228rQtzib1X~pY`WoaK<2x(#CZ;sQ_psZ?F znzLKyAKP!2Cv@v+LA<8=%@Xlnb^R?sw3Nx!VNEDIA$MnhNQ5Ai(*XxN8|=QkK{eBG zzlFn}s-SeKVvRz{3t=$w42FI|{8!z()1NMbtZ)=V&v2YETFaQM=ZrUV#_Ku5Nk(4i z;z1;4Aed80Jb??As7|qEPIWM3zB^{Vzh>HisELDCtsG@-TWYrXK|tzUA;t;F1;`!% zf5j|=+7~B7G)I5^JhA*bl+P+5bpzbsPO`~EWb2RN$9E(7*gmq;>bn`JLvpC0o*z*i zy+nEVB-P=Qgz2-y`E_kes5DDpm=l|o0q44|nIGYbEnK#)oGcKl>x9{J#CqC&*J3J? zjYZVd?TMZNcdj{r%Zin zAJOVgqOrFMsh!Rx+y1iD@65goE#`#o^LG>=)(511vN~50v_>1$l(XN zLgVYzA)!j%>Nk_Vb^(z}dFv;a;bnTMhfb?_@p?JvjQ ze+p7r+-$Ll6S7|T;+VUD>VIK75(_@G0uqQ-tzmLYNUk zX`z2})fUt<2$dxro8YoF#0|iCVw_T!JA^P_#jNBeL^UaaZ%6bDz*`razLX&9 zTHlG?gxnSfI)8!&^|nCo1Mn8Y_NTt5z54+0W9I$8Nd0SDjGh>Bs&Y(S4RxAm2(F$Z zB!<9P7WDumJByEbEmifu{6m>)&Bb3cSWZbPMGD}gyuNWvDva+XPSgt zr)W5zO7=;OAEQapiST~|A(E1#EyDSdr#X_^yXd==bY=I_0VR7CXm( zf?nftAs>0NvC~!ly64;~h`y)!UQIm>3nuQY5FiNCgEjW9o@4u^^OVyZ-z+Aj62JDL z4uZ@n@gI&Hc^BLGuZ8yQ-xPNX~=KautX~V!e&X7(cpGdWT;ozehOjY^C zSemn7%4V2bu7C;RhGrhH7X!}&ziJ_YQ+gkO9&aHGERn@p_ka)}ddk@vRi#N$ur$9K z36M6+2VjYSVsu1tCzFmw{>?2xTBv$qdoT%O6{2iPrW;p#6+$*VnKzT}e+TuMo^c5lx{hEEE4# zU7Ab>t-c`jPm#LWl9V)y5}6Q!9J2dO6Ofz(S0TNi3hEb$^Dhz0CyDjTK*VL6_|XFt z=iW=c^}x}D7cJp=Go!twxK2QHW@E1jVK1Y-1*)sRrSaU9<$dmoihW`cmEPI#*TiMWz1X>yzfU4Kdq) zbyO2VV|+R@gur|{V*BOG>|I@Feq^C@jr}8NW%&Rdl=L z219chD^3ve5hy%^amHk`V6r)2v|gx#pu?D$g~{jG7-)^3SY=d)19cAEolqSOlvyy7 zfEWXy1h2&iENUW@JCp}sqdIzpP|v}wA=zD!KLYtf;4h||Ew$ko;sJ!`iPe)(J_Ys5 zK#B7c{O~f_`a|R!@4}BCQ0G8cWp96#NKC+-Q0@_C*NO9OVzp-yzD5P8Ibg2gfe0dn zG6JH~ewe*Tn7yLyYCae+2f&Lx1JL8G0W~HISYe7 zdpk&We<7cE{J2 zOg;befnzYrC&3LMiQv3rFi|F8ZEL`2J*ODj8Uu}qfQAuh zUn@~V55-4f^i+pKrq|Y(USA`W-ZUGD;M;$*eJwRzJcJ{vgRfB?e3km>Sz=v-+eEVa z%sKD@)dZZV1z_=vv4rYbbqp-O1l3E*IJgOZcqjShqvRX!zzr`WezdY5Un^p*iwlMM zj;=Turo@=E0Ldp{PK-fQ2s=wdj1bBfsb|+Ld~oUQA7cP+w{*Zg1MpUYW`}VIcY&-3 z|I@);mSf8K*fRb(LP`SE5PdP{sf7l>`-;J2&iG=an3TYwI@`q1NGn=B{HExBu2#uy>d(>EH&9@PlHABcI01gRuSbWwu{9 zXCCrxD8r}(P{)u+z&Xfr&E;PVJ;l(I6=pwax1lW!E?#DgO?+~g3sOL>+pyn_rwXGuNw~+D&)Xl<1osVJ! zTwY~Hy0|V`dzkA z`TN{r`^DBl2*w1YzD|A9>Z3LtT8ZX(`^46JNl3p}^-a{dFdJ&3A3tzf-KukM5u&O7 z%fmpJ-=yQ8MCvMIdN5)4r7iZajWp9=vyxsUE~$Z(32+X426-+N1Iz87LjT&2dlKLNuRz2Ueo+YXoZ0r6+4h9;U_`9_B3HmM z;-BCU@r3!y)caqiKKL48epUO+t%1K&O#%5kz~5`y0Q(k?wJ5!~xkd+6&k(EUAnfZ$ z=?dK70@>tVvh|1X;|Fm0x)I;gGz>S1P!md9O|Uw!Wq`}Z8L-LxMKlvYzA$^nTJr%c zn>>a+1JL6w19K{K0{5B*;P})dXvV*4pgV%SW|c&fLm((qAX1YRQzn;YjL%Jxctot# z*{|_X?-Ci?Pt!tM2x?lC4s;GiY`(TIsYc~*VN9{MIQ}vaYR!>uyaDkWDfM?GGeo`m zeJh*GiaVd$hmC_6rx7?hQ3GwIOt|L#U#u#3SB8o(XyGD2A&3_qo2C zMg8sHtsm|2+bYJCILq&+b8h?i;zi*zp%`aO)(cArVJ{P>xP|)-)bz6A-Yn7VD zSP-VyChR_SiTVE61l`bR0#1U+h#2O~um3vL&X*wU>iKRB$?ro3??wjigY1f3VPU?< zkRCQbc$ru}t>J<32#Gb2;j&HgwTCD+A17P87s*DJoB!nY-4rC+YJW$Ba?i|@Gh+a- z$N!f*_tMELSf)?0N#4YfOiT!)_s2wAp}k2qqct|_?@lE z2M_|qq-6b$BZ~19aq~sUO}pM^*N9Mel5Ed~-HCAtiHf(yc&$7}TcNLU_OoxfnHalu zy>VEg7fz-9Z0K~coWc_4z@mQ_(b+~6QWl`a)V|bTdU5)3GE#Rf=)D%(&Z<62W%<~V zjXf@RulrY@9N?dtTREnb7l^9*x0Js=Q}us7 zPz^vaNDJeni`p-9b@8I`l>KzUQd#SF+7Z_9)1v zMhV1uhZ(Sj#sf76gdI&36pz$5!4*ipfgfEV-*}vC@-VL0vTIf`6|Vv@XaqpHr)GdK zGu8gW6SxUWw1Frthd8w;g8g=F19PPA8Gs&dUer7P8}-irW_!^=d1*;Nl{OXx-_(!dbRm_*1lZR4 z+3v>U{c8u?U8#M$kgQh`f2{p3Q-{BN^!ls)Nlgn-Pc`2^ERU1Z5vj_Y{p*|TUt4Fk zKhlhpt$29dnoeklpb~#k;y+a4?{klceFLwB_$Rd9M>9CmOY9y`KSWIed13-4$^;Z6 z^-V}?3pD63cxiyROqcpSx;o+Dg)Qd$6Y6#jW}=k^iiN|@W9Y3qAUp;NTxx8#7Nj%>Qzs+fH? z(oz$|6sKLQPeG^&pt{nFX4Dk2K!>ntVmK(}=(FTM<7HRr|k=`Tdt5 z>bzMV)XLCxkDmln?bns#Xm5?{&t2khXWWb{owIGMH4?9lY)gdWz1jW?$8eOB4>G*< z>1ryEHn>YbPdarKmd>@WqZvS*6P)03HA@U9IpejQ(IjIqv;~HI(hQ|{y{I+)5D{D! zsiy^d&s^f@+7|UJ)4pi@BaTDF6UrmXz2~S8pCp#gX`H_}ORh5le;z3wLrrpXm7KzkuKlBX1TL7V+66z@;L&E&?5yD{AtRL!} zsvMZT^f;16ARm^DHVzqW9Fh&DDv2)`XvE+0 z2qdXL#)W6U=ICF1vnw9$4a3r8>%r%mAKwq0#q=klo}2VEwA|x4;s6~%;=U~QIB^ci z2f+4M+WOP+u0|j=B=uu*qPIEpG~$mr{CRWu%Z3^Px2W{>gBW8}9tJ{n6RLkAF*pu( z&aw0Id5(5R)TKv!ij-(SsCGiq0yqhHkFMHRI92`IqCZQv|C7)@VhR%4|oJ zne@4%7-kH{Im59!2NokwmK;dUL2&WD)3a+m&PQSp=6eIC*VZ_?zCkq|5^7ltkS;{j z6fobXI`|6J!IQ*#*CcmA@Tw7a>yX_6xrGZBk3;ru@b@T_Kv<*`4%Zf)wTSWR6AVy+6BUA^P2&h>pFij+FIGuy49Ze0q+&{(bydY4|0K5f| z4bGDd&J)TP@xu>k-d?(c99_w;R+ZqYIVp|%$<_fI7q8i#a#k2Y7->LDJgg+EvPMiYPS0>o(;vCnmZoP6ZT1{sKjPvQ|b z!sTn4V$=^b_E^;OS~{x!w*7yZ1~0#*_OokW*ko>frc8k43_PK)w8n_fh2eTeHp;*! zbA+{}&73sbtwD@t&Y9cli)X1?A|VL#*??=$UFO=;7Z3rTC!N(o{oh<-og%i{pCA_KsNLgW7P%>#yNwbMhRrCC;<)c z1c}i$`$j#uA~4$CGad4N7USb1q4+&Ewjngzp)BBPF$v4T?AH)ssF|FS%@&yoxVXnCWY(bzT z`D=6ti!qOyfI^rPn{c9~uP0wlsCN6HX8_&;sLMU-a*wTV{>9<&$|v3>ZnD10sYV$9 zjr~6s78Jp`Krxsxn9L|fGh0E8#jIuXQ__eYpX$is0z&PGwRymY*r@t7fsi_Z zg|up5uuwnD^ErIu34cOF?d5*x$R-{?vUq-R;0naABiRPxC%R5-!?m;=kBDHYU7L;~ zbsCFfD|)vnN*!WzYGMX-soBM$Rfs?~@)VN{H}FW-@P5phy8J=oytvsXCU8S16c2$J=w$ngjOb^HULqA?1`V7PFwOVWRPi0e;fkWVE3 zCv?H`6P<7psT)@u@7%+AM>fzbg`=@X2n@!Vnl5r(vp^isFn!h=R<{l*AuES}tS)?jlk=1cUb>#fQyNuz z5QC1TMC3);Hn9*vKe`h?x*ObZg@pcUpc;)>&xzGkR|brg694WCZ?NzY=r~SfJp<6= z&5PvaTK(L;;s@W1A8mFy>6Fzkgw?M!M#1Mb!?i<-(F|u9f*Yws&w{jPMGdWLtNmM- z!~n4p)d~jvz#2y!lm0_oR`IvD$W73S*9js?;uoAb_xXXx<+{4Z8EW#@6)fu5S*f+X*4C;Ic+9ssqZ>ahD>mUBOj~eFFu7qIa>^-wMqKlW)52I zyh%hOEc3&f$`<=sMFW>0kr;*fbi~2+O}3xiqMCZLylxTyZas@m5L;$Bv#`Is@D#(0 zVwmCmBJFScaTf1nQMS5pHCkWDjn7vK-6?DR5Oj6HLYaWUBxf+mDMr~si{Xutk<=U3 z2CK(q+7I)+AxGENm|kC}IvT1r?nDfU)r@lQGt`G)h3ZAK@h8M)Jga}eQ2hh)yPTx(f#*Z%ICl4Tg%|Zij0b*?8`(r&_&I!(qoX07b>< z+&+FVTgnG;jH;x`JFPI*IAJAPq2-};nw?F#0Aj5hb#19{EjLG!Xd5lSA`rj**LSE| zlLa$?&3R1?sS4ZA2A;u2fgk3Y4W~==m$nw+Z>dTbwXJUTNeGpO{l)6+FV;y-U1eN< z{tk9t+%UQ(~#8M?&G&MXGK#S>0%;9{D5!V4nc*6yK-4dwo)sLtvc=)G zP38w99ouqT+7?lPp*qT_j=n}Le+$AjbqZ`=of21Kg;1;cfehS+h7Ath2gL`$pNH@= z#3N%W)5F=j5{Tk(#U|O>1Bl-+jl(T~joVmH3DuD<2$a$T#}d$J0PS+oaUZ6{aG=k& zcx9Q{HdejFw>5eO;7yD;{iNomHV2nbO)nAa$G}b6J^(SM_oYk18G)ZqM;vT#vUhcZ>HdJoGVx!oC_Q{M;;*ayWw|B& z8F;gyF9_zDaf4Hjy~=Jktwif!YRk&5HRiwxK1*5*T~uf|&eS9@%2X@WT2CN#M`AC< z0YRu|8MEy%N7pu(A4~{UcEUF<#Nerqu2JrOl{o!+v(V4-n68yEAUW%J(+F%L*%k12 zYu*6F&Pfm1x?cpz#`wV{Tyaj<3rGiU0TyckRB93kDJmcdN!rIEju;L#iBPQDFCnv> z0Jj}IyzL(Nt%zpH%X+pEV|5oIi!}fw0z#;Bf_eY1`mB6bkqt^ROOLJSoGDgcODbIm zFAE!NEFm00tW-jXA?T8)G1>NQGorR|V0)7ge-q5Ifl#cgBbLuIVsOMTK>P-ht#_pU zxvDeLn)6G)dgMSqC%xFRE8%kiVk);sSI_hyq7 z`>nE9!vsVj)=7;toToug~(%#TJU6dZqkagH#J%&+ZGAN(eiU$(?P< z>c-n%K-Lj|8T?)96A27c?ROwc+19x}A=-F|@wZnSHBCQ=*$V z2Vsve-!`YgrcZKX0FHOk+Z;Uu@D_j$>>9#+NGLZUDy46Y*btO}9YYYj53HZxWwNo0 zxb)H42X2(5nUk6i#t6P!Ov<{XYoMM5jpeU{h44i)1E|Aanmdv-8@Go!gAno2trByEX0Q6_(hhWIaD z5!kDVAt|NdB;QBgs<#5vS^k1T{E#hw-;si3UDSwNW-9H=X0!Pbl<&*|B?Ny?Dj7A?z z)0`T0?8L>f#Sgp3@uCx(WOX?wWSK@Y6vJE@fl)>=(&tp)0E=K~+OPjbR7(&l&vbi@ z>9tMfyK98tTHpQx5g~+{a{m>|y(fv~7a?9X^?Bk0(nnkybC9HK0UWX3BhIhudD6Uy+(H3Y zOrURX+;$KAR>a{~|85Z^kem>&MrcMWU$m8ufLiajoA<#Ah|5jY9^Lga1E! ze-^9TvL)z2UqsC2Z&tUvbM86!-n^BWl}%-3xlFmRF=cQG%d$WiVf)Dv0yocoFb_On zu<8jU{DOp#fHFuR^HvfKDFSb5rQk8k6C{kMbf9rbR> z`us7w>m^++4wXhD{V}1bvGuXfJeHsY(&%x&y63-iW6b|pkGIt)5|H@8w971D_1>NC zl=nmnAgcQz4P|}}m=Lh^zC1J5;&L(RiTuF$Z+I?_bpHQleL9z?h=>K$!vq zcJ>%M|48TSU4~=|+BtEY(tE>oWLkr&|GV+=WcnB|j?k^~&9w+rBNQ48=x{WC?%_QH z@Q(nT{nM8@{Pv##^C7;mvJm53l`TRcxMcsos!CP$pO+O`>9JX)=uGGO;hIX2Fadny z>GwUp5?ep2=J%=&k2`Or9wWW{`jWqXbdvrEK?!&2 zBW%7@{FR)1HlbQcA(Q&0fA3=$Qi#9DwtH`AHa+dOgQ#kK3q)tMYCC6hdB*MQC$zf) zmvtB;S`lnggCX8ToXhgpT9N*<%#s&E7>iO**^8$za!)hkwG=+N7D+!kxg^dmX+A6S z$RxymY6`gLoivTJAdY16PEyC1(FhY_o$M0GOGiG-#8GfAsVFmH0u0z#NNkf8pO(JP zsiP)fvl!>p0fauIuY20fC4ToqXn!B$Z!kk}pSYl7N{--Fq8~ylW&q#l{dk^0WEKJ@ zKN3HH{73?44Rh)clJ>*_7%Cn+HOAd=;tLVPKSvgpmOCll61pwEzENgo=!nPwymR#M zoonzvS`bmji#dJut6)A3eU&)dBsml3zqmY%_2jdLa=FLms-lf9)rafuaBT(XYa#rh z@#5^Kc4{B()g<`fKuG>-qW{MX>fLWk$d{gcX>qetZ21h6e<*f-JCoojFm7GcG$sD( z&yYe&@$NyW0(Uz>?ED8#l9Bj(eIDNov4a6?ar0w})2C$1BV19aty{G)kdFMpfF8nq z&(e3&XF8z94ackYEp*$SzLI${$$k$Q-R{>`C9CtNtlpf_)e^2c(o8`_k?6-alm3hO zbl-ob0e^~8?f&Zcmk!GWhWk_EPu%bk@7>{rB2hnN2vR0M3y;qSZGhg7%{Z)E2xG$z z@(%0A>e0f3Ho%e3lo^w5B8L$Ro^)*tNozX#$v3ZnAwcjDRY8zopqq38+7uA$*(l24|=$VD3~ zA%dO849H5+1c*jJk}D+7zD>Jd=o5{he)2 z(P2ptr6AY5?8wVbLaG{J^CPz(am*nC4*~ir&}==vmxmq|QV;W{Qa=#lF~ier2}CS= zAZDeAazJ3QebaWn6|_CZLVj#0PaOGtjw`-}$-a$oXByZiO5x(@H+VMFVWMl{qh`+W$eg{mJku8oWA3Y;m97*4(>U9$TeE8-a z5jIJ0gLE?Jw~fWPBTV)T<4y@ar`dM2yB6PnJ;@&eed}0XKH>b+k7)K8w$S;gN%pp< z!>cndz`h=MKG;EQomSuRN<%hV&;U9NJ_i!;QiRmiL@W=$P5Gy z`~*x=nOGii$A>V1vHr4?MjS$ixr3M=TxR8bib4VfMJ-64gb_B0f-m9)V-Zcj?Ge@W zDb40cOooGFpw!I}@U5rc2m00!x)q`QjL`gu(0wL{{~&gDsi#-Q`OpMV6GE+V`YYKs z805e`77Kn2|3|$d<>rSt&jovCe}Rc3Ri3 zs?}FL*9sUX2fx@8j6DWB!?%HMU(@e9e5(`VDF zxAZ!Z{^hve(eW?KEjEq%cgUp@KXNd|h7Y43*S`};p2t6Fmb6TJ_#L?(%?k%i zz34uI0UU--q0WkDUM!i~4-<;6ymh^2JCqU<` zhrSDRjiGOA2@=%5g6<{s=Y;-BqyN>3*MBqzBqo7jOI}RM2+(0|jw{b_^Y2M?O>?Nh zimZ0*lcAF}P4UOb1dMoSIujz^lU*{Z!;B9nCV=MRKcKnz4<>K_yuy11;2R8Mq&Z&@ z{0AX~6FK_wU>5*kI2P47QT@BD7vk?EEUT1fhLFMd5!q-F_!hdY{Kcp=pWp_9N~<0{ z6i3p?RA?IXsrRM$!6g5%pp)N5D>cb`KLkWg>IzG7;waBbTzQIdPa%5(Hahqws=*-Y z%h<;$aTYkN-yw3JY6YgXNswv$8ySlvz>kshc({Hi4T#%LB zK>X2ev=eQ4+~=QON8)dA&QcVXawbvp^1^D+pRx9__oa?WO6xq_kJ;{;A13b}bg8VT z^hS~fjX=z(8nN_w3h`%PoO^+h`01P&+GXTKO6#QUPMLtb6h%4b8IvsmpO|pQ_Dd*Yy>HB2Tq53%pw56pf5Rx4jGYh0ie_e_ zIeYH|@E*Q_U~ERWeGb7tBZOy!P>4!xvV~<>+}3%l72@w)hs`>S6K5A8IF`^`f|mmY zLp-_9LsuEP%836Aj07P{_9?B2s{Rmt(^Dj+_l7*OJyDV&Oc;SQ4K0Zkxaao)=to^? z$d`~Gd0ZJ))=%Wn9yF3)^3q83qr+b+QS(6E4(}(oM)a(I5~3diBqd>e)8Fw`;Y;NE zZhl05bVjy3mGcPH)*9vKl}AZgzz2kry>PLwOfKsj6^>ZX1G@kfY;Od#CZ>l5^*`w zHmdA>Z}6?5s||e<%N!_@Uh5yvK=dWcJsfs=9W)L1Bt1+9;@|ZC!(cRqx`e?k$mhq{ z{0z*QL`z2P{ShIglK3D+t3(|MYD79IQTVF*#K%dWy`A_ooa`t4DE)1$!pMV~flUV=^#v34a{TCEnB5747C0-_(kL-~O!-psh=`w~x4a z^@#PGB@l4#9;WrMyA6XheklE?s{dj(I{rOepOmP_zv-AJ_wKt+;l6qBK-S4Ohwo`? zZ6%rjV=&nqTby9COb8wkkoaMmr^F+ZFMJBQ7Sk}{v!Ry6a9vh z5Mw)rzU?tCCqI5lar_uJKf-32d}^p?M99e)4e&sn?uGcSb|je`E1}8Q0&JB0_q3Z^ z+TH3fYT8{;ul>Hwxjp}g+t-h&*9DhbkG%bT|(oeLmbf_|T3rUg1o8r^S@^gBRK z;~SH1865CQY944cPC$<5cmFbhl< zX?M3Yn``=dn-HW2AQ<{KW4}J;{PPc3y*?5L)GV4+k}kACLe)m%pGx~i!`Q0Y-)6!9 zE8+t~Tft19GmAm3_XwVuV2Aq3%_3Reym&ji%=fB$EE1UK<#K!$lW=M>xDr>Q6%N z5(q)skXCZSM@MmTzRQh+>J$?v=WN*HeQ{QCp4)SUT#(s>C?z=wB zGl7Swdji9INdd7gM(S{f35btlR-;^z5$Cu`9ZA-T&RG)2K%3i%1|Z9&?_4f@Ye0|i zjyq92edE|&ow2_;rQInLV013}j=pW_>lWXoOn_(wBC#LUT%z_Lob8f%9q-F70omDN zT!x)Jm7}=RKtCz5pAi0dFQ%wQ(tZmJ+RB($Ohm$5gl@0?Q~@nmwh+L32H-vX=|R~2 z$AsN~EI(WkfTs{XBy`FEq(sOj1Wbv2a@wCb0qW0qHyC_p>07JoGTQw|Vk7HxB8JNB&?=8C=-#X~kDTbz*}JtjYTgqt5> zTtqly9Ve>)KPU|CvST=3lS@D(tHeJTeB03Nw{)8uy6p{pvz7S}^~U!=2+-CuHrJ21 zeRIb4aseJ}boh(-SgTL!pNm z4~B6VR=s&&{y!*8hAb&~m|yXCa_?}O#b=sQUw}i9&*|3GxH}-#1n5qIEE98qwTMKn zS_DkMdqcY`sBV_x7}%7m3DEi7cXU;QZ=<7M>gAuB1(Y!!=5KmGxfkE{4aQn*ag5F8 z7^~a*CLI#5Q-&bkyXV=R_aupy07738`r-KE^yLJH{rtnb(aL{R!R7#Gz*9me6q`{! zW>gy>(iKYB#`&IV)Io^4Z>_5S)$TtWM;leuF>^d!(8@mGAQJPPZGF)p@PP$4U3{A7 zUM4_^>cO?KhJ0x#jtjEI2{wNQ_8G=3lxdI1MI?>T?+M*Tf{+;0u?S@Z0w9tHL2ENX zzFOBonn^fv}VI&f>l`Z(&`C#>h+&MAga&hW5%j) zK>YZS>)@qGC}o0-eU+v^3>ENCozy$&8W|*uL`@3;qqJR^7BI(39?n=~0t)t+gsaX_c1ICYxi$;)!{ys#A!@a{r7Nu(W?e?#L$#-pJJPuNPe)!Gd zorCunr$~rP8ObNi)KnWVY62|Q%C>i-nt+HCLNIi7#`fZj{mt3LPsn#3-*n;-m=gXN z{V&82)rqvPn#H?m3>-v|T?NMFq6KhjrZb0)Jshj#{+*7w@3(3$bqCOW850)k=N{fO z0N+%w1;7!o2%uYMJb{wH3@8W`gXv0em>^%HPJpTPJ$OUtj1Yg1VhUCJN4%lLU5*wW zi9h!e{^^1nIq*Z!d-u_l3DMJQ6R=JX@>ymS$8$NwFFO^LKbcDVW886(`nQB`O$e<> zfD^`GH$L~RAQr1B9w&NFiU>%~2Z%P#F?!&A#DCDF^g<{xRs)_KQ=B}dJb8+nFEK9H zW+xK02+3!2-PboEAj79v%C077qQs*>&X zF*h$BvAtLfJ5L~?sd_!~QzGfRgb5h^0VE0Wk0<@fmcN-s{4;i1C#6-I0`vhoFMo%5 zl~hJA#!@07eQ4e$jp5-eKP#B{pDb9pJ|yhO^Ff0*K+JbY1gFbOu0>m5C%Y*uS?0(x zhs(q#z&ax`a;p8aJs|}4*9&%+C)C>|zRLzCpl^D*eT(lqj8X4@O#yZO|3+klR54ju`Xn+Sih!Io6f>BeA}9D|PcZgGG#^oA zsQZXRzr%O8g!V>>eQ^dcRYh){Zbgba1B~th&c^oAZ|gfQ=sPN~rR}QZ6!z`MBjT`9cz{@&E#aUXLi&{xuj(NL1zz zb>Ty09_E9GZjNy8;{yV(_eOPoB7JHbUr7lqO>z6!2Kf3zG>@9+~N`W@(J1U6gOL9GTmx-rw<}n zRn-@|Em;v@?DGKu#)RINHjG+}QR+8V$_b&PuXnVY747DhZg)#x@5Bz8PM$+hBHlF_ z`_+Q=n^V^3M^x*A;0?w_LaW(fw7zPwqs@Q()M)pYzft-ZuYV^DfS&Xh3m-_jF=FpG z_Bo{UgVj_B%pX%lD(y5{Z2;YG-ly)9rpeY74ix`6=b;hvdhPaph9_?*jlYt&zD*sZIsC-BK6m;9tK=h-;pDB}Q=<5y5<_*==8~XiDmcEwtmKp)z zy=A|ebMxwit1r)}R;3&|4wP5q+5q&GBtKb9O z-qY1e*iDB)_y7C*nSc<@TB+n8`#wbGTuhh3F}l%CH0g`9p;LS}xvxnymO9Vx(UK_q zj3f5*0q+@rZxD31|6ww3?Gudo3*a9O3k4?9;9%hoy1?<{+oW!&c7iAgMS>sO5ls~%!5@ge6=y%+Ry3>E zG^-oB-JZ}zX67sKosp=LU7fRfbIi@lQ#Kb%`Zh%wv9Iq>k?6aD5g_qXkvSS2|76Rb z9f^M=NZNHm<_!DYhKq}rJb(EqpMUu&&tHAXdjE#btaVOB*<9r@%1aoqJNM4G0|&u(rUuTs1vO z|0iu4+8CJNAQJQAbea#H2Gcb#WKVOy3-F!+_y$4OY{m&{cntjc5c)^rAY+p4E^(>~ zcZ=eQK`p70zV9u*w}f7$&xH8L6k>dTKkoS#b^n2sKOz3(^|*w_1^6&+86`$*11^JX zCfoe7xy9x=#xCV#&S2H%FZTQ>SwvgBKvKU4ljb{6jgOMF5?q2X8QqT1t|U;1Zxu<2 zeSdKF^Fh4(V+s~yOI&$Ee)O2)_%Yf1NLBuC?GS~-I!EbzwBwKUPp{*i{-j-~I2}+& zzgybX8@lZV-}Fid$FaH>jC%U-3%1t_ZeJX+elw@p#(jMKYBv>=p%~br`WudvIhcrn3B3pu48+Y_(#ozMkY%of4P@q zVkEzqY^GcMYO0GbsBhjdYI)4N6J+Rk)LFN zw0LC#CSijIEr20&8cYc#{!vq?{s7f#&i-~mvn|EE*n7HtkMC4tK>*WZOh-UXanTIm zA3r^gzJXF@mx&*O+Wsewerbe1#=rU} z=ywOELmg{Gdmx#{B^fIjReb@QOGw{*X~;^0$s)4LHL9OcWRckN2Nhye>AnT-JQji~ z_S!=vfJpuA8sA*w+YR0~YU_{N`&0sosSkusRQ^~;zIaT2{EU402v;sKc~toi19VuS z2ks^HGSL*El0KRSLNAVecak*_I{NL3=JtYazrwe*wBc>U2L>V@df479xcuUT)vJ*_3_)Dj1+g`%N8nM}0BaA={?h{e5K@OxEv;YGEf@~oE66QCbIb5z(6`fyd-s-xJ z&E|%tU6bXW#i`-wv15J&eOu8~E!HHSh8zs{(9j32VH}r`T&Lss&~Wm={n+96J{$hK z|9K?z39~UM+3wUk=8Jg~O~3)eAos+H(pk|0Oc((tjDWSmNXWcNOaZN7e=}qK=7hE` z@m-*+#3x3o5Y(AZf&>i=0J^nx&;&?lio4-}P)1yZ*R_z1=FJHt+R#I|r^$C=GMJMe z?-IOc0KP$BY!3Mx@)IDO0Z(FBOy9Q>q~&0yMglxwhXB5__|_8CR-JO)k?Re_qkU7G zf2#H;xt?Opap8@c0bv3nzR~rh4t_?ZMC%gbzpz65gHZxk5Xe>1u63WTY$f{I#6Ng!k3S1)y&*4K+^9)h9oEcLeF>dPgszJJ92 zCX+F>0b`<+7Tc%9KT7?2Ed)T?H4^<~Mn%-AR z^W&W3CytY+mZK+@*(_juPv7^$G#QD1tUz)zt*7QrxT0iq`6V26NJe*mNA#9_YLo_gb0y*i>^&*|!n zu92;Q0TNALuUi6jYhW7NLhbK^)E_%3{Z80Ww{i-??z611hL|3gr9VW*OV z+L}QZ{?7o1O&E~B5P0A3@$D_Xxx{xn)qbcJML!u}8tA8MAXu`+Ddp+MlxH7{qhFS3 z?$OLL#VLpBZ4fIijM+%M4*dbtIZzKR>8l&++gI!_UeQ%MIaB@+Io<R&VCK z`2ACEUzYMoH75n#8!j;$qQpO*0~r~fXyP#l!!Y1$L_It>{<(n5EJf)kW)kMtUQ*Zl#Lr=Io=zqKc0smJ^|XR>8tUt)pG-!`U9x+ z?`-@#O5V{IKb%sM{?6b0N<(x z;9!!=q>mD~9^Knpyq8=dnfW69r^MeqK>QURTn-5q8Hmidh*JsCW-9eB4B1?Wzp*HB z%hm25_s4r>0Fr(Cq}b~Z2oX^l*~1)sMd&u_?6;94PJ=9kh>rw6MdA5XVEAfgw4irh(AxX}7nun=9J&CEfOx(03X?;4NUl zm_XlJ_N$!L`JC&Qb8cUh)LW+~Nv1C-yP48dBljn5GYp7Z@*4Tp#O`m&HQHZZN>Ca* z*qz5D$Ud;TU2}VVL)SLA9Lfb0Gea>qlygHlcl5sE=K7qv+N-^IsQ6dUpRaiQm2l7d zDLuazzUuiy5U0dpV(e@5P$VA~8ZaoD1B|YTSZ6Eay}!-bUd?HD z1>GL{s+VOy)W>6tY61ogKb)-ZKE-BoK`0Fy>=0&*Y{jgr2^wB_NFf6QYD9IR>H?9Rs7|&TxNpcp2>cG2Xuh z`?-TnB1A+yFd4C2{g!4Eb#J<;d#nrOGnk)Q@`WNNeODIrECxE9NdDsN7YiOQzZQ(t z14j8rQb1w|v^NqVu&(}hx{Dk`UhQ8@_N5I!x)*%@7>zwmXm%RG%5w|aA zvNNMV5v%lP+`m6cWP+IQ)>`gF!Xma?u+iS^BpmHP{0rHGF2q01E$OQez&T3@f#;vT z;PW4ULQ{1(XUGd-BE(K@$V&&VX0cRTKWNb*U)YrBT)gL{EwCymV5M2bippi56gF0>m_+8q4_47-e{kG5~{)Kx%TRZIP-< zS8I3Q_k38AqvZ0=!PmnS@8ORXcF+HPcF+I)I88I)+kh|tArO2|=sVeq{&gV8d$IuI zEY}quM1|%<667aQ=8kzs7#9k|v&d{fz?fbVoRxi2;PV(WX5xHKXM3yOt2Z7AIs!ACRBwzWyv%J8Me( z??Gq-;g9*EhJZLgZ)sQT|8yK85`@sL=(caDu3pn@Ztz`0@QJzPAuyv_zuh}7zF2bp z>5|oXNwambUDTkee4R0oo)}SUqck(75fXdGmEjx+#FQh zARi9_cAGux%UhaVk9CmGBzTaq!tczMhWU{J)3Lg};P&cV=6#kW)b60tX(JB0`QYNP zp?4vz`+Y-j-#w=HqpJPEypRz0v^~i^y|e~`G1Mk!V;8LKlHOW%q*ul)GHBL-6Q{sK zCLsC+$e}?}coZf=5I(-yJ8oYus8%I?4P7Ns0;N9D6y&D|Tt$LEFv%m~mo@}-9+mYO zn<-3-GNTa!iT_i?Z}+V(GZ{$1i$jj+wfL6a|M`UX48S)4d{^VUI!bmK@Lk|TeG0xO z^csxj02{p>=SQ+GlRrlH8xQq?wFUb~X8f*@)fZHkFX{Jt-3oZPP3j&9h@;;w zV|`ij=En;zKbcc+a=>6Ssgum9DD}sxXxZs?0+H}rBa*pua^$SUo!8@ibCLdCF@~SL zr>Hy7b)II|(^eiV64yR501oCyhUKXvFD;wRITz<&vfuB-3DORg`|1=MYqVZzf5zYU z_3=Ho2KcIB{+S>hleBKJzLEmanv!etgctT>p4;zoZJ$w_g^m#;@lP27m+T109a-+k zoEuC5#s~x8l~{`j$*{dD*j|@Z>zsBAeWQ&wsQE$s0fv|WsfJ9YeW~>{nHUvNHBM4j zZKtl^q4O0d-QV4B86bI~*9Ch2>p#cvo&oqKKtwDyBlu8)`DN7t2(j`#ec!5-r>d_+ z;EmF2IvkG={4Dm$6 zaoEm>Ky3Z6rLSI7Uwuk_bxpVPgKGCH!GLuE-x;=7Ij??v%!}_I)9kW%=1~H1#Pwz} zB!(zqi54k@Xkw9PgXBM`ksZ!CvLX|8e<@6Wb1{y;!hOT8_pC7lALzSIJk7lhU|cc| z%7tNeY$#?HYkR8dmRDc?h?}c7;2dNzr0fIf;G5Hw=1nsm)Hx|@=)3zMSzps^`oQRa zX}$v(yDM?G3e^?WDAo>8vlrg5qs_Gx(aYZ1Td-6HBLY>poqC?O! z)R`xE4HMd^RB%t@1~|Ak`I)vqK_=d75FsJhayEc&KT3ThqSUW@r5xv*6&9DdQI$M=?0yj3@9El>zU%3`K;H-YRy@#2nr|~hxv-o(HOx*7!Po3o zuerH+$@=1)uG(v%hYgJo+juZ%?}JI-9NrwS?`6#HYqVi_FuY;3u5W{(9%H_E)dt7f z&-kK0<9PCz^$;d`Vowb>TcAG7^)A4B z2H+b2Hk)CynNZCTO11wNz+nF;gsGhXB0=50J`DdQ*ZO%!%RVB`=X_4M8el5H!G#5YV8+RKO%3jbBXKBn_EL z2t$epBuWv}twuq)efb-&6UpBL!C+iLwm79YeTJJYMN0B5^fiQ9B>qq*Obf{picEk+ zKpV{hK{OvG7n6sMjKF>U&)BBW68dZU{R^tg*EFjgzL)*~vL)*65CZt#Q13D>KAZF6 z2MaDfU(i;LY%X#5rIgfDMC)hd*U-h*WAYk1Ut#Chn8g)g@tRPsglO1EG(>fr7qZ2# zm^q35WVAB^l!c|g{Ry<-e?ZAZ1M=o<0I@Liy5B#nv`scSwnoPKCIer!b(kQuf& zFL?2j-)41nLEp(5ntmkxXmZm?R80{URSTAOcVr}nls+5F9r_Y2>|W41B~=?PzJduD zt1Oba(fW7{t+(tNL+Cs?fh`NJIpx+I(U7ZZT~z9WDIj46QlEe<9vz%HoQ|W=>c~t> z<-5kRzAV{Zn7cXmUsC%dqm3XHGruxG8-hC_h z@LrPQ9%Ce8q8#88Rq`YAkn#{gBl}?twwzHMKOvtVt7BR}s`-`hPaXLN?3<24QrGy~ z$+((AcRnOYYJg-c08B^d*L1sA)YlhOH#_>azgzqRV4Y-a_m;~SOTPTU2{$iGnypIx z2Visv?m`&G-^#>~~wbw#D~`uJ!bdT3~d3#r)Os~)72ZUUwzKSi_h3?Zsqvn zG^}hod=U&nP*DPD;?0EM4?~u`9Ph_G>El>N3h8(r6f^!v>KQ+felvnDS7Tt|YL3kw z+tzyAGk6>uQ*voesVUViKd!sMDNubltOcW6HnZptkgHa}S)4KfUNvXNh>7X;^^Eo9 zjIJ`Yo1SLZ>vJ?Tv>zR32L?F_89hmi*Cul7NrxR|4N3MPkHUQ=Cr|@Bt6cI&#&h>fgyxzh3vw-Y1O&4pGmDaMXlA zFc{NGvb{L`6`p(%$V$Ph7^cKuL2d_y?iG z1E{1^%*f_Pa)3{si<;8clG0;M2eDQAMm!HqL_{og@ZAJ(N>*RReJCIf@asvTDyjh1WDr~vK z6&)^@gPcU-4A`tA%b_STiRr({nJsdPQY6NJ9^*U2RnYM`tV0APaDCs=)RmsJD9&Z= z-qY>_eJeg2l3jNoSSaR(qsNxz6U*XJMmdLS^OBp_pRm4u&3=1}ZyT8mhs67<;Gv%6aZ;r6(TviQ&)#!kt z0T>+vof9S?S5tr_hcU@|(gUQbb;kC(V0&9ouMPd);~Qc6#C9JEf0w+RaOHQ_eMDF3 zx{q0!`p;%& zs`gLHV?gxrdl6g3Jeo;<9Hf+59}xE7b@#xS;xWCW`u~9VC&h+dh<~xnDV8T><%!hG zw;GCArGBrf;|EP93Q4o&ht)XdIR*{NGc^6aay+mnbXU~3FQ~3AXt#mTe?4z`k+1^Z z8&>BtUj1mvi{C$DbCHwHynWtJiE0mEE~Zh;bZdg3Gq zqo!~o{L2l&X=5*p&mRCY$xs0sbvAgX;5`HI4S?v0TONNj1CGRKEYEz`jS`FAjD##q ze#EJ+4}u{ChgZqp2P3Ng1W^bxaez3KIS`XVWEiYO^|P&}Ziw&~iN7qUWVz|(q>jU# zH0krVB?O605=!X(^!{Myj}DNrcnxPuP}SzllFdqNxx{9Ltc1{xehEHR_uo_XNqgdD z{I(T4eU$nKyGYvK@!AXi>2K(ESJb!HblWYyX~jH|6n`JYef@n0o9mJ{pB{1X`JC13 zoN8t1yK(DOI?@7T;RA1we9u@9w#8&SW+xpdA6U*lwwye(%$Dl1qMrE0JY&AhDdsV> zuXt>W2fvr&lS9A{ap0w|hAx|c+_27)7a3Lq0`*;BbKSAJXsI`zwqiKx5Y+$}BM}U< z+)yqJ%SVRO4;{zP0$IMJ-d(W1dd2$c4b5&XYAfd=FYhTj#(z>x{a3NZ)d zxoi;(s42h;li5~=%~j5RmC^1kz6tcTr>})s!1}=#AWULp983gV$0NHHdpI>2PG3u; z`kw`AFoOo*U4r)vz&8Qn!prg*#vG3#BlxbRZ);r)Vs~Sp3+lWTF=+G;2xxq4A>I=D zcO>q*g!C0fTEmJ``@eG4a$2ClnilIS@&3;O*$lF|#TCkq`^hRy|0FjLmu7k|UZ?3m z@*lJTiby65fk+O+^@NAe4pZW9b4xaJWU~U}=JH6Te)05A+|2KVgfWS~hid~k4A~g6 zcj(_ktR)8@`F2HLzouEeroLX`n;>P}kt**(@P@9nRGW;eFK2xD50+egQBYSFn~6lm zLoG2R^-h~3-!*xMD;x4f%h6*v`@nJbEz9v!!|X`%_+I+7m}QiUe2nYwMEdOefbaAa zMK6TH>s$#zv;ucH0R5Te8MDP4mu1>lu)XQHJ#X1wd+JS~t%UiJ_qe9w08D1W zWKixMAsF&2BljT0+NR?=O_{NjS^+}izejY#~v5v8khjj*wRsJo;E;or5 zAST4|*x%AuLiqRBTe0mKf=F{Kj=KLj1Q;9Yp&mqe&&WST<+!3Gz4kdDfdV1Q?`a7=Ylpz?IfHdo!_fxp% z{yn$Gt{a&AfK|1>)wS6N_@H$Bg{McXkAI23ll|BDJNCcAmwX#Tr)v2WWXs*?94I?I zjFs2`xoQC|1fxzXLITv5f@U6uJIWf?;p3nuI1aUi{?h2T!d7YF8j6h6M zUolffoHq7D+KvYxBz0AT=pTPuOr<*)WG2E;8t zMg%32yGZYc(mx3kz)z6aGzAU+UUQpe-;k3Q4u}g3QgH9+I zY~E8GH!Pmi96#+iKC{f0maK>l^ip_Ndv>=q>zfT--^-ysN(|7h@%`xaFFaeytm&K` z=D-11N1hjy^MYcoryh2JYTa}7qT%AphMQL%+bd7K4m7)Di(o+4f)R7tH|$rRvc7oE>f#OSt4nq_*X-A~)SC_Meox=D(Cg8(x<2GOnKA>%nZQ6?4(}hR zuP1QNgY?$nH{vbrzBq>4Zoy@@qz!hM2YrBfX8B-Q@bv5{=Ij^vVfI~q$S?4U@6u9| zA;*mqw+A9~ac~G6d;=t=LzX0KWq!xC7=ZoCvA)RJ-e$CQ6lemzi)&YzfcqGLv2!(V zI!8qMpY)bK8oKD7zPb;z40Qs0zYXv`{HefzSZ0K%0TARUJ^-=}5T=AbO8p}eh)7nY zcs(vth<_wV`oBv3QcgnrgC6gz;exFT6vb8?|6CwjfXffoFnafzfvNtzmsx@cC~a^YZuStS@sgfvoUDz`N0?KW*3Hpcyp3 z&OmD{@hf$b- zgEWlcLEDq}=F5`B>5&T5fvyeQzG->$NyW>bR9wI8SYLQHmw{>(WS2lEPJ(F)UgkqF zw;VmmIDVQ_EDiPU4VRyPpXWdLd%XC;-{;Lwf1j)8pRqoFL%mwlR}G={gx>1`QEKn@ zUZURha(&p-LpvrDR__~qI1sl8QDZQ@bw5nU(yHYBY4e1CP(5KCGOSDnQO$<{7=HP* zF>M#0LIF-%ft_$&_kV!kuesHPr&5?-x#i5 z=4@9P3=DwelL3wzy;QRo>u`VzlD;yGb9|_An0jW6eSc4aWNnxR!(I<9c&Fe!1Mm$1 zl_|iOxiK6mHG$v>eW!5%1bK`EPbYu84U;GAh?2kLPfP4j;$+>XufRx+v>6y z+0n{dzK5=sZFzm&)9z)L$|0c=sd2gm(1$?p16|wGD=`%~d|wG{Ff133IXU~7eCEK4 zMxk##yH(Hi%Z67!tvLUpVS5wU-2}E*l6E)35L9dN7ijijh*O^xhWV-C^jn6rk32_D zYw~hU-(OR0FIiu|=KB0O=Py3v<>#OB^3zXv`RS*;`TTP(U%q5_b4y>?nQ<|wz26&k0*q?^m`kpsON}hX(cT|p1$Zx82CZvw zS&dPze^-bDT{KYq?8N^eNDx}ux^%tAr}r)RgL_8pzBa0)Z9?=Tl^KXla_^p^1@6Bq zgEp%DN8+D){`cT(e7m8qFX^@y)VEvOT_;)@qY~d+zCIj^BnI* z8x!N&4E)RkjLiT8GFNr3v*I;>)U$lHWBIgZei}sbFGTu}#2h0yxoN#$xF-Z$T2_8DVI4eH~3J|)VFMIUvc&3 z6W)CJ173Xc4|(;;@AB%i-{<^`Pq=yWn(gh1u4?d2PiQqY9ii=^?V%No0p6>YTbaFd zzD}+mnr8y{GrQwGqwm+gVC@Tn@N8hf8N*G}@q5=>F19ro_=VFszxwEiM~hQ_T6~vJ z?DuFWhB6b>F-)*QBQS&vmRJwj5H48fiPo*}U~}nMUuEppPMk)GG(M=rubO~~IUr>M zG+%TSBqZ7abW%!1-`;}>r2P&p*43<^f9=>~HToeBTMz ztgCVGhz$us85rhxw68bzCBmE9%>x;H9o_17jGr_%*wX*FRbC{P&iee>S77!4-Zi!>9&H+cPkD=_gd` zH^>1y@x(r7<-nfesAchF&(Q}pi!)ELusEk`|Jax5bV~^ILtveRlNAO)JpR4z3g}xo zHa7Gs86Uo^^Q`Y+v);4c_LRjl=F3MEb2lC|g=iSomn~oX-j+{(d&3t$*m3bi!|I}E zck8Lvf&DtLy$P((12->vEy zoWK5p^A}&RTdnBpdTJu*MEaNC{m2CPFijyze(2eBstsu*{z+%0>wh4O;IXtRYF9kq zj3Kv%P201nJDh=Eezf49|HY?#@aSW%@{hSO$5cVIR*5x0W|xVUt&ss3nE>$xkoW-d z?GWVCHiPwr<@}4BrZyToK>b0YHe^I#qWK(l2Ba|oQYK)i)p)58pME_sfN8isZ^>qd z4}b3AJp=HK0y775f-!DT|LZoXJCk}q3`|w}$zS0k5(z(~8)?ve{;D+yqXqziNd2zH zx>k;LEi5+IRra$G{|FDzyNUFdLV|oa_~h`-c+<*OG!qHdpy^LPnjnj>1^3k}sgzNh zztJs!CMKgQ%^kt7=yo?W>l@nbhOTPm5TEdtswm+P0h*oT`t^+0pUt`aB4hQ&QEf!S zGsLjDhmjZ@`qFz!^sSZi-K}*vo8by5jvJOw_bi|8nVoowx$L7Cr%4S9tL4NlHzp!* z)I0ocJzORy1NvTK0my+qD*1Q%R~dkz$~sH|XdBOd*Rb0*v`vq-1$l8yIeSb|o{|>} zAvn(9`#`cX?W@@#KB z)izL9o~98EMb~=z-s8QOklen<`;M+_sP`-O+Z9b!(YJC`cj%R&QD!GH1Wfz}WLHWQ za;FP&SkPmC1fA!@eSHu+Exo7UG4$%=V~r(qnVzI42!Gdkwyi{0T;zsl%aUJwbjr!; z2Yl&%fm-n|xoBOwweGY3uq7eWxp-+Ptb(@8$Q zDeEXk_Lg!6)&GISAEG}%lDujP{17j|s>;8@7%v=tJimPq|KrEU%dZ6oYx9qU_!}Yq zHWRhKiC*aU5XNbR4?c45y|lyQeWTm_gy0(^On`79q8|_aj?iD>>sQpPE9%vrzP1p) zMpVB5!5f;rWp$DB{QC<&|NAqxw}xN>E(?Q6BW>cu+LLS#<$(AP(wc7JDwZAd#~Y5G z?N~l)$>&0}t(Bb<@l?kU$6*lCME!4q!R5I)o23;p;&5l3!K=-_?_^tG-+74-;Jx|= z=nF~5gaB35vbx#R)a@WCIy9lWU*yt!sNYg;1UhGRj3W~uX`EBT&Hz0%5RDH2fu=HSZydW- zMzgar=Ftx#0EByDdqnkrWO9;q82ey)SAV>1fkiN}kSmPYM(5Rc4c;>V-z=DGBtRFu z7bh{_CwNttQ>vR|O3=rxd}4zRNid%&W1zo%x?RxHdyC5&%Gn0%ItiLH*JyvqqDzra za{1NpRf{Zb+M#fhTniFX;;(ASh@kE#{t+SqiR~Fbc%S4f5L5y|h`-Ij<`^5}{Hvp1 z*b)2{zPX@T-B4Zc>8ozE{XPUL^;;_ks$4#w@#PN}JpbX0)uq)@SM)u>Q={TPPKih( z&_0S1zjF@fGMvrHb4xz&D9+Z*pRQOwtC*ekHbL!wa(T@>+fTZ;o;S9xq^ zDP{%MDJn^M027@Ch46PxFRK4RBA%*&V*w#R=mOQYWplfyYh?|@_FHSovXXLs!hHFR z#nHEzFF&L#KP1mTBzGTD`gmx{+$jCqOiTk3Dp;8S zEB*jiUl!b)7t%D7)L+{*sQQP#iOfJM{Rc5~sg{F7|Ix1nmf-t6gfB7n<_}WB&jY+? z0KQp}3lm^$@SeVH)B#W=?>N~97}rBW{25IGD$$1^egUKofJBd6BYpsb*&s;JpL~yV zUey12>ezEohd&5BwAK#VH(}({Z<^?LcS!t`Ja=HySxHJ&jM77QRFMQFwwV(ALc{zT zFrE+^e7B{qZ|JtywA&k+&5m~4OT2m>u3PNazOn398CS0h-h5W@<|jGV&ojCjTp^3#N4{C>x z#T%S+WLZgGEGWw(%JP^zKO%ESID1T%9aEMk%;qP|7pKhTr{u*c#vjw|m-zaK&>ds? zV@&+(kIBp_v*HoU*&~*V#~dvmbG&@Q$~&r>j;|92P>g{f}wDhqatHj810 z7yFiV)6#S@?*WR;@$~43cK(Dn<^w%8czhnvu{|^gsKg(A05T^bf@RK1wTzQ7zk1=g zy~yyL8yEP{9|!%DG&&{zvE6C&wW}Xo8+X812!2oCb7279O?b}$e6v7w%LWs?$9D}u zqQguwMN9rvqL1rG3Awj;pAoz+v_a~ROo3jjAAtA55IEaoZ7)#Z+67ns{78cxp92)gBd^kFXmi6cXXY>m1;*<$xC0E^yy)D z4yt||&vMVmGe=ffvRO-hd`ot6MRBs?=xNLH3}#1;VrIyc_#c`=1s99d-c?X-JlpG@ zw(2Qn1*eZrD2n{fJJq&hw`w2=vo@CXFuxX=jJ^-Ft*33oR&8x;TkO}w7Cl@?jfcVF zpfBj_CEf0rZg+~W9uev%nC1zteL~hfAq!8)ctma5*lvq<>O@>jG zy7%hG(D#FXP8&)2W~zhR4}q*< z_P}$ z8m`~uy!@o(t%rn?!O8_gZoW>}NsOpdd~ zm`ow|d{>aWf;=lI@{*z~$+8?nTp!9fM=iZ-E~JSv4pr5$S?#&L+;I73#pRndH6}xpyTgf&+YgIk2jG;{9sFPDoz$D$H6&MzL>}Ory(tX2q2+$)teT*>_&Tv%b zJXy|oG%s4Fh6J8m0Lr?Y%QuLEC>n$OB_D^jz{+kgX4My({pZ0r=*D z0q|WWnn+f9gkdolg4a_3hczRMWYidp>i-xiFa(3Kp1j!O@>bOAg~euq zVA2J3-`a}H@V@0ZRQV8M1=F%eS}=gd*cpgnM4mqjjP;KnjOzWvFr@n1AWnWN^<#7J zp3v9$c1>4Z(r#W;-`r5&R5V-gy+pzrLIB(c0s2my{MI*)S3k-5>>m`o_+id|Z7G+5 ztWe?)LW~aZ{2`2lKZa(_WM6h}aAk*E>~PB!`O%iyNzc&}!_gDV?8K0jvQ2B)IT0bf z4iZVP*#*{@p3P-XTX}ph8i1qIBZ@K~E9e7V)6-NvUDJz=INF7E5C24(PgKR;2fEHv zS1nyDR7vs(;kQcY+H!NbXS1rQb`4$K zX((Lj*ho(&NeO>?9mip~IHYhotwR8V#~J8@MdA}eW(|uX4w$$Olku|$I|3pjrsEvJ<*;8FUjD?fy_GG<18AR2Qrse_ z?H&G)xC|zfb?7T;%EMqYFw`N0H&ATjZ8Q6;(|kYY@SXwqWXnQ79h>z7qX`U>H<%`dPRDK_((G$CMKNNcbfM6EN-(HhY4x1(+864ej!E z7uQrbJKCK%v=RH@f$E5K9&j#*)c>mBv+tMu@V91Me3{X<(NWKglCHiN%ZybILpy}< zy8-EraoO`MC(8_GwuRXmJKHip>Nz?yET35BXXC*>aogmS0wv$|(6_K(1=i=D^+m^i zrBVDs&+KT<+0#>sd8q?uXsV9e^F8&hm7M@tjK&zH#c>aL{EZPwTh!>Dy6VLFFVSj< z6QfF+c9izT;Y^r=lrgZXk{+Z|eRnVu7=yuLg2eV0TYMm>J>Tng#dw;b2@v`~wd=UP zSo7-h3toJF&gmp$w`WXBV`C=bd;vY=)fAl8FBP0o#Ci-oX&HO z%8cF`Zd=c~@zkA!k}it^H#?%r7S!Yeot;c?qgsF=pp?NljSlG4=R}VXmUXM94ijkV z!0kn#+E{#(4~I|5{Fa2aMG|8_5Ts{@j0!135Ml+#@}|kC<1P)spTlyOl=M!)dj{Z7 z5kmF12-V+8Z{@%Yu)+6q^YU7`RPG`jiJ{S$*n+Y*ba>+%4S_b=JWGp0~Z2RkQ zSwA>|-TCYROprnXfstqt1VPv@=v%sK zPrF^wY;I^bH?*5I-EL1`_4rOJCA!=@AcP-+H&nZfoAZJs;z9# zvQD~qLV z1uqhR*ND_#tpoK&BIvEJI(92Le|L5?W41AJAofQj=y98% zvC@4ZAlnOjvHkl#Xr4&4g}_)R>gAEpq|*MB;19%ps6#ZBX@iIPso(ZNob?CCMLor? z3p7>7W?gZ8x#IlQ4HvJjxxHMmS?#EHHTAxs-q-Bbd$y|`tD7~~=hs}mxaQ)^8_vI2 zas7HnwP~sMJ@vMu*>-f5AIA3(;?znLFkueHHpqfq+C9(g9!sE)ZhR`WTLZbXl$j-W z!XVTEnh@Cgz*T3sX*~O;rw)$J7RmRfFxeHLTAE?JVvrym1Cy)~?>%)DSY0~Sml=I; z^bCSH-w%<)n1)&??z#h$YCiPbVB8E`-h|+<;KTi4ws!^IGXUQ#D1ikb*wA}?*AjYF z7bXnx2m$bf0KRwhy;BK4$s1&`#KkZ;55;T!VUU0w#(8WO&|qGgF-ZyBv%DZ?O{M*N zh`-{hNwFdsj(hnB_@aS6^r{A(1JvGdag!oJSbguX@1iNpcZ=kIL_1d$)_G~UZ?M@ur zwzn<&mDu$kfB1ys(}mh@MXOV7JF0CsdTS>V%0fOVhkw3(2f+%kPzIilX*Q5 z{)zNH68}7peG!SjAB+)!*|H+t4=VnmT!?069_vZUvqxkmFHa+W`Jr}QTc=6de z7q73`Zuj^gOwPb`BqoPE&&Z36`Etg|qZ5uFoiJa_Awa!tSzXoKo>%Nvt+<{%FtH

6hB1w8Ux!Nez*zz-qoHrS2wh6PY`Fh z``2B(7kOYK<{HsVrHoiK0~iA0|6*O>`nl!J=NVmVg6tNIm5l3C{>hq^agz(wmucFL zd*J}@NM?h{7TA2z62c9*>hQI91>Q3Nf2z=FQZNGpV1n=QT_?dYNG9;GD0DpriQw1! zOr!V>Pwrfgnt{}QCSYAJ`~KDV7%YldMwK&q>ux$ks7ml7sK7m0uu%v{rTi!froyyQ z%oH)qA1OqlD&cnVp1$g7*B$k3OLbFIuPgexC3O85tmSQBWG}ySfzVsFw>h8xaK=x6 zr{wuhGgcRdzJ|~lj0OcV=`M!prCy}c{*?IVSw@~`WM#n4D$HyHyC@(4f}OZv)^MZ{KBvP z5+8r}Tf(F%!Q8FtLG|yl$SA2Fi4Ss?d^rXpvQAGBWR$>r-7Xjcs@AvSb)Nhc;;x?P z>bw{=8tEtrTcyNjc%Y7by%PRD5`LMRqvS8l$bMIIeX-)r>npAqa$YJ9B192~2qo$Tz<)ii)L;H>zW)NRA7%PZd8uIam8m*|v494^DdwnySW&R3nk zs(p~o5zXcLGH`Pd7<}W(yB~^ZoyYnI5+C z4#9f{;7=7YO#qz%vj8%JCwMtYOlEULYC6-yIOBu2^nHf!9KOzum*UOfzT2i+Y2B2AW zH0z#j9|*lkB>u0ch_|$jWw*{)U1eOp$oc$t3O@V$ITv3#y2el}B+Ra;`y&FK;(Tek z!CC}~W}})vSE*lA{Q+Ba*rLW1TTHpelp9>pkQafxFl2cEBiquNeW2cY>Ybd9SFHp4 zczWJtU~}o&UV65df!%drzY0{_z<%3v{krAy^O|PYQOrxuo;~K-M^9NiKEW7+Z+n`m zquF)zoyX;JNQ~I`wO!Vb6^?wS3_v`r$wb179OJ9R*hH<6nmh&{0;AIXC=yQz(>+r) z-U~VxLyXI#OhE9mZO>~cU*AL51*)oHeY@rI{FdvBTej;RK6o)HBxVI+(xM}rBQFYO zvpI|9lErdCST1nu-%$5nm*&`6vER0>=XzUlb9GI#+mR8-=nqZ?6qxk2ERV4tjPy(NO&PT# zYKBQ(t#_XN*5iAo0?7pDM8uNb6TJ1+CV&WIFU9w5R^swmL-70W{LBCLH2XUQ?-_tU zRfrQa0NGRE7-ERjejw08f;%q3eedYoY*;{({7D)hs1LxwLb0yLX01xZN{|xMxFF4` zls_oV)3V~4_2MuU6xl^JF+rLe3~e%k1iH#ouX?Jhmi=W*b=}eK z#kmbehqe1~%mh^Gw+8ygv3gVT`@c2k`+vLS^B-ii6_iWJb0d5D2XA&gT9r5rgb>CP z`fLoW;v}$&5dWMk%gGB%HtVp96=8NoD6XN{VY7}blW@V-1&r}Dd(ZYNuzKyedG5LT zLekBPp7nXp?#5H^0$n4Ln2#2x09^;S7d@Z-?w<2cE2>RHTh%=K&PV*xpZhb+W`!PN zW2kl=+Z#D$E-%F#VKZqfK}-R8=|uW39Ig;1#yXkTlR!an>)+5<>MUsP+Vf>V(=-wz zQpm>8ztHN|y5@mPf}F zMS(GP&>r~^Xc{>eA=WEO&dsi4eO0r$X{h%aMBp9_J+^eDcSe8660>Bsgy;I>q zevev!=))m>l++bOpQ&RY^*_`gM*I?`3;7$EYBA%SCEg!zB%t#HgK;@Fo2@W3`N=OI zAEp6T@-{^Y^Tfo}tk2;jR`)c^8qnlxxg@RqL4>AMUcWBk7r#)T1=?)WI+@|G-b z!1`e^9~K$c-}L49FkuviwK^7H6q!lcf&~WLJ!Crg{Rf4F*c&5^OILfEou}FKG@G7o zC!uWnTD1VJN+S1YD(-+$e+dKh8N1bt^DpPT{IuZZrx{mYIBs7%_O}viVTi1!w&+n6 z8u^`3%C$}d_^53^&mCD|$mT6>USStom~Ca}QdWVh39bg)5v=TBKnZG72lgA;w=YNH z2C9`x_Uk~Uj(znG_PfA-=+)*7;0J@XSAd_Hr`j&h25MqY>p!0IjlbZ!M7=+z7mak*#^BC(Ge z0i8Q>IL6EA{d?wEoVrsQGp-F2#5_>#8#e1Lo7INhPPgL*C3eQ(qDdk$b5>$66h+Bw zzM!1VB&L9wqS)XAP2JO}k3_7RF~WGXb-jh+KBg)HR*B8P0e2@ zU-M_(hE>~hzTWZr@`e|0u6T95;(T3kwePvy_q<+LJil7;>Sj&X^%Qi>sL4W$yH9m@ z2u2!^G6GQ>Vy*fB#JQjY6p-kE#wLQn@Z=ELM1+!b!B=Pi4ss`82;dF&jdA%4ptafZ zFw;8&?-_tUCFnPQGyS;)eg$Kmh7j;=gKwL0bq`oerFX!4OWPFmy&Fq8q}VA0DJy#Y zr(jGV%Nkr>3m0!SCgH)S4-riYg1{3Fet=O@Gj=?tcT&>8l%9(%Y5uZ z^<&T>iX)Yd+Ss?#6e6LIne?sbP-dhf={wJMv*Y$=MOD{$?-L1DiJEF=QhRrv7ZkG@ z9Szp(jKi{!kB_~L}71Z0ofX6bk4Zl*n-tax?_LUvA=4m*FAl$$F;^jm~_P5{z@t+IV@yZz#2=pFS+{igwKBGgdhKQ!IwXV z&8nyCMhQ{sBuF`W_)BvIAx<6orYXpD>H1NAP5l)sg~)h+)-EE@LcK|U(&zhRMnpbX9B;J zzu;e-|CDE@;UZ-C08Lf1xm|I6aly^S1>4n%zH9XmA^2r;!=JNXGGmV?5iky5_?*^3 zyM3r*)NG|Y0V1PqKz18t0XgR~!7EWIFroe9gW#FO4v;jONz=08+6ekvz8pf|+`j0l zo9A71)%W!(e&n5lhiB@0_+te-f0X__2L2-Ot)L7*rwjlIcN>C4?(4f8-|K$=VS$jS z#0K;@Ss3?%30T|XT!+hL-?cHx;(7>Fx)%H0G_NtL?oX;gf*g{ZlRtkD2z{V$16?hI zzuSAdeNVgfwA-F`+tXJ;Li&dh=}#&*5d5@Y`7QM|bd6zs2$n*4GL2i%8%qbaXWMPR#_Gbq? zA^1@PpnKN)F3`1}t_idaG&Qspv~{4ZpsAp(4Q=h{nvAZ_>6;m$TVVVVnLVN?kC@Gm znaz(lIz8d!?1bg<0$1e28TWnXX{(Ol15Q=?LwlV#{gv~KVy1idGck$CR!{9}okMc= zO_ct}u^I^VK-6`NlIb&yo<5BIAMcICX|zv^Mn)uiYb^n2+LqmRM^#t!y*R)Pj&0Ve z)GyHo>s%gBp@JTGwWuH=6o_}wv-SDf$m;7VpC4V-nz#3{FsOyH^cEf(RrLAikFTsMIu;V*i@v(VBPK*Bv z5|Mu12!)m2H^KmqW|Fv#GcsGE9ddf6)`KumbN%V{*z(8#r1|aE47PU%g2CDzn>E-xC{hjt6NLUnFY9|CO8$eBa9r>aVMkL!MAG_v#MbdaEb##1 zf}Z#lsPm%Ynb3=Ezg~6X%y-dJ-*mJ)k@n*^qjS>OS*e4hoRoMsF(5ME88+9BPky`P zAO7b#Kl=M{{;H*=BAa#Og~m;YIO(8i!URO=F_rccRevPfnb7wJ-&;a2XF~*U!CUAve4FFjg1(;9)kpaH6w^Jy z_{W%Vijkm{BLUU95&N+3M3N1}z1^cZ#X8yUmzQpE_KfENh(s?PCSz+<@{c9}AQI*% zts^l3gm^>-E`j8BBr=h(%k`+jkM~7=FV_Hl-&5B$+ufF~>xOR`Giq!k8lf@)gOg@P zo|PD5#%;R~fif{&7ig;vuTGScEQ91M4XU;suRq^%^`@fQkLH%x1;dg`f9Nn-EJwEH zFU^0(`yz~*%So@mh*Ah4gudQfH0zfa-S#qc+c%SZ z?-IOc0REJ~xDv{z8kHp+1CLSXt*)-=n_4ptZ;S*hhVK1CLO{I#^Rgx@dWriVXN0bn zVL?UOIe1OWsv8!2l*|s8h7lns@sBTYus(;?ITHHdMdRT+=xgZqfp#MSYU))_y%I^k zuRXri(5;7#e1i!jnn@xPF;)4;dxmjOc~eegtGY{V;??1%0&oK2pHi4I^{E~gM$XE8DCZ=5FsG8X0qWmLu4fNe>1B7C9jn^H!uS7f?P|A5Pydd*zI=gc02mMCj^--!&c0}<{wj(Y9;*e zP_eH7N5GkY>3h0XV+q{*YS7TsVisxYp4-cci&s1L+g5f;#QqqPuF3eH5luj5Jdf;} zU&~(bFJ(XGUkIP_>-{U9`4vyXn(uMVKj~icSF-2){PH)Lzj?zw3B+fv_u%EG{v^*wKsH)rKue2tBfyxx8$?`vf#~6 zGy2X_E}83yM)08Dg=K@^zYsi!k=k$J8_hADp?CtVT{Eg zOh9Q)nVTofcuL+sChH#Ix<^?38bhTr4&0lfFLZOeAMp{iutTYOhE1tR6UEIVKVBw1q;it{j7BiltYqpo#t zdBqr+S20AcwT9ig@(E$FfiOjr>!-mz}e;H9evky91L?rdR>_s0_@&c*z_}7{kcW0r?EdQu<_y z5Dp<~fF#@!m1-(ZV?ogQWVF2Q>S;7$%+*vo#mSC*fZ=Di%6!E4GJ`piT zS{xz$5ibLRq`aZ;3|$>)wt;#D)oq}<4Ky2Q_s};6-zCQw59$WJR-`bf_aniNnv-A% zir51BU9F2T;*`|Xmdob_pZ~)-Uw(g%?=rI4xR-gb{Z1M-mSIfL^8`AK>GXs}$6_&K zHY+IdoV*x`eAEg=WIn z88FVlm|sLm?GL>-xlZSt68(e$AR&&EISO=bL$%)$`c4kbQAfW#b245^_+#H?i4TBi z0>B!N37YU&P0j=|6UdFn>5L1yjG zKoG~jqQjLQ>qfhxF$rxQ7W4G=m~Xfr^Cs8RXCq=DKvb_-hfYU8Xks*-6RdyWJ`&iAF-q&}~hI&iaI98Vh*Dp)1U*udr}hM<+|p z9xqrNm2zBcYFAD*9}@_mVUm34==zqnYcztKCC_t;A}7yFJ}Y^tJm8jja$Tznz?@md2DDFYBAwpl$&SCZPIGhqT;W?}Fzhyhwe zG9QBWBn-yTPdWh0Ks3Mf!#p^ENJs`uJT?#_x>l(%eHM$8BE?BCnix`NvzS+2pMJmZ zJ6>I{`TpnU{N&Y&&n|X+akb~gO~u8gW!rcHmLkuFlt-scH#!2!w}Yf%X3FeKW~J6c zoNcq*>6sgcG)Oc@StiHn8UXKyrdPY3)m6jwMa6#C5j0dl(q+T-aLXXfugxeN9On&B z+=|EUmNU0uVQMn^glX3ICRLLk_uLvG&eQS7FdmWkN9HRl33(a(7*y!1K^Oq>0T|wi z^GAt2I;RfXkc>hFX506FgWmj~HPgEZ5AX4K4}UE1@BCYT9>4!RTzNzYAvebU^BD72 zfnV}nXWQ+D-Q^qlYKN6GtARgC;xA=c>&c2e)L}H9x&*k13wJ6h4a-LnsWH(o zs|Cl0j7T{m0r{{bi9;Xg_afPMJ40I`#J-cGilh2|#PCVs)0zxLGhqM@IGEvn)B*?- z5Q3#|ExX%{S3jC_{Y61rWmsc4Iw^Sk?1cHE#5vg_=Di^2sO=aVb_nt;s+XIl0Rves zTgF7nPXp#SZK{?VuZM0J?+Yl#)9wl4axlCzj-4Q1%v3F&jxQ!k%!#_*N`EA%N9P7ki!uJeJ>hP^-GRP#%Z)A|hG|mNy45`hC@&8-h9ygo?ApL5ML6r%KWIy&x zAbv;xri@c023pSu#u$S4?5aJ#^`lq(FaN_I^TStLe*C85(~F9iw+)-dgSE`doMoBo z7>#{slm3cQt{E5>t-~-ArjQqoVxHkLr+qzwF?t|U>j|BB^7cV=B*uuQrSAg!O-EK( z*GG79X7IDk5{7a$+gOf|G}ne6h0`ccdJg?clwq>t(xX-+RtJ z?EUGpK9mdZtV0eYxUaJSFnFKQ)W@{#T+9ZEnqwGy%_~E#+Ml7!sFAW?g89DzpIH71 z(DJ|f>whn1dZ*w$1Mnvdf9>D-*RZa@WF`21VT}DBV9Y;iUAdZ7?=Q zJb7?c`~ksWT~9e*Qyx`hv&8Ou=twlY5fQHCd3Gs-e2%Q8Z5a7OI+&I&OQgsPMb^zT?lP=pv_ke(jj%bxkN$P*%&^ey9W z>DRHp<8$H{ho9;AXx_mjlMuy}c`=G06QUaHBF|)7V=>D(IuR3w(G&H2FN8wh)^CXS zza2szr|r-*fcBl16?YW$gCn4*wxa{t*vx5P#CaLZAKNy5DZpqqQ7|S@w=Gw<8-DNe zOa7z3{e~AcR9#?Ib*%Os>#F5;*KoP6cy+Vmi;FEUZuVTPYj%xD%kwg0rdol+ZEp91 zPL+I?QO<>-N?Hfn#J&%7O;6Vd(>aW5%n&53u*9|q5@Okjzr++qroeDOw1+7>&fOU6 zW7=I);%`V|f*e55`R?PER38W$oT}@D@OQ1J_nt=|cmC{I7mArgQVS>zQJI@*lUdW9WZ|r%nQlcy=MU4!=DWNwSV{D#JEgS@J}%2 zU&ok#3^2`l#s2D?X0synoo zItfe$oXm*x%XK8niwsLf}qwjP(PY@=@h#vW#58ao>ijDtkB?i@htW;F@k4{bE z=;zq4b2gVbx35a7>yl!Yvpg+)9y+i=_U>C}ab{GPixhW1R*VFp z?|a&|rRzJawPblN%t%70rP|Z$*p#84kxv;Z98~=spN;Q~#BeNgEDvRd#`iSYs6~J* zvy`)(#j>O*bLj__+O-11dp0rv$#%fV1dJ6QA*yZV3;@|1-)npUg0gC9KaloC(l)(0 z)L(Ave@eFwhbCCoyM~{zaKdd-$D!&U>n+r)qoJPLAFct;JntBtkKBlnd$4Loi1CEZSO#rT6MT zG5D;+wi>!d^5ioy(Kr{^(4<89llDWrj>P{^@;@x%LCOCB(kOmj&jRtXW2D#djSRr! zZwmw9a-1BCaerSK6X=>F_S;AFU7-wvGd+x>@NcU62|;O@Sfe(Ih)sC(l@p2z`ZlO|A@eNvZ7_S*pbhA zY;G_vKve$|k#2%W)1<^9ZhNyv)WLlN)hcIqGh=tXV1K<}f4iXG&S~ozeOuD^CBYX2 z@_{&;LC<~gu{)A~`fO;-(5%4^Ks5;=j3*=-J+voyXsV2x7YlA)%-P=-gg#@jEO`8E z$;sJ**|MN4GdZ+IRoNi%?tLGy#*jJD1QfYA_GK=Epb~6~EE9-*+xI<9+tSp{;Q2qb zk7{@5g;6P3$`D*UNZpBzTnK|E)aCxB5xE#o0iCV9|;^~nQM`hJKp9fo6;M>9aD8i1}3Jo#=L zPM>yI*+?<;RQd-X1WVf-Q}0g*K}=<`BSz*>)LNz!EnbeMQwt^o?2ioLZ$bENU=0WZ z@bAB80N%qNGlc!$8YihSkAUCAn16u~zU8}??d2PGZ(gXw&t1vj4-IN#%d(ncwr93% z$Yvg!o5Tb#MeI^tMGYF2$9JBtHndevvzt?GmsFc2^+t$&voGkHTpaiOxG06dOw&LV z4C6w608#`tVu-lXwUCMQuZY41yf?J_jQ#DL&EkkrSBBABK6=rMP2Y(W8CI>*V}*W5nT0vbve%|=eZnb8yS%yzv9+N{FMPn%Nk!8K?s-Z zaZlC7vb#Wu|1jWVUB|X4V-~-YFbJ{!MroKxqhtGm&DrIT`C{eyzx?0--~8~!PdUmK zN`;gXMe~D7^3DheZ~DOPzT=12EkFKZ&+mP<<+nfC@^`N)s$EUhG}KMUW?yr&t+`m& z)U6+O733_ zVHt0M*yk~(!$bqnN$NTerswH*+i>!v!^p9i+7shMF~&o%wDl29bxhaJhPg2L;P^tE z_ID`dt(DO>v36+bCRs}SleT)1ki~m>W!P(A_ja*njoX}-nbW7%F!%AC5S3# zdo^SAYRTsH9N$~A+)@^fT(`sJrG%>;RM^QF1SI&6AhM}MWQ>G~9W()mM#SHP=L znL4bE?~diA#9ypAqW&L-Zu|-$#D8!W>r*p;+KowwP}&Z)bxfQYBk@<_ZKB3xIAb7| z6|h-Bn4Pd*eutNR!B3w*=kwYyZ>#p?Jp${3YOD!P;NeA*7*Ku(lz!V>uX-cqD^hbzNfAG*&IqUOd zRcnAiRf|h5sEwb&-XrQ3juBoG=b$T#V>$N=n z*y0S%zKi+b*RiJ`@$`ca`K4d{HhtT3^XihHzWgCK>#IrHt#_1pIq8?XqbVVbI}h6~ za9aniYdIo$SJj-~?D+J}iWk>=_MPYK(TrzLmSj%miC3SB_>I2vG}Wj9h>aZfziWSv z^)Ps~ug5u@<)TrN_9tsaO(N+|3^Vx7MEGj8|6rj@7pVS@CV-Hbb~=^*10DIII%?$<(O=VG5O!MT>gi%?*F>#>|YK5 z|K4B!yZYX{2WfY|hd*Wr)!$M~Wgvuq6Zm&A=G)DBB$pMBr!*#iN5=jfV}wwcj&CEjPl_BvxwNnQxPah;qiV0*0b;!hx$ zML!-Fsa7S~`#UlQa__L^5r5x-0YgpS58l$Zj&`3>Z%WqZ3#wItb6)mo+d$^xUU7ZZ zfXf~8qnyQYfw5{s)$Lb8s65rKWqT`9`+Y<`BBG{g*zGIU+bwn5-f7eD-PjCcc>LrM zj~<^epU>2pYwD9Bf1^tFP)e5jlWq#qn_~HqCqbpncwT__e%P`VRz1Vx-!Ab7&^j^r94Zl3zW|Xq z6TgeWUqIC2^{&@x;=y;=r+)_XtzV~o^y_SW!S(qo-n@Rr#rYd{+bwld)At>1+p^nk zxj28#tLHEH;>VwI`Rbe%Hw55_6OK-fDVH;xyDLWp4eQ))i!etr9%H$2T@8Ku01Qv%rSZNGI+i_c)6+E_b=^@{ExT=tH#Ozy zo{xXE;?ak#>OK_WTs6?QC3Stme*2WZEi}SrTs!hTL-buroRL-782N#KadT|(7-QZ4 zHtYYB|4EhqTf3tBf53YUzkJrP^9mf`mJ#kCC;g^3bal?=e97v~5xdI;zIC`v z2*0xd=THyrX$ig$WV!6Cj#BJEe}e4)_r0gt$D>&v9;bM4OxO2AYjQ7YDt%5x_E7AD01#-5jA3|W~` z&P4qmPx2FK-wdbviSNRwd5HCkV;TPp5c|}tv!B|Fqq=yAIvHOx(WIb#5mo$pEudP0 z=qRU06?dKPpC>@*$a|>?Gst#L~1KUtDbX z`#-th@BQeUPhM?s*6`8e1!a*9J{n!;sVh(4$)R3pe@5vaM)Q}fIT_!2FFO=w^K1;o z9M%0J|2PnM`J&E;JL^gz-q!AxG9Jzw)VVX7&Ae^_Y#WcsIu>UQ$B#Q^OK&DDzfK)P zps7!&c4zpm(CxuP@#DBF!#4qa76R(`lwsTqlO1)|7Jut#{lEKvHswEu4bK7i_x}2C zP2Ycq;GpN;!ygBP>OW0>gbZW8i?#nY-v3)&wP*9@C6_D&Hk9;QU`<0TC%(n zJG@alpf?1KuI0TOJ?9hEaOB7#V3f#PBPxGuMe>(8_(J@J7!MyF${GHoT7gJ-5{Ti6P$7jniI1nRZ#6+8>B0}wpu}8zu*+zRQ?Zu#NLgNy6uLxT0$AdJj%tkTKSRBh1 zNznj^nM5N0jf_I9<6A+QAn&6FK==Nu?G3BjTeh1Gy%)_uwcqpV z#h3i}_rK47_8|c1wU;498 zI6a#2=w!|>efyNcShlw<`>LmDgV_F+cuR`JKmL;4I0lKSke8N|MHK@2W10h-1ZjQ;1T2~x@VQl`t>FlrmuU-EM z&i|JHJo_jAdQ$$o1z)vf|B-|V!99RKjT4^^>T?48H?j6#4_)^!@2}2Tzk1H*)ff1- z#oVJ#{G$S6Jl1st@9@1uCZ9g%U^VM~WKl(8Ypoo7V~r4gVJMXNPY8Mhy^h2TEicyK zXJG<{pQCC%^w91zs#VG6azTAtVzb1_&}i5KBQ6-x5&jT@56q4Vjvkdmoc4eaDA5i$ zy0&L?Q`6RC9QLtIf)_=-4!!p@eb2tC*=)CTZA;a3-0nNh_l6f6!zULzKE2qouPV;h zE&u9Ye#*c4&;APE`}h&F`AjALxI;s~H0fLElXyoQyCh$%*T^1dzJ$^1JgZfhbXr41&S?o@&46<%=)) z>5qQM_kZ^v^7_>)I^VHfZ&E{CEGU zkNEHXmGANNXhys3FdD7Q9~`mAHN)bGWCHG$wAT{~mH zeM+@Eg*fK26!bs&sH|^cScl~i`@qO99GgGF=0|Ijm;br3?*9~6{tXj$xc+wlc=k{I zA0+=f2w%Bu|51c*Gy`DFcL?Esj4}V6zOH`l>XRR_dHJ~<{~J_C{Kp6)`Rh00!c`)3 z2ooZ%#9tTyCHmH5jCl7C1U<#haY3eKM`9lraa_R3f)>zsl2?`FOCBSB3(YoTeKDiD z%?Z83w{l)U#J57ARXrSkKhVX&2g+s6^0Xu`Wh-C^;`G;bo}$d~y=S*>sCFG)>&f(p zQ>zkl(|K-o4XZYdcI`(Z~*TTAm+kMZr>G9t4<@1Vv@t=Ck z|LDKOf$}*Xi{&|1>XOD@PKX$}9=lkxxFJDz=mPF>;@16S{8$R~lv0XGEFkRu- z0nV1>nS^)F^Gwu2*@P>XFY%Sk`i!3D2p%vrhOcp%->YH{HI#mpLWiC3M{60 z4uG|9xW@pzrJzA@g?$Ebxc2b%VgmLtB0_!MhvWZk^U2eb-JN*j<*zWjbp;*O1O4|3 z)Z+Yl^)D;`S_&Y#M=uU2IO|9{5uLe&q#Y4O28XO9%iM}>fP-vQG8*Iz2N`?g zoMBdw<)Y^wX9XMm370npynJKG#m$ln+ZmVkMli@Fh<>CXax6s9O%$>BL^yvv=jn&K zeE7X5_`nk` z!f*V_M;WmLz*=ja&SDSKUpTNcYqRLpfTkOa8Cm8)`JG&?Ey=`CNKy$e-{~mdEoa0 ze<$19Inuv=g}v*Sne1(&z5n>{1qc&Jh;zO2M|;BGkOs)4^Grhc4ywr*&a3Nv3_$a| zp4ioAHF^UFWueLXG5wouhTEDf6XGa({op>=FpTpAQ+pS^JAreKI5D)kG3{PLln4V* zOazfdi3SJxq+~qE+1wiO+?5@kzq-TA*Y~)wGh%y?Gs+8!a;7eK0cB~iI^t5<;m3dY zA-?zNGsLl`w6-#^6J|!~F0w0M7bvl(^IxqlpqjoO($> z8i{L}clFb%p3K}*BR#Z2E0kFA90Ya$Qu+fn7y6F&3LAjbxNuR zL!Wy|fL03SGRkC)!Tb}9yJsnq)v8Qy7TB_+-|utb)mM4;%U|T*BFM^3F^ouY7__y<0@s*00sh;bM##5hhh$Ii~to0COG zC4FfaU{>yh2QmPS%W6(ijj86#A?>oXl!Y+PW$r`@kQel~3p(q4ckGc3mvjrIwDzdO z0SfCPCX+=5yX%yNkNNLGq#FJ@RM_`-^-fa?;7ZUj(cHsCt>u>#oBvhf{`SXm{?7vd zUA_wU7=X7PGzjl|fDZ$|3j9_zQjLL9jDrAF``hb}-$1C!5k{zqzKJ6LBR0?fFa4X> zdRymTpcwYCwtRCU|9y>65%dP3SIT;wTDTX8z9$&e`hR9u|Nb{H6q3n)sepXfc<#S* z7V@!SvKuoQBxD1_WT40=vU;ha_641-s(t$_2H-CA)XpJZ0Bw;1q-`I{wG@}K!KC2& z){vJkZLzsEWNT-{h1&xz+#d1j#+a9Pau}7Mz@)I8C{iQLi7+Jl$zvd5&N(K-5x4g& zdD-P}{a5eh`@iu4Ix#{meLVt!o2raQpiT*ToI=ZN`4z4WUIL&;ht=c9F~(H=Vx2@Cyt-SGv<&Y#+U33HmU!s+6318PSzGL~*lS_E z8V+b(JqzK1|5i*uUsc!}|Fk$lp{Iz6pEbk(2cjcULv|EKy!8&uRK z>OFvIExoMl<`2I*_n&>{{+<5;fFn=+6`#)A7iOpHTLKykz;^(D26)CZ0bc;N>lbUC z`x`A4aN}RA(zbbqPSOsFAGPE0A0O{*Kel`AQnGvTB{4Aiy|nrdB7INbMeH9K051_B zFb81*%CFo9W<>tY_hfR`%z{i>e=npFP??qOfs2V|vKKSlOqlG&e3KninR z&3vMWs(Ajh3D<~i7E!i= z(~Y?Df#8OG!pf+j@2~C!bf|pa_^uEIu_P3$SfPTE$7a3_`^@0j2;*icZRpb`6JW8n1ajJIeYbGxw$pK`a9V^R zKI&h8_c-IB#QdL1+h;q)5Xh78pn-FwFv_&i=?bQM8l5hDR@vP@o|`A0Z)N`+fFn=+ zjVhJ5D;zXk|D%Tn1MqI(KLtMI)d2rJ@QJVq#Mg@fAX$jXb{@dlzdG65{ll9tKhJ3M zCN|IH`GHvT>kswHzh3o=CH)NXCyX39uOtCeRcT5H>i72D6LdcFjUbb8Ux@x_JE0i+ zfF@31ttHPVfD;RA<@K>s8|rvJ_-gfkmu>987{$ubE-unsxY_5+uioY}&)wkG){t8} zV{Yzb?2Sd|FUEhK(A*&lSrwJ+ZS1gJZq7a?rNbi+KE{*Z{6W6y+rESQ&Yfm`K4R|n zZa1i~u1Vgh_uRC;uUi8WCo`y&JofGSjS z!!N%|zj0nc$O{QLQ|0G_{R9Re_>8*}%3zu9oEUsLFFmk6jTwbUXcyBk0t}6#$`M8D zB!ji5nY4~ks9v*R2SQ*l-UtY7;+&%_O9?cTwFN}A#p58wH68UiN_wdTU!2qb4)qX$#6~`^t`8 zuEbg2Ak>Mzj+j{AM`|VHj&iA~B zm9;fm?RM3iT5F;xqBl3s(PJl=TUaDDj=3A3Al>*lPPH42?j-fPT!x;$7QGNc#KwwNmC|NN)fWs?paR@T=^(zGJVMd`S>SAbPKa9rE_q989N0-{nlGE78e3y0wOBt^c}it^Sn4{{O5~J8AY40IWUzFYEW;rm(LG-wN=B|4Dw| z@n?UX-Ak{i`IBdV0@R=Mk3R$aGvFh@%Yev|Ujt^Df_(;l0X&kmd4}$OCvaIadHKEh zX!t`rmtOh7(dNyEvi=^nC?x9N?*TY)t8VrD{3GSU3Er(Pv7yydF7`Pw-2yx?s4M12`dV2sVqa;+d zb)X2|&O#VLUr*<7PEp45|KFbd>TL&yHQ#^K;ELY_z>Y`g?mXq*_TN%k|EP|lHcI6<_cHK#Zx`^3 zfW(Bn1ANsCz+{Y``)&iD{_gROE8jP`arJwKTeps9{hd^hTVT(B_n;!cLA>A4_t#?o zS*Tg?JE;R|2EY@30)x@Gr-cX<6UA^lVX&E!j}>JmdVid_?%`K=0F%jxNjAb^iKCb# zPO8wfrrIP%BmqGM5RO?;3XImoMl;L`o_TeH=dW&aZEL_+F7NX3^FtEtSV$G!#Ou5d zfbnp|)y+#&_rBv>{{T;Y-~+tp{ZF&JyaG71HY7<(x7Q^}M0Yz20RcNSxRUnXi?nv1 zB^h2pm1CUR{|&0am?$;HtW{^K`ZI-4B`+!lphEr1+W1V}>FuyeuSFIfJEL1RlChOB#zeC~eo-Z@Is zt(crJeycX}(-LnRffU#OO4~Tkti4gpKyz$PCKHB(0mI>d%NH;3xlezJU;g=D;Dz&F zM58!)mY`}+l^@TMg9 zpLm4(AA6WHXV0>@yiBXrW@TlK6DLn`|3eQmH#aXUD8IU|_XaqqeLW}*&Jt(0Y4u;F zv-Np&vF!ucG)AZ|T-6U%d8dha{ZjbUi_`siC06%;l>%i%0-z&E2O~gF+;BnXU#kJaYEy`JZS^SoQ-l~0UMEoII3lv8cakkU zMAVD()m!s^+14`wz(5j;{Q@?IfMbIRRBc>n3C?1T{_Es;_kSLN}6Ro z#-l|hqj~SLGLzYBw4Efq%g8>QDVXlO+E%N?RvQk_z>c36uk$^D2Rl0AB$%{Qa*66p&!dI`9}p z@kjGv|9iJDonIKEaf*_a+P{<&^Ey6e!VG=UL9)?HzW#L&^7k z=!ban=@0Pk_dUhY6DLU1)bHjOqz3y^Iuz=VHgf`l5Y@{%es0AtppxXMkZm_!ijRN{pN!~LX z)rt|Ej|NzI1q5R6hfT0j4^jY0tX`!P-2aSt1Slous+1XyhF@}-Bc=_*dgvdZ=K z3idGWw&eIFL=iCZs*SaisV@hi&$^xuqX}QDd+C0l^b3~EYy*Q`*c(8R7Hxs`T z_`Z}F4pQ#Q3!p4320)pT-ick>O9SH81RZ6RMar;$glycUEMNaVDAh2pnTRXEe_Q7I zU!oxG=A8ZRzgNBgc89yiO#cyrbGIpWK0`5?u<_EfCt8cEe=%;i|3KVspG~?wOp=Ps z5H$qO<9HR^b#S+ETmo(YJ6`!Q+gneJceYLq zH*S&-cCcmXSF^9#vi#`~%@2RluzDKz_B6 zB~)3!WB`+aX580|_cYl+V+##R!ZRGk0F<^Q&nHYKBg(QMNn)ZnCNgF}12F3rh;(zL zHP$%>lah_zUvvlL%W3sDQ)$v59 z-Uw%kXYgWpA%f0d*9?Gs>X)=Azp@S`s0pmnH3OivU;P^~0#v3!{HqnWSo)fuFMtqrXC;$4x~ftc?G>$lKcmOpETNzO&+g>!=uj;>b5rE`!^#w7jn#y)KZkEA|1S(U2S0u5$ai9A8RFjUvwr;xuA;wa3XbYow_d z14?^0n3x8yRYS8+r|;Vk0LZIygn5y}dK&;0mCT*mb*-fVQIaXG3(BHRfA<*qWIF2K z>jCLH3vdIcehsC5%vt>jaJ0MEIQgCTjQ;|>F)jXk6t4W{U!%+>3~pRv_tlSe)0Icw zxAMqS|5N;6;>r6}aUk0=s^7uKen}3oPT@QJg#B zoIByHT`lvBY_LcF`W5=uFXGA)7m)Csq4X>NUjY6b@U6hV0#;^Ue7#VW#1s2z-M^FB zt!SXwS@5&pKiDS$2s(d+&^RZ8xO@ct+ls-KVcgd!r_e_BlZTqv%lY)ZJkJ=72joSL zQjjL~>c3_H>*uu#B>jTe~BE<(bR;y-!_d&gQf<^b*;559D2mVpia+ zW9`HdmRDD4b=sUbafHgHxLNSLC}2UbVNG7$@2AI z#7r(@RY&dz8a~q(__3zcbV4D{RD*QM_dXrDFBb|4@KgEwHzfg)LK$F24N#AT1L{=K z6h9tj7=WNVZW;ng*_ir2z&h7u&WQ_k_Awa*DJ{P z(u8%ILhS3nHAPX9=LJPk$ja9DuhKH^;yA`cMi?&79E74v(she}t)R8E{bVxX){UF| z=EpwDCqMq{4ElX;T)oEjjSX7!ohh4=apBm?Eblnl;XP;O`QU@gtj#5UV54{#Ts(MU=Y$5Vs4?eAhh*K!5{g>stq|{N`W7<~iHvzswW=>0jbssdq>3 z`=vkkgWAOZHRdV*3JN)*`g z2B3OT&Zle8eD2X`Sn(5fu9Nq&F$^|fxT6^N@tgIi3I|UU{ps_Nx;C0Do6sL@V{M7n zhBQfJk9yAlRK#B!A^u7v0>&s>v0`VK^II=$@s%r^T;JN_<(oq;?_|UZi~DfxxWTnjr`|g)yT|*ydU8mlkY37J`53 zyI}PZTrww{1RS8}R!X6@VKT|s+3s`m#uhiPZ*cq87Mq(p?CtiMWEs{vj4`y@ZPwRU zID6j-PMln4d1W5w!#S7UvOY)zoZnsXHHOCF;OpqDqbv$0*@Rm+uk*!cp5Zq>@*nuc zfA`aL>2dV*328ImRE2fKMss8?=FD1~C(q9F#L0PFQPP@gasMO7>Gj$&LINXL83C$# z6TmP|8vR>UCDhYPZYrz);Qm)h02C@ISvb2}v={qInbMR+N;a7z8_#+1|JT|;`$4G^ zl>4Z&(O<$wUqBZFfaD$nFa-zB*S8Y9_;3GfK-}`snsPiisdV(6DE>s0wx5o>bKSVz zC2DsuX$upl5|>|VlqW9A7{4WGSVlRVEwN>Z&2!2;BOeW!>}`?lZIcgW+W~E&SuB4L z41I*cUj+UIAn`%r+kw9TJPj<)eDk^>i1@43`e6(JVT3eMZh#pTfbxVxL6JGKk^D}E ziqSTVcNN7%R+U=UD^f{7h?Mews`G~UdXkOl_qTD*5g9|AB*c*sDS$R;ZP3OOe{D$O z$Q$`(48~)wZVdRymp1w7FWqKza|=Bmae6MQbjC$qaQpfV2J`{=!5{b$&fWh2Ye$Z7 z^5kib9Y4wH`a12lXk_kAygv;UbL0PnU#VwxQMa=KbWA+iVD838h{qS?T^WK<8Ku?W z*YEOem4{EaF&6zgReH9uuqH47zB4NcfVckF#(M#H34kyFO$opO&@5{piop)R6aJ}R z=Lvn#{ZlgwDlAZ)uV3Z<=hYSfD9RG7Eg9#!+AQAa0dj?ga%z z!Z9h~wpIMG$LINm2Nqds8P?Z&oO|FX3yWRZr7$pLP8v9 zULAoU$U!HTg>$=kd$EtwWt>gsn2hHr^A^^=k)}?vutC|M&L;fm(RFicV^h>QCstPI zee=B#zyS`NuWv;NjDUv}_`d@`1iWAL`L*Z^1Ucy_B5JjXT3#{`CxF701?6NyF&R;g zhm=Jj81%J?{VWWD-vNFK`1?L4L4e1BKkm!;K;!=F1|bSwUtci*_3u&46=_|W(L0FOQKPL7{E zLE37)A;>#`4n~QMvM8yvoLAofCMKF}(Yf_;;^C|4QX(LRx0-}o{x*d0s@X@LIyS5B zZ2@GJ8Xg2yP7v>lUOfhB_b+O|SE}o?*Z< z03mf%F#vV!e~{H|Sz4Tmp}mSe{sGkTIh1LOuHb;q+}zmZBftDve&eHGJxss>t%~xJr&~8~ z@YDbMPx8P0-M`DxQzx-yS;ZF!V6DR{&GChV?|E#IcR#SgxwEURuFcc#c=T5>D^&*I z=SH1#WB0z`4G~;Ag9>0)|6fSJC!JciaCUdnUK}W;%XBhYWHOqgv=PpU+wU6#PK=r1 zpD3a~W68#vgfvMwvbq3X#b=_3$uMWUH*N2|`r*Geb^TU`H^MhrgkDS)$Y> zoV)IvQ#iMXbMrwqDPk}SR$N(Zo>7d)6r&;euunehQ;dd`lQCtHi&2rE6oMP>Y9PPl zBNP5J;FqWNC=kdzgYW?G;0)@1gCG#)fZ(JOQ^jvA1olB76iSg#V6Y9_*B!gJ9Fsnj zIp9Jbl2Ax{D$R-rir;@gw8n^TH7_#qd_q|k;EnqtFZK`mf9<6;?KHtU#phqW#V4P? z#+NSK;Pt6aZ3@0;6PfFPbOTuc7fZww_wllhyUas=llOpe}wP)1K-O74?V)l z>ME^v8?B`rUn{7FRHLe+k6fsfC$QdLVfxogp3{t7QX zd!4;5@QteotU{^i(b#Gl`2;d zDd2&;$^kbkX3iT))^&A_m<|eM9IeGHi_*e@j*GHQQKWtxhS7R3$QY5#MWEuGbFOf* zr2&AJUyD|D&zSgyG)}*`I=67;C?_`-Po%cjZA;ZWbE&nKZK$(pyPd!JlOLP9ek;S< zh5`6H|Kd~poqzEu{_GEbLl|X!l)9vp8Y!i$QaVvuCray7X`_@Du|LjXZHX-kY(Bx} z8Mes1aUX&ZD#XyBaQndlWA9n;j3@g4*1H~V0bo&XY$12J+)Y$VZ{b)07Q8n=5I%zIsr; z!is5P8i>AlEi{Oj_Jk%7HXUJHj>$GL`3}0+^OVr1D-G8e4KrwTs=-5l&ph|{lus`Z zQZ>Z{)a4Tfpcef%$Nf~^he2pc2RJW3Iv&~TB6bg)ZB4& z?-;r@kMfM1_G8Fd$8a#_GoSi0KlV3%m76!Vh!RI{F{Raxh<)Tk9sKjP4}pyIQ4|?k z?F17khQkS;`{WH;UCWW9i*&m!y4{xdQt=)XUQ#mUNucgT_U;TqSRGLmv9h*Cr_&`# z5>{5%a0QHpBl0XGip9t|(TYepKKp8h)|Q3Tu(a4=X}*m&e{OWnYnRFeNsgD$1T{@K z7sJ>fB?t^ao<*$!P;pVTR9PglNT>(!R2G0!N?EOyHCkC?w2dNT<0!Im64@k)tk&8n zrL-}cI5w`8Mx#!veZAXhkCHT6q+6tZfX*otU;bY|KRNNur*SxRr2S?^&f_}8pa0|E z!k_52dO zrr5vSF0liP8#`32+57+QOaS;!ZrTsuYHB*ukDhyVYz2$$IW5xaL#h^#s%K_uJ`f&4}1&X`Q0Dp=?{Jr zCr+KB)9nJH&-_}6egLVypf(|(BK|j?pc*A&^$@@)Fa)|0)leIQb_Hg#h0eB6`L^#P zzY=W_Mak1Q@{El|eOh-y(3uPRZ4!1N`k{ZOi2n=|Ao(9=1Q-f9^I(br2qNatQld@@ zb&_)VYy3TLd>GnPqyYfxKo!68yjqRA64hEp&!0edkD!yD5OAM%9BcahG0#7Lna_Xz zC7yrbGM!#boJ6%0D$MyN(}SuRe&an(JR{m$h}qsA@yg5BIB{}`lPA|mTM_LvrrnN7 zVvW*}Z-e2X;DLPMR04rG;wF+&Wj>{s& zmT@Hk2!q70_N`K?)LIo$q$hD~vQ`}B?N*w1J89ADw%vTMqr2T!WQ^8EYt>3)y4@CY zy>8rYr^|5?pD~esOlkFQ6z>Dx0l1}itX__KY3?$KQkV@3CA$($>pJf-0B=F?QUDq# zsqo_W+kSQaJn)>i#4o(>zqw0G{0!*(od>V@v_9ik`9BBz2jDkxJcA+wN|h+apBamb zQz7HeTH>;AyU~5|yd9N^m_ajgrMu)xUczxnDK$p3h$8j)`)dXjbe!IbpC(dL@+UAo zu24({j{cTou;mzRSw=fz&GXahBu+j_!SDqU*CAt`*vu)Jm zwog-tZkU@iC zD{e5of(ZgXXu>RC5F`Q4t2(Au|Fy>@QQNB4(gc&1+Bsv&GQpKG&I#rL<&4oq9GN1G zV$vv9Et9BNM=CY3X|)oQwqlc}aTF(U6h+2Fkv3Xu6~&QCl87{kRTLSmwN8|x=NEKq zz)2M6fK?Njo-1srlp1KGv(AYw`A()Buyt{dxD{bb$N&5FH@6y{VMuZEdQ0V5)N35XS_~W zX1Ei6T>N=6=x>(n-Ym#R!r|-C8lC|NFpJETN9=)U1fmz2TI3)6xs8#qyW{bg+gsa= z#uJQR!NqY*uh%7s6ULe4qhG$xzxwPoUcR+Qgk!xcqWc;Il_?DE&LZ9J8olmuqNwZd zwK;xfm4_cY%h~&nbM*KMtyYSjF{HX%P^#v~v}s5;0+IJbMQC_~xHY~DZKt$Bm1ETK zCVJyp^u}lW{s^Y-WvQN=Hl*pQalZyntZSM*{gM`DF!W_bV6_6{4H(65QtpLkK8dQ! zn;qbZigW%?&G-;ZytI;=f#{UhVY4x6>2b{Q_n{X~qEZp+ zDeq2~Wd&b(?p6NY-}wc;@}--s9!aY5Nuf8>vRfTKs3!-q5A*w`Agvo~gv7g#S9c)bwEF}pk4{LW`T%V$3I34Z10f1W(c zNYX?YN8gmCwOqUj-~Hq=|IHtMjK|Kd&`u(>R<-Np%n+LH*3gF`jzic9uxSM7_3eox znak-OAG)}mQx;m~S&t%XVXekl4QQK0@i>hl8=ELG=tw!GZ7HJqxMk3OM@ngTU$!vz zX3BR64EzG`-}nXDGrAK^wqD-V&Ud(pwX=mKZpoT&?py!6*)-lV@V1ixG+{;^(1fuk z*k1xZ?)CLQ=LgNtc;mgF_2)nBkALI08vggdM}gl0z6e}Ev5muFz_c_szUKz*cPF?s z3|<|Bdt50VSBfWr?*hJ4DZW!F_3cXYElTlC%BXKvnh!dwo~CdQ+md-otg}pITqlGEQCuyJdXjoVx7?GEY9b?A0Ges#IOPKSXC zh{><|E9r(`0ZQGx6u{`}9j!H{TJ?K1z!dYKQIlO%|FRg11kto#)m99H@4Du_sykKP zKk`$(EI*CaZm4%q2MBGeSHF1Xpdx@Ft7e`RG{wmt0+A0ySI8;^@6xF2%_TYEO$=LHYOx zTJ-q!s$X1ARZ~r4jQ5l<=*Y0WlaVBF>hv1jUWYXG!N#UQktPwX)S$JZC@op;O?(>6 z;MW3C6tldtO4@3ZO)|E(x43ZOW#;D>t3Fo1ZfVi3q%2C>t%x&6=SU($S=OB7!Lk5< z<@~OTLGRxT3KUcW4x)}FStv+4h0?|1M03$_Sb-u4n(Mr*-NP#t_cuHwLq!b@iiuY@!p3+LaLuvJ(*6NhjYQ1?VrB;A>RT5ER zRq3p^ht)VD2T_m*RC+Br_Fis&vMgsX8k6NY*6+d=8G}=b?P19?7dH7Hf9h4v z-x#wpujnSm6Mu)b1xhL6xJSEvf^P2woz5Cb+(T>6c_~22s&hQdxqfkn>sNLe4##x5 z2}v5$N)t@fSZyByf_G{H9z?!TD0fq^?$wc56|U$HI;4!v)H(b9p!bzQ`BYp-6~0? z(A3D?7o#e_^Xb$Kz;X2AX-Io0ouCluQkE4w_v}S}`?p`^#*G~SG58A%Kp_5};1ePQ zdU>{LjN^(aFvj<%Faud`(OS{%rp(W`SzVn&sSv)ou9wz|Bo^i&Oi!i5R>nejXPfS| zzJX{nTU;1t#-*fR1vUrO!0Z;#eaPuDs~c!IlV({;2I zX24eaN!W_W7q4-=LIw&}el;8{N~9HpXaG5sVOz-Bc?^ ztsF5WsVYdxX;Bbiox*{VP=BtP05X%S=^!Tod3#JMD92k?DJDZp|5ipel$D8z0)q74 z`P61-s~~B=nlz%z7URB1h<_XrCt~bp{HkAvc}V zU${+| zfr+H;gO$H-{5l{n3MSc@ET2%i5~Vd!9ATo!O9N`cFXKRywi3{WSI%#7{8*3s?>~+) zx}jDO2<;U|hE^KUN=58!eO!N;ONTV#9l$v;WbJn6SYBOa*xzGscUKH*M`K@hai@)A zgHk2hl?*4A)rA(Ti|v{*J2ZQFArN}&_iG6ICI}-Y^-a2^OXdrwV~g@G2ewSGVgsN= z{D=zkDbm{2o(a{Es34?m3s<@F6_b)8vy_>{A8;1Dfzv@vsJtZLs9(4}zjUUTr^mZ4 z+nVU+2XAEtV1KjRg9G6X_5xGz;2)GdroZ@Of2w&~0V+1y#;Io5FIw8@4=By|D$P?$ ztA~|R>p}p%_*IL=a6sHs2r!^B-+N8OhjJp7!-r6{&XuL5C@oGo(W*tN(6M&PkRY~K zwSdp#TW1}4Rx;em*}XBL82fnPVZ>CKSAV9;r99yhh9wZaz{q&QuZ8H#7Q`W0pO$lM zZTGpoxlNuI6%o6%HR6kxcKMmlZ*b*W&bbo_+Sk`PM^WrzOoxTV2WhugN#Y)H+{NhF zui&N;Fo8Jwm9`KM$7tv{b>9l_dhdO_dY~;_EzTMOK(*z1iBXY2Qh!p|BFR` zu&k$A#o`HgvrntEt3L#@ckJ~qQeOB)R55H2$HsejoD5!qBS?747Qi7qV3oH2@%=96 zGlbvk`DHAMEkL+e+W`1?rwZ=dN;;<|D1N|(RbucVuWSPxQs`!2m{8=ViU1!Ouv&SF zO2=A~V6z0?iQ0-Mzl%jD=CIvTcZ1Xce^9la#&ppSnqY{I@+95EEqdb@3Q^NsS zCNU_SwSM&<5k(R0c89rzMWQ(I)gz)asTOu!BK_N?hi8* zaR0G6e)Rhv;r)*uC5^n>YzXuf+TMc`{Ne)u)nR~(!cyiIS6Z(IP_&O^u6tyRNeZQm z>^_)h9g2xW0kl?u(`XEdj%k|&jdp^~4uLS%8#k06C`v1|QBE1Yce~P)q7K7ahW$A>* z#L7~-9;hdjQh!7#{;1aKL=Xdu`&VrOJN=Talx-Ycbk9ok(;a^NtjP$*Eb=`!7wYL)m~?5 z>3&-2f*1EY+2_1Q@sg1X_4O-2F9OCBx;%#>hadQ(@8`WwJ;vO8hd7ofZ>r(aSJx?s z_Jc%2+CuqNP1SdSm{qf{CIC&SA8VXal-Hl7JpW6md{68ELhOmU=LLMfRCS%kk{&`K z{FU$5CR0%{0%05mwL{Y`z%#4U41iC++0MwgbWS4r$&xV;ZtGq5>UUfyUKkV2q2|1R z%D*qnL}LY7TFPRCT75tI)CW=RWnlmmY;5fD;)~b$)nENQpZUy178es~JzJ4E@jU78 zvAes)&h|D%UdY^(ktt2;9Nk`z^`pn>_U4I`q+*bi7ID6HijA#|ANbx!`JUhZURGD; zNfHUsI}0*K>g%GkjK&2!{V~H)?pO4+-3^3se`ipQO^RNA@dbYJC;l;?{*B+HD0AX8 zkzF;Th_WcSyp=H+!vFZ6Kgu_~;{<2cd$iMtvXO6dn1*zx4gWkN;G+P#QgBoIXoCUJ zvY05c4tdtXSyLMVI!&S@x={;_o*vg<4ft;In9=E2lXPPpr6N(CstA19yJi1<;PQAk zBWcINK>M-xR%HP0sQ}(2_|qSHl5AYy9IDrfT+)u5-ExMM$5H&K*6Mq-R;P5NR5QkU z#RRAt@zO+qP^0#M0R6oRcY9{SM4Biu#Hn#^Ozr5 zP34&-8x>@O0z5KlP8{b8;c>8k2k*--V(;Kq7eyj&3`Ty!@QBD?DM79^WfU>uU^HPk z9Fs(v8#`lu?ssnTTj%?bD0*=%AS{aG%N(f_WkEz;?=0gLfs{x~+GGmQ;#+z|bn+PgvY|8g$k{m{2w)L-eI zJpl=aXQog>Y~64J+rK1U0j@-OPXHMk!U$I5q{(o221CY_{|(O?&E6aW(oBuARQi6O z*VMf_k!JpNVvT!FzNZ>L)m!1E={E33GpXtK@y3I~!pf9z5{9yK66Q}q+?G($T5;pX zHqU(F5*IIRFrE~osqFQkBkjFV6xLa`w>Q|_*pL$WzCzb+iIy#@hrA zsk9&W+8C74%=KDy+HDpW+Vr~9p*zC7aWj0HR-#I3r4dPN>N)27OrX&|4LInYi2N0E z^9z{7@Uc&Rgl^o!M3DqKvyNCpw+-9<46Wdy6N}7s5{gn}=~GY@TzSL4I@)14JOu`) zNajkCxxy*qP+lu(%g7r6YOvC)4$x>46E%VpeGMREQH1|WWzLe9xm7rP*q~-RV!Yw^ zGr)BnX&1F3Y-y`z{Hy=)SL?LjLU6ER^B%mRFwP4Gdt+?JJ_vl9R_Ys-Quk@2bkO-W zSNj$2gn%X+=W;FcFA!h3U%x3>Rmn=+1tuVAMG}~#lc;tpF}hH)-(eXDu>af_qB7(O zNVP_>9%IQ00B3Q|2hIsAW8;Z`WMt*KGdorFd9t>GrUFP`dM_D`eUgj50(QYpiCoN1Ai8$8lWknhx;#*@vBtiMD zjJdplmo}bpNh7XY+UDgKud%(|r^pJ?*Cr9IMD(_48j&P{5fESRI1;HxW&Q6h|E2CB zFV6`1BLoO)9?Gjpv;rL`=+*+t_`qhN4MQ{fiwbLn_H7;qfvUd^m$UZ{gfQS5L)39d zKA}jn&%(7Y-&B2?Fk2^>$~Xw4l)r8BlCp43lNXeN!C=fwuiRvBkkjs_L`h7X#6(F# z+)A)mcK5dF5BA850vB}fQ{|L`mbPTC-)At`V>}+Av?6XLKE0SYjp=k#cKbOOuWT|L zNieH=--T%iL_T-}8ly>KL#LfE*G=hm64Jy}A%=rg=`irctjgZ&&GFzvk8tjO*;+)Q zD9h4s2keL=MJrPL+UK_U>uGXj1zJA` zuWpd|zIHl=*8>U%wy;GpE{kkbI9JwcM_?W}=|irsYwv>mc7S^fz?%e0A=d4&cFsYZ z#wl8TKq)??l{yiSdvkRI)qJRDhVy@BCwdbhgwIC>sL4F?+r-E^;+1VCnIml{M4nhDX-twP z6lKP>E0-Dc2Smw1u6v%@@MVo6!`|K=8=JSVu9QuxJW~-TF|BsWq;PC(4ajqmq~Y60 z+Ns$V!ceI4%ykkvt%Srg0hJ_eMsgIOx`z<7I7wJtU+2WB(|q^0e=l=O z^Gt^0>Kmz&Vr4~f{zjjl{KzXj^YU$+6Q;gVXsJW^=Njb?{eMvR2JuNSBK5nE2D_gC z7Dr*rD)jdo05OVKX_c3`&9XsJ+R|_K5T3&_@Ca}Ur0hy5cToSomEax&@Fqc=M%4;h zDSEcF?^cR$M5%Y8X)EoCU`Z`DXYJOhVcatJO} zl5dn~y7Q^{CufdwuTVw5P%g9BEH8`EC?D+(-DHr-j8=Zadju7TzH{Dy%NNjiqqm?B z*IHwOb$_+0^>vwrPYnZtwGpkQB1fu`;LwhbUKfT+afiBDcg;z`>XW5 z$h!HjK@`FV^6u1%sLnW~-Gr%Ye{m45ZdPRG{!}@|#!+57=m?)Vd@UOHn#Bz7JFrD5 z(KRc32rs5~po}5%1V2u_1R#!ylLYOJ=1RW;blxMjc~qbk7)5_DU~795G{ip5AOT3y z7^@V6aY<3FDi5KM0V*C_=9lvBi>)-G*NN%16WVDk>L#zY2u#3KGSl=LkSLmG&)v_5 ze&7#r^wbHiZC{>#0qDev?Loo6{}g5cm=1gSLr)!3o}~V8I7{J09qwFz3_teyhP@sQ4bdPRPa$ZXdM>yi+Ol zs8VWOiP9G;9OqDi$qPR~8zZwZ0GqST-wsG`mh<0-JnK`r){3}gNYjW&YjmMt40dQK z2Sr)*i##9XuAG#9Qj3+e%<;yrpXkbO@c)(~pU^E#r$wuU5hBCE#mmI=Cr0oQh=Go_NvAwlN>_xMI_*X0bK=iBCSfd*b zuku}kGBGOcq2iVp-VyqK_RY{IuR&CsQ-wc@DTbuZ zclw+9Y9_7F2L5x0SoI72kaq*4s!*iugrp@zIvgf46lFnP=9c8B7L5TGLdjcT}n9pvOd@XV)Q(EBczj zwSFIgF_1aXE^wjyX4JIN-9BheN*VIP#m*+`?Of0}o{_ZxWPolml`xX56TdE^^b`{6voVi}GH+}^ms?Twr4^>-Ky_UP~J zvbA}O8#k`7xpfQYEGCJG(wHa}@qe5o#9n%U))b{9FG`dW(QNSJuZ$TRgy;}F{I!FL zQArP?1m_I{>Q%j`;UVM3swzmEszcSk@=R{jS{0g!T| zpePGUYcY`_P9hmgaY7WwDATmJo~g&|F#|3H!Ew?AaU#ZntyI)cA_)*9(_q*-Ehmw- z3rV*-9Tu0CSz9~8BC9yR?RgUmEk-Rq9Xi_kA41?0o{~=o0Pe!*FLZeOy8drCC^>n;Uh2X(TNqYfwCxZ z)^YmWqdfV65At2#^C3>1KF45CFv%=YB0+|XUwy?%f=OajWSC?lc6YZKPsZd$ULoqj z7Cy*}tl+k`Zj)sr(pHNk6$7y-Fa$|VyBo8;JLbxjEr!EMv-DpVP}-oP6s2QP0fhFP zY1`1&)zP>oFZgd7=V7GO3DmDPzc~;N!}xat4KDyW>Wu69HOuC|YnH{o7wV_LYp1D6 zh;tOB#X3ivM8t_OhmmIjw9yQQ1NQd%I3-dm$9}?p5RKM8KE!Y^U@{q@jTR|DEJ3e~ zkMvg;rIEs6Z8`%o2ZagHN)bic8=i`nK*a=9b|zEZICHLOwc0%L=o5VJkNhBcmNVQN zHgc0XwHG3ud3BpleCaCvaYpKQN)#k8^}2wUvbcTEy&+|z^Mu)SC~fztpK7~;#=F6G z#xF1`)mo)u^Qni0Nf=lDTR(tef9McF5LXpTdnrKc?c^PIj{$fS!8wd`tOMszoJDr0 zg6VlL`v6*UTe`@WHWlvF%9gYtqE?geRyXQI!a%Q9gZn1E7r%#jID>eiSd(^QTD^q0 zWsEi|Zna{SB(doKJo0OT5S4mz?iYc}chzdMk!OwEr?30toZGu2F5c?1w=p3xGIPtk zpw;Q{39(&>)%*`)w{`^gLcPF$vfnfWUdzzq)rYJK8gFbt^yEq&s3hsWv z2v7nOaXTtnHe}097Gyl104I)^J7ZR>-sdu%7HLbW+_cwCg-3iN=i$E z@Ec4d=h|rUY{FC!Rg-oJmbwXBm1I~-a z@mBd!q{Ztb7@rzL)QCZ0yuD3T6`z?%DI)HB;6WaK>~SW837h>}Q+a6x$L1n_(@38aGneHu>@3; z;x;E8f?SpIE2@AQJR;MPrqxSGJF$r(6{ApEE8@u1R=|ED3zC++YA$@5GnXvtJfy|} z0W>cl@p}P$;nmyx>~CG*+V+IbVy%knZ|u@(wfUBB`*z;<)YG(DZHB`!*RJm{&dSQ7 zJ5CZI+^v+t=G?e`mA$=PbZlzE(tug9Zoj|B*7gSFj74{n#I)NfqlxAEtv$wBKAY5= z4@!FmKsKwX`ZjnJguZF4nkx5Fl#f)`V9@+C-53kfw_a^jrC$}G{@LG@aOX$+p_#7F zIFwuaiBZ+5y4e3s4e~-mUQmH`kQbJsq!RrHn-LR5XcJL7OI8;9#>6blN(J!Jg5hM$ zIL|0iHP@?!!Aw%$Zy;rCNX=@=ncSx#X{cG48iIF#(c*<5o+rUGK=ve%=#%w!*mc`T z;H4;vICA_L$4;DJI2uw=+blITj3esPmauioO~%eT1r@=Y$ja+6Ch-{SJC zx4Cj*lk1nZxOI7(n^(5jxVFpgtv;jv#D^2F3+=2^&PosaTgvPH!|}F&dknyv3kql{ zR1fHdfmIK3$g)xmhm&Z~AE$%<#0&=+!$HPym@yjW{x@SZm@ph>42KhW?vK$hV=~St z^HPj#jck`0q6=08*drZ}2O6`tp2kXhNkBVNt!}KfR#t0eTS<)ZJM7iSL zd3wv)klz%JJ^-|aQC4zeYsfRNZt#zO;VQeMk|SM%EiJEJd66f7-v{~75BvbJy5mGFyiu^dwZ(WmMpwx95KzKE^#=nsH*e#x;?wQL|4|Z? zwi61c*xnO_@^uHLK^v6v%uHb9kS)emQ|BDFcQT&6G9*{fnM+w& z>9V-kq1Q=C62E7FF~XQnecK?MD$FPOeJvmVP)zLu21Oz6L~y&U=3?04ux=;kHw)@^ zdvtp}k~^rpSGtC74FAVRFY&KGc7bPJzQy&eA%4eXNwdkR>=ytyZ`{1ktzQ|?k%Oiu zKvhmfo)rxCM(k`2*xKl`?T?+?eRehn>~0O&-5jtJjx9O1H~VaD4A{CY@Ar2`Oormk zq}<=i9VW%*fW4g&qd`WISx{gMM3E4*K$HW<_jF_02&@SX zk~E?-m%1p{MPzi5wj!cn#MB__N(I-xY2shy;WeLKe;Vr0SVd2@eF(f#iCgRERU3JivnoD| z3wh3_)i|2p@4vWvm`zuK-zByIzU&7yvb^TS#vZfRuLUb}xnrWBM>f^gzB=+7RZSV| z9WY*Is;879jWqWkX>;G{Rqi{p&e_w;oIbJ0vGpFSOC9FBX{|q(RK1_SrL>mPiETny z^)_Qg95!!2LLcMx^^tBypR6N_>L5)~>}xosWJ~UIkDew)_EDGxC;sr9Io{<97k2s4 zAO9>L`{HH#qpVT~)T)*PSN_g>HWm9GR(L4H0|-rA;{)DnD zWz((Lt5yyv^WZ9$%=x}B%?nVv$r#1*w2Ky^X(}N;#7H6g8@k1F0}D&QOVye z@OU@|l{iPFylxGkC@iB<=0>AT<$0-`cqsWOS$>>4FT1o(Vrmx-S2%1T`*#`$kk!U@HGmUN=*>@U)Tb z^lJ^VvVW;EBx@YT7}9o|cDLid_nT@Ra-d*bIG($d^Fx2|N&fm@{^R@?Kl0st_?w^L zUH7f>uKSmH|KmsbmiM0EgYQ1d!)KRhx07n+8Oj(6EPCz`s~}kX*J`!dc@)YRQqf^| zN$vNdXhfD2BHLsdrE?vYZoADlf8z&u@4Md5g=;&9NbL<8RNP^!^_)C@KlBCywk70Q$)G=BXLHET?IDA`30Wo#w{92(HTAkukQy;e zfoB5JcC6BNEL(JXy<$Ze{7R)pEYs!k$;j`1Dgi!dkaLc${)DR=d;H7K-s0tpBj#HM zrQrIl%giq>@-5%>ot!>%j&`Sm)&|$un?0=1MXxIXeYDZ+?d`I&y)AV)WGml;AV_H^ zlL>i|dw0UvyL81wvBZs^qCf{Dz60S9B>7c<@4y2Z^?+Mb#hkiT-46w-3s#>sKMrH3 z9zc!L8F<~56qripfQa`}L<>bbc6e=*iLHBMX5~R`^6Gg17uCso09fzX~%j-j6 zcbK!h(Be;g|6_d92j0WePraLWJ@Ft9o;}9#)gH%IyPQ6@z`2u4JaBrM`%W#=?RW-Y zHZeagoD<@2!>)+Fjq7MAo(cv&KDNB^B0yU@hW!aQ zFK==C>JG)E6ft0|(NRdMUOg&bI$;c^m%~~q6~!irQxnIjxEzTwV4wq@Ice$`XJ`Kb z_nK2YjSX2*^6x%-f&cwC&U2!tIJ#cj-xL%qEHCo(H+?hb?tied2F8mkEf6QQzkdke zqm5xQ88PS&{A%sa5`g9rYz6vzdyIwyX=5K(z*Ku1m^uOuyXFPddje)LuY=72O0zI6!fqttf=2c}<@MMUVb!VXJpNk1U@N?oN) zWqhZM0_BL4gcGOFa{BC9Y-!1|gN@<>TzPJf`%f?PpZwwP;K}zr&eBqkI5r~254JbH zXx&!A(Ul&ZR$RsTzcUEov)*md;i?t=EVEv;DrodtzV;4s6QD{w8_<4#5;ds|~RZ}u7N zPOzn`T;2pp)MeChlK zzwxE({QM_xlNjhE(?hb`onv)%mAUyjz^{xP6xLy#s@%9L(O@hLKv5Qqvx&^&*BIpi zi8{Qx02mC0jK*WEG=wlZMplY(EYSt!+ph*s?0@%gM0+r};A_qPb`5Y>OhDC7b-zvB zXS#6euyj4hnDiH4Wu5L0y#Dr}GBi4{W~`iq*zidz?H62157aio|lkA`C%V0s^}Ku z)CeaYHrVlc#W3M!C*|GDoV;{=>HH=?`RlLp{FPmnS45HkU`tC;6rAXu=Gd|0Bx#DN zjI*R{w)8dOyPp_zp(MBhzDf<@#uNm7Za5@$howYCka#^}C4Ni{@r+AXXsy>e ze2)9>h6U?ufpg-*Wy=y*ies}1-PmY<{QZ4!z&#mH@*p(BY>7iY^#_e7RRQ)rd}ATx z6D~t;zL*Zr7&QaYSPNx=vkt8kX<}$4!UV|fl(i&43<4Etr^Q2$pJ8=<{y?L+8Z=1~ z(P<|nX;jU@diCv@MnBJjUjJ)>urW|DVpG2I2X%>RmO}{xQc3AF6%*h9XG`*I!erQI zK33d+Y@J6>uJi7*D?I%`kE8Q3#v3g)i*6mnMsfeid9G|v_?tiX694*>7x?IxuJg?K zEiT>evptwF%nFLqDx8bF5TYtM@=c?^cb(e4_Ak0ki+d@Z{esK zZ0d8zEMkzo0_50Vptm60V*uVHkYVT)xEMuLV=Q@Uv?hu@f`BGUtMRW3DODHK&plKV z%MWnvMPbG$276;RZtgMaPbdpptx%Nm>VRq{`X4RVVHKqnmDt;u+J}6WX{kWTcP?0z zH*RaCNaKjXsNi!i-Qv?P+~Buf*kF5D&}*#x$Ab|&*SGo3ANm8l=c)J8YKh_BK2WN* z=r%@n`|~mUg+Nc2ZdTks%M>{0c;Tf!&;9moGHqC1o#*6$W#K6EvLYtFSt# z0ySe?XBn3L;nMjK+X`%nD+_QTbh8qo-ARa3@f6XVdwG}Ndj2NA@$6Op-EUvuXFl~ZKl`ay`RvQLbXM9pGCER*eO7l$IUf95xCw%A zV!s064#W7c`vGQABzVr*>%xkxWUxDCw3m^OC7dpv_*c9~1(KWdWd}jRI@lT*+37Ec z7;CP)k-|)Yn+Pc{Ew^_@ymWP&kA3MXpZv-#u5M4z3gW0vWV}0KhfU6$J;#}|=ZKS} z(*65X0l(4-`wj%Ls}`i5q$#bI#9ex=HUucGV|(QI@OPc#&;5n(;D}JHKg5?h1DgFpFYh)?|7VV|G_6gX?C_pvOTr6SZ6EA!1m673zu$iYh#zJut;2) zAQh1^m$EIv-BtB9KLQv)@m>V%{i(X&jD;%P)x?;gFT8Y!x+P2H{sZFm-~+` z^1(-s@)y4Q41ebPPxE~rSYdr3B|~w(?|5~y;N@Ed*LKAn_e<9&{K^-%`KjN$#XtF# zEBwEH_B?;}*RJy1;cq0NyO9N1(;wcP6QC2Fuo9q(WHf&#n}!rRp6A?tvgt`V0!qWLz>H z=Hz(^PVy(H1AJ~$x;l3!iGae%iY6Ex)*`toFaPV1)j@@D{9&DAXPEIDU%tk__>GtO z*q5$xZF9ug<%HPOE<_H<83VAmyv)+_3Q-h^zS8GZr|XTn0`ZSTuWL+1r#Hv^;yg|v zn;9Lj`VU9xEKVs%TYTHMzKEqH_i&5uJ3^y#12V7MeQMks0$%-5hE=&=syAV_Z}vTJ9O0)q#1u7g4Fwc!N^O54 z<6=6!J3(F1>GQjRX4)z!!e^dUZRy3nN`uXD`3P4QUL5R*W5eQHO1qs%DBw6EX~ncU zDXmU|(ohryXCHi+Z~gFhva+_owO2+nA-Nr_#$3F%%ddatMV@{6I$L`g!*M~DmlTC1 zFCCM@G0IBD#l9FguMevBYj&VNt%!fH&8c6Je)hHifGrA&$%w4KOPOaVt%wW~Dp+gY zcmEnc@D2Cz1K)T*zwbRKdE(3xXV*F$=|vD}unJ1q5_zd>II)&+`ecg-&(87w$Cvp- z4=&hlE4Dj>oUtv?v8?p*M8A#!;G+U2g-8MdlQT{Gt2!Ju)MoF8VH!YGn6qzH;72*- z+hz670c~~<-XM7P@BS#x(E`3rX?{d0ene|!looB6a$?Co9_M7aAShWaYZ>?+nH>bu zY4TFlfm1zMy#WZ}PGUoQE}^?9h%So7Yrt7=ZCoKZe=isxmDXih=|+2*8t!FkGASs_ zCPEWQLKKOPTpQ7`MzN;EF_;wG+8MIBH{$wcpHIKI!AHNc#b}h#OEle7Pe~1|b8KI^ zO3Hx0@(=$RPk-Q>NzxRpHO@ycv(7QeO3q*2=8G@fMrnzQ9-u4=`g?m^x%eud`Q#_b zvb>T890XsvJm5Q@JkIxh=o@+JeNXVf{io=(TjD_ zRHM)b7Ty=Y`F(L4J4+r46`}Jpp`yUy+>h5%>_*DMVhc+?&KYj?Vg5nVGw&fe@&IOT z1+5L6J7X^1=yQH!$i`jI076LYJe* z*Ex3bI7d&O;MDpmN0;VlrIA>s8)2}O(O9Kfol7~f+{UQajx=~z(C9BYm3Hw>Md@AM ziqcXP@>`acvK045>lAr5VYqRNn=gEcE1&r&#dt)!6SKS!(QRouZNpqAB8s4}mhHiW z-NA&sECn|pIK!5Xys!+%C6h^sQR3axiX);(XPr2)+0`dFb>&SoebI7z?iHx?5Y zBp%d^P+2(AZo=w`1>(e1u7GjN z&{{~)Vw{-+=Yf9){2gE`q;B5%7pt7!YVfw%^x*3a|K*3DLP4b9B#OtC;+;N7|J3R% zAh#e^6egfa3id;F-w*WZoApIC36QN&m6Fwa6nn9`|E6BqRJg={AD93~k(a8-OVu=H z3KL8zg;U~zkXuJ?E#snOdoba`tvx>ellH6aGr?N7L|F+xWo#>E>sX=CVg=O~MuS6+OP@i-?*4i9&F z`^6nT@Qr8rL*M_MJaGRRdfgUUdqU6WS9$cm$nnqc3ici@}4S5 zD`k0YjZU{m6h|zs%(H%Mo#SUtaPFZ8Ieq_qtRFi{<_s6F?Q!MykV_jwE^myuyfx-_ zKW9`r=G!r=b15c_sW%kr1gkc3f>nY+q;+CHAkq;L&)Kpd+uLUE#uc_NyZ|^_t(Z>B zkVKluGkIDo(pa-JmvVfi%gMDlPOZ;zYHglVYjd1j?Qwj$$NGGS^@R>6S9+XU>2Y$k z$C1U(c&V3^owklUtEEbpauM-|Rljy<zH%u{pb!)9exbu5`h|Ayshx5m4Bhh+tSnDVZU@+kHOw@-2Spa~Jr@k3Ppwe)Kth_7gAh=@)KrV`ofz zG3EH2;cz<~$*=?l`H(Ej$R<97rzb}Ei7t`93{m6*pBUr!BdD#fmC_VtL|Ljs$Z`#x zcEa-V9CLGRS-ojpMOPD7F&~?uLEu75%^nBAYrf-e%8&oM??u1QeHrxsas>Je(|FON zz^QRipUuDl-zX#tVGRACRK5dzzvCrZcO?E*MZ&=L=U*i>OaQB5%v7%eg@$5`9qnNA z3C>y^jwCiL^b(eODGNQ3hDl(jX$TC3(u%cXM|kfCpX8gr``h^D-~Vkq`HfF=_Q7*3 zEG=MSagS|x6Vg^hk{XgU5(dI(&aJdrpHEQ-_Gbf{gX6W1sgDBqcJb{|$3OH>{AH7w zb!CYwOO#SXMiCn&+vPR7G6-v|brjZ16|5Yk_e@Yg8f$v(h*n}SMuj*hCE69qd`{dc zWamF^E5ff#FaQJ{l|)G)5&~bXfN!KM2RB|d1U&Jd8jilwaVzo+-hoXPz`fn{|J-8$ z-dvEC$({8|m9?;u7=K|KU{QG=fY}=0d>+-sfl#Mmi;~Gmw$Ky?Ak3Wl?ErGiudck` zd2lZ>T2_IBNzS#cAf=g7D^1;Cq!CSR%A&hw1f<;$ZScE-1HV2LxrbX0Tq(rNt7w{C zcR)8DNRtn^H3bJg4~-QFeT8-X^Mf*ix*manIG|dGLU^~4^kKP7KTv?iN#YGlZR#;qFVPR>JPPa>(h}1wwnpQg|X&D)l zvAE54TZZ-dl!cB+pAH=}hupps9Q;Yu8FHrTTa8mc))ltQu|*C_5l3=pZya1L47~Kf zTD%Iu$!}06cy*yxO12{Q-&yA<3mlPk$x=?-$;I8z6Mk*19NzFxo02G=pmnXv06#AS zS2F{3eGWonwZ}lxib*>$N~>xWcEE5gfgNDCx%z*r!)s&Xd+;?v*xue<&pnz7d&1z?v(e?&|ty`2uA%wlEiy)~uHncklaZC1Hm$0tl8klwyPTqHl zr@r-@c;sD=GR|xI6ND*sdm6@*oXxF02E#E_E00?I-|T}b9luHp$ARFvz=M{5RXQ^_ z>w7cbI4hRz)=GW{CeVOJ-|xHExHSd7j;c{lXw)OTLlfg3l3FMuG~NmAQNMQA;J<51 z0w9#xUxy+p4cQRezlF_4I47O}APTTi zv`{4}HQhiZy?Q)5Z!Z+azjb2qTn%*#CU&%zGLmjC;{HJR{Sl-9S{Fnn7b8K}7y#-( z6~8OK0%87zS~T%t#URWMLtl`%6_ErLPoo+$Fb1vxH@y_#Z2|WffHw&m^Q4sRFr7#M zoILc?3cM5`?B|VgE0;&Sa(T=vw=>Rf=e)9=@yb@ttNnuI#V$`iewukQqR9~DIn-30wsWhhREP2Y)Fy8jT0T}kHhS_u#b-egcQ9WI^s;w1R zn^TSlxFQn?z)Vt|#Bgf4#Zo&KCiiPBvI?p&e<-6lx7OwHlZ$kc=y1coLvFub2+6uB zKC2cN*&-t!>@wWA$z*54@2(d-e5SQJQ++U7-o_A~eFT6a*0GI~UP0V0(OOpgax`53 zv;!2@nJQ9h1&siZv%`Vry)YgcVgLi5Ma3w3-?0AYJO)gt#viQnv+4synI)Udr!=ppaP-} zc_}e~NxN|so>Zc!`3c>agmPVr{Umy*=$+Hpu-HvGve;#@+hU=cva-s_8W zImi3Y&hxo7Wm);3w+?w1>XC>JP)7ja_(50lS>IF7gFwDY4hmO9*?ZebKm+R zXV#WDwz981%q+P-lU*((28Eej^Qpr z(d@X!y>Kosg#WlAqa5y#Z(M}&ZK5=6`&vs!ss#M+RPxP>{ez@FIqaEMs3=6Yt8Fs& z!C?fCeN^erP*Jj(`^`EkCF3?k%PSo=x0Jc1%rdOiBF7#gKWBSUE& zBQFtiLW}k_!C_F54@8gNYegKLZ*l*T9>Xb0P@#9(rJX*hIj3!PaTD_Dg zsrF)%@3g`sqAFBcWxxgC7lAJVdwA>rx3U2s2cUs_@CLybf9y};WNXQX4g8Q&{9jS( z7#gj$h{K`L176IY2BPNra$Y^@)7D*CSyWdTNeC)?R)TpfnKWW3%RZ1pkyO*$f zYL2uW0gfUU>uGWSlW1x#Ad%8C9ug4OjkVjW?}g#1zRH;u7&MxnhGz4KtsL)>-M+-|l~1E~U!XG=5w#@# zLC|AMI#Mn{_&zOnje_8We15rn`(Xu~4f}EeD%}jB7g+u56F# zXN4Dw-hsjKAVqPMR-|J~?U<8GEzYiXX(tg{AKV;9-P33nJEJ{mW zloUltX}#pii8^Djaf8kCFL2>AA7gUs5}jU$Zd=o78QQ5PiG=}(B8dwSb`v!rwt&wv z7zdW6#TK>uuq_nIIC{rNZvNzu-qEo#afvHcC5X|HAK%^`a58AIx6xy;Jx4xHP}*UK zmSV4<7)t*h*hUq8^LS7u3^+(zF`fAqt+|vqi3G2C(2*i;N2J{dtySN_XMn!}d;%Eo z7I*&(@CK}7?!g_v0euG>&anw@g6G0#5wonQ6vh}@iTD%ec}ZTBl-5?OcqOQ*BIe&XkJtmnddcL_Jk+G!mvzpwo>xBoi#?1pN#P6D_>!kc~gmMAL0W%(Y|Y+X)NZ zltpiCz0hsR(MegEYja{{jt5UH@vd{Lyzl;X9y_(d>9qw`=h}2z3279eY(ZJ%Qryb- zOu+fw1Q+L0=DRVSc1+riiP8uYO%s2m6j72ex46j3b7y$p2j9oH{Qhs|TfgU9dFq?r z&jXJ>%#q{A=+4hU6tg?A-0o-G+?#M?H{vIppMh$qa=QD7p*Q=^n zE8^@@c58Dqr8WWi)n9}@tuMm!2KakZj}ClK)KQiC;&s7685{!DJn<(}Si-Mvk z(UEMUTN89o)Ei%b%pyrYgbwx-W-1J@91ia)dI>E**_*h5fJm(MEB*!U zd-y>fdFK;6^3ErC;L(R!KYoNxuj6eo6m#<_y>meJN`BerZBxE> zIHc-s8Ki_TbuL> zn{*|*pLCEz8PURoH2q|vEDgmZ#@aByy;{MCybg6CjQLRGy2AcMK?!O}bqMw(0q6RBQ115XhWV>5vN|MBoMB)V?Qh-|TA6CdSXhHG| zILA)+nX`(xTe#lwVVTZnPRF(iE3H%=_dl%sW%aKp^O$^`U`y>YP`JWTX3Z$2^%3$6 z^TjD?0OupBN@Pc~Z#afF7YP6Wdrpl1e%reMzOCRM1Mnt7>Euv~Tflh-JM{qeLotlV z#y#yf3QCd)hZ8A4AzlH&FTEbuHS-X@55!5%1LyB`b=G1c304xt#z&I#L_#-+1p&uO zUbP{RM+o7YnfLd>A=PwFT(U$ZTr&reQI!r-IZHn3Gq`n)@$NSGJ;KAR4o%ojGz;yB z<&L-;23w?qK-wb2T9Bh|KasMS;8N%}8alez;@n!7Ui;wfQSTPMns1u#x^R@GxU?0S zcm((d9^KarRshu?$j!bwsGnW~L|P;SRy7CMK`@JTziOBnG_&UwG$>PpUyw1Ta2PC# ztiQoz=a%;fDE1B9(7r~Aif6eik^7D;v^cuh;@Dz~V~cH$Ewwnh*yhM$i}i&Tt8?Px zpGHQ;RdW@55Zvk6*9r~dUlYc9&Ns#XMK)o$b(`Vs8%%a?V^l$!8sZq@NakK;^w(JZ zHx~kurDPfyi;%ao;0lPlC3DAzB%Q3HFv|aF4h^Lo&MERqLOzZu3sW(%Rr!6;t9|X- zxSksKPR457lF-f^5--i;vl2z$ul}D0Mzim|)!`lk@aBOkit2mNWay zeqw2@X{RxfG2}(baFmhd61A&|*Qe8%xvmg_tfoOka3<22I6_7Bj0^;QR?Lp70suK> zl^5*gaDp%ZIbktQ(;jYPW3%Q_m~*AE(b1soE_LSxR0 zL7vn{tn(H5c+BqgE9_mnNVap6SXW!6aVSZ~%B4 zfYR&yuLD7?8m0};Ee*;Ny11a!?6i$17o?>AdJ-)VN!$Enk0@$k_e+USza(2 z=Zq&g4w;nupt%aD^6)EOC);)!V|>t@X`-N%Ahw!FcnCz^D5bSlf(+z^>NS7TEK;*t zuLXhlORNDOmNeExk;WAhhPSUU8SGWWh^Zn9LNZGB7g+7ataTD1EmrygVZ9bO&v@mf zBe#xD+i+&B%X`l*a(tyjWF#=q8x7T12p5gE3->~YIHnA3koBz3#WW zsZZVB`(D3O!_K~YC^TE3*#NVg;vMp0IzMN{_$C}>kyGX)%6x(?4-Ck;AAEMr)o-P8 zdyT5U@ldx<$hIQ%Gi3?mT~_`=KqZiurYtR4e+N4r5E(}jtIF-Ka{a3$01YWXXx=(= zA-I0kk8{{kp$+toP3W$TiCd-8+V`PvG-sznnA=iT|HGXwlR*nWR0B?Q|F#IOnKcvG zSStBzBm=*>nlYNB6^nFp-+%=|kYtf|?g6iO7r@)jIqR%rvNK__^Y#b^c#i>i6Cn$@ z#xe1RCRey-PEwsjXA#9=FD1`b4TWw?<5qV z4c|m?)t{Mm3-`)GRv?+0S_;cgq?W?nYyn?X!T_MPqO6ei+XL<~0ACL<484x&bHKCCxnXz|=4}(7(-3#1 zNld4e5=RDWEu%?Je>i3|sijplvhtxg{r6L=1jOJ*#M|Bg#v{xi_HSDEjek3RRCKS*zq2e zxkzCeW9QCa?(ZX-=&|a!`Uqm*seVx4o`rYA&DqyO`u?7f zdAX=1RJ9+g!eDJlF&<*eqVdk1Kr(F>yE#|o4bKD|P?gsQRgP140x=H`WMTWPoqVfUl)Q~2cG!h2DNN9(O@XN~I|Ero)Dlb99ypG0cgeWo;MagKKF`ne)r5J+M_^=j^Ip;;8fjD{( z105`TJyl&i7o9;9SLj4x18AWjFSq=3Y-jktnJrd?bQ~-)3lC4{f z))a$XMjJONMnkXXokov=*-=1Z6!Wc!wYh{-i!JV3X>)G5&B?_UCl^|rTueE=*yikV zoBLNgJhax~!L<%&S2`S7XtUH!m}^HQvG{}ErAOBr2ebKw2D28MkHyl;_xEf|+!1^_ z2QvZTq#hnJ4#H_YW)94Db|@SOvmZ6!z;q9I_YV0~s;NLTLgBT+<{9IiTTJ%0D672z z4o|Fl(kN44rlID6?ogvQ44Ta`%Y;xd`2IW?{CZ~B`VGBC+Z&8-UB(T!h*d@_HKeg3 ziKuk{G6zBX?Ru+rblxMUbl5^7E!y1TN+(7aT9Yo9bdTnwa~hMhP^t&22Wk$-Jlb?I zNgGs`d@{#iYk|Rbn`{^f4h#6kItl7DF0q9mx2axgGfF}YYAmj12k2O6cAd%Mq z=Xcubv{Txx1g#Z$Su)9TCKDedC?M(zQTfw`6hJn(^s9Hz90)=S|C*WZFPK7B>Tx97 zp9bVwt+txeG)y2bs@yl3Jo6Bkh@ks7epf`}-I9`66UQ18873Q7*?j5CjCZ#hnS?s} zdi&M7^=&raia52@;(@g;4;|@o|9Y4E)_UB(*5iRAJsv(rba9p+jQWf=^- z!lpZodK`Al!eRGc2RLV;^e%v*zu}IAY!)ijO+fGm9gXMJHzAAg+pOPfW&c|3P(AmZ z*gW6&tsiUtzM?Ly3#W}$EDA6YWjl5O1}WG6)9n) zF{vTyM8tCm=|YS7lQD~@Ba+?{IzEDm)=>HgN*w{#i8`yamX^@bD%to5{jGJ1NedHA z2WKjCOF1dAxrOo$@g|f=I}0np(oCdTSnAO39PX0o@QaN|mrC)1g3qHlZ)5CuXM#zL zSM_|o4Lg7L;2s0;^@W?jOMcg>G1bb|PhKYorh*1O)JoAx5_;V>kuhX>!EiKYJSiwj zd9fb&f=DXj*gzy2CCJNqH!?56tFTL>EKP98q|*^-Q|kuFiD1Ht z!y})d|BsC5|C1zyC53GJ20Is@CmRi5aT+gEXe4blh^|Hs<9{)MQ2;@+vOLzNCyT3l&y7Kx3~OK7ik>789<`5o&VdH)HH zeee{=KX{U3PakLLfwQz$9>%mDLYezf=021;i;B*o$|!DVPFDU|zaZN!M7l83JpsQ7Q)4N7q*R5X)r#pYv`A9fdielw)Lu}rQhXf6M|G?- z9cge*16Wj(-+Rl$JqF-Sgqf&-_()T)_zfqn*0-x!UEewY;>gfxCB%`&ImaX~7*BF0 zlY*jhml5!|%3p}C%wOQjn&>;%H0Eif(JV?h_xk_J7_jk51>W$ACISoR1On7BF!Daf zMvES@Vge$G2aqPB3b5l{hBq&fkB8Wqo!y-0*h8J02r-0i4N`$f2ZJZ61Kwz=3_8sQ zVy)6Yf%orJAKU?6<8k8!KOU(Mb6i>PRk zsJlRCb&k2UIeKezbXR&L-4-}aF)YXjg;a5-dt8{SrKRvXe^7MhTJ#p%q^%ee9Z1p~ zpp;h1s~RsW#V1vyzkmfE{qs2I6wW#A8WPpF0UX#`_u!2OKW7VX2k>javruhfcQ+^j ztz~s=bkM^qkpzq{E;eBBGm`rFEG@ z`K#4g!(X|wjCNwx9nOUzlJW;8sA{_k!TUTKZ5!?#4E0-8!yI(`kjM3n5}S{3#aJXO zfk3|=sEDQai4OlN)l6UzWINh4@Qiq!AtWK11R)Wn)(E}^sDqjzeNg$GtxdTgEL zC)QbhWR-<;OZ1M-(Ozs3rI9QsvJyAUaf1v-8BB6qp5yXDqE;5A-@3Z=z2FaVQ6O%` z^j7CsIkUq2kwr`tfmO2lNAQ?PphBo|OIenbWl2_+SZ9f2!^)8!ORHVbT5#1YI2q$n zYS59sgjWAvY5m1wT#T||?sk6pFN0EVFUs%X-gdxmBK+wOJ=werbh!XB;53eR0O^59 zHsH(#1mvte!p@7b-rUDIoN_gR)_xmOPY}br&|1^(B(ytXEQ9ilKxNt6z}*hC9>B%FvFO8|wsqX}4doQFhmD)7S+>*Z5I9pH-w#jZ^BENke ztwiS;#ReV8u7%1>ZEo__L$i^p^Fu&26vR^siF2u#5KW)Y~Eggd;$o%3-{Bw4n^ zhrV`K9-c?VKsq^B^_27V zlCSqMroP!ixZk4i`*2v1c1(6|Gq~~+lPk{=+ac{(RmOjj231<(c0_xvOZVhFonv#P z%N>%17V%t4)Jf1uRBZvR@G64B3h|#5Fe${}Irm57+>LYWFee{ml*1gGmAE48UZqe* zqauk*Vj@G-ifJvhiF+}2Qc`9mrH=(*ofXMOQBsx`l%_Y|W_fLnxy82M?XPOmDR9my zr4>orU}E!e6YGDjBmD)On>_bVo@MQQ>&iJ-86)(*^}pw@|HQA)Ci9krdknyv2n_~6 z0ZMBeb69fvIF14jiL8v+V+$F9hYaKZNgRPvjK`ULq?9Mh^4u691Yz|phhODd=**?G zIte-s1lKbF-fgIXj~d7(SmXw^K~PDHcomt_Li{~a474b4^2!qqp&j+T>Zls3!2kqz zMHE&UipdD44DF?LqBIqRTM-5Mt^Rs~UZdW+zSUbQfT+#At_E> zO8vbUJ0Fv8UM0JIfpX_6+E|P?j(o!yfB;PbdssSp#zHJ~)=X!govjnJHhm z6?hBhnNsU0O2`UXnC7LzS{a)*A7k?gMbtwlZQ9))TASC*cwe^Fbv@R@OLxZ2qFH7L^F&cMU-mM>z`Vndt!lP zwL{cSFsVU_UR<_sE=tHOWQ7p@aRKAp6aS(n{!JzzE3m_YVsApWIi~1ml%oQdTWsl( zlJ#~6fJq`+3oW|KZIW&xo&Z@vmKA>0FPnK;>(EBi?xZZQ&9S`JBl6xlhqtyuN4iKl z(Pfk9e`~b*KR)_jKD%?@A6%z%s;iv!Eox;Sfwv3s=bj4S>jutCu+-WGpkM@i7Wg*~ zZa8^E2@=?kGY2$%t1}KFdyUfCTUu$r;8cWDTGlX)N*sXKP&CE=-U!eHPXLKa9*!i^q<-a+ zZ(U_@<0{$k|IglkM_YEBhn?uJs&+c@roNpUjYcC7i6kgS1tv+BD9H-8o-B=Q%i-B_ zknFMj)|#=$mNjEPdq(S7_Or*5#|MKdg)fH@w#n-*&@eppf4c-I{qW8;=Qi=d zR%d+)`=T)=%$W)5;cMCtYdM&#>K5vC>;eNIvHuQNl@d04H($ti-}z5o$MD7&rIfd2op0d3h0XK( z3wJaCzlU(Z1OTA+vfuy*gAfk*FmR9BkH%ja8c9QPl2=x01Q3vi*z(2WzaezKCXgOu z#D^dS`LONHZqqcsAy{q!0!b1z4ZJKb5Lsl2*_T|kp35i zms{ko;?@QZT-!7m*0`&M)=~u3(n1y1sQ8G8KS11BBwIX$*3oU}{2(;1IQI_qcsD~3 z+Ni(JPwT!{uW8mn+I7p{GsblOmwLa}emYgBSBoClu|^g zDdN<8(nR`S>80#5otCe3H^JqV+J0f1&f$(|M}gkE|CeTr{~*8}2H^J)ZpQ%B&dE*+ zPizBs14n_SpplUk{YAhiMI1+1=Oi`o+;2WezEzzlNY(0kkrwi4No6f*nqZ6&&zT=U zjf86Fxcxn97z00J09?%g>_<_7fYrooc4(zTHo}>=wyJ#_l%RrJ@0Ih`c}UvCy=CHd zkGS2v)rKoue{K+iMxsX6;otfhvorI*g>Q3B&%PgE0_4=K=e}g9nWy@_rOjfv!_Etz zCEvM@(&FhHMUv4>7yz~31n@h7xp#co7pfV6+Jmf_tb-RGgoD)WcL~Cyo4oY3383`k zrJ@K-fD0OJhd~*G&ibfq5tB%gt=Zfke83D2{#0Kp!yp||^-Ri_8F+d5@NvtYZGJy^ z{=nHaeYbp3DzX!pxE1D@A9)$;~i9#iv2d0YK12F0L&Pv zSO2uzLUa54O9!Z5sL=p~3z~_VyEgpPfGm#R6HwIc3ui4F08dfXS^!}JBvr2XtdwQN zw1i2e$=V%SolZ0MGLHveW(LiA*f&IhahM;5x*avQF2g_deyO3^X8X?H=3BTiY;CNa zv;F5|+;E-z>K7>2p2v7gVnU%G4QVH)v)ZA1qEEEgl73ZIi2kG$iNEopzs-DpG4O&r zZ0V?Si!DL~QN6DBzg%+cfgTk9B)3Z|11TRC(H zino=OOk!d*ZxC367Q!a?b4-8@ctiGXjSgp^8UjB@{2O0_nHE5+0}gF#zdusjgxxR$H9XuCsoeD@?i0JHE`J8*FefQ5n{m9$Uy4zlV z8<_8d@(w#4N*?#?7pRIc+C)+-Ay!0jNX;Bf0QzN~u>*bHS$#CiKCMX|l{a)65B|d8u6-*07UV(KA=M~n&G%p#COGbG`XXy}~{z7<# zz(l>=90#b^=iHf>X8;21Bl6+<{5rXX*FFg0g4!2AG#y^@;Fl$Kuz_1YPjT}F++d9; ziijdjY!p$X$vO$`f#l+o|sGAUVVik2_OgkQ% zPJE7ba#@vjNGlpEqn&BTqz|1WJ@b{6m!AIvN&LCP0Q~;I%P;`-7Ar$opaYHos|T)y zxf=qGnh~Us0We8ov{96$FajVRt@9hXmKtOa$`8(a%F;3&7mPr)48`PV=sDhWZ7eY|?OZpIqSwr+g4ub;>fG`0PDxsAULOB1f0huZkI7=}ZquVPa z3x`O$eWD}{U6WCoSL@9WLfvkSy$_CQeWsSc>*vllBiGLj?A&j!1Yhiu=J$HuT*Y*E zozdE5MjO|0WsWhL$Uqz`;zZIWHzt4s^S%G&=Kg*qm~~?R`5J^Ho3*Pol1(NwKL1P` zq`Jb2pGRUs8P>Ue9wZ3AEs(}!)ytZ;PElG#UMeOf+Yj4mmBX6Z3pkQBC%! zZoWu${x?zM4NMe^6Rj4H|Fji}^lUWoVn);n41iV;8B}ag!5oMW-25xQy7Xrs(YM&( z<=^bT@VOuNybNfu`RiB{wPGn-9vDq!G&+rh(6XBT)0r6A80`E`mL!#fPX9r(S2moWv*Z?7@16NvwPK_jpa_U*+38&ieS z!CDFN)N`@(vgLwwauC8fXFWwxQ5F?tB`G%Rm}2j}5bXLM*}=+t@Xlc^l$F6bEw#Rz z2Zalj5KFCvNbM*3qPiC1FNs^U4km%1_Ma!TDlimyM^%-mq=#-VkoJ~{lDeLFbNN1G zqhuK7POzUDsFAmv2$zN%!nJdM{+=)Z)YmA5!sE)Ez3Z3Qy>gCxv|pP3I4#nx7-&7aQ<4YC8JE8Sw<^d<;kax;jm=+!+~yIl2I{`o_bEa+M4&KU691G|2!9@&0jCv|RSR}^ zrJ4+IYcJw%Jd58vhsI%|q?uY{G-*2~PNGl@N9^o6(lliNB^S4R_d(52!yJ>-OjR9W zQ#rBqmkw7-4h9J&mOlI7N91k5M`0iij#9n9lnxmQThacCem;Z^)~SjsD{7v~p=@wc zv<@n-l=q-;N|1;_kpag7ew`rYe@B4DLvpms|NOuG!oL3eL4i9A!0#ixj3$7P9OxR* z35)dbK_)7q;}_=pzYgXqnwsn3t$vV%@_gEF4x31c=pP-@cM#8lu|eh zP9>xZhltX42uqY6$bAjgls4oALjM9Z&!QP%IVJ4~p%2I@TsJ#E2VZQAU)?1D64l@x zHXpHZ;W;+XKZOrj9wWm(20%;zVLa8mgkB%B`E3?a`1GPnZaz5>?QvU}OY#Ir-Up*m z9;(8!yH~KbKIQV2F<*FomnWXw=F^|s=JBU?dFl&$oWD3?eJdv~EZw%DlNo#!kozk= z_W;z+sm(2FZn^`Bsa#+H3YZq+3y@ceqEb{|Q&x^*no~|Dcogl0L&Rx{(R1^w6b?xw z;c&Si!5QePb_jF>@QUMt12mRTy0;+U-&K5=Cdf1qK!c{PPIbl z<1~^gc}n3zv7NXTp-larK+q)3yd@9x)CY;*O4NZXoJjtK!v^AC=Le}Z1I~(o;YyFI zfzmvI(@LqLg35ce^2qzo zKWG_f2Yh=8*sFiI!vNfY-*dPP18@*V!5naZFb9C_&0AUK8Hw6QnUs=>dU0fk6H)oW zOmg^QAku|M{z@s5#E>LGH7Y%6)R4YbwU!aiOZ>lV?|>;mP_Yuav0wU^OklMGpjLtu zqDZ53@J%W#MP+HHhA0XV00HSMrLp;#a#~<|D@0i*lp&Qsiu&ob6VeRkzSqNd@b893 z${5e+XkY}GA@_avei5iId8JuU2r>7zq!{n9edR?4H!h(~j8+PxJxNSp03c zi64LqnQ47hqKzTz_K4ybZ9;wxr74^yx57A7PEmP9=@e!7tiua+C}w5CFza~}lJYal zN3fREX0BS(RiBgVnw>rSSDbGo8IBhp9$V!2jf-&g3H;W1D26Bifkbv?Zs$gggGrOekx&!x^g1@3ujbMb*-pTf}NDZ zd+UqJyTU48Ii<8xjd=rlLAd%zD9#3dfEj>Sfwu0z?5{VBXl*>>zpGmEApbEsw9VYUG%0V-~^;vgX|<>BC;%|(@p7gQeh@k9d{d; z0B0#m&3KwpIW3$&9_1ZMSripoImz!I32~2NO%%<%*G(`Bn4rQgE6;dZvAJ8YH!QK% za;P8EZ%3rD!ds|H@p>K(hK$RERzpLBW~Z9-2hZIC_3U~@G2Ufx^Agve`3yUko*_;%Vgs$% z)9-kC9cZ@=ajG$~4))JEB42m9hIxAGVRLKBuYGKdU-{5FPd_u}4}I+t?|sK1-u}iF zTCHfdDCEV3qFB#pQc+ZnNp87tWz5s(27L0fyL|rfAs27t7@!4o78KcnB5egfg^@P84t*9vXSHThz+m85-?Xf6S$0N>!Pqk`6c&Z|ia>J7`U|YyeU_CIr&(M*LaUvj zqlgNP^*RvGIl>yoM)_a`F`h^ViK?i&GHA5v_Jg5=VIFNP01?W$_8nk(Q7^ zNt___WgX?zl8-BjX(iHpEP7)6q5lFUfO#(EEFarSGk zwun2inWD`j*ytlscc!ef0Mt2gWTd^>%(&uX^{_>A5{)3%|W# zD(C&U+TTzZcpprl*S*%^m51{V{I0_nVE_nbfHwl)1N> z{n#R3`S21NPd=6Y=hKqBiYU7$NKU5KQCsw^4Yyu!x0$Jx7fk$kv=HW9J$ zv=YZs*VF4LT5Us|8ceJa>QhsvrlWPsGa~9?cdz99#XWxJmtNw-AKj(fSGZF1ZSPy* zTfg=sM-OEriJsk~6~u;OSn{bSxA^Qc+dTW?E`y!#k~7%EBxX294BtaGgWkm4gbie*ZA3Ay~*0Rl$qhCgUlC!G!U&;_&emmX^BUon-54oO0{AlV?d@ zkXq$$u{LBHv>spA1F4x67tAtvl+q|=q#)D2O(0+*MUoj*$o`qMB09?nos|sL62{Nf zH3h0!K9N@mH7nx8Dal7lDO4K4LIz0$N{!I`bCmjN@Snp|`LgC-LL+w=fIIN}1-D@e zy1+Yu?^W=1z~L}cUgX1&H!tA%8OR^?CZ0#cDr608ssXyNiNgk#TLKX@l4m|iB-5M< z^kepnpgnMoqKudn8KpJBj4b<4VbQ+0g#nQGb<=18j0y3+S~1Bjk3YM`$3C~s(-%fu zTdy!0wssYN<9k>5=69^pG74LYMx!b!ib|3D1a;(5TKByTvv3#{w}Y=hZKenbk(%*P z_<&UeSq1IDT!>;6Ocp-;E)@&|MGRxE0s*)MLCFx!2wpQ`wTHSFWa_-6qOGqDH66<7 zl)alTvH8Li6yqV@O6l52JF?iZ&~bFziY$|GKod*)WMx3>+WhG-$`PrGSW6ksW$0h6AQ$F|f z9*;jc;G-WM(T!mFgr?mUPxE~ml2-{ek=x#O+`R12X#U7|_4$T(u5xU(!}3DP$zyG* z((#2C_xSaX-{jx^r*%qK@#1yQ*S({~U-`bfc=UBkEH0!t6*KiQRg#grh~XGEwmh3# zo}IB_I8jVW@c}>?Oc*$?3}{2vU!=Wqn54f*l(sNhH>IO%VqPX4LVkjVDGfh(*-?RBh3{dl_`n$mL!j`^;->=`uH$#FLOw(}*(Vy0!4YAJaKy@q z(2Jv*j+kt&F}ZP(#pMpmhZbpN2|D0~dV>gq94cNqk@N*$)Kx^~yR~x+KwwH{j5kvA zQw7IlEwTJjNZJEp672LNItwxFPDHkxku0TnW5fhG4c?kIm?yrpb>)=8fmh0VgNL$& zVc{T+iQ93dG`|M?yUzW`eyX~@Nt79EZc}Ac3ozb!Zwos~`sw6=FN6ZTTK-G(=U%h$ zr48#H_&tH!FaUU1RPZ(hKLGq86mg(FHqa9hKARbwo64F%5irsm)XcywQ!f`cmp6!Q zUic5^8p*^t$|_=#XOuP)q!AbZQ9~9eN{sd)d5t0t8h|(w$yJyQ#Uyv!*qrjKpSZz) z{q(xLZ5z&=yg{Sxt?!Zh>##{jUOIB? zDQkk@gekGMVmcZ!+`Pf)#wG9;txb?H9ckp~wmhv2(pbU)jS*F^d^#d!1^KIrmMO?g zL82>SEn?aW7Y2Olb6fn%Z(Qe@XT~hA7}nM-@BZpO-}u$XdHDW5M-QcF4HvGA_~j3; z@sUq%@#&9^IDAHvwIsRBtAU0IIsgZjWdq*BXyn+u=6K&XFY&Io9^&0^TV*gR`49i~ zDxZF8hwE!o(nPblR&nNR%Afn5Gd%LZAr=-pRgj2!iSwF#+a0)&v)Ikajuf31a6VGYP{ z_4=s4*V1%N_+70!udlZbS5EP}*Kxyjd_D}+R?q?Uz733uQd<0Ma75JvwRIJH;ZsB| zr_*0xdATp90BYhdh)4S4CAWxmA~aZG27Dt#%n1^KNtrP#K|lbs(nN7gnx-Ua+LUQF zMzM0d#nNg@tEDmh6nd$=f93GgpaF1m{t2%hJl;F+yzci?v& zZpQ$`21?62M4&aZ92dknM$mj6RY%1qJ=CJJSvi(yo%s~Bz9P?L*L@+}x0f*ro z-s4nRnZN+VQiD9W0)jBx#=p zpnhQ)upr^pL|wk9z!=RWT)C$ny4v|n&1p&+0k1(9wWKdnzobwGiPM-}TNMSv?R6$Q z>y*PCKuj}$H~>bTb_Q80<0%@H(69LjJvXDiqb&6k%F=T2`W_dqjJR+q=h}^e;n2})E23B&-fjmo=8(qm ztYL;iqDo^RjzrUPU^(J}s`N}Ju)J)z=XAy!A6y_W9KZG1UDh^o%F3a&V&g*2>DPDo z{y+a#PMVEi6mN z`=nV$6q$W-^^pn8Ysg!ngULG(j(zWgpY1Cj!smQAS6}3OU<{kIzQWvAA=!^}7CYV( z!av-Ad=!ZP+(Ha%TNnUY47Cr7RtmLy19jmO_|XtbHr6h^u-Pg6YFEGs322ESY zGFlUTk^Y1B&<7Ppc#oO^QuVe{V&W4Y8-sU>g{3w}Pxe_k(x%gkL3wm9MfWoaGO9!a z;6qAc&D>ah5s?1lt7*k_R598s)nsIujw*_g#a14ZXx}^1+Uy-~fA-J=iyzQgv`ppB zhIH&LAPP^M0vo`2;4{F_hLG+3&%DC`+=1T>m}3MKVm3r+mhpTI@TY;dfjY|kzHer* zrbhFp<`BdFfA+&Z1TuHJ`A3k6Vus}K-h1y`HBC0mC?k~>j>fi2_d@vT8vHBS`LsKE%-cwIG7IRN)!O&UIblRFMR-~~=%hM7DW6S22CC{ZwWs)f( zGaGxtJdDSdqVODAPQ^qtEoH2NJ!R|Mm=kYWe?G*R1-E+oElD9gKtTkE}}?Q1I1t2logNCesKgEE9@e-`*T z;J1LwA)i14uT>`CP8i^SLogR6r~qYRgLh0o-2inhaHsd6l;j8yLAFMj%}29e=8)0s z>uq+^{B_Mg^X)W0Hya-B)eHeBN|#VsQJ2qM9kc-st$hduteyWfajYpS$8(oPJavA+ zrJEy^5&|;+Ji9UG#M|y?`Sksixd&~D)Rot`{B;fjdSxlJ@cA4&O;))3- zXff*1Fvb%{kjA2duOldC{hRN%s7|H7;Jl_FWl*(v>DrLXFWlh9+L(M&i54bS49Av> zFHJaiamdx1Q{n{fJrPW`wp%%Sf9GuTY^(+w}bHpDR<2Y8Nsm3E}==pgBDED&OhufTe>>;v+CA^oIcO4j` z`S({Su%NxdC`}p}I%z~di|Do@I$1;~HMCPhD~ZS=MWR4?D{D(DOcbNF4!$%qB0ZDn zWeo^pG`BqGj{};K+Q(6R0z4-8pCpkcjTD)&wA_enx<*!Pllq)A(xgd5ni%3p6W1n+ zpplSuQA^!njUaX?6{n~&M^Co#sNfh}lII1JNx^88GaBcNCpnWzNnVtcrN!3Fz^nUKM+W`-0BXFYKmao5>pj-Fhgx0s=|YN`d=Qc9ES*kB?p<~r}a zlDq-8F237?$9sxN#rjJVcGe4QDLJB}Sd+92OJ{o=esD?kjVID2cwoJAYp}EtRix|IhxJA;~#xdGMNjFn{mt>->-V|7_H}64z^; zW>oZU(*|yWc?^8>+ILWgx3&&Pd=z(#iVh#Z%B)geZ}A{LB>Ky$~L)6tSrfL7a_k zw(j3sL&_CIm>u=hw;`LpdB z<3$6|QY3Lm+M;K-?k;zo?$GNcfWq$ORNGUkohiyX;>?gO zW|-7aS;yv1!Nn_M9{>CvPdqi^>iL4W?>T-l=J=76Y3|tGEyZ-Bf)idd*syzH#F0mr z_^vbXy_P?B!QJyn&e=lhp-CaQ{lBnnFyVv z#JxUotBpzKOHfO`jE2yLbzyW!cr~|1>UFShZo+xy*G9;u<81+>E&ON`Hyz-r9B*C2 zR?p8l3eoyBT$FtGo;j0~#gzrs?grJyRm#nm@Z%knv-P%~t<73%7220Ek#~z?O`1it zIti^#LYgILuN)Gsr#yIP-PUAMMB{PZnvTmP&J4?|9qzhk#rGH6Xr+`5C5)YwH&Kx$ z?xjSX7}GK+5F1EgCADMVV{QQ%bFYBOpkQw!S9_ZU`B*d;#n_@^P5*eCmHQT0IMwxP z-i9R+RyL^3#F$eDUN=u@-~#Y#z`q85v$^0kssT8F!S2A90)G0TgQs3Sq-S9I!oE|V z|H+>w>q<`hRxiU@r)=fa?%K$uotU(jb&TTCC^r9HnOE-vq4S@`E=8Gr-l z8kpTYcb)uGBboWT8YJdiI6T8*nQ_@gX$Pui0!kDGh61B4Q6vmNl1gT>ZYO4USn}`R zf0g%ta+h`%5W(ETyz}flzstM+{MYdIcfO6Zm5O(AU;wJX0El+qOK6ixP`y=D?=ZTv zENO-zc=FeSCARgN_{WhVnqvTJVo>)-1qMKJ#n06C^OCCQT;%F(z$uxHL-k@2JnjrTuB9xPc8>SrL{;s~Q7_X_b=L3(}alTY*U z|MGEm2SduD!bG>ns~|oY){0|U8Y_BjO~0$@w+-!BvwWn@vAY*Jd1ir=r+S<^)xmUP zaGq*y$nfeOqZ>o)v?OjtEFSIBT1X+%Oa>KKu21;<3p-rCHe!1(=f+yjB!_+{W@k`x zeQnwh)`PHhe$0tCEb^!R!h1P!_bEm`gES#ZqzFzDOBvi)D{zV`cMJxW-CavjD4d%y zbc8i7b6Jyr0q?{XXF46?PM4(JK_@9%&%D}eB2LhVh_j$b;;JF8GfhEF@SC+zuN&vU zmiRKq7eg4_l#svB7kOOh+x$9J%pzL!>~B{`oj76ataFrkPBGlYZeC@&d4tK;CgpU5 zx0RSO=GHApNMn{7+MSqIFC|SQlGM=YrDSPBqz&Hs9b39>?{G@74qO`yrt!|sXkoB7 zU0FHOJ$m#+e`R^KOB_eO$gQeMhpTFHh}bnvY=}A$aX@fFJ(bf9l|=R{^rx$ghBo_bsxu&pd;PWJ*rle~8h}l-{8ZOGkRT zztW+!y41MMC^66F&H-FmMPW7u>J0rMe!tjFV> zQg{m6p>Ww8%K$g4*jlnog-(Obe25$V3KLm5g_{$p_oGe2mc&dt6VGR-*E6rr9`eLoK3Ud&haoQ9&`tDMkgh zbf6VUI~IGh5=~FP8*%1jhc`aB$YT#KacC*Ud&O{M+1f4{jU~kGc75EvUa@j2<(=<1 z&auNiqBNt|N$7WCI;kNG?`?t#+yhl5ISWcF5hlVEhILmTa}0nGROGM9;ffqvOk~`Q zq}B}!pkW9JV`r_{zN_X43_yT-ABo$H!`n&-|8x&VoA|*RsuWYRFr7^g5#k?uS@&0k z#U&kSR$;x?A_K8eq_LshY0*ElN)dIqd~?c$>m#nLjo6(kwnnf%@Lbt;ObcjdhQo)u zoIJD4*$0ns^sYsg4|P~r=@2I|#kiy@-E-dgU&Qlofd8zN`XGuAq4Ym*+`&Qch z#n!_LMO8Re6|<~>@>*ejy(Ai{CKax<9*@_F@hUbBrJR@e{+i2GIFGHonhZ;|b$zP# zHgl$>B&Oq50_z~`0slhXTfDJh00B|f*3KN?Wt6f%!g)C_r( z1#@fyJUj0X@LDqk++hHIoA3(KzY2~dw_+@qoz{s2ZYve?t7{H_#UqT*pC?KT&Ux}t zL2tROio8l`q55INOTfgDGFG8bM=F=wuUCnhsB!ao8AE2_Y za4tYi{A(#jBo>eI-gzi<+flhowNkb2Oa;waU;=_4fH5KIj#0#kVOm(8zA)hO^@3RZ ze{Si9SJ3KZq*+R*-yv&d4f9@8V52ojq#Humi9GFC{%*BeWUUrytVrtes77qTf>;Au zog)Ozv%|k4-3KNhNNmCo)Lz{oOe@5AyE=(V!$|mjD)}0mmCA<0oh{1A5L_7wBS}ZR zm(>&-$Wld?YLaAT^OZUPbIxdWO4@zrg5QOLDlfS7!b?2y!E@+zu8QCsRF!8s^$hnE zZ+lah@BF4ie9arWJbF)u`%ZN@b-2aqQcABC(_KjDF1N^fDY_Na9FUAv<*>OW-_5aw zMH?-NrQ(oZ!YE9viL;2b6^k9d6>(@e;rNl1G=r_3lB$w1KG@IU^^(;yE#C1}_jBmT zswDHtVu?8q?|#rR&jpP}Re`fKTeVpOVI9mE0A~9~L}+oqa~@w=Y%vv8y$?cQn7Bqw zA8H8HYt@IA!&VXvT2xLL#E@9h7sTy0Iv4y|SgJnp!4S9QmlIlRrjwkt>sx&6!=L46f9#`lkEW7E@BnxZt(InKA>n;reTc7q<1(@H*rJ+s zEG(0#9h0rJ$d2@g7P1+4lZ_GE&uvf+3QTI~ETpviDXnfY+adFyr5Md{T=Dql zxB0)`e}fla8nHJhB|G69Y&<#SzW1#17ysI~arVB`R3=0K)ayqz6C%DUm7|z?#$(6M zj%7Ud;7yR8XCtVBqh@{k>}+V%hsu|L(iYQ7h}vy*(n7}>DvE;HX*O23TRX~oye;wN z1SSJ~K7eu}?1Q3VpoMLy$2Az_>va?wQ-Mji9q|WdUIQUNhLrP!&p-VFKl#spp2@JF zyCfAg3EpqRspqTC#=QBSl+1W~iz&y?EOX?<0t-tmZ!15Zj>~hqH%A|w4$J?Pw4>kh z&f~2|X~prg3mBvC_TK*wRq4L5EdAY8AyEV`*UuXE<0kKQVu;(3H&Lke;k>HL5Ko2` zqe01NucDY(bgbzeZn1Q_%i_rnN`VVysa5GvBIVD!Qq-$ZI5$}kiY!9+QXgtx%=g#@ z{Qfxb=R$;lH1HZT0o=O#@4#;dR)9B${QZ9n_!GdN1^y!N*MPqX{1EWN!2cLR`ra8z zR7$GfF9No7IOm;Gxc;LHjf%^A|9Rj)0{;~F2|PdRz5jLZ{S)5%o6b}DS|Y6_*M^|K z%n_=21qMSLk8H5_2XUq*nn2~@`AFv*nHdY>_a>wQG9emW4q@JFqASv}Lb1A(a_WdU z>(zG0{Sch@oJcQetm$PDE4`GX3oVW;WUTZ=BF*XoNLoCJeVOBTuE5S!5&2Y5dIhFP z*HYpfCh!Q8BggFIY<%jmx&2{7rZij0QPqbH831kY0(YLtc*JC|hb;<`Fl*MyNzoeT z1s543j6fZ3Hm~Y!sF&J@Iro9qis`iA%B3~du5S}{M72E+)_Tg)bK+RW*M9XX|NWo2 zhj+g95Q*U6nWI~+#fgNn+Hon&ftZCFD%TK$aLRixMPtf3`@!w|icxgiF{{fdXHK^1 zbq#s3e_?nJCKkU8bcCO?$BSrP_XT;5mdJo8RwSt+j%7S&1a=-|kIX~;4k(XOP7WMc zg`GOey(#6+9>wMc#rjS1_3PvtS1C5GQf^+O+`d7zyGFIUPPKD`YU>)+)>Z7zb^KsM zvintqJiTGEB%7YZ^lR~AnX~iHB>xbm`!d5hHxPls$=Vx_r;NrE%0jdk``5n+#ZrAz zln|pq&Xx0Z?G#8`RrDy$RH#pdOKfM}XG@ZwSXjz?l$EvH~0m`TwhVjX-w#4B6>3q^Is? zdht9a67TtZRFP?|TD@3}_i~)`C9s3{HzZt;?GUGW4aKgsseEXAsuWXTic(Wxs%9FB ziC1cbX8;WGegsUs_jxcgRCp?&^qyi)v+)e@QH5^Y+M8w7rg^(v<)Pua_gXmXI zz*Z1tC>?w zO%-V>>6CR7b3Xs{Ik?SvV+=c61D^QQ^IUlDDx<-qDGysiRS6UD@auX!_RunKdT^1& zPQ++8$5uh|tV8yK8Ak=?ENaD=EN)6N6A-VRmgHMwd})PYbr7c}XaGVe=RAZlLc@4$ z+1@RA>H3JvFBNn;`#F|sT(Ww)#~a`J5KAiy_=YJ8?bOWCfw2;8fJ8mmDy)FH3lz1$ zH?J9Jz61?U{VA0by>s|7IPaAcd=ZXv48;_x9LlL2#TZ|VARj|DfvP|`TR(W#_FRAJ z=g-vqHG?qg=lsp%rm@#c*svqm`#D z9izQm%Js&ku$B8Ps9*2*TEDJWqhZfvakkTn)=NJLkX0mVUV^4^H;0 zgz$1og=(P+@@d6rP_Vl_VeQ&3TWbUIq9D#9mX7y0a^EsZKf#wyiV8^{=Ac2DpVZk? z!oT%@BIj35&dp3L^-HLb6zF;2DzMIL&;)Qt1Mq4m{lWT-0=^=sfBruB9|rzB z@GZbQfX4!%zZcX!z-i!AU>NQJ-U@sl@b`ef1AIS{^Z)4n2k(a(f#SW_TKS}P3;(tb zd=SsSMe*anKL`FL`2Ps}qW65jdp_hnANJ0F#C!h{@BMFh??2?d{~*r&ns@%^z4Jfk zz5lN`f5gL&_Ap ze2Cw80Y6-yC&>-Mt(k}0qt9Cj`t6P{3WBQvMLwCZx4y=7Zx@>fHx4DLW$!|THL36` zSrnt0^uJ&Ae>({8K6jB)in1)Zadm^O>jO+Ob26;KdoWsaWHn`ZF(IE?#=|Pu--Y;S z9sCYLh?@eiK?^V{#EU(&YqE%_EoF=~9;Lk0aVQ(7>6Za{`6SjX^dt{KK0P?Xo~WgX zB7+Y}Y2W}#uWy+{*-A?>nk>__GL6i63LPhdQa!bFn!bN%{=^Iur!xu>qOxweaQ6L&y5^~!Iv5;4Ngn^suI04TBB4b-9i?$ z07nC3un>F$w!Fn6v zNc-w7&Zln~PFK>>#>yx`aDs5^%z(0g#2HW$*%+hAS`mYB$x|;38BHBV-|FyHPAarf z-231u78fOlxmLn3&?q(o()56}BK3&dgzVKS7rk+mpiCse?jT4NA(F2sS^o||q(zOh zj(jv^yt~b0Zx>sZg1F}%Dh|#fASdyh^It3ouucvBv{`q5b0=pvFd{Q&Kt(yK=pSzLz{6+gFZPMjpn<4~-Q4@5 zy9mU=DhKR^H4(ysiiRc*TupFwNfd=m89;f3pQtlOGf0{i}! zkGVD44F3GTvW7eob~uAz@2_`A$g`2>1?OM5!ufMo+1%KLQ2i3%rArkjPsaR_Z#>2u zA70_`;SNz`D053$NLk==S}~oJdaygy=bpPUQl8y!dFV|3%m3iFc=w-t6l=XwinrLx zzpE3WL)5!!)QY*YjO16WmfN6Aa0A6 z&s9#$P|l-j$HQA;-;^Hsj&fnnVgp8brB$e|#V&9Ocp>BmxT691ast!22h+KSsC|N+ zk2c%%e&9R7zYkwNiXC-*wSzC$@a1)UaaE4;D!#aZuh#L^7F4@n2jIrwM57)OO{GCY z@E+h#g)+d8hKhju<|ls358ZM+_!s{enw_bVuV4aG-L>SHMNQQ!kg@k_ve2L2Q9AL_$f^BC{X8h8a5x5oG1soG zvvzZfqO9|F?7Of*koz=s!D8r9;%PnHz?akgs)j)PYdd#CCYjPXJ{g+Ypf)Dyi-?))zXHO-q&3r52!qtS$NT;0;nWb9a6jCkF>eeOEmVPz>n zc~2Eo_cOvj*9W0;D6O!Qf^u()D}$Pqz!W$sIjcf`1!EL8uNbV4$;Z{L>K?)Xc<8hv zj;^*ibF#<1cen9@Q6W5cTMvc{E*>!?rxw7%S+Ie9$ekq4G}=)psrKD)xvQ;RIGcIfm{k}N_;I`ZDX$yV+= zyz}4Ytbg6rr`EXtJI^o;rE|Sw70+?!ypc?YzdfikMOLL_^X7=l&u_A|wnvc{M6p3> zO_Ihe9_rFx%1Aom58~$>ieBZ@Z=INMRslY*lox*qiqn`XV;Y~S|qm`1tt+`zfqrRDf?PXq?pQNS2P0DH_brR z>dyHpaPvo~2p0tcU4NG(LNyVn9p((+DRZ&+4>#AD4)(BRA*RNfYM_E=xfmdINUs|i zvBw78(M)Qb4eu+i5T!-yaP{&U7oWdEJ}HP7YxS|T<2~GX(bDT0&YbSB*iVQQ!TD1p zZao)fM$HH`kntWfyMQ;bWBaV3hY+q{F)&`LEY4!1ac zqD5Xf#^V{8OL{SrQOR$9;7OkS{COsmA}GQ9+@OTN8$u|3*GeiWwmX_6q0#KV8bUE6 z!r@!Jyn=RXCh^aMXgyx8eeY>V^uBXm)rmElW16PhMsKzbFV7t;CnWOUSjV{k2wu8Q?VuU-HEKfr4OD4v>I;1b7R$ zQ@-5Ne)Dx#){0pY+A2KJAO&`j{_1`2k-%`76G7 z;n#g}>2aT5y5gso3SX{+9R+luRnP`}eTXP{EX11vub6wFfk%GuCtl|GaUS`>ALrp8 z_;I4d$Pvq7!tu~w{&61ufgj`HANVm`o#-ZPnDFVs;Q^9`UH-ZHpvT#rI4jR5t?5>; zyG6S-3dk%(0C-^lRR8AOxDEJ&G88f96<-{@>l-O!ku<0PgvF60l77yIhl)nu6_4#l=#32xWLdOn(Y32nSmQ}gXK zU7Y*jcFz%zR^|HJT{Zi?{dYj`tE~sFh^qYWCM=yAL;UetHf!`T*YTdDJ1$OQ07fsQwjn|5ND2pGB|y zALt|h7=7gL!@~c7^MBQs*Z-!UJn^sG;O9SJ_x|e(e)81BS2qJw**xs-U=nyAaB^Qa z{u_a)lVj2;-~G}5g+xU=-KDJ$b^6;s-|t`B>U8%2g9|1Ai11$i7KR{b0i0w=D=Wuh zC*q;Idz?AmqT7zp8rkRvHmvDtHrBRz=Be}Cys?Q7MPlYb5b=y?1&kk@sbX`NoJgUW zd8ipcV-!aYrQCOSm&YDjH6}uy$js85JMe@xCTNVV1&u zI#j4kGjR$urk=_9LEKMp>v^uPZ05bT`-kyp#y|XiaB0ooJAY38xt%&cXk5atw}<_` zs);{%6pHaU=hDR+Jo)7FeC&fyGalu%d#S7uC#kUyuO__Vp+z2kXo)N{_$ss&DWXSFO||p2zPQkJlc({;lc3tQFXa^YIPl@{c{SMJbMRB_VCn`RFGxsK z%n>|G$~_awi-PHBNHH4Wos|%=kVm0zpvFV!wjBFnu9Us$HYf^s5~ zRGpSs?W1S{Li7|~36U^ag2|*H4_Zkm;JBdNnNsZKcsC<%by|j`WoRuVw0Z}U1J$2e zF&LD*aCyiFe(NSb^M7s7?s-fkCIx35NfLAD=o0UI-(x)T#``#Ye3>{+C@XPb6j3LT zPA|-*x03a+$Q{$MXEb!=xx!i*WhJ*XuiP*^_1}O|zDe&)6DmII`t08Dr6JC<^R>T9 zbIDvg%_$|luN`Td^S69@P>rsQ$cW^>xv|ToOV@ewsTVl+g)6LG-KE`2F~R$P{bt4M zAMNnYx32P@cO2&QnI2Rj<#%|#vz~HdnGQ>KHbW`22s`ohSTcL}u3hL)gCnamw2kdT7DDslBtZ?3;rTzd(7IE(*hgn(e zingorU=-O(i@2Ad5+hsQ&V>V7CysrM=I>R4^U#V>i!D^72Pig!N%Y?U|7_lI`?Zn~ z=#B>9)qu`Ya4Y!Yl(&0bpFfMYR|E5>0k(pp-OmF*4g6~Gn!gBK2epmqPxRt9Sl#}H ziHg7BqKe=1S>nh3i<|t^zjM>i{i@HuaLrd+4xiV=w-d7aeN`|81Xur;2S5GLt2%B2 zN)90mvrk3byIYQ>hlmfog}8r~sC$Z!k1KxZ=?h%?jc-)X{KTI#S3dJCgY7S*AH&-Z zdDL@8Td$O#sr}J-qM!i?iFB-MRLx~!sVd8n<%~zq_BnGrqu()9R#NNM`!r4rWl?eN zvsd`S(=T%Fxl3%WZ!?{UYOof+X2`S=S7ok(S;wRCRfQezVF#Po!8Ue0#1%QNs&H09 zhi-ScaM-e>DyEHB|7d%Q;r1rOtxd)|+vLLm)pUw0OR4Y{`k_=!U_|ntC;lSji?duD zE22a~uWA#(K8!zq%z-d4Lf|(ycDZow3TxN5aPcf%t#ck*!h?^rdHY*exc8nuhYw{a zBx7Eku%&*cXi^S7r~XnCC~+tdWNRUK?3*mcv|@B(q`h#H(h9sHA6fEYMU}fIqizjC zemtE{#F{*%$f3=P$6mwMSW&jrpRc$aN5x zLi(+>_yS~E9cdvx7qz^7;Fb45-NwGZ=f2rzuA{JkGjcI;PyZ@hQkj5|9dDCdEu6Qd0Vic5~>%Uy`UGf z%XsTlv~mb#R+VmrwtX5F*AV#3zM>O<|6lKK?zdf>2ott_dZ3BEZ!$;gUR7Gnm2f_6Yq48Sd?f2LRw(SrY7{bwwr6M>31XA zSwv-FJgs=?W-j^cL!vkDg(#)nnBDCmn_JsB=ZPXix7Q&uQMho1Nj(HVq?zgn2rYG+_$|+J|0j`r`R%Yh@T3X z+JwN*h^8Vq#2qC5!2vKypw(7n9Yvgmw6YE1svDYXZ0<0z)RGwPjd}WsbNs@8`VFpM z*dSSs(OQtcv!E)&`@ZQ2@A;Zz99_wXjlz`{TUcD_BxH~M>i_0w91>>?!p!6%{iuIe zVdA8UqsLb??rAXdKDW+eA~mZ{I6qz*sr8UW^t%z))}~y#RFJlWpwR@AdBo$Et4Tfb>7tWb-%S z{(Yxa=*_;i=K8K^Gy|e-3r?d7u3uZ{@lSn$&wcJWUOabAYA>Xb%nOhgl9=nhySu#o zu@&C@`enM^c%Jsppw5>On8e}U)KABSswyXC$(721=RWbX&)j&^pZ|%yAO2h4RF&KL zp|W&eiKlb0x!Xc`KU;Zrx5lhrA5fJJ>l{TIiMt;l^x!Wz_wktS{@`Cy$z6X;XAgETz532A@V_jngw^?5c?$(NysM~2S5R>W zrBll7Pm|sC{Sp3V2V3^>t_QvYzJ>RxFc&_ABrK}d-;as#*=K#=@Bzl8L4Wu}b@lv)m zjhds|NhmB_S)20N=XdzPr#9K%6Yf8WYg2&i$MK%n?(ccs3C=!n7k8gM#nGdyEG{mP zWHCxf(hx~OEQyH33LuSmFSFylm&8R;3MRuxsYETP+VfqW8ImxC#4`@-DoQ({%yaCt z3Pj=nR=>>-Qw{MK!rJ7WNB%YjIz3N+5z@AjqLJa*`sQx# z^6}?*|BpS+;@LLYLV~lN!ItOD{TXk6>mk1CZL2(V{}Ndwj8HYHs3s*ll*E%mv5H#xc(w z*ViX}^wS%B@`-Jper|-vOL=5G)7_GV)eaB5@idRV`9AJ@=roIm7HG9obgg{|C6a5# z!#N=sRRQ?~rV}V~g+w%lbkLy>GEXzYUdR5|s#K*yRKPp}P&1QFGk^8C)qe*9PiUh) zUlaf4{B6|#waGv$j}CpAOeS2vw$Ag~(@D8T49 z{_fY6x%dusdaYW5mwZ7;7D6RZ$|~Q@)zzyrEiS<^t0c9T{|nHkpYwgwFUauK>gCe`wzn3 z`zPm{??3d{?hVxdW0Hry!YlK@bzeQb1l@a7e0)i%Bn}wC1`hM%A=94+@OFZ?6I9f~ zy9!qhK^gM(k6`+zNqVnqQ*9l?=C8w5kAZzF-hL(CeHFNOfqz%1NAR|gqWIx(%%?5> zitzaWN}WKdWl%k()RIzqfpS~n3a5zzKNlnP;h znn+L3DxY!P!O5(44kIKa>2-yG=Y?Z5sThpyEh&QIG$KwTcD4pwxpQg@m)z;K zluvk#LzuVm6Dq+g%xghv>NQz#MM-e3uTa$-_yKu-G%0yG|=2vOZ;`K!FCZYn_b&nC;Q0vwZkSzmJE-S*I zT3!C`uYB;SANlLwM4H4}DZT>F5%2lpegGaOs zE-QyS!4G6V^{&Usdr4+hO)Bg}B2!ejR;gg(@-Oqw_59CIUcFA@2qIHK;|H)AOul=( zhBN?o7=TxRAO2h4Ez))IIQUkK-F!E`x<~Z$N`cx&xBtD;-Csbd%cu-|FihSCZeaif z6qF)>SHF=e{Xhqu-G?uG;85sYRP+?^5lm+tA2Ol1T=G$v4!AWptQh2P9Sp+>a_aQ;jOIEP;vq>Mu95JpY@wK{bS%8O%Mkn-#I z)FC0xJRwyC0*a*kZM8kEt|Dp8M9Uie)S#5)7|>c%6%`vdw>kIhB|h=dCwTJH=eYFz z4F(%y$=jY7tQ85j-Hv(JyHU(4cXlpFr7?EqBw+(36ptn9f1sTO%obMppGI7Jz06+Yo>ZDKTPiyI?{(|GPvO--n+3exgrM&Kd;jG8zGEKtF#v8Tj7E7e zC%(5taR^_w@zod=eNO4@qrhiI=~wS1fBVmXukh6#0InP<-TM|lzVxG9`}hAq_22Lf ztFG95k1O`R#h1gcbH(5-t{B|yioIo*@AZAL*R{p4?TSI>ieci4VdBeC>dJA;SL3#? zrd{l`>uuS?S6#gAEBtbBayg7r$5HAmN}oWflPK;B#g85fp+IlMsRy0aC&zn!VY26q z(t=2ZI2aTTqeilmLfpF$|JoNoY<5`^(Qb)EZH#AcR56}9T##gIe5kd=nS1ZKdTyP| z&);A?o{0J{iK(pIV@yaDTO(w|35}UPVs>7zv3zYd{{e!i6dEZfD^Rl!Gi)MH3nV~E z?6Q2;HvbuN*9zhUI(<*tR#K`r^YEqF0095=Nkl^dech1&;zl79N_-va@d__h-{XP`JRIJMw!!-_GINB@xlj+@g~TQKSQwzWISZFjzwW;8a}CxX`%lSO)!(5Z{eSm)A(Yy8%4ex6_dPfw9{4N+=Bir-*9Q;@}q!(GkULz;KIWrc_CUqTy&otyVp zf-oB1Xsyc1`L%0%wwzW*8?C~U{{rw~rHm^}*WTTlJYt=H7}Q<${+??Hf(EO|9lP68 z_O>TXCPgFpJ10(jaTJkd39VL2yPMGMr)2FIZc{(xAk>c%=VNg|#(N@NJKhR|QC}mP zkiZ0};4R7=Gn+=J#GvG+o!|@bg`f?%!vK6azz_dVe;fce{wSz+0{YFM&IV$rzzkJ% z=))>GdLD20Pzk=e4hN+D+rbe3>5I!RVRwI7DL#lBT#f$f z5vN)YE3((&i)(<=*eTN+{}E+6bRT@%5vBCkg8gg0-1$yBx_Go2K9`ky&!}o}j&k?{ z<=_RXy>pa%&r|L_Cx4GFQjK4t8ehjw)^PbYz8c`lF}M=%>nd8zOEX!>f^`Bo9;zEI zq11v>ri(J|eBz^gWT{FoDqp361cf73J5o-yE^peH0&2Cm#zcxFF)a2HI<1JkQORIb zF`8JSXoj?#QB>j_n08{OdCt|#H+k`e%Zx@-v^I3RU7|Ri)eC6GUgR&aOV7>;@}2v> z4_ya!Y$K@!yY1X1HBqk#w^9l{Uu(XJ0+92@K$<~kQITXd;SFttKGdg%yJIe#yT;?c z`7|H?#ZU3n}Boo_I_`7Mil%~u}f;RlyFa-@X{k}gi+ib@VA zw$OS`gy@Aa5bDtMLkAE0n)ui6*>q9~g`17AFl&H>Y+CTPW~#!Jc=2~|rIT?n!L(3& z=GQ~wp_Lkz`Y}-?Ou&uxDT6%;FI7sCMq$7^Vfzk4F~(1oUx~2J=NEhdCtbo z4LSyakj=j4BK3*RJlmVp3_8s`=V403Y#|>CVRR$Y6K!=Zf6E*?Zb?q%qN4A)`S2 zrxVL?H)nTe%wTWAcsvowUz`gu#*k(Sagxw#CoC?vXm`b|Guz9zfrEW-CRWyBl<2zH zD@sY&YE?S%f$*ZmBkY4_;sKRJ5F4TYik(ms;PW9O>@~vx92}lIa2qHueFGsZ?+2s~ z0B;gkVRK!X#eaxd`UT)cT#nKas`qZ@RiZZO((jZF=4RR_yi<9RZG^SX7G3 zD(2eG4=`Q&$-jZ_f3vDaSMk*loh(vpKk2<+Lq})M;LC6HzWgppraHWXPBggidyI> zMVT0-V=1*O`e3Tuv+>e|>*t2tcz%y^ToJ{xkzzd{Raekzj8;~%-i2Zx%@IeWQg#%S zW@lJ(;o687uMBzi!jQ+G*<){LSzR%R;1L#cDDq+}OFk^{7VduV1gFlN;Ml37EG{q8 z?=P^hxIorwp^d?N37NB&CJUhuBbgXs4um)f8lH2;YMipf4qcCPoj+dsR9`bMK?Wv3 z5f}kTTb_2$(^*o)sW3rW*Phpky`3TJH@4W`+++Rb7FRE>@#3>rxcKR7RL&B03`ti! z{jK%nQ_pl8?s=%id*6GQM;}??p1XUjEM=HfgA+;HS588vCM7Op<*WVHR2YPP>xY08 zYc0$?;SZvi;8=Otx{bPBS2=86G2SZ4hYl6TQYZ)+W9KACK%79Ut7$DI#4V}Zw~wf5 z1n((OT-iL~jxr<_)d*K*oREso!Jh}>C`wzk1wZ@}ipHcx%#MJ_$HhHfj`y@WWG_;-Q=#yXEtilw&V z(UTE(Eo*w2V(Czu)su^ydSI1qKckuyVjhv${@Ert@D)HshMl#c`|L+A*sYtx$a$xf zQWp5vzz>}|ePnav#`b%xwf`tdV47E8+=+TDyemXJ{AJY`Wa8s_Znj2RE7Os54^ zWkV)PMHES{kSs6&-G0XEu{Nz%EbHz-zg`t6iLS}o22&^6Qi{pYGTbRi5=D|}!C6M5 zBB?n5K~2?5QJoZ(Xp2_Q;dwvslOg>3HRA+0zt--+%RnI3?NGw^yMpta7NPFH;E5mfo!9+ORGS~dEWPUlzWl=|_1$>;E<3%BE7v_3CC*F=?ubXZdz_$$T|P%5tH4DBohfLQWFxjMZ`8nje^Qw7=Wl@0A`D9L1Y5E`Oo#nI=?LuWYqz&+e`<}MbOmq-#xKqS*y zC-)NHfEt7DX8;6Y3pJBp=bk3a!yE$uvzb-(QA^Qt-y_Uk|f|EiV^_iKpVf5GLk5$&=gZCM&m-lPS4yp9UQOu_n%_` z8iL=fok08plccq%|Lfa4;GE>iuvQXERb|2U<}Mdryu!yn{3Ms3zKM$*ou!O8WO!`e zHSqWV*2B?7!##%+?p=lD78I2uGKS?NT^{R{IiD?*s8bU*J@2Vor?)u1o z{*y1cjca?RC@N6OD#iZ^{BWm}9kbSchppTX01Mg}y4^PIPD+x+Vs@~ed|WabP8bbG zLiocHBWR4$G$G4kk|ZWhB0Bwy!^b)#Y1AYt`cgp~aWqX@MzjDxky~~*3wG8DItvlK zg_tA@8jHXLfG_~6lc2gODvQ9Vi+DZ={L@e^^$r8@BcKq&^`e+`xV zyXe&a`m^~{kJ$A7e~B+M1({rrcKIeZu5K_I zj@jPWW$oG)>sNOeY)ue_OCZGIk+$+|-KbbT67$F-i@f(eM|l0C%N$;9(P~9PJOd+x z0$)~=ws&0Oi`y7e8#)&lDKC<@(mL=;4ONqOs_#>Q_RWt$Xj+A~%5g!yS1{SCsB8>L z()?zfmO28;lJ%gy7?brAqF6~4=Q$!L?*v8ZxVf40{DlF({+sLk<|p^4Tq)^(lfX69 zbtp=SCvSC9R!=Rka(IDmzs;f5C5|3j<>cw3EG+dmd=wBxDlQN;1~g-3*l&cX#$!TifLN)thW@?JyjU7>y?E?TpyExko-JQCf08 z%sVxD56+9}&1flD^^S*Hy!pN^DHY`;XEZ6Wg`l0ny(b3o;x}_;rM(w>ytTsQ z5Z>K;g!xYrvQ|PAMUosVjp+7MmRH*(NwlwLuL{DNG_fL%HBo9vQbSc)u3g$?XQRMb z&B9_zZz(2g8=^S)CK+KAy!Yr%g6^fLZVEaiP|7h>nL)xc2ZR@Rz!2sf0P=MB$DruMk%N) z3@4V0*G4>XZkNrSoQ<8Fmu^fM3@dy{fhtjjHF2CnT!^hNiXyrT9afL8a^(0C4j(&0 zx8EmDvcTVo!<{yw{*&)oRHVkBwF!ChXMPN`Ep>nam?M1N`ykm#MnNdiaYdX}M5#q< z#c(j;=1Uu#|H4b0f9eWbSNF&#IXVLu9F}UrZ!MI$IL&o?5r+;ZyzX^<-tfo@4?eKS ziQ^rjBsdh>;P)6PlbaOS!4yBOUN-i7M%*MsPbB}q05tC??ajaPEyyK2S0Rmh>nKMB zgKJ~*iN>3(QL}ola24Pkaa@x1H0_m)v~5H!8=hVFO=(HeQss{It%7II@AC8udp!O8 zfUDPY27?NeCyGK+7$x&yOGi1Za3fC?N1S@YVeWb81ZN*O$@1y~#u)Jp@rEc$iJ}Cp zVw5tn9zuU*nbrOg!Ny%Pee%MyA&@u3d(rSzRY_SC6nRcj6gV$Ze^pd$ZSHX6+Bz4W ze~BwEth4>%08&U-V%iI7aPSK)2BI(iZHgpP+W7^3f7XVIpEdK~gQl#(a*dWo_D`)5Ow)ucO@bq+_+Uhdq1(?mbVM`&^Ssup1*O2m znkWuF02)TaoEM&6V{fyd)yY^{?Xa+vk#&RtXzF2vHgqdO^;6733u1E<=YJFUhan%p z9R}db2?C)uz+J$f0RDE!&_}2V{RHp}z)yjC0o5fs^rz~vZI_xC#MzR^4PXT5W0y!TO^yIwf*nt%pGHlwHeArM>vPo6Kay?u(Et+NdF z4hNfmg;5noO^MWin02%gN4+QtoOxVp0iwn)Ac{liRzR-1L(AG$!C+{)x;Ez1&unq| z`k2wQY*g#71m4%G@`P5qMYrD}NmHUY#u!5!C8SwO+G>%uGSVy~O;h=7wMes+IEjhl z7!yUaDs(eiH$VLl2!B;olx0aVoid$_m`(a)1m?&zZJ?bHuACEebR8>~w)12YnfX$5^u3x>$ z^{Z=)M-$4j#92pCRFt_S!KuCBUk-eDjxmaMs#)wrJa%7)hwf@~@=#1Kll2*C#b{FU zg%>tiUmMZsr@ZN1_i*&|GAfPG-l1MDF%HO+JSd|X?@qb=+y+-JZn3#Oa9XRe((1p) zk@;Dp)t`6He{ET-^$#|4TMz-Dm8GOQUbvSxriKXQ>Y0D6&vw~RE=DS#S2bGwcIR8=Le+51b zcNl;#D+mNyg|d&|1pIa2k>D2q_+3!XE7Si)Wfp$fX1(7sRR_KB%@DsG@(-$d_s?qp zYA7%Mp@XLYh>rbj`BLxf>EZ^iR``zBV_j>2=_Rb}Z?L64C=ZSyarvvDH4r+{C zVXKtsbcLHY-@@9BGeo8!G9?;|(H5h|B-}tVl8ssCz>f@Z5*UGo0jQY((FBwgOma_E z!OmXE#cM;Z+#GXteZtz7Xa#mhl9xd=0^)4f^fIU#Rj@TiW`D&x6B(j7CQf6LEEVFP zW+Yig*2+lIIR?O(pcN1*G)HsgS%mrr&SEPo3_w0*IvFz_4Hyjf810Uj3<`0Qt1OkZ z!4ukvw{t-L)fq@Z&+qqUfcr~d&{K>ZkkW?(Y4Z0(g?xiRL&Du}1krI@43 z3CsPMR;)2f?lD?1nO3}XZNSYN1Du98zT<9=-MvE8OC)l|+8IMAuQ7vw3zX4J207Qx zZ*lp>P1dgOdZj3}))$S@FQ#eyC~zXr%aEmS=0qt_YfNTgz{VJ&$cVi^7So`ueISBn zq|?thb!LTDJKo=~R|!f9qZcQJC{4o>J_G3S# z7vK3J9G=*X|GhH(ZxQLeq2&9k`R!u>RDwz$1$zyZy%F7h2vh>54X!$lFCGT>wrcR~ zd#l|KzsHpWywg%;O{9JhC%@;s=VyWc=siyWP$`IikO+#pme4BfpQ%<~Y+Xi140Jg388);|k#ffrjtb6@Q+IJaOzthI8U@!F8x z3wz{#0Ux)BBB|o%J$NFpC6SxZUW#ZhCuIEulkR6c=GUcCViG_p_V!9{Y~)KO3w-HR(dNup@CBce3H#EC?{)V7eh`6jF#7l^&J z7F#*0(o*IX#iXR1mXuSAiXiUB#F?ybSv%5L_>i?;Hy@Z*V-(%Cp_6KihLwKAiPe;Q zjjt5A(He zanu?B#bmGG+KbyH1)YP|YoKBX~*tnGuuKZ;~O87(z1 ztPA7kEM-yA>1Et~?<$?1q&5ChLDdA@NMA0U-{9gi8|X*`kF1??;o_(h!mMc^myL;-vm!T}Y15=;Sq2l$h7=RLkuM8{szoj3i4N>2W= zN?-RIpNrmb`HlH+)UkIBybJ@Nz@U-`Jbnw6J%(;STo)bcprUWa7vJOU-ka^{;<0l3 zL&jHocv^U&+hS(+T*mW%d(V$(%}X}qG!HSl+LcumB}we8eV{6eKjEzX(>Q;~JFgl7 z7>Lb5xXr13ux~*r+3L13?C#vp=EfPu!&O|BU`#3I04!RUL~IkW7M!B=txP~%YXA(U z(E@}V|6WNt?-0sYmY%`b^3u&QPoCRhZ&WeKD|UxDyThE(q!fA-Y;I+s7g<46o(JDIC-kg>C;{AySLBX zcXc^-Oq~1(gaKU>3?+Tifk64d08|z~9E$_sWM<;I{hQB-tI|qx{YO&nS6)`yZr;0Y zVm_iEAlsm)7C_v`tey~`~yKa4(% zY8YRc*Lr`2cI);Ite^UQWW5Np>m9_grr(XZ=V;8a<(PikaBMl@_)5xB&(KPB$gU{Q z7N$P@RXajj&$XL-ymW2AU3af=;@(3n-L*iH8n1-mnQJ zX-S@!-Z}5J*4`McRY)5s43NdTz=S}vE^DnxZTpujje&{wP*s+ys;I0bpO$p`DQE6I zLT@1>nu~yWwV;BgG0!Wuw#TIdII1-G%$Yv6l>Kfqgo1wf>H-9yDEuBr6?&+F{$CosK_ zp?l9@2iHMW`wgvL#PxC=UtY&g&WR+_x(~hdy;PSU>qe{p;taa;0H}vh=56@$%`U%s z*p6SM+Wj=nj-{rL2Rzn$Zg|hn;rP$i^T8naX}p9$dGJsCvtRVD|4V=9j4P`@>74s^ z@7x>f>{pG%-ykii_5MX+4p%mp2RpO(ihR1rU~r1{8xJ!c^@*cG7yxBa+7U4zVgt<- zt?fQ0z|_P)sz1dUug>b{)m)x`C+TGK5_Se9Yg;)*36tEizBA$4#*k}kBPK;fSvtx} zJdj15T5AUOOI`vqOt_C&24X(<mt1jO%!AAsPSpz17%N)g41{zAm* zyIXw4W6PX8-esYmvbdPg?5%|s!G;H-Ohf(TtB2HX0HG>gGfF7b88@c@r3aT{cqL+5F14+GxWQLe#ekRnuSip z;iZJTkER@6jERk+lWMxHh%^?T1aZEr_u$<8*5(5TH`a%|bZw92l`bdlJ;bs5S4dm2 zbfmOmU)cA8p;KPWC4=oLH(uOfGAt-7@ma7|;`bXy$&2RAR-(dhqHC0_3%xHJs4xQ! zljvMy3M-3}>9nNNOS${(VHTI$;s|(P{=XQgU;-EobFN?BV>HaEii)bLh~kKDx6RU_ zF5P}QV*sLA-V0#>9J(C~1JI5?1^jE2`gy#630^x4z`N z01-$01nkWo`p{Wrx{oLo_aza&n;=#8+?@LoU=`Jxrn;$p{#oPQwjo;5OrBm*t@k~o zqUCQvMc)hRzeA}9@I}W>FXN^c@OCdO{3aXL9`K}sf0cBmAIKI440BK9V+E*>f5k7l zL*Kc|UGIJUsx8W|an}At@BHh%7cc)t%%~yk(*qdbl_6X@+mi}~CyI74#xok7AfL8G zx>G*X0|>H>QYcE4FPnyDlD3*5OCS2?19A=c)HhlH>3AAPEcG)EEw)+gwdk}GT4_v{ zMlAJG7JDhZc1#l2CIx9nGy~ze0rA(!tT_Ur(ps32*&)6FViwqc$ZvDk)>4la`=T*| zY|>QIUx+z!H0AW^HfQeXaQEG9?z^|gBM&a|);F*6z`cvC9u_-)95+T`8T1+%hJk4a zS3`sySc@N3Qulp+RlgjB;cplKGnb~gZnwU0?wJh{sQm>Rt--7$e26594QBJm8 znsInFWoaoU%QPmE;zPA#>P$+l9scIlz$+dHZTRy?7#1yki?lGkNvvq4noi5Gx)gKz zXp6HaTbw=7=JXL!^WS%}&AlgEoLJ3R>>65`CJNzuA=9lesdMvN4~Gwo^Q5qh^9rLB zorR2r!#(0G5LFxOit_^+mV)nrp*-_5F4E zY?v`GHZTEIX)%$e)62-RSV|l3>)opZYdzyp$!x;4fUYxA&WCHv$g4<{SYPbjZp5PexW-$*qp+sf{mE7%h>kZo~ zK70|KeF4v9uor>nK%K)E*I^p_>A9ZEUtD(M|8oI#--_;j#|fR?e^!}8uS3W8gE|GO z4-Rj4sdher9e+;j{?3b|ln}(1yyN|N{uxRVQh2YF_fU?eE}Pm+3$JJ_j>2P z&pY=HobNUg!W?lGnA?QSE8hzBW>xbh--dYzf0I*IOWeHv7~9*&sLC!1AEE)Aga?un zv58g#p;KC%_e^BMA&z<`lHC6@Vk(={d&%Tyt>7-_6xM6J(^OWG7oI#w{oZ>j>zGVS zuC5Qcczu_(%`v;fk|Ibd0e#A+m(TEj^V@6#&0*O&XvX7~ttR#7y%!1J1n=`s$I$CV zoH&tj_vsGz-`nT#;TB0E$UTZQ-A+tg$F<+mZU7bjsfq3!;YC+a6!^^&pF2D=GlWQ< zbCWlF0U^kZ{XaZEoF^bh2+T-8lFc>qivTcok6{JRM70yj6`e{aimCMO_FHZsixaDblaL^ zD+y;$v^l(#&~KY2{X%5q`bbO8ig_tt9D@B!OBI+yPe_WT6{eH0wKL(`m0f&c{gHc? zx%aUXD(R(i?WBNejzJ7Bpp@jB7;H=#Z5I^NiZWMw* z9@Ty`vqyAm#5-N{&7?$YW+5&@7%X!48+2;0he(EuFlqg(MWV$_cio6l0(J$UVC0A2=r+<|#` z1qQ$XZv@^4d^7L>umpe~f)mMCm)m_@ zzCzqTuFS$IrF+Lws@Gs{H^AlBD0e@B%bx`n!{!c~&GEE%{IvJ{TcvmbJhntV`A>ey zKlB&gLzKpuEviRtWq;5+|3~qz9T0=}Av;V>=Nj;#?E|Nqh0{pK&E;}>t}PEJWpOrR zuy=x;-MiV{If1hgruG9+4y7t0H9#}K_>uSn1S!Ep^PiHPOMVLpI)Zvm`~hZ6fOQ(@ zfe_0bC>AOt`YB4w=I)sF?JJEW_v!OI{iBpFLB;deTQg@uTvrG&-Bn1zLeZYQFZiN8ay8*^wWHf#P3TQ0QTKpNPH5x`kDJw6GK_!K!8iqPNv*tUr2CanHr->#_H0_q5(-QUmLN{Wm7tziPY0w1p+oJC8 zcOqJe4)YV741KNUulL$)!`6cuT4J5#@UdXWd-a!SSh zmfSbWp|oM$G=tYL0J}FPjJ6A5rb{P9w;JLvgkOk%?F<xoN~Y7CvZ#n+!@^>R<997__~?SH5&y-R01*;AMQ&NYF=V)#3(g4RsgJS79&un{&mTPOMY0tGcRlw{k#8NaSEleqduT#()EU4%pAv*Xe$K*T#On_5~X- z28^F^zy_0K85@HnBm|1BRzPa0rS4YeuIkDs@3g|429iygAACe54;l8zmdMoVI&te`sy$*}>tll&@){zvq)$Ji}OIA8!?P_PdJ zFo)_q;r}}C8SpCSE*LN#sO;tF-b+Qrhd^~IT>3u^WV1f-F?*4Kse>XcT*nq?v7`I3 z(%>_uXrc~8v?8>UtOAz@RV(iz5$jt$<2E^cZX9s?_ zVKADrzEIi)WNC-sZSE0iToUJ|rBv+hyod|uUqmtOp-^aLTAL+eL?V|_s&Y{RgJDpx z4i1|a&p9!?L+C;<3iJkoHk<n&C{W2z71P8WwEqOxfI?vOO%=9hD3x zjv**LBVa0n)HOyFwQ`As9Fq6QOws5!<4BR`5#4UgpdYcansVfD&WYn4jvnc-wwANF zkdU`xxGUTX8~VO?w$2@go7(;7iLdhF6cvbZ?HGVv1CLMW3Jm{eST;0ha$Y*82sSYoZw+GT`vZK}xo zF)PP&ItvN04}bdy0_E$ayq$~7I0V`;l1vo#g^OdZtWVk4EZH5^OeQW1 zVO3eT3idezB#bTpsYpWO!Qxt6-D841R%~( z_~b2XoVxjt3+ChPjh+jXQcNc`!<~ZRPC+@X(Fzx1Kr6C5rPE32bYs#^M3MznT}xdP zu(B0&o{${tqdUpZsVx3`yKj4Beel&zU3|a*yujeoFaZg08h8WnwSGI~)B$6Nj-k@q zP}vz&as(AExX6IbfDN;|J<@Y3ujb}UYhQ4)bB0J}$fE%tO-t*U++V~;nUnDR z9>js5^^no%b}pWO5#!Mcw$9Ps5KwzbK%`0{cF~McR9-je^yf|j5Uhoru~QSJ%X8_1 z!iZx8f}5cG#raJKCcu}^i6I^G7f%e!%21RwMQNyNLuH-FS8R>4HHC`UO&7S_Jx;F} zv9|NHW5n>rabDb*B#OMF==LD*DzXk_nTyk(=bBC))9J+Io!E)>o1{1`j4k^NjR5Xnn@$A)kya#; zCXE$YqUoeAEHGh}?-_h2=5No{Fg9ir&@cM^v+mn%f*Tl{q?fXAY=Pmhkn@kP%li2p zSvuNRcYo0-ovd_0D`a~DMLjP8@XcW@jJHZAJ0&jTrxia=RH(D~Bt+I)H-`M`U;GNc zsf+8{W?w?2Oyi^qdl>-dPADuc_gP&VFc{?Y`YCzGx#b3CqRkN0m1Q)n*xjD6vpsRd zUn{zu)JFx3=yVgZ-0A)s*FR7EQOe~235+TjsYJyWyTD+JPCduX9MZP>V!R4aHR-qLaSqj z*&-XA!<_G(V0FCC%~u~l8{@P>UMdpBiZp|64|)U0yF!{nl!{Xx=@#M($b2t6pBcLM zo_*gFh?%%p%9VksaZ#K-vaCwOWT!&Jh0KjJ=aVi*TuR=sVvoHVz%yH+%^Me~P@X{G zm17#TC;kmVQGVrLTc(#rY<+5jOV141+A2UPXPnnbP~ONjiWRG;x-6{a#6DiazIFYB zK&!0nbAd4kh`+ff+!p#S{DiUJ-mEh~Y^ZZHSzMn>AoRxl8slO`v{&%WT$PqRPWyY_ zCZ)N*P5j%%u|m{I$QE*XD_w@WMScE>jdJ7swpv*0MR&gHrX*SIDI$ezJv##+)*Aut zRt&c)>cWaIuL@Om-wgF~MB6!j%rgL?-0p;DI<3>m*R_`bR24;0QB}1M3gpU?Brz*1 zJ(gB`EG&0Ov$zT16l@Bt6{h2w^~)o+Hb+dxQrV2MV&xy<)dFziFaUoD`Pmm1v^)Wx3ku*IaIg0eSOtzd z>=`TU5UDr8Y`O4eDszc+h#Ms1HtjYHQeSbzfBXPaJ>!t!9_MF;Y>8F>+0?v4p{^(e z<#2+IBG&FW9#1xgchyz>m&MwzKqPj=aDGzHU=LEVK|kz&5u!LE$y^?FML>#8;8UFv#?>7<8fujeqeB+>?Z%D?ij>pg#~KxToxV57Y^>eAo?oXiDtE?yD)y^t|5?C! zA#9A#ekC6^-+w-6 zUt^!)33>Y%Z1~w07-hM@9}uw=Ma}N+l#PuM8&`*HZHyQW3nt@=>9}TV zeazL%yKHXmG8#<~5f&DE3>Ld|yD6P+Lf%bCGnW}qw^sfRXSD0=>jS7r*U=!qsIusN z7TT=h&q391Kr5t%6LwnBDXLLFO! zEkG&|@BStQVkcmBpt_6{PhpG4k?LuXsf!92CYb3S>Bt)Kr@jHlEz(;uG6ky)s29MW++f%M;?r z8Ea~-=`JQL9?r@8u}govUz>c^!IxEhdp5seMenZ#q8*rIf87!L*5=FH5HQbZ(^9dy z&xCKyhQeHZL;vj=*KVghvfO|FDt9K*3XC~BtT z(r->$FrC&+MkPDj6GppJ%BmucBYOP~3yWR)gPgn@I|)D*6Q@4)ul5F_Z9K!Qd6jZZ zmWosvE#!~rJbABJ`%x6=!+-6DA^x<6(gFM-VILI%K5F1=f$#Kc0T(a`oFSHqQSnho zj-leiF2yb&QbN6fRA-TD9n2U}o>!aU>@c$*7U9jdRzK6ZdHTrCBOR=00A*sB6C;g41cxaj;AeL`Pxq z>Hx12aI1^3(rT4en6qEd7-}7}k+1Pg{}!HHI76*sBC%Md>6JqcPcL%k_%ROI%S35H znhSXjovtNLajWCVnRLvMcI%t_G}ZjceJEbLeZy{`BJ4vnLfdQaC_b{z&C6deMip1i z?K0Y&ItE~5nU*fQoK}z|ie4w;=*>M2pIRVZ?xK4sDvhrZ6T5f%b9*lti%cu(%?aD* zc6scRn`~T}5+#~JKcUx2Na6@34iRVFn8hO*%f~wIJ9eM8_*{W6yUNwZ# zK?d#!lpkQTXPfyOh?~1FFx*yL2<@31-AN3t0Z$;oGwV$;+V6690oDjgE8;wn&PqpR z{nRR@c1F9?cRl`z%lAgLe8uw7{;Ln)va%d6bu@{7Ruw=S>e4XXttqF5sx=WGVj z+}YkZe}8982+rPx*0jN^Si(CIL8sAnc4FawMl0Q4l1cSu0Dbg_{9QK&97q5@OYkg` z0pleBSAF21L%^CF=01fkC73aoZ71%pEvG--a1yfqlX+*x5tF)64McRUTtSsx_d;EcmA6V#T zw|AF2w{= i91xE}mNg0644PFmL=$GrmLDD|gKeg)shSzs`%uzagA&W4Y$?>|9U> zIA&qi4MAGqn$8jRG)?Gsa~2l53>Lcd1{s}BO4f;;*gtV%f8~)zyB@0P9ybP5uz7YT zx1vG%YtiA}`_Iz%3Tjv@GlS!P#f0{ede>*9LGtO&N^q$lA#MtvdqQCo-F7*AOjXWkl=7&I2GXIs>4LZmHmBt(%V)|M!e zW{V?B8dXS|FwR%l$`3J0`wU{msb0h_3kiqvn0_L3;)-rw)9qP09ZQy3l0?wK*e|s2 zwaxH{gVri)-?V}p zK1FYX(mq;Z=G^9-5uHo3J9E>WiS`>C5zi1iDPa)%2f`a%dtKnGB#B6qm^6(^vxF>5 z$@7#fOWe7+%~|qyIw`$=&cZ^6#ibrg%RLsCd-NA_XYD^n{2dN!>e?_g&EX7MeJjF_ zoz@Q!z3eIH1=GIq#()C}z-JkrMG{~=!TuERv^Nf12AspK(#|75B|h;_;=0C1w}U;C z8>YaAMEFl)d1u;@^I9tztxu_@6-RGb);k-M7mJneMyY!gW=e%Lf#7&w(UvcId=byshst4o5^Ty#!c?o=?EPOd3Oh;Qp#xuYhuJ|loFRl#7P6Z zWPn-N;6@rSn~k%TllxW5xm&5os|B=m>Vifp;8X}Iczi`T^@3md$J&spimlEup6H+9 zVs-?bbvfFNdGTt_sf82^C^MmBHaHq@vY1TJNkkNT{bnOR^+--LTm8(VmTL}SKMK); z{qAo+@T||aMKrEFjUHQsDAJ^z*tu0jin^#UwHpgz>VL`o9V1^}TQbB1@ z#-eJAstimks`UxG&+M{wambZ(V=g{3W;(ItS;W#HrIW>Itr6>(&E8_d;*k!6L#ZPa zR_4ah=Nv-&wAxTLI{7e|=bLe^z2`3Mg)nCKydTFrxKm+_xbOKje?uhQ=62kQb@oB= z|Jt?(Q4*2%Q?o~?tWPbY8do~`u!13ctU!4uImu4$@rXuaKYgOJ@bbd0= z!E8kzj+=j8Hqfr3lSp`^(?Gk~_ToD?hkQuo5K1`KE?sz%ID((ewmeVibThi$jQ*g* zV4=fcA*VOU>GT}oPjbhsM5$vkX0Cp%W^C0d6sKud5f`plt4~Q~e}4MF16Q&W0|0*b zM{X<$zySmBS%!TWfG~`#R|8xH&I8W?yN+*EiRS_$?{@_4$q>NNwhO>JMEIZ9@{X!B zXF=P)ct^!oe*2igYR1O-;c;u_^&;|Z3XaaiY5|Wl!nO7opMghAR=k)K$a@J%Cm8-Y zXb_L`I=@;R1K8V(?_cc8&}If) zqj`rY|J;n=`y_dezy}+GNE$Uk6!}0ck&x*E6L&e^y`87KXE>i7VMldX?PlD*(&gA7 zA&WJ`$}lM>sA`uJ(IyM=5TeM1HucPsvwZd)(888;%us-RPR&r{o{Mvbdj^Z_y}oBa ziN8Uq8D$H^#e&opTMM>!se;o~lVp)Ih!n>h8gCeyASmM`Fc=q0pd3|9cM7JP6DI2u zhF8Xnu1*+lmrRB(4Q`rfIzHlE6uFFR-GzkyYQ|tSr@N34rOpu0mDX2iZ@oUxplAl< z^Dm2U`uSdZmLtETnCYTJSGoPxTxu1-84tEZ;s#7@MFg@zrm}uUl0~&r>fOMvE5$p@ z3mZk2CpwGbuaA4l%hQ!kqO?+Cyu0Y9VE|mYTsc}pyY!Mz5L}4N*0gPgp_``e9A2W* z9=gqYy_bO2#F2JhNIpYon#N>#OrEFY-IPu@rQ6S%t;e2?pk)*o+IW7p!(rfcz*hn<0oD+X zIzz!`C7_xq;=+!f6Znu=^{Y~=_Ys@RSdFPswpMEWvCFozn8&7;uMm+xCGcmIQhAF3 zaFc4EUY|`$k3fuzm2WBwR?%5X$$PPzFw9S65s&nzhH7dM5ws6z6DBZiJ-qVbzp!Dk z)@2O5a_L3vY^)(B@Rh zI`yuLVZ}eIJHGC&arWrXz3Er!~s2@SWtqNe@D1zqv8A_rpzB&iZst z&8YPw#QJ{$KZ0;^Uq5-zCB~0jo+Wt(1~x(XTv5 z9SHG^0roH>N=}3rX1BW*Cw}sH9PFM~)RhY)V|`E{1zyzW*XRDF3a4*#zP6tBi1I0b ztv`;Lju)_26KUfg4N`@fN`Tg{FY#=t(L$7=j)B>q`TKj-KqLMK6$wS0^LYMZK9SwQ zXnh?hkog`*dE6$HC$JGW4(H2^}06M;)uAHsonKWb`=KGt?=v0U~O;^SEwk|->GKuJf=HH7_4S29?n@f)S=T)h%&!2+Xou+u4@|W za|yoh+J}3aT{Zt4G;O|zvh33rB5uFU!@0}uyUhyQ*ZbM(?&-h#b#eJcMT(@G>drz= zoJALbH!8(%=_Gkjtd;S0ffyoF+HZ>c$;-2qj#i0wp)ktYy|7XH?LTg5s_(D6X_$)J zBE*FU7V(TuaEWZn>nh%wvJJHBJZBe>Mx<#(n#WF`pT}fbOpiW zO3q=`1(aO!HUbX;j{%P(d>r9}0`In#`;_9MQcQj5c}y8AoyMe#i`?^uBY8P7x0Z$Z zQzG&@h0-lz?}l}Y__ty2F&>e)3F}sEC`j|zx!2+5Mxbj|X{igx0JxRQ-1PGIdZQrE zmCsEyg?IOxg2a?XA8VcTPq83GIAh8o7JE5yfB4rWfIUHa2 zP|;bnuSGb`ZN6H~LD(1OA85mVr}sgsd(SEHE^dBB=3W!bogIS~T&|*6k;D;6;*uLh zv&hGOtb}AQj_~Wquey9THE=rqteesqBy<;2dP^CdK}y<9(1~}&`ZVQ!HX`_WgMB{V zwA)^2_g%Bnz4pHSsyq*S28ztOsgVYVcgOX{z)2@jorR2~lT4#nzZc=Z0{4rxg$PV` zN^ETtM7}BRr!UV|J4(foGd?Oz%L}0W?b&YoTe>cshO^F%+@E|OpD!-gk5q;De~2uN%8jrMUfuJ+V1xHVeiRGrrF z8?{mY)6`rMW9`5Em3PlSaD%`NXt($R0|AT%#X9goubcZN5&nzceno`0B79OQCMc*2 zrK}Yt7N$E>sWyiaXA#xJEJv}v6V&l$)M(QU$m9 zYfa35u%etzoA)U;wQc!I*Sm~tPd1!(4>;zB9DGU*cx`+6u=gUkaL*53Ea zrto|?ZeMSI?>Ru>QxaQ8_#1J%_TiSjMYmERz`K7+yFN^^h_vHYUCs(TCha7oorEM$ zNb;B@jT<+ski9YMBn%F9>96GE3y$zdNz|&#d^y3ljgRzr&Di;T!QA8t^Qq0y&FDtc z1+6Y_{$F#hk!!Rs%;r|}f$&6_u>Q9RZ5_ssm)xOL(n-ksX%$84eF$#>K8&y<;%ANq z6)B}O+O6~h67V10gCl0g`}BeG7EOW4_g(-&)z^McGn{Z`CNKq|ecEOz8dN+Z{%%F@ z8Gy_a|1@#|%Dgv1oH}N}1^1aT0kht6D=%H)gF9 zv6e?1>ck|mrm!+glP-`&nn9jHXO&5O7^wl{TpB~$OF$$oUGE&h3&&yeI#Oxw*=KuJ zMxbfdSs}wu`x?y9UDN))vlZyXBhbVn^WZ9_yfh^wWlEe;Rotw?+;J2;m(c(^Ql#CK ze2|g%V)9->)^(DU=K?1(_R^pI2+!vm+U3~0-@c~}zU|vx-9GP0xI5RLqPkDJHE z&ATwytrhChC3Na6=VZMU9Y^PsR&N*NT}rW~6HT#OC~E~BM?O-yM(Z{=ic&@u`?2lQYZdT0-?`>3u2H0cm^T$u86G= z)vo-rww!C)u+xT67UxkMBmiS$y$grf@ea=r|?Hd&K=E(&Zy$t0&0TZYDc?hWyCwB-9fx`8+zdu z^uihR;0$`-@?YiJxm5CIN9rPYd__5KjEfM#PM8nEY}?GMC7qzyD}8U z*()d?STBtt(yULMF1Q#^#!CP~gNSGEn$?cig9ajQy)~4zEx&SanAcvRTU;a9;D6pe zAGTH}gnplO{|uUQdoW)Z50TTGCO-6YW495Ia}e=+F~9Z(R?#)9KPQe&vWV^=r8`JT z^N1vOi~?$=ZrBfI#oUXb|EM5Pjy46EFIz)UTBql#80JiCe-7Hu&JixZHGJPpw{Csv zU6c#e+*!y;I?2;Y^Bz#|5-XolNo2YEI0(uVmCNWEYl%|F2!I!($+hKgAe1NU?}b3P zJst_FH{E(J;IO71?PvWKa8Mlk6~8C+ai*J?17W2fC7wa>qW@;0(Ng=l_qSA_d)u`D z_CN{04WVq-FQgjXzg#wk-!(Po>e5nILOFKfv2R4!TkQk*BZlJfubV&7nj~cfSzaS` zPF<8UW11S&SkTM*&zMU7;qJ!t=3-bS4nez#6p*!!!vxr;>%*y*U7e{dWnsKkxBH$_ zjxclveg&6k##<%B&B7awwI`grKkvt6y~OGMn|R(Hf%%oIh(V-sp^$AwU1f}iH*xjC ziB4W-SE07v`|-KIg)|ondJ)!g!}-I;?_m*-WP^?!HE< z5gx-^O@osX#F`|J==5UJPTZvO-ESBM2=BpH>AD0zw%i<@HNb2)T$@$MNrU{e*8Q|s zzwVWx^49@Q|uI~np6^{ z5#79CRCN$5sTldU@nZI8^J4?0v{IBcGAdmxfW2)WiWd63-BJF!SfQ>hbz!LrLseL+ zsi7(bM>t)2ZO7RA=Nsbh@KzK%iBgg&FXj&chGs#A!u_F$KB=ca2&$FYIgv0Iog!tf z_@RHqGv0ojo61s^HW)eot}*=e-3{~5U|H7yQK~ulo&R_E(hUWByY>LCbJ)HAtLKiz z0*VAUrIh+!YviwuHm0jCX^ZE)y@*xE-V!#Xb)CbovtLI?+>VITd)0p8n#yg0BJFw| za2mPPpraa7yQQdBF1ntMg*et^y_lrq^13@CC7(;cBMW0w41I`J(D5Qs+($<_M*56~ zhbhVdNIF|}CJ}L-k#stwoepuDIl`YLD5a=sgR#yfG0b`JF#w{7IEsjqm^gOX21P|w z+J$3qRs{iL%p%(s7A_T*CnuJZy^N!s7~@}F15b_wz4bJAU3n9^y^JJ%Xhez|#yK8SB!6v?y`lXcvx->)`5Ey$iKTz3%K%By(XIrr;+!Wf_3hu8VLbDkj%ttNOK zf8ZKiEkoD3@6i2_UBmE1;n%~sui725QmMTtTsU~jq zUpXmLDn|ZIypa9b>}Wq~7=TITB09DqjMq>X@lve4AU38x=*!-M;N~D!2Juyfyoa267G@qIp6H!8C~Z}X{k#qb!ls3 z5{EhZz}G3I{**QHEu*a>FLo=$ z`Y3nas8`2sB1Jy#bz3bEhC(o052wP4*;F*#d|kRk9pb~s1|67l1#|WRN^5lNEp)w} zPRAN!BaG2l6Jf2wT8&6VWqZ_Wl_)<-+&xT^FO%d0;-rhxIYJkauD7iB6j^JCoQoQs zkx&YZsTmH3OeRxmAFU=xJ)+1(5Od)~bMm}{_FfGRx4F!JT1P0YvAD!&-h+)Rh2_za z;dn3OXg6_ccLf#j^cd9ES?;*}-^uF>5Ouxo(Y3QoVV6q|~%Kb0)z-!VBB76YNQBmQxsNplyGGWC)BT&iA2{O2G%?i)QcE4ca9>=VlCjH&$X zbL}qDYS-E^D|KP1OR4M1e#BaSNx{EHQHRHF`Q9I$z2F9e7s3?$f`Y&Rh!@jaCjnSM z_yMK(4zcov@ph%AyA`H(KJ>~@m?(B!beuWkths^j2ZLK}g%zr|_V?$)oDW=mT^g)c z3xxZzmeS^o?IJtnVJ3EfQV}|i(2>h)AjIASHA3r@IO(9{4l3@T;+!bX&{0Ypr$lk= z#Q9B_WJfiF8lE#0oY_;qi&#a3|$Zp13k7C;t|d-LY!zx1YP_AnZ0+vBdy{OU5yP z<=FZ9TjN)s!PwM;^8VUULt+ne@m_u1@W zv4VA${yw&eX8 z#qk4+$fiQ|+k%gNG=IB^m5W;Dwa>Btf4z{r3j=+;_{u~=&` z#$f82X;Dy?g}*LXYkcM~i?Ovsn#NMsHFZ@|RRs|>D$-1o1uPLO{VuQn;#YI}^vz`5 zuCpQ*ORN;zmF204rJp7&WieUgR^Af>5A9mg&8PUH%{P)&7pe51MRy(Ia;b>5OGAum z(h*y$Fjix%vn)1NV@!l7Al z{%m}gcGF#}XKui^oA~0jsZMCpHbDYU=vy?`*;%xE@Ki$a}vQOwp z|Ab2PZ<ZF&pH~V$ zNfWw*l&qT&CypboY|Q3(iAUGhxU|!uC?l+BBAt>ZIce&MeVV4ENlFq&Xe`!Lm}-it zr&v=WQu%brwX>9J#qxg(&m6Sz6F`ZHrQ%qfhco#uW{0WAO+A$$%>cs!uUZ37z zk+i#rPP*jOB-N17))gLl@RL0C#1lkf$b5!6Pfv*v#B_{9Mao?YZ)PcHM}$5y!Sku~1?&>HuCYLy4i zEpT-^b4b#4kS7E|4D7uz!dAC7ADdsS4_IJBzwYVZ=Yz)lJxW2GM5Nt>ICF6V(kybZ z)^isMIBZ!r_CEfBd22~0{;<%D%Rn5x(P1!<^TuUig*i`1_rB~80Q#`?sSwZ%ZVO%M^W7IFO#Xhk+ii=-RBMQQc-Rjl7;Ce_Fq;mt4p zXG}N8YIuHUu4nK)}-R;?I}|o zlcg~$k;2wBo8u`@ZdK&NOT47`D6tt+*vthbvd)&kh{9NfF^bx6mDQBBqO269QIxf! zHk#UKP{K;T;MOA}?m4+ln%0O>ju~i(fg^l%ZL#8_8perBnxeFxYU zP)7g$`Q!O();I}}2~q&hSk92T-y&az&n9^M+va8FsJh@1Sv3ZPjtICo1~a1Yd}!Og z;J?-S;-@7C?vZB6*(x_)Mc~i185Qq|(K;{IS`j14)S^r+=vY;87C+uu%-)l9lHZK7 z__s$_Mx)MBj#y!IdB|jaJXe;s1mMYE`I}fHiCFpj`9k(RgTuXB^3`6P^i!9{x$-HU zpRIm-$4FC8ciI{!EetjQWnnPYOwTUX)nEC15J?u1_hLGOm^j@hBy>{_*Dg*-sT!R? zD25{F#aiv{jgIH~Pu$!PpUudMLFNV5ZQ#}E9=P>>rMZrlh4 zU!bt{p|9fa{ot7y@)DL1?g73H7~li0AW%-7Ww5^wJid=wNi&pxk>iBtndR^erJSg_ zd5_-$ZPk$?Nfe?I)`vNlwimfN?qdZsjsc0Z`>s|Rtz3q;fQ;QY_fB+&1i^9WS~F9R+7Knrfgj+l@%9I00zO?6Ju4`u`UxPoGP(mtINMSRUp-I25Uhw;(N6Uu zMbe2M$_Lpy;xzvGc&-0F8JFWEi(U8E!p=D-_HV<#c;ow<{lD_fUqo%JHnn|)7`am_ zb0qGjQQA)dTm;BHwjguRAPN6(pZlaOef0RqE$C-nN^$I>_jUSS@1J^O(P!-+&&V}> z8koA)fNM3Y+X;{QzQ^D1y`7x5f>&#n&VbR>Qj6gilT`n_hT_5drd)ld=9fP7LI1KF z8=kd!58(QQtq=K?{|rt8-vImr;23_@Q&)Cov0cwZl}baFMPyy)mZ!98ba>6&Z4uwu z2nq2)JTeHE{dKK{qSQQfIpg8;$NA)iBh*HdM9%Fl%ThX7Mw;a$NlF|$I{>{$0uYkU zIEF+M>4+pvy~-eQmig9D79~YdG!g(u$h|ROL)g86l(d)w{5{q*_5(8pz^_DfUd^p`WAxl&8 zG;?+kaSS-Us8-PLRGdCE;+~V6LC7OY38H#}!&D)|PVCRywRM zcIfvKvdkwZYDZ&p*l!*Kw2`+bM$P`->mH;C3~S~1fte_EJLkZYUbniCEh;uCIYF)k8B{4!geHjJxxuk`nc zSh3a-er4UNbf}bid(uhX);rX>H%{Y6AA8@^ySM$|YvJk;4lTgOE|=c+aH}*9+7f_| z|GU48LdDkD?~7vn-Dwto>B_Au>GDmB4mTK!lx7y3YQMJHJ62|ub}F#iy8?O-09(6E zk`h7;_`Zn~O=lq??L_+%|7U6AIq=_ZhHNOCFILlYp(+||EmVb}82d67hN=?kT875R zy<+)U9jiBq6|#<7gq-=F8`to!4SSpT0IqXr7y!XVoQrrhif;pc5Md3E*G(-H6K@PS zF{sx3iGAwT&O++F0cI0;hOgX=k!CVE?%pA-YbRqA2}PwizaI0@xubmOiNg&8ptL4U z64Epy%bfl{iDPF3=#2y278AvhGZ2g%@sHz#G;{U>aU7$y#)_q`oc_NkoEl(8pew4X zrm8Dv=vPk*?>L|s{Sw?~{kdzSNOFLLhTD_p8CbC@M= zz56)5%n|Ig+a>F`I^lV#(mFMTSodzN6>;S1)n;;{C?ZW#vecHdhLI zS;ft3V_tM}!!ZE03xg~om>M2?W{U?N+u)hYLpFCyw1U;8oSP2!xcS%u#}D^dUCN1l zSY8#x;0=P^4+ZQ&=>F8R!roUr*S&v8aKy8x^RC9G>!qew>xwNQVo|IYjE;_Zjn{^TVUcN3{bB>>Cc@Z14ve*dR`5QNBz zd~+P>KNTm@w=Ev+=SwFR=&p9ru|^8xyaCKioz_5TlezKI!Y4j4QHTRzyysA(qQM!~ zgou+_&#nIVg=cBwd2sJ-P+A+e`J#mrf$=M+hGJwWC$$S&R9fm9jFG2|w?tY! zj*lY(aQ9z)VWj)YKz&bBFEZ+=#7x2e{#c-d9v%sC~R!oMKV*otjR49^; zroWteZ-D(pcUb4^?{v=Y2HO$`&XAj%7?pvmTkzo7!@Tps!xXh9jhtvWiei$)8Q`Uf zThYh)!e)~<|QZB$&!kyc9GyjgsKvL|C5(_`+euQus&uqsZh#U z zhd*_h3+p3#-I$vXFYu+WI>xJCbeK3&7!fyqv>T5uRPBrjc+S3T>hH%w`&xi~PqyYr zn`se8q5O~A_UQiIc@c5$B3LU_MP1b6`Y~(dm$35YD2+Z=>=xD9U5D7cIMmiyx%{b- z9KNGZXAr~lU;sYw6Mr5N(bmcrr&;_blO+C&aisgbl@5pRIZVEgL2Z%RTe8-k2~cgE z@$3u$K4-^_0dO8e;WnilW0vGjDmgP4-3OkfjpzDKW(UT@bFT8`M5rr82! za`h1rMw1DG@SR`(?c8z89cb;CGKG+*HK$g`yyWCn@}#1w90LF@JK4t`TIU__yTI>1 zeued6!E!&Mu7zGF;ie;f-tfw!yyT8U99`|w?Zh*}?=7Z3EzI@xA3Zb(U7(m)u3nk) z{`)U*@5e53?&^@8Nkx`udTGj^{9~v2>MuS;5^Jni?+&jHGd3^QGl_^T`OW*j< z_~w8AL#lhIOB9LJrFBNW&w~ND_h0+~VntV#Io<7N-ySE?{}C&-+!^F7pIM^6)+6nw zP6beTqre6icxczXjU)Vdu`@%!x-i&!7KBGdia6EIgCzG6A{+dp{7wE{;X89(YvsE)CP2l45KqCvN3mRn}?oj65KgH(Dz{8pUd?edNl!|H2D{@CSI7 zQGWo}E6gzf4!$4w3kWas5dmkQpe`-NxTY9a)MbnFjv&dLM?lt1W_jJ)lUX^7b7Q43 zim6-CyR5Wymww(w%J9g!Mc#PtGCPx)P8yRWv(q-34}==FMJS?&m)2vu3Jv$Mn2 z<`x^9n`~`vv9-C)&i0Vu_K3-FN-?f5ruGr~G-)@upT)$9S0O~+o4~v8;l;cG$+waH zvm*Y_BTUNzMEJ(9{Nvnl`VMq7V*s*b#sGAZlB&{JAMsEuoIN+>;YYW5^!z4IUfSi- z)`Z%+L`6v)@%mRC;gxqE=C)HyEDy4lOI3^6d$uNMkA>?5#HVlu#m1F_hacYJ9Upp{ z_k7|K{hp6)0gOk&_kGK){PEYHAx$;LIu8jI&1?bMOaN|}Tnm9xJy&z=b74jwJz@7{ zC(MLex8c|94{wBJ2fa5HdmogVyx9k*=za@(Gk0o(*EbpdtmpTlN_30n&yNr!iu9XC^r~UyMw9iXm z0Iau3nlS)6gbB}`OKF>lp242?G0$vY1Fo@WOhEIXU#R%Y#kgX4wQ!ONBb0?RB(+wI zSot@`$S(jNQA(8oPrT%>{8;--H$3dqdIxYlLtp^HDiHVq;4cC%2RiM0@f~a`VYFQ| zX?z3Hsf;4-#B>)D76uVnIv*a`hXiLd5w>?N8(Wt3P0RLB7>$KV0h2-)PhdP1%F;0g zTf>NR8!@$UD`%~}pRK~X`MFs9Q5?CDyPol|R=jTC>GA8@>+XYvzh9j<2*!I5xL3~z zeW>|fg#L#W+kdX0C<{d38@}R?ar^1py&<4$lr*V1wKC>qr>>C26;-WW-}`o-|3>W~} zi!|FrX%9%CG=UzmAJKP`ys$4m?QvBYieX7zn31jQdqw0&ZD~Jb*6Z!VuR26s8--xs z|1H1AOMm{0v9-lz^!p4MfPeOVEUfmJj!H~z-=H-AAxY!gvpgZ|B=lA~4Ay#dRystT z*c-X{D1n~H&b2|VN?_fa?M_-v5>0@Lz!M2YwLc8Gta@ z{q?X?oQ`UWu`_Z}B1}u+{8eFVVj)o+J)F|*L{ydI&c*9lr-iUH7PfbUjcwuTCT#5} zcE*a)M6ol5D?7r|o5IdTpjPNZ!i&}{T6@9)h;@+yospBMg(wf?z)qAU>L>%a7Cx&6%TBtAhA2uW->wKC@Ar!JEx6=kg(!XhHXqEVtS zC7i!J;$x3ovCrOsYbO#x| zr4IR0M%qsup#~=bus$tyfI#&38Cq3osU|hmq{dXXA@*?|(OJse>c9QKe(lni0JM77)IvEiOm|C^2-`!;y`Ly}&;1iV^iaWF5g_zB4gSAlC zaCy^k;fnD1MWHl`L9Xd$5qXx7CeDq|5oH&p&y}h5QNO$YAe)^H@!{w1+wVR5zv)JY zqAUU7>)!A++;;jlvNW490Fh$=UUup-owTAdo&mr!SKcL1qp&6HY}I`5!HeAc$%|ax z8F6)|;K*vum%s8juef`S+s-VJBoX2RpfvD&n>I*c@X~1dxgcVd6>vU-|YK#6UU4@X-YWub~c{)SCd+%yM?I>^SDC23-~#K`&v^=TO&5<#Lj;{i&^`& zA8Ee*2Z49|qwfJ{SoCK{D=V(yR=maBV@#nNwt`32_X^*MUN6+!v{o&e&ROFE5bf;vzT{0c} zw8WK&sanL}a#<`NvzCt~8AI{03SP+Y*%?6x@Ogv3`xnjtAVLHzdENhufg?Z?#{S-U z<1C%sYFjH9jxF!{$e8zhxL|o1o_@x1?xNw!wy?1)3@4B$isdEE>ayFGdzx;hNfJdI zK^!R}AI-~&==XedF9ep=HsVWUR-ejkGxbwYhkfl zaddG^5*gsS1yG*si7Vz;86 z*4w7C9|PW^w0etD>OQ4Z(J(Cjo#`OORL-aV_;>x`b<%(8wRbx=!^$XeM)$XfJ$`?WW5Zh#?an6q7S{SfCdaqjxbHBPIA_U(ty9F%f_e#%MB zWV>QIs--GKs!}kuRW6&QAi|~yzaheJXw5^?N{8^XZ=OX?e4)XC1mH%4u!wM5NCY=S zH~v~95%3(h8_-S)kac77UQE9i0h&lFR#y~9)-=afG)I>;hZZ&6T$9AgN3e4NY#akI z3(JdlWplr?qU{So8sNpBdoDKBnC-cvy)O-SJ;#@BFmNo7@lglG$3~}B%Z6Bat93`T zTfZU5kA}3XSy@ZC<8+@_-Lk~%PAu|8%NZxS8d1Wf2e0tx?>)hz?|6dC4_~Dml|IVb zX9??mw!qse>|P#o>62G^`o4=?eRz{%SfFA>rG$~O+;Yw#^Nd|n6UjiV3zd7#{nrdu521a9x~Q3K zO&MMuGv1hDDg%o9bfo^1QtDTLj{we{<8usQPWJlQmbLPGWm$i0IxQ#TQOR^%y5Km4 zO9k!q{bjn3PxK6#i+*Ap1=op;x_RwU1BU6-+zrtBUIw`FQJ`6x3poubI${m z@80Qd$?$5yWN0X-Vye=Xb!8>!{lx_f{S@%8l;UlB-}6F-KR~k{z#k>7zwax+^U#7E z0=^5yp8{TiY8e5B&TV=)tazL>^~y%Y|9HnXZ+`cX_kUtaZDFzNV)Q%1J4fUrt~$9WK9;|p8RlJsQ1>su>{R>sntR&f<+d!KbZaP>pIvS0`+p+u`Cvml<8!MJHeimrFYB zB`n;$z~ZSzx=URKt6c_beRLjsV>|!OHgXR8ZCUO$1n_x)@~IWsv+A~jEe++!r5v8@ z6zpCYF}gIS*eS8bWtfYTh-qmkW5v;ztg&`#f#u~6QQ|{Z`?BpVnrgjVz7H6~3yfpkMN8GIS#(mRT>e8rsYN)2p zAWp1YMX7fvcngYm180F^R!9e@zW*opp8BkScrC+k{O$h}trb;ezFTYk*P=+js?*7` z{-8sD&>`=*z+u`mRc@?-j$HP~ki5qwf^v=QjC~ygV5`tEf{HZRa!$IC5^F!6_8O+{ z2hZb{P_DYL6uT9Zoswc$+p?1Fy0nq0rE84De&r9syF~aEME;Y~s>z)6Le~8UI8XuH zVDNYU{AmD`6V}DR9l+fvP5>^0hld8wHQ3BS6e)~_$yAt54Zru1f@%T_eHUpj5PG-T zpU=|QFaUw*hn49b!9844fIWLNm=XN_&V70&VBhOE5Cp&eqlb>LxUfjC(<6!^K+wvm z0FEt>Nn(qH#4*0Mt{?D(Yrao(tkJQHerJjrTN<~@)lOYtYRl--h^;5K8DAb@1=4=% zvJTfSAH1zCVq7G+W(#rQ+iro+r|DbwiT5eDwZT>fTRM?;J*k=Q6zpCcvHAEm>kn@- zyf~s9)u3DeA00b6e%^^Wbfm|LJC<2K+--@HXKm9Ebl)b;uyTms^Dr%f?SI30C6-OQ zz*BNeJ;gC~o<(-(az-{eq^@AIHP9)_O#Qb*1wD^s#08wHgkn_5WT&LqDOEMCv4&bH zHkDHERf>O);`e}aKFD_ir@sFu`SD-BuYKyX3a=bq;^E)^UBt&9@ElEStvzL}tcrCZ zvZE+MtPe%)^ITY8$GY;#bf!+NVQT05UzaYUp7HTR+ChYL77^t!I`gin`$|(jL(mHG z3~({57+#%HjBBYXnbwtT*Of%ZNZ-3+T7ioq{DKnuiz0RxrR3#*{U=_~V*fTAFaS3g z{GC7N7ywTQEN}|A4dGTGV=pe=4>5b!z$j9T#)jYg-4UP|3<6;f@#=jPJiq#P22^`i z{R*%9b02DdF3jb*E3F%5yWu_aFwYq5Wia-A(KUD72q0onC=M+jVsWs@pw}mg6A;G$ zEO`bXjV)G`udpX>{vDnNb1l&H4@9XZ>Bc0z6dh}d%_*w3&M>NZ5bDY>-k!2~VVkQ@ zZnF9G7CRSq8Lv+$wx{gSSg;RZw+`UTg zPzRkytu|>BecxKGqPbOHv-+EzbX32k3J^pLmpI15+{C(Cpdul`a!l6greF`hoG8wT zhmWDKC>^7C^Xh8=Pz%4T3@65uak6`+A##CvTmzgP@|9n z7;kqH+CJ(ej;RYsKydr+*8L%jE9KN;L>e0@h$9S|@n*qzqhLBRRHeOISF%-CvS^I- zgV8i1R|MXU@SCXU6Hcfq{M)yDZrl5Mf&&KN27|xt832de#DZD@jw9S9&~FGr^RERB zk#*D}juq?MHE(?D5P(77x%DaS((gK?J6r7s-M20Ew zo1L>e?4BDkx;$aJQMiCHm6uq!YM}^;t6YMmrCSzRJ-tZMNgC!uHTTX#v&i>EKQICA z&NlJ)1V|iXR*T{pPV)(Ml8MStC?bUAsHWQ+kgS|0ic?fwBF11!XB}TmYNy5+mXzaK zd*y$|xs_ddvXf63i|%N81GHUtW5WooUB zmC~`bk{V;9_G(_NlO|f@Bmu@aVqaH+sT~7gLx3G0Iv}*W7}qH}cODIDuQ8zV1G~L> zV(*wrug_EpD}t%SCH5IsjIU0a?o?G(%2r+4QC&-Hj4X<%3_z?cMfi{s^NEU;%h3aF}aJBlv+me+)^Yxx7*H8}A)aPNCoR1m4>L z=wR@-XLGOe5`gC}#dg7DXUcSE%4B=W@bZYQv)imcw!!)%>s)<&gRQ5xnC=uri6+is;v@oVnT|@f zF6?mS(RI#0aFJ*3zsUKIUEuOVSJ*ha$?p1?Vp35VgHZypLd6;tJF5ok4b+scuQe8( zMD!1LS-N?F!Qq~F^O{vzDSRCHmOVfq_>BbGJvfI+VAdp0Dy1G#N^MtFWs9On%Cg2<(ONm*6A_g0gg>nGO)buCu;pLhY(9** zSZVTn=t!fI2%UIUK%3aNSNV-3X?9+eS3yh-XhN7G1Hxzvap+VWzRaDKWo-V z=7*9o#y)In^BW@a^VZsJ?IS3v7r52`Ubz0T;{nXU)%Q9hz_2n>vC_7ZSAzU7@TI_D zjt2Oh_BpqjcY5HDJ~-iLetClre0<8~Ez9yC$Hut1rWqp z+NYXyF=KFSK<`kGte;_OLoq5DZ%mkMOenUdRHJIPvRB?pKXQg;O1tpTk&gly7!##6 z5sF9@QbYe#j}xyx%EHkeX*Y58Z5Q3whn97JQ@4fzXzrf>@$C>{DM-1jmU%$Gln?1M zXqVa!t>CtWoLiT>oLKIVCkj(dVD}34{3Fy4z6%+yBT+URxvoz}ezpG#z&n9QXXSA4 zxia+oOyJl5w{LIu<2a7$x;|c2)iJI0T9Tv-ola*dOVc%_xJ49q0e5Mw7PWFl!y$QA z)EEu}%GtRDRZbK+31pf_Wc`?QkdiERpAr)c%#ZivQLHE(gXhNL0?1``V8=qMu#Ty;2f9!Yw z`@&W44Pa}F2x|)dzrZ&EXQV|O9rBq`h=7d3Bz)wlf;Ycs#5+H@%iG^qaQs+I9BH4s ze%|uGVF3I)ohqR9{uW$&#=%}m1bapQ&%yvOL#5$@KR5e72ThgtxptjFU;vgDm$>cb zTY352FQeZZV9bmGc=^p&=w&5FJaU|Cif3a2d~`LR#ko_Ai6X6Y;9D7sl|eFUWsYpwcP zX%%~B&Z!jJ5g0X5q)8G@n)$68kq%O_#nknycJWFA;Scr(h(ImaqNbX-=z_(_h4eMX z)^#nDx|SVl-Bi)U;P18^pd&y zexbmAK1By`1A#-tQd^P7tjKwXklkv{A?W5FH<`kDKdJg%%^jyxP8@bt=X0yTeW1B2 z;_eUodp7qo`<}bIb*}Zsy(_eNggkd=^Edl`^XAz@?q-mtgx58A(J*D{(ivMHT`_=& z*SCh|4dQ-sQ)A*sNz*tY-q6^6ocYe32x)LjW<9eU2;+SX&y9<{6?u3q%GY3sI7w7gkXx?u4bAoTM=TduyBB;fV2g z%4A$Hos<;Qipi*EJTw%AxHtpDlF@|`+fVGU{p1ci=XTjWKV<8v9k!m>X8WmKww~H$ z^Xx7g=f`Yap0K-FFdo$uQ)A1iU9U>}vAQ((S7p6cSM{w`Rd*+oiP|0Rva_=@8I8uj zV~qJ}rPPzV!y#AK*Wu$2?XBh)3|#-qqXXC%F2C!`z~_VqdccFSgt& zi`GifbLFF{aQ0%wuf27hpZL!^96gdYasHdte@g-oh!xGsQ@LO$t#|t`?7?gPdWbg@ z%F((uTdiL^ER|A?uDm(duFrEkJOA$M4+4{;wdVGlZ{>Bbd>speMXWVM+Hi7t%*#(+ zqMKJ(nyv*}^t9;@zdt+eVHPZ?8rROU|LU0Gxm|{jZBtDv41)N$`E4f7h?4*q>zII` z3NYeU|6*F%8iOmDaa31FnkaJ~4PvcZ<%dL1$_1H9l9(ilh@;?r;^R-0kal7Qw=U8@ zIiP#EOSY7wa!34U^xSbip}c`H@y$Aey~m-E{Cj5QS11ZD#kcd$?w7Kat@A3Tv|+3S>2cLS%DQm;`;-4SV>Mv+U^?Nu%p;Vk@h?Cgz9<nqjRye*0O1>>=+~Cx;B%#t`lqRt;X1X zUDs4qNmW%>>e{^B81u%WDBg0<-FJ^4d;D>fQY1;jxBQDYwyXOE1J~k-1Gu5!!aLpo zkN~%c@F#t8pp*U_1R@bct)6Hq<#hN)6q`FWzw}${{P53gar8(+8ploy+b{r;H~w?F zJ@?KTBQS&KB0vGc^Q|*2h9V&CYv1i)@A)}~pv_sdp()co*RBHy3_xuRx8Hm#U-p_W zWpQB%YYnkBoLn05(vz1x12CU9RW<+oaqHUb9P{n&LpO`S@Z1g?AGyM0ee5!|Sw~m} z@8d1v@(qb&0IDk7K7d$KiqW&g6(<)!H17YKxj)}{%c^LQ+T4{7y!q#SW!%^OJjh#EAfzqnqB z|8v1!RRNxnwbq^i{w(k<&P`bc9%m@k3NIYTFf-a+AU*DUf1TPx;BT6G1PTUUDslb*|pZ*i&FnW-~-C3V;cCjAA3{#@CynK zyZ~-+_*;MW6mh03!ceSO5mGECMOY95Vw;JOXW$XEcGn+0Tk_lQt65xBh`5y*-u2HR z^On`WXC`K^dN$JP&$cekcH4x??TCB(?2hn}cDeUq5SnM^%5iOp_A(FG3wXrHw3xEI zu*8|0PLt;yB)9?Q6-O3F&J7Ung|VmY+BMs+jb~N&eW#o>AnC+(j&w=-Das0Fy+j!y z$s%H{i6ccEY0@Yni(@)jLN`n4<~jXNhoz+j){d-l=;$F1A3w~In+|jQ^a*ad?Ibtd zb%qmnoaX51;~Y78ltaf3vwC=y#id1hot$33ORwK0@8l$Dg4Pn5+62>x0usoRVNs+IgMD+SwIk zT5%|kNxcQRR#4T3-RYF7uHTwJ_U4~f<@!4$Uwae?IeXQt2J`Uww)+2UK-+U5fM;lj zz{9`;0^165;D~_6OM_;%B^FZ~>PD*LgAE1MkPoJ0jaaAWw^L*6PF>rbx~`{XS$2z} zTq}$6P+3(AbzMhQRXJ&uwL=m4pTI8&+^11ndr`wL-}~VFi7z0yJ~83}Ja4%2t~XE> z4wr~!P2lw+^0$CDw0pO`@>d@DE3HUkO;K5X``#hH_S-`qdZOgYwqj*4^8ko^Kp;n` zoN>+^G4=cV52pDQ=^SxtF3&$XPuyq!+t93Z#S=4k(p_u)Z^QM<00h|D-QmtNxA8Tv z|7w;OR}irz+Hlj-h?m}UnNH><0KpNXsZOf}L$kUDY0k|KTjvx$01K4sQ^uD@j4zLv zUKmkcEkFeE9uapV;(kj1wne(f`i)+{0lyn0CvJbw#Ww7BYL0>MOn? z$SeN<2S$K5IBab>I{;&Zm;bT%UJ;QGiIoS$%DNa4F|!C<)(7b@wQUl2h;{i!j;$uV z@~(_-20L5x7;|QH*Bm)fT)+CkmV)aCdWf z<*ZOGn7!fp1Zyp}(Wm>9KIyuMowK%|HH52oYZv@)Xd6Pm%-!I2P3npqv&|MTx0uY+YmP3R~9LszybM&P{z5UcAQAE7r(XI?iP<5dSb%*gIaD zy*=$Rt7mABW~^BOKR4WJQ?RwAnz+b)n^m7Hro+~#q$(>Stw^;ZQ;Jk;x^aY7iVNeK z&B872waZ<^u&UWGdiSl5JW;M^%S1kcVXIVMFtD_^h_&{EolgF*qA2=1z^?)iqSQ9H zKC#A9S2bl>G9HZ>?(Q-i4jGTfOs7+dqLgV-%Csn$PN&gyI?bok$;xy(Ju;b0*QV1V zFUyLmZdU!Jh&%?oQ7QG0lu~b2Fh~3kz`;R_+~Dxc+uwi*u29bUKh;XTR)lXCkv|J8 zvv>8Y9B1w#vns5>`E|?vpPKTszq-MP9uQ8SOlEF?dkg^GyXI{GX1nc0&Yo}X8F0?5 zXLhG*iSYNX*5}`^{L|s3K_%gJ#B)N2{mL-^?&}5Cx3{?S^sRjD>%WGTrBzTu64jho z9P#4g7wM)IR=itPG*boaY3bHMu>0^0xVI_7Iqw!4B0CnF6DF6&R68Z*)d}UL33h5g z6e@P^dOD6tx*16?C+X!xd5+FAbe5vx7?g5x{>utGEvR-!l-on-3NORp90y z|4S58!-?a)cBx)4EC2l7&%6b%Cco03F?CP^kBi7hlv2M7+zWi7Jxn-Q`Om@ii3tzjGlH{k z{Sv@g#YT~0I;n{w{aWCk0Ixz=03tOPFwJ39tsN?(@SF}&kU({OKfGKb}MEq-umB3EaEgF>7>MYhK?i008}-msxhX< z)HT-DuIx#K&LfgRO1j!1JKA&62R)&lmCu*kt08nKqaQGH#Q)me=0sy8=zp9*VJ7xB zr6c~+QHh;SsL1%>>Q{3A!mZ?aj}t449A4}Z&&Oc$%ml2Ynj@Wrr8J_bt$AW+a(Ob` z{fRqoJNDBjMMfY0*MAv+m;CjgZ9V;k0l)S4z6*eF_~*aO|N1-Mi7|$qogJ2zmW~=@ zUJ2X;oCk~uYap*yPEBwMSVF0eQY1<_#aF-&B5o8asKjMX+yI^eJ^;K6_?`VSDjpF3 zc{or3ya1pW*A(NLa#}MT8=q)H9ubkB6)SJHRyKl9bkL_dSDKlDO{#@XEF>XGjL;If z&q%hopMd^aTOjUxh3vC?tQ97;WwW$gE-X{=h&|F+6eA<7Pc7$n4d*uv>pK7=LEOGI zqp6{)gHQKt)#kvL$A7||pOtvN9Q&QPzChtz9j#dBY8U7oP7@%l_zfMUM>YnN6P z#h>(qE`-#*#$w*z8&<;BSZw7~5m6_ib5ozCR~}~db;nr#q9gS0UZ!(Xk7PMTcV=1K z>Pg9TW5np@%j!`RiFnE-P;yedd*RmUw?w-*BxW=6^H5GzD%;#K@={7 zT;w6gNkv_`5VmC{ zOl-oK#4(|cuY6W0Elg@lZM}P36e%6W;@GGI*bCim7p?UbrPRB9E`)aqya(hrfPX6R zzXAUYrG5qYum~5dm9e$95)mUJr8hD>C-7n5S5WHz0{$xSFM)UONBj@qT6m6OeE>HK zJnwt@Ap;=Qbn3* z;>bq?Y^4C6t^R}PefH__6HbdbgQ-%W6Dv*)QdT<=gG7@@idebTYzWz^vlvMtrYJT> z6&J1+oWEFd;j%#|!eCL+?I@DO>85o{ZGiGp1GnQ(T|310N-nM!*xKFZ){|%W%GZ7c zt1E|yqlhf7IleIDMMp1@Ck4hj#~o*s=i1JRNat7h^WCC6N8nq-y8(t96)h%!78emD zFh0GiDGl|o!i+1-)VLJGjV(!FF8sp^7s5A>UCA}zj1j8OaZ!*yw>OY3ZD$}wY`bMM;M^O2=n zSj`h|KD5ZuR!TjtlzP}&`^-MCl7m(Mv%~d? z2@l{if`$QbINq(~0wRXvz-tly1n?zZv=;i^-K0=Sq`9=_kDSNSB+IGFH1Wc^naI1xkoxmqaG%Wk{Yf(VEM8z%^Zr9$ z$A=eAGl*kuJ+jPAhZaa$W%Dr;F{0?j5i4oLkxoo)ZT-p3^1^U5`mt}lW9?@mk@A26 zcz&?27l8+*R0MRC8?<$|)0vFMW5fp~YQwkw%l|fad;rf52P%LU5LhcHt*|0WM~(AB{PEOtZTy6xGbYCJ0?;$hyJ0o^XU~F8r(@ zT%HeAO)reC=(E+_{=_bda&S(&hMVE8P5&BiwxZA?|tgO?>g!-NCEA`Ziwm z6=(R8ueybA_~twLf$x7gfB$d4j(_xjyq>@HL$Bdae(RmQ=&m(PmGaRCY94*EV0T=* zsB}%S_E41@1Ogfh#!cazS9DwhVf8FN^sN}{V?WP`IBnYK+h*28o-npo<1KM|INzv_ ze3?Xfslz^-7a91i)g3-^n^QB)Ti-WhtX&Sj1r>m+V|(*V;NGqEu247kJJa`<)pDpC&SUG8IK3>2Z!h4;Sb;jgGb-=ny~Bo)!Wo*4aTUB68kFP+kmeG z?!g7;0FWp`ji$o6%Z7Je0x_1xYfkoQ`ZG-4|h3z{3Kucnm4ev zdW1Yp$&-o`gI(@Ea+y47B?D@Kqqi+Wth^y#YxR6hjT_a8BaQ@yz!U6-YY4nV``Uis ziLBcX%mt1W+{1j#?R(fyQZqNKd|g7_0)wmOQe)5V@fSQ};B6u%!*{`AZEzVCh+-}H62^Rl}R5u1p*63QU8AP}EtqgdA;D8FJh-m)G7VGUt<+r2si z*AH&R8sY@FSOK1T&wd;zTNwm2|xoPp0WT~7ePkEo)(F}45DwbHh-eXAPoLf710TM~hd;W`?|)=OXAycm zO`f`3^E$MFFZ1;XyQ3i|kDlOluX-Iv4jrY}>ClNwj`nuABsbfTtJz1q3Yy;HK6t1%rrz|czUatJhNNAZM&3z^iLn&{siBDcgZK=Ef$QJ@^i5lW#<+$XQ(K&|k<&@|biX zC11*k6Bjv-7*^ItEpI~sA*(PO;s6<^Gewd3@=UB>`)wz+lb0^PhuC5adF&)1?& zBw=PK7mVhb^QtkO4?hlC#QoDkOKLD22N`b~vAQ_*@w z!{CJdrf##MAl}%o@;?4`VX($C9L}gByw(6$flr}$&r)ai19tV)`hOh0{%@YQ-EXa< zOdEkXj_u;=A$5GI$MIgQPzvJ>&|)#zx~xBSY53s%mq%|JOtyZ+9y&h$sjt2jfCql^ z{|yHWzyVx`aIHe|0A5h=L*IE~?pP^>h$hc=O>Lt~re1#B+Wc{AGZD#`tnK%AMhWAo zWqVlg*p-sS+(n&J-W4n0PK~0p!e(h0q!D)=?(q6E3*3Fv0w<0vaCmKr#l;?JniA>A z2m0|#Co3o`j`+6?*V@NnGZtzKRoD!wwkRtNc!9%S1^}S0dlcm%khFa1 zH~zN^Pk;QYo>5BgD&mQdsBs~ARol*m^&yWxIc8}gaR}Ip``zkOu~S*{NOR{(&Z|!^ z@QO1l+|0^-yd#xW1r zz!(@bioEO93=27VC*j2LE-!uY0w<5g)KkO7jhb;`$mJRhHGLy@h@wtsq^obz+BF{ zTzu5H`+&DZN%XevQvQL*-~RNIqm$oN_4RJ~f$h~z6L*GXlx7OG4D?K0t4UF+?P;ZU zC#4!rOSZ=aTjS!w`lxu%q^N%RjO=`%SUzs@Vu!2W_(goj{U73M{?ZR05dQ5U(yM=%Zx`UI(&{&~R{sU~6{Y!9(n-d*ebp&-=$4x8tq#APzhO77Cyy!A2P{zs zrCzSIj)re9)LIfx|0ALzyVxuu+MZl zfEPM^=s*0Wup&~_NRYPv>U*Ey&wTl9N4Ce+pT2N)_&vY;JDTE4VzORLl4+t? z5rvhaVm3Ub`8T(cYY3kNQMb1bNF(Uwki{Udu|DSVg&nS(-{u1!y~vOK+FAOEu+;lB zF|_3XeQXa#V~kp*gFM~l5I-W?Zf4?KSL%+otXKaX9;KyZd- z$2&1EJ=*29w;$pqx2$r@P0K7Tc8HV2$6OC0*O?f1jsS_bj=i?QwMN2!s9t zojfPibt3_Yl;_rbJIn&~ctWV~q$eD=2zKb`(3X3^-J%@fkDcB=Fc!)iU=js}z#pr< z(Fa=$LDO%oO*2yw#NnMTT(C|;<~LtP?L0RE^Ag6*T~Bfj|LfUmx5jaS{d#x18-SX}NBC9#V{=tH(T zoo|a4AWkZvK{=bSMigx7S+qB|5)7L!no z(d~!0=e9$fIJU^*Vuv`H<)$al<$V@_G&IK%2WhWjgHhOAnf6c_<%vkx+Qfe^Sb?&J zafwX5eSiqd{ghj7THwUt9;_uO<<%0`0Vr<*X`GTDfbDU?GwZwZ)a7k`SH0=TT`TW>{H;%(ucyWgj`h*8Chev4S37gXJNdf5$Uphk*Yi)l{VVxr z|F1V-eZS~51Ep$|Dis)$B+WqoiEn-tKk-ekbiW6y{{y%|VDHpCfG=S9@W1~{0Q~rW zdw@5*_{i$ku=pE~oZa}gw|?;KOV$P*UVCPhSD#+x_FE2d?ARjxL5C>P)U}WD=2!9H zh`a=%@891hKH^iSCYdJhCFI?RB#VfWAU$ZU?g6w$d;%E2p=5FT;1EZ^y?FMBUkXB= zKoT`x13MdIe&wx?^V7e6mMp5NYjG-wK=}TMU{Xvuw6wyD?|2bsPM%?Pd6f%SF52}= zkIJHbBKqQ67P<4}k;Vnk>HOX17uSxsYDJXj84+!%RAwt`A0HqP)z)gexi3J&%(dRr z?w|1SIby%3|Mr|~#)sCB_;?ODX@(t_)SDA*;h44%8^T37^b!ywjitY-T*N^U&`PLm z#N}~^^=W?ga?yWl){XwdpZ=SJdqw^{@N+2jm@m&in-%Q<4&VzA4kQ2v(7@(S$>vVU zOKw?aSejv{lfH9Y)E{0>Q~9!+S9t9mhq?Q%qZ~i6%wVB|j3uI^0LeGgyazu)@_-uRwR@{aqTUi7~o%<)>n%%4B>9lrnO#6Wu?5Pxr15V@dEDv2C3BA`Wx zw9oAj+zXXLYM05c^eKsz6|%?)`!DPW4_@wZ|D{7bwzbT;-G%t#Zq|L|QkGNvIr#AR zaPKcokVhiqkpuIm12}+#S#SUi{GZ?VRV?*8Y;BC7v}(DN#-^xmzxBxAOI~^B5p~y@ zHI5!#q&LWk<7iH-?7$)WKnL1q=jniR2h>^-#hN5{Zeq@&-LFXZqZ`a#7FLA{A3bpH zy5IZ?*H(sVTv3in)-Mlv>ZvX6|I`K_J2xgzoNj%;?|r@{0>&EhG-G*bnU%$5`rSUe z!(DaZ$|c_Mv4_>W@Bb8U{mA3g26|aSFHb0ILuD*Uwo8K*b;G^#jH9UX=_=1E32H*f1_`BcrWh7C=bZd&9)^R_HZ$Ei>@S59C zuDs%oTMz4F$Ck)D30mpKoiD5e+aUg5pu^2MHKRbv8w*?JW~b4TmWKy*+Hx2IgWu*1`jt@HS!>pc48HXna_m&bQ%y74@L+zX#iCcs)t zmZmHYmRMO@VbB|}JKE*S#$|Qs($j43Y(bn-6cvwO*yLkRUgpa77^M_P7Q5tWtgLuH zI!Ck>t#;enQjUFc9pacM<#R8zMEveOv#wAYLU`e5M%dl;7Qqi9Agx^}=dj9;H7btW zmPDvXJGIfILUyLesDQHeyn>4vQ0!JrcM7J%lDf2DT~V%XPx$@EF7uWTKg@^DM$kD; zr52PW!MdoEJ4*4W(tI?F?NeDIbriv9ybEx^035&h&a(iu|`E9 z%x#-s`QH|iQMgdVZe=&QrZ*qrhh^mRr7E5>-eeJJ}rVCZVM~@V52eTIpFX0u6-_H zQ;XmyZnaP3(>()H*2t(t#uYLyQDu!5r{AxqhGJY%3@hq!jZ{wBv^y@jxH;m z$;;gLsSCXM{__;s&73%TnkddaV*|j$3Vuz&N0hSbN{Lly{`t@R{R85E00(fu02~0o zGjIHR{H^bN0}F>E25S-9m+N@>Q1+rMkAE=lq_6GdX`~}H)Au{&@4l=52HM2Z)AIHy z0isBgq?$C3U1A__KS0aata+*>PFCRsRuG?RR%(l_EW@3G%_}1=o!{Y^CpJ0z=sK64 z*_7kkLuEwEb?#{`tdbplXVmdRGZ zWV>LxTQZqcl$D{XE$7yEx&MjFy!peA^Q-TDkhg#I5(`Uf+;#J999cU-9Hk&O47uL} zeir0O&^DMnz2kkq)vC+^9KaVY954U}z~B1LHvkaD4sG@p@L1UY;L(3WXrf4wWD#k{g^LZA_(34A{EAZtL$Q{6KpD$)T(Z4B;>yJx zE}q-w!r5&uoZaHeg&lU*$BcJNrqi08iQ)WC#YfML`0x`W-t}<7h4U4cu2fvSY?|%r z)Kd8%GQov?Kcc_ixz7ez5#lH!OEZqH9btKKncY1MKomtzdZHAO*3`x_ErelNF|8Ck z6Jb(Jxw<{#?3G>eBxbpvyQFv4b(Zqok;xWIF~@cGhP_$)Bs5Y zUaYSgw*=fXm4#{Ti2lwLJ1VeKXPAj{@eQg;#n=;mGc`mgYGZly{3Z{b+u*4y+kEJe z^StZhPxJAouJXt;S0KuG(QS8d{P0PZ7Y`BX2obTslfdr)ZvkazVvPd^-~bLFz~=^& z9l#9*=YH+)0?=QGcPkl5iJi*9XQ`_yOF1zNhZURKB^R!ioZqY&*Op$U7<3d# ztce2k{2YL>hBQuD94zwcm%NhO&)m-WOV9AYryk(FAAC1Yo_m5U&A=0GtrbdyX)Vs9 zAwSB^$5(jG$&{s@LLq$Vi*Mqkw;f|;WtBYDC^JDv;>7k!yP!>tai8z2P`}`FA8azh zC9OPx_l%uZs4PNdv10OewkRm~gA}NBFNXeuvIp~pO@eyUqwrEPWWjRQuD4G^!Nz4=hGl2kzoOXeY zvtee#?Bsa!z2~0Pp{o2xRrl$0@15NN2?`Xa-+6jYcXf4lb)S3see0{QzONw5E&Oy3}E5eL$uywa^o8eoKD>BET4f zQUT3IleawZFn1ljldDTtIN=4rSuX&FWbFO@3RAor8VIEzPBooG^XDGi$0KjLm-jyM zHug?MsQxtqp}n=m`&=mJkm;Nzx7}NA1=)VT*2QtiL-#tNkUJ0hx`yH3K`s)D!!0^- z5e&1~1@g%fgOma5orGu4EOBXNlclvy9y@uFFTZ$++3_YxW=OS*DA^wjn3a z(rAR#>H$hAM|!w+8)L~*Lz-v?gOpw;W^1$0#!{El=i5B}@&+f*ZLz$SGCLk1y>s0+ zQV1ApooQbMJo2Wu^M>2+*&zVxwL17=5+QuNeBXPw){@X(U)aelj;}Z(GXCdU!!+)g5pWmYxdK3!(Urzqzde?g*uGeqT`Lw=7lO-CH zW-gEvA++{#X+7pQ|KPJc{lZJcM)9>%OJHJumXLa+K)@g#FgLx2_r2r0Ikf*)CMTwm zQeCyyJnF{&c^qg{5r2gWyW)Dk)e1KW&i~p^64eSnq|EIZSUc}yYAZ| z0Gf@aBY!D}J%29-%8PUS6D+SSF?;xKKJcC2&BJ#c<_!nNn3f${dV_}O6Ul@?S|)BFiql&L@qj(E`}ofHd>;q)9;Vr7A*FoMTKiFN{y&#rzY+iy zD(pn%1bCCfA5S?<%%G~<(!si~0J>44dpfZ5rA`Dw-cxMHrM zm6PU8%}Y_nG7b=nADNB@#FZEW`S7ij11QMf)q)Laz732&Z9GDwaH`l$Gwzv zkog2q2BYfe)?VzMd&%bCz;asW%(V@kK7O35S1%LRTSUtFYKUBo_`jztOBo-Vec zLzY?6)H%#)KaM}7zajDGX6gLX8W*>{*G*`*2V7p-;^|Y%eC6aazx=`mpSjTI;#P{W zmS!XvuS=RWNj-A;;JX9EOP5n#dL= zaK{`6W}8gaLt07@T8oS`Y%f7~V@xl`_EPAlj`)+zi-OdNf$ji$vD-G*Wvy$3sHr-$ z`zCnf{d@TKw=FQ<3~2Xrr^j8oyMIiiIvZM2Jn`jI`IHI>0yl)=hB5qSd0jeR03{XU z6XOV-@#GUdXS=HjfpiTai2QYWc`Gs=jtY%j$gVYogPVdK!2-8x7}k9L!u^0$BvRMycK=R zyD@v;h@H6=J2pojiO-(vaA!+!$An_Gp$G%l!*iq8?uB2EBztE<-h5k~cRk$X zJrB(Au7~#Wt#3KV2i|dn54_`6-u0#f+fo=?21L!2!L559zUU@08jgVuazu_XlyU^zX%lYRG z1%M;^{4*!~;WSApCDJWDk%ZAGX zuzi>VKq~(%l>36#?Bmt**jtGPVCHG$c6jZRQveiS6}7H zXU=kZS##=gkC!gAIdQH_JGvD+cR%5Q2Vw3FWK*{x_PhZxe>dsGtt8_|NG6V;Ck|mI z4j{(&K&=HbL`Z>>3S%^9PoL(wXODCF(nZ$RR~T!K`N)2``QJY$Ak9*y$7i_b_6Hbm zO)Oh$z6N{|IA4CImHEFyh22qE0B&*!HyvE4KpX~+0S#j)()$){I&zS6{Icb4)^L|I z`(qjO6WSX+HrIPBu68(cZHp(*Z19^W+pKmnE^lZ~Uelc0Fw|=y58gJxkAB|*f9o$F zKzh1+> zYTULhmSH=G&SW0GE;hFaxM2dDx!DFnN~i|}jgWdx(Fleo+x`sx*zg|x#yF=0;Yl2D zgubIETq1v@o8BiJ`AaELQZc`0fwh%YE}lP6JQ$#qA_^3dk_1vBqXwcmgPqt1vxl*> zM;MIlrCXn8(3-)tTF?qe8yQ=2m9}1EpjJtP6|!&z6ZR2NhKMwx6=5c3ShWq#w&BdC z;Zk3*AtuPi_aP?sVxn=9%n}d!V6@kemLy4NZ*GExx@e$O;QbuDm??yhfBw$uq@@r` z!1KUT{uuw;|MfqwdjAzFyap-(aFfHE?1hjVM%bg)5*Y2g{;|HoHb@_Y2I0Kn^93CF z18A+;YWG=P-eR-e=ghSZpMPbI)2n@ELQ5|LyJ4YYY1KpSJUq!G5A5T6-hGr0f7jjo z)jxkffA#zC=LbG`CyzX|k7EZX7;8pYg!4nloF9UlR%YFpxo}Yfi-bac-hPoS(2IbA zuyeB%GD~Aa*&|9~A=UH<5e23*o2e`R7|EKUd$Edl673 z%Y2xiUazsfy2h1D7fF)@i9iWS7zWg8HG&{0goaW9)(Tcv*IB%JkI!l=drJGMExq`EB`08%}=4?Gd%m`=lHpw{eSp> ze(o3e`0sy$Q?HytYeNu(q)9@r)1lkxIHBY3#TrAFWC$T?v|0o~KoBUG@1XE2aZana zApmPFTSCZ7LWmQ--6c=DFkvJcAvAaGIs%CY>)a6$rFrWSxZ|ArEhllyeAGwGB=skyd z^F4bwcFP3&W}D1TH5i+yQ>#ZPr5pzrx$NC_th=D+=V6N-QReJ8)G?(*F|MaQ+!}>& z!a?NWa2ZC#OEW{SZ$_^7jf4;aV-4E4YX~`X0u*BC36H>MvCS$E}3-+oI;uYWw zuvvbV6)IG?J}LoF0na0|)-q?UEo}Qfq5Nn?PpsD`|KWOOES)6dN-rTCSA6J=)4czI z1>Sl8e%}4yExhNAhk4(_hk4hV4)W&v_VR|KGaQ&}FvP?`LP$CP`>`PhFR)JOXCy#4-w&5aE@oh=X$Mj=t;$X`lHmSvnhbDCfK zR6R8K0>0zBe7>$G_`de&WyF$M-#Qj5pu4mxFs+wCW11#ikY$8`4^1^W*Pm#JAPRG>(bge#Y?@Z9m^eDvS_CZGKHAF#Bzh|Y8| zv|_ZgG6mj$L8-uzzX+U=0pc`aer_KN^9PVhy`rQ#p=8k8-lhr_DqJ6x0JzDKkKbEM z=oe?=4+KFVyr;j*{wkFqj3jcmxg$G7fM902$9By_jj(%(#pHxuGcLflD-yD5WCO23`b-Ehf&vefv5LBo654sRjP zw?=nf4^l#?AW#qnVByTUb)Gx1M7Ni5U|~28o#Pud9Z=v>FB{{M*tuzZqb3Wd1%@Q= zW(ABo%H=Z!@_P;=HwfRt_+LWPPXiMe?80>Ap}|C&$z!N+;- z+2brOUh_ePEWKVI{FKL`GvhGs0l2@niLohWrsjJ=5WYA$G5ylQ+`g*!U!lU+fl2_} zOQwp7j-apc>pqFF@W}g`W(SqbZY2rCiL6sPAkAR2wy0K@6i_) zf$JbYM=gL_=yKZ&7z{GL^0kZnv!8#NB-JeJ*-Zs~14MvtpS1>Uw0q8_VT`htasB`$ z^7o%*@^}AS-F&*_Q_nrd(()2nnvfX@0l0isG6orgWj&tuF4|475HGc8u z{%>A*{yDmx4*fx&&9x1zwWz@RF?hcQDP>{h0BF>jOpHw~HfqgRUOfGL`{b+7{V^YY zg$g$pcKs<=__L4G|MtJ;^uPVDF)l%iHO4AqY+$q%#!vrKfgq|$>UBlEp{UjJx&Qto z)-5~Ux+N=sQWB*c@krrJ1X^3tfhNnd`Q;>SU0|X>3Fq})`s*xPA%t?n5a~eE-AKq{ z4W;aaMG~Xo?~rwm0qvMGfzLsXFvTZ&YXJH#ozbDdtlxL z;`z)|DNnu_lVZ}2)Oa{yyqWA5*3ym>PAtXV_%dR@5x^36LE6eq`j0^ zPOb8rA3eo$&#!a$ZTU~;hR^tQ!aWOP4O%;4I*6Du1mYT9a2hCEqUst zl;3|mqgAs^H%svua$#2bTM$AJ)glhwwV%&??9=?+zx$JX;Zt8AhyuSqzqkDF!}$b+ zDrBNHjW&8QRKbZ_RPQJ+f-2&#P~pZ=34ogv#dJE?F{@ik%|Zw`FL`guw|=Ufuebdy z#hZNx&y)^w=P0gKRLIwzKq&3^OVM%n{)qY1L)YsC8Ms)Mna?g~jXO(mEm0OGr3rwg zYwSQRfbkmC0|xz!6DOB>=Gm(}cVdODZc3x!O#k_?$!;eqhE#Swup5H#vj8%!G1hvr zFIVtp@e(<@XOwUI??dc1S}$mgwdiy@JpbIY{QmF$F2DY(zsz&Tk8|&x4^peuU2Od@ zA}GA>oex5902h}H8=YZV=p0rAXdAG!p7NE)V!)za@9mN|P6#Gu#<}b0os3Piia#bN z{=B5g9UY}43__ZjSW<-w6>bdGFXkqN(FUUpad!|HZ4Ov#r+sMX z!rLq-V9O4UbMP-}Yu$9ba-D*_8FJ)sdz)E!_%VW^YuR9Uoh(V`@G&b06vj7T= zG-QbU90U@iV3255mb#pOb%oXQ>nxsMNXa91OU!YI*eelq)M5)0stQUI3I&R^BX%ZDAF# z#`t&whCyanYsZ{_WtkT~b&6Auo#Vo@S2^?iB8!(g%*_Rak@L>q-e7A>M86Ai3&@Q^ z2!S>ltuw5(BV+nGv5qFk8Jfy(j00V0{CuMrK8Nx%8MeK=-|s6* z+?rBKx0y|B6ot8EJ_?)!Cd35HIIUl;r%9kwEGXTAu8kXaZ+YrwLUYV(cv zKAhdibFEOJ!YC>MaFfD&|6{FfTEm>Rw!ZxZI@;MS6Pho!6$yn($TsF z1LtMM+Sh^CJZPk$LwN47)(akON#cxdJ7#^g%ktGWSI%#6`OF%ZPp`3beuK_hA7d@O zjXwRAE|b#ozky`-LEX7(gB=~Z# zpOS-IVg9}`vK0lP=3^_{gv728G;5N*hb8B(X-=GtS!-+7+Ln`N4d<>}jvR6>6t*lZ zwzuhe7uoG`3~#(71O#A3nx#Rv-%0l`9NakYW?@1&rdbYhAkS0fT-sumEA*IDUno;glb4_s?ZWRCjCDB;thH{~#pgIEzT@H}|IYnB z>q^{Af}!=qT5Aw&2qFHDS5BY&nf?22;mXxZ#U(3LsBmMbEC4qtatnYlHn7Ilt+mQB zG}}AuV#Wuu%#y^Wn8sIz@rioMJ-VEz%gb=*b=J3)c?xjrd71xI!7fu2a{{rJEYo8Gz;H% z-@&>$wx8Pxm3(nzpNoRmu>kmbO2Wmqu=>af(il_Eva|^Vd#3j>J~heA+&p*Qc5hy%LWK&igWbcKRroWH|LlWr z_8e($0r8NK;w~ZNM3LohTdzNVS6d5N;>`cnhYcQuB@A8MfMLYA{6wW{?7~mmvCDqD zjVpwJu%-y>3Kb5$;;nIxfl2Jhe{;3Rwe#z2EO!}nQ?g9EB!57lB(-M1*mQ&Oxh7Nd zW6U3zWY57V_8gjK{@@go`z9HiZ81IFU~Z~GoNAWV`gFPpoq;9{cI$bUZdkbgwm*U# z<+{dLCdS5@7@wd~Z;%|VC)?uOJ0>YNpzIM0oY*;~t0 zl%ec^PkyDxqo*au_BNSpy429G4JU(k6Fs}Zmi;-ltqO#dLSCGk-E%HA*~WN%JZsj+ zP(i@l^gMGjdstap8Xi=kLWLdJO|w_H36Lk7(b}Mm5!P520H}CL59{Wu)gOMvtISA{3NBY7np@t55HUPDq` zA487!7J%2ZB6!%mp2PwI!`PJK(2Q^6?zc6>P=ge!!z;edwTJax5=ZxSM+n|!t^Lof zF-L43z2drmm=!8i*p5m7+@#Q%MrWEV(^h9jYi+F2K5CzThwgZn`tkJLO#eCZIqKxc z=cJt{9kx5W+pg|cT+Z3dn{jTbM4Xw*DkKJba8|A#SVjBiZzy~ z7BDqG#{Oe79KCNZNABLkzQZ%jE{xNh8>2bhq&`+7ss%1ELXu$zDK^O*5!M4{=9(Nn zIL`Q(qP>!b#v9&*TifO&_&A#dV#IoI11Brm;XbW3 zOf@CVx)UY4n1XhJzgk{(-+xWRCpFQmwNrOR`KGV|LD^FLRc)e&#@_Y&&w(vSa1EN9>nkW!pi1 zdpiXTU-i2bmd=?DG6vm*K__8zrOVX|>zsRekqfUZv3jLV5@)C=APgn-R>b6Ni@gV@ zxb==b+z>!0raWv=?71=SW;n;tTIWO05WZKW>T%S(b_mK_;SUZt8)Ijj+NEsX@pCe>+-FAWmlVBur^MRLMRpr#oeX2 z2PoF!rAP@BEydjlP_($aYl};8r&zJ#6nA%*0B`!7bN<1bwUU*UFS+;Z*|TS^xn>3# z{RX_ug7Muc5m2yumPA6Dsq!)~j#&fEpZYy-{k%^S;x=fh87;gh&G2$by(s?J=;@F- z-HYcSnZFG9>vn+Kf2_Z{OHR^w)ZRwXX5lZ6$!Hlh3zYa&0n5Q8D@rzc2s=0{PEFs< z5^SB~Hevta%7;!7jNccA)UesIw0)|3*q7F`gWfH_NhoyDeEP%dV$?phyMvM_^D4kk zJaRb&+wT(+Xk{|VR*IHu zz7f{2DXuO3^GYF!z3-DMY--#sGfQ`7b=u~OW>o+vy_=uHgJd)hMTL5o^^4}b zjN-%}7*kTI@`WKXEMcR#KcFOxXKl~)Jw>n5@m&DV%2$~U?ogMog5Vq7 zcEq&!yXLVu5t zXolYAFkASi_Nw3e=OmfsDbkX3lbmhV<&?a_OQt7XmUt@?W4WT+DQPz9l|fT!G^{bl z?crW9z=1JYE$YYixIDU%mq}7wc2MtqaQS1 zwn)k@o@q1=yHVHczW6=n$|Nm(q(K9wPD zZ6gwtGAs=MyK4KRp*v3@YySkGl5ByLQq6Ex>-^eZ!l5!d#&@bsF9jfgHgkey;-x0uSDBNJi87 zsNR^-sEZh=ThJdlaO(Uf4%doy5u~8@Mf!CU&^D$gnibH>^I0RednD+f^(Wh+EJ(*n zu#P7zopNUaO*Cm4GJSRWEn_#438eZY&72vuDw4rXF9TiA;1H*JWi!Al(~*o|TK2+* z$UikT_MIE2Uz=wO4RX)WB49+6{gKca*~}lQjI~~Ue_Np6A2EyndKrCBZ6b*@*NWh1 zSrrz>6j^t>S<5(Lx25#*9ZFjBep_0Qjsn8?Vq$6cqS3K@q~o#N%G%oe&4FVG;R192 ziFcC9rv%E*0Tr>eCKk889aQEq>_(b|ee90R_%D?5IR$vO0F+tVe3vI?`6LRNlMtF< zdP(|gvFTG+0&aS*6ALw2)&%X_J>*`VWA10}-Z!U5;8Ut^w>iLdduCamO*ldw{1C^Y zb-+uuZ!QbQPHux?`#qa4a%a@gZ8E5gMc>@KWIsNCOoL6HaHHEnIKnO8s!z!8w7z zXaG%zJoXtU%dghUynnu<%zsvr$94~YqJrOb9JDZ*N~7!(lhOUqCOh?{sbqmQK=%|B zOAXkJs(zmBXBGvl4KJ&67yWfmMq6wqpt$TzESIDz}#T z=MjL8DAxM)`E4R}dFP$^$`vOg*e83f{g#AA)+x4SJt&sk3Jh^tPF(TaKbL%YV}%F= zQnM&cjB5sm4~7020mlO|`DhON&0R5h+svI#4!+^hNJ6<>oT~-Zy(^7%$Xi}+(`ttB z7a}~n2w={gpb7^Y$KRxY=9?mNWG5C9jgJ0_!}cXBqMp3e8_uUZJc1UuAQ#<`ap+sQ zscI)5S!32YpNsEzrFo2$T~#cbP-rGd%Q1mLik8OZ;q6b3wQ`_-`jZrSrk`~n`-3kf zPuZdSiY`tDm5d_Vt;iivs-1ISVP`=H=mW9%!e(zlpxr4Y6#?uPMKv|b#&~crIV_Hs zH5_p=L}Xw-hyIU)C~eW#`%AFiqHgc&5j&D@(RiOl&qdMV`jUZXNKzATKOi?@_EFUP z=3^C`%eJRrL`*+n%!FB)=5Nt6EG&hx*LpnXn=&(oE3cGEtZII#S}jhyc>~;DOSaH- zP#wH`O^Yj~hzPGp5hG;^<+<#)KVg36XxR^&K&{55Qb@f&4>+><9Rgslr?x-%cDzY; zQ(7{oM6 z4%G_~k)$1PH02jPr<=+?gz^OLqGlsMajn{+J_B!Gn;gOh2h%Fhq=K+T{{tCWV@jm* zV7;JtOOuwj2aqDZQkc1yjuCTp%JVRmoAZte!K#8sLW!HP&|BLwC)qcBvDx7tSK}T` zA$6ud()&Vp7L8*okVRas%3TAD5G<-yG(Wnsfa1VnHj_P@-cRkVT_4*${h@bGJ0;T$ zA+}iJWQi(X;=CNPoi5kOMvthhgax&D?u3m@&Mb+7Vd0;-41Wh48oUm>{P8XGuh_|l z7OSlt==;sF>E{b_oda1V2Ts+?&7GyUPc4R4f_YTe@CybiNBbl+n{wDZcv}&QF2u3Q zrsLc5>SC+__lYbt8ih-NB`z{jnuhiNoMFc=CmxkBODh|}$od%}_0>=({l}$xH$r50 zi8|L538AnTS+zLpb#&xC6Kg*SQB^>VHpnG$iBj(CRC;(BdyBdNxc9TzOs7@O>eDBn zj`B>H@Z&ly)x$5AEKgr7(T)C%hS;!{Xd9CyI%2rb*3C9H&N!b2armhOl6%N6DHggykTDV0T3Dqxv_puHtk`qCa7u&ib#QaL(D>l{APiBTl-z z)}Ei827H1vdndX5R!s7CriG`E)#?bf(?;XFE-@=vFtT)xTF_1F!PX0}=moOTCFQ6x4246W5G7jbJxuzbefD?p1z#Oq4^ZEABMcVnT4GeK`~UsU@`1< z9HR~*3>Z_yxPB+XPc9$1KyEx>W^g~7x+p8-h!V&F2c=UaqOUTBATXZt5q^_lGn=|W zjrU3Ww5&$Us~O+pS{jEw&cUz0)l-deZc18r#lYQ;K4bTP z($;rgpLpu7KS(@glPuzPLUs7r)I7047!BEWYj;omNGhuH*>c8Kmal~{dKv$iR&K52 zTVcZsqJ_Ju#;2UI^L^R_aw}&MoBMAPim&n`FSQSb5PO52i4k`^N#rhT+IVz%DI;&%#pErBZxcA+#q0^qx_eP9e&!VD%s{azx=l&Zd zBAF%4ORYTV8~2M!`0o7dxoGy}Np&X85H(A+)?bpe)qP(WB6byEn8lTZP@BVlA){ks zRvgbvnr2_h$C}~YHzNv@xaBbNXs$>XJHe01Yx}~O95}nfafSKYZi20=D%z*A4(DrM zQSar;KV*{snt+f8G>}x{A>Om`+&UEx_)-gxju9f znM4^BgrJ`!Xz84ezxJ`;n7w_f@6iiS_)ZPj#lJ7JDVw0WRMW^Upv9%FVK=L78=W}k zpAppNk&s6UDma^6bk$YgB=CEqy!)cr+C|{+{Jd%DBtj~@pi4zWTkFWd8lrMOEZ1ir zH%Vs&#ShKN49$)ikiRA@&#mD~$922bew4YG;ntl-AF9QJyXv~#k6=3m zQonyeew5<$vHlhwpL|!S3Ryi&#Onj;xqNV>T{v1+K4R8(^y*fytll3!+X6Sl-qH9q z?FnnoBn$gI5s{N0&|3~uA5R{*?Kv-8dKw@|!a|fW1z0m*nF0#JCo?QxFobk#l-iXf zbHce%q`a)+d$&q;tgujb9;r%@Xs8um&S$zr@Vt2y38togo9)!TxpAL*a&&_!?)iw< z1_@ctQKrBjaNdTiImT`WW0dtWrj8n~BL1=8&T~UlM`vzqrvr|a^pTAaLHIMo{|8=g z^qjONH|_DvG+-F8Yz4xuMg3S<7_RhWff!Lj;{Jd!&5C5byaXF><2r^&4&CjH{!{T? z>V&{toSX~!?rS{juz}we!?QttIYj{4Fx=n%e!+q-(O%jZIk6L0qH_Pd`&26B6>~Js`kOPm7HLJF~h=lq!jG+f_Q|=1)1#FU4#Xw{S>h zxJE9OBS?e>Lt2XHEy!ffx>B=r+7i}RJ!4!(CPH=ppjw-t(lGMYEAr~<1N4|u@nyct zcGOUa5Q-u&5P)WxhM}9pSzt-=D!;>VYrYpI-7%C{N~*J>^V$+2v;WEP44&D@lY$Bu zPnJ|rPcTHe0s-A>!Z?2CQKmB3>;Q*?*`ryfe#uNS3$w8UK*=<{bV{_cs03AE7Vq~A z&)G_+*T_<%4KKUXXv>-crJ9h`CPwlbNM;tWEI45v_q|r$Telx1uIFA_Bx6jWl3q6s zM^>_+)F<1lm^WPCKM$cuSx_K$a(D`N$ZDw7^Qn$WRz6rs1jRK9dJMt=;03^SPOBpnZkEJw zVj$Wm{0K5YSGV=FvJKBHOmgQ|dh%$~drxpn>Ef$)H^)oy;l<6do*iaxk^mZ~gPJ&X zNmGHOM-kYD-67A?O#>p)F-n@<-d*Vf|KNLcQ(42!mik2rAjn|^K?LeLbb!S}44S~~hZ8vI zB2j-%WkL-&RG*`sP;OjPHz@_dM9Ph8NDV^}w{p9W5eUKiC@PPgHoptT=sY#%!h)IY zD%iEQ$qWCusjuoRUKvbMVa|L%1S``{U_k#b61;;>5f)JT|zoa54 z5b$I1vWJ?v_cdVgDgfB}cLgL!YzMs2wW}Q8v(1GmFHr;$TvbVzYa@oyxs^HY3>70v zULuyX-fk5;u_kD}#U`Wql|jT?W6Qpghu!U8$`y$4jmC2StFib8DsSEe@x8EQK zNbv}YCVn-UcgR?_EcY4sN>`B3F0Y-XDgm~L8VfX8Vt3hinmMF5qxpmePL4NE|CEl%f5C7;(dh#iv=@Thp$4hpkl-gUI3%-=5Ol7;~_5RHj2JJ2(S{SOXhp z^%j21Ebnmb2kg26=|Km@cb1avW2-sk-W!%a5{w_q+RL*tl&;W4FcCKS8#n;kCgA+xRe+pF~r5tJO}W=LuS5)msl zZ)UZdFW02zqzY1oN2+;SEdFFfD8}r8%Vs)s8#$oBnFpnt+Ijn`tOZVRS9jZ-;}`C(U%3_B5sdz6^@^T zTfa`c;1dlCu|9*vo#E+lKFJOs_&&>*y--8rry|1#LaSQo39k=IW|Qm;wYH%&_@tTt zWW$P!h{v$KZ)3fXX9;n8fL1nWZ#pUY`vhRswzwito}K)%JKXY@Jk4Z5JxxyuHE2r6 ztiY1aelt=|6hpF>Jq&wMxEc&Wr%+M7=8X=DJ|I?>&Y{=V;jDD_SR2MxZF5enr0Dq7 zPubR2%Op}(&u>z`ShL1?q4%pJ9cfPZPc_b4*9X@f{carpI3xsyYEf*VYhbvBP^!tF zg7OrX6n8BGO|))s1@iDu$SOjO77`S1Sri0F36x%zOHhK6A`L$C54;d*8wfQXhC|U#_%KDO6W^Y*3vvkJ@%2-ox4MIQf zZ0=m|M6bN=*szl#DrWnYM~J-kC*j2Fs)sp9=A4Pi7h1D+vpT;$A0zr&iKVa(tUy!v z2?(Z$*LWSLu`lj~V`Z6inSOO<3cL|=xn?jgGXKx~MC2e;1{?lo;rJ~;;pJqqMqLoF z796T;L^ByoKd2Cw!0vSCa?$(W^n;oEUV?T_^u0{2&R)QDt$FELjpRn12 zRDBLnHMVZpC?4d&fZT$Y8ozZ5ryzw>VxchlNWp@HZ$3B;F-2Gi1px;U{QLB$@;+Ev zjo$?jxCT|}&%AHXYM4>6v`KIRURZi)zE84rE*eig@Y$%H`_U;}%)$^eG1l_Y1Mh)= zgiN~Y{T5gf|C2>9{fI(bgpi^l2H7|1-$pS&e2q9Ev(n_M*1tQ$>x`-$&A+&yXDF&- z4WmkFJdz}TB3#XT*g~0^c3;vEn|TajFSza9F3I{WfRc!M3tvIpt)V2A+9XJ&87@W=_08Ki0;2ofyr2ni*+lrm1&y29(pZSPbz4GlQwgr1{+Ibr` z-M9&!CYQrjuogK20p9XcsctfIAPiZUpB_gZ1pmh@U3Z$(IZF7rEqvN+gN;CHjVi_~ ze+O-q^AicO9{Kv5F7?EmE=|o;7=be7B$ajxR&jE}?bKPg_w}9&9wkWSGrMQD@f$uP z^=*^M9h;%q3k+h(BuBdNJOf`P2Ew)+>ny4)JB8JXVk>`0NB;tqCyv{qCni_hJ#Dt{ zAs?E=^`nB9E6rJ^Sw3z4Vw6E|r~OXF%^QmO!A#!s6U#4hb5Y}YnZ&^)p=*EQuAsQb zzDh?#-Pknc4Y;Nnp*n!S@ijViz;j}gVM*Wnrb-EiXK_2U)jQH`&Wew@VDym8j#F$w zafx%m_DUVWzPDg|w$q%1^-PVQH)JMJWF}x5`;F?~q5xLXH_W)G0SW{doN-1e@`PHW zm&cy2cmhns8%0IJ3$-Va%^$c)Og_QgGs)@%Kt~esQ-9v`&Um46R^BwWE^l=!g)oiU z*0iS8Kxt^z?y6*#FDTNILSzMrm^{R>AsplRE1XL8M`Jh!)mH~H8n2ruj{^ffIV-UL zIdbvX={Z@gFmZD{pHh^#N>pw6)3IE;EKa;40mZvfXLTYyw=&i#zBC-)CnrH-a2#z2 zevUk3%ct;a3bhNg^ZgWUA^WY|S4sqK5PdF3m{U+Zue+4e-Rr&-ugG!C zGBXko=BvKBW|+V!W|PCS8iB__CwIYV31Hy$L>X)~e_{*GsBCE0qE4Dzrif!6G%*}w zo<=`?86Pp?+g*6Y8J%sgqf9zqMad^>Xu=*h$2@6^_#X6n#6%D?5a-{w>R+J zkZN1%)PlqHMKsk*C)>g*lKCaPmHX=(`?1$I_6VswhH-gou>AmAMKWhFwF&*^V5U1_ zGc48NYG|rEZWxls$LCs^WDdjUK$fHXety*0j&!=i73HwvVa^^_T|iO*bY)M_W#0Op za2^13Gyph^7#m_h5O4-;T$w9dqUpS|4c}_b;td*Wj^J+CbmRxGt=~=OatM@gRsAUl z5o2`XAQcdSOw^SCCJ0BTYk2qJ^)h(iyvKzv61lDJ%5^wS+>7wYtjj$Xs+%l5Y>T4t#r)A0E5K4PWbfyNw_4a6bw%Ib{_XY|};uk0ja?+N{*2Pe+Kf!IT zhB_4u;XrqBogI5xUXw6bp&c5=Wx>>u!u-mQ=~vHQZQ30vmhrDj%VF9k29B&wxMW^EUxOCajo$CXZQj9 zrsLMFkIT?Nm>WdzHTfoeh*#Vuf~7P3na=-?_#h94vY-z zw9LH6yNY*~m@FzP(5a2V)exsF)@2)Y<`}_sDB5F6v(2dftExNyUATj1^&BSg1vS>x zkv)f?nZ;aq`o*B3`-D?KK6UHFQ>?GO18%QF#bRxSWcGr-mP`b_5Ub7ROi+M(8-RtN zQXrUp==`bH#Hzm2iyyd41N`!PeJtT>_1t2HhWMO>dfBTGX$jMTh;> z8CM~PCAAVK&0mT(rn}dW87DF}yUmazF@f8gc45zZZgMQddhy;0#}B^t0^Qi$NPMR3 z<^{m=WKomUZL~p%cfr^3yYABIovGdw3&wjW}mTdXczS;RMT&C89 z{oM?Y$Oe9v(BPOa{EUCqa@7sY(w@VS90{|bX5-XEumUP^79a?;`xBKQEz%;Wok8)9 z8i7?;KcPn#2&2$XIfOr*IcY-O&wqPW+Vnzmvs3X+`|w`c zcx6tN2=QUq@KeVGg1>t*2Vpbt5^12lj4fvABeYc+?VRkxBX4?dj9EZ$V8#(|dz^no5IX z;*X1jsy_S5+3;}1Bws;pLY7p9`Afgk7RqLW$2&LgaGjJa0J%C4sScARdDiQC3dZrc zuaP_=T{Q2&=&AU2MRhU)SWlotz`DkZY#h>d8!#RsSi5lR({v*_h14>2kv&@51r-Gs z^i{hyW?>y?+MFik^DR0VeV5_mNN}X((E9!d-IBLW=&y*!+WfxZ!`+GjGNWGZ{43LK zr}=p(rkJqjGy)}FWLByy$0mMqznzf0S4X0}`|+I2^_WjZ7ey#&z%>avivI(W$3YoN zyuyP%8a}%L&PGiF`KT)Rr=ml^hfZs#Xc|Ce8siLQKQvmZ7H~jJmZmrwAe_(JD{f4& zgB?X|4X0neT|!vWh7e5#Wem!?6$O>Jws9hKm!Py;A`+NAA=Wu?n)&>~C@{vgmEX3A zk@0Br7Hy;4L0m$Ba_rp*{bc-P`eZyG>Es)atyDr)4&SxX?C0xbl@52wDy%@M3mNX-=Q zw870|j^Uiownuh7^(9rox2C&C29G89OztZG_5uA;EwYrOeCSpQGACrd|j_-DGpIyOy6G za!oa#mYsSM#ozx9h(>6cv`iP|?M8ur-R^k3^Y~sE;gyc!B;>D-rlHpwm`JXoO{3|T z#BqIw0_#c@u-j!m=#MRByS*NEZV<2P?i;4O)!U$Q&v4Ij?SiIA zZ&pZQg6g=w>E=)#_q!hIcX`wiR_bkrm9s5Zo^1xO;xS2 zkJqy*MTQa%oFXn}!X<)za-|R^K%Us(s2(UVT3-E8mg6Uf=+65hf2^F(@_=fB{%`vC-B|yXuyO03f)oZI0SLyTDIn^0Q*nyG zeW638GINh6P_a{y@Ip%ph$ax@pQxe3QuskB)wA68;41isoQq~SEuma&RQEujbO|c4 zxzg`(70y8(DNCc3!LXhs!-)nhbIyI-9mm$3yn_@^izWg*~S2&0ec@D(EK8 z{^3O5^-tkZSbLmu`J3qQ|8fHPYvpCgQT-|z49?I;#%|S3J%wI~Nz~l-}h_9*T z)jsrVgzjlTxfC_^#mEyT^vtKNVbOy=(|Vd5#tkU6_Xk1_D!_%i3}H|6L!_$S_qRX# zileec=9FthPC=)d%j))44-N=roeNV!(z-1&PA5iMX^HmhtlUxF)gaQm$mZYz^!fAT zFa%knaM1js4;7|KB>=y}rb$ClCj#3^0DpIAydD2a3 zBpq$CfL&x8FB(e3UKzt@Oy0@;|pg=w!52>HQ3Ozug` zh?M5kv&1978i`;2)D}4nz(a#(0uC(#<}m_uff_V18q8!tv1$+`G-;#!67yGA!Io3x zMblr>s%KItsnY)tZp54C@!R&LnKVNx5A?K#0;u1i{@`UXV=Yh!1cm{5Nq{&s#w=!K z1>e6>hxSkp@54N6?0oG!H)Fr;sXiY;e{~Z7I3naet10ufne67{(xCY#2=Mh;UzxPkjaL^}R(xOaft%iL zk&YosoiTR394qc>lKr8$-d|7P{^8{_LXn>N&I1AoXi`P|O03=7o3}WsaJ17}NZl3u z4hNbq)$D;h@1_0(JMngUMx2I`+&fE{ow?Xo*<2-9ICc|xATUs=X7SiHOTx$FPE)mm z!W*9YvEQHZ)N*y!KN^*7A^Klg3osF>sRCmHr8oQb zf~0=8Xv-#vUG`P&FQ|Fe=l^q(gJ@D4SE=th$i(l}Hpkt2);NaVJ zXbawO@5+7W>m~g5v#4$Vzk~O-UEaS>N2AHvj*jQ;eC}@NI^dU+8xY{vRYbqahlgD| z$$A9I46pKUdI@6ff+W(wQ#$BINPYZsX6G}ycgM;xs^{3|+$W-vHvc$2C2W@PszJ!2 zJFS++%OGTp&}D5&h&Mbj{LBt|6|{?Radn^1!}x;ke8>ZthCAaKoA5WU%=H(MP)>TP zi?xzEOn&dUmPt~mtQHQjttCT*#IMN>Jq7M3!fFLnTu9J=%Sxnb<$Ma1PhGLgncMHb z+8HxUZ?CFJeFz4u1dIB2pnAKv?EZUF;B<68ILM9?Y(#a63J%SV)tHg`QeMkJ?Y>d{ zXaYU@X17(Lf4#YBfsU}gF32%bukT-P9=*cJE8f^9yU)3Fmi>Y8UYP$oVlWgMk6kX{o*$W_|NhdUf^M zc2^sbA1f;=p0`P(Z=QSmDa&6=I(Z!Th9lTWO%?fuWOtyul;=;ECc8V2bC0v(Kp|}J z@a%~}PE7$p|6lkx0M|6~!)cfR)2N}k1<7ph-(HuC#U`tvk24F(ibaCeyRKYGs@YB5 z`CM7ah`G_d_Jw?Nk?=DvXmQ4$ddE zh@2iZ3WO^Ue^E}~@#8{Py*=uAa#|Wg5;ENX0Tl=M>H9tSJ^1MQj$Cx&bhh3I?5OcZD)7$&i?8Waf1ubvTjB7&)J1H;R{#Q%wR>gm*MR)YjhkrTuZj!>cwa~J z_^5cT_&;_&JmR9F!rSB4KbCC~E)!Myg@pToRYFsaPUwhdEMbf(85y6wt-tG;WUzlR zHqAtc??)I*5fh>|;BU|66fU6&VO^TZ)PYM4d!gX&_LxaD6eGLx|8gJ*dE(W%rFjX? zbgvzC&+pP{dz()}pwMOXCx7AOkP+!O zL)|5HSxdu4u1*@*Do~g`HnC3R8X1z;xE-L!k~5)D(_rn|>i1|2{A5EnC{x z(V&N7GxtL^iq~+ib@}!!>W=fXo!`@uZlhk)`WR^vn6kN^bu%+Jt3h5EB)X>h>|2hV zazxyHf2c0!5LBf6HkCLM&+UW;Te0olfvag5g!Bl0QX%e=74KH!+Z|sqhyn|lRn(+) z9iS(aIwCXx$dUXaTsaUFDQOZSZrKPJ;}?OxF9K<@pI;Pe#ezEZ!V##M z^4z{{b#whYJ0Xgf4;H87%N@BJ*wgMLKyXkd0);5KL6>CoJ~iw;%@%QY%g zi;~L!WhSA`RkNb~KBZKIR708TN*%Kq`(-yp9f#r%k|+JmT=$Q6JkJo%76#-hR6&KO zg){L^LsZIB2f{j1(k@O1)OVI7T^Ogtk_T%hzS~{djpzm7pyxkoh#WBSle4tD<}I>O zmp;bVtjn}zC&_E&^~`x~@jWij^M|5K=Vvsu&bo#`cK40|@lLwV^v4SplWBZ6v4dpN zHaSy|^bM1L_u>D@0RoT|=R8NDHXK8j+UG!mCRDXO=h9rx#5SPXov(!-K+r5D+o2Qb zkA|1Rn26Gm(^vnyI`yZ>q}d_!M<^HLlO1mcW&t^hT1#t785PQ(rwem;MnvF&@D&g` g`Ty<9lT7b3e%|uafCAvK5()8Alv9zd02>ATKcSEo(EtDd literal 0 HcmV?d00001 diff --git a/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json b/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json index 4916b5d3b..aef8a3993 100644 --- a/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json +++ b/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json @@ -13,5 +13,7 @@ "explore": "Explore", "category-menu-title": "Categories", "all-categories": "All", - "picture-galleries-title": "How We Made the Graphics" + "picture-galleries-title": "How We Made the Graphics", + "no-animations-title": "No Results Found", + "no-animations-text": "Please check your spelling or try a new search." } diff --git a/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json b/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json index 5af3c38c9..a3dc69922 100644 --- a/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json +++ b/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json @@ -13,5 +13,7 @@ "explore": "Tutustu", "category-menu-title": "Kategoriat", "all-categories": "Kaikki", - "picture-galleries-title": "Näin teimme grafiikan" + "picture-galleries-title": "Näin teimme grafiikan", + "no-animations-title": "Ei hakutuloksia", + "no-animations-text": "Tarkista kirjoititko oikein tai kokeile uutta hakua." } diff --git a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx index 6b5d7541b..6bc1ba561 100644 --- a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx +++ b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx @@ -2,7 +2,7 @@ import cls from './TabNavigation.module.scss'; import useSizes from '@/shared/lib/hooks/useSizes'; interface TabNavigationProps { - tabs: string[]; + tabs: { id: string; label: string }[]; tabsTitle: string; activeTab: string; onTabClick: (tab: string) => void; @@ -20,8 +20,8 @@ export const TabNavigation = ({ }: TabNavigationProps) => { const { isMobileSize } = useSizes(); - const handleTabClick = (tab: string) => { - onTabClick(tab); + const handleTabClick = (tabId: string) => { + onTabClick(tabId); }; return ( @@ -30,16 +30,16 @@ export const TabNavigation = ({

diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx index f0792f1b2..646decc93 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx @@ -1,11 +1,10 @@ 'use client'; -import { useInView } from 'react-intersection-observer'; -import { classNames } from '@/shared/lib/classNames/classNames'; -import { Button, ButtonTheme } from '@/shared/ui/Button'; import cls from './SectionGallery2.module.scss'; import Image from 'next/image'; import { SocialMediaIcons } from '@/shared/ui/SocialMediaIcons'; import { PhotoObject } from '@/entities/Gallery'; +import miellyttaja from '@/shared/assets/images/heros/people-pleaser/miellyttaja.png'; +import { useClientTranslation } from '@/shared/i18n'; interface AnimationGalleryProps { animations: PhotoObject[]; @@ -13,15 +12,28 @@ interface AnimationGalleryProps { } export const AnimationGallerySection = ({ animations, backgroundColor }: AnimationGalleryProps) => { - const { inView } = useInView({ - rootMargin: '-150px 0px', - triggerOnce: true, - }); - - const mods = { - [cls.inView]: inView, - }; - + const { t } = useClientTranslation('picture-galleries'); + if (!animations || animations.length === 0) { + return ( +
+
+
+ {t('no-animations-title')} +
+

{t('no-animations-title')}

+

{t('no-animations-text')}

+
+
+ ); + } return (
{set.title}

{set.author}

-
- -
+ {set.links && ( +
+ +
+ )}

{set.description}

@@ -66,6 +80,7 @@ export const AnimationGallerySection = ({ animations, backgroundColor }: Animati src={set.animation ? set.animation[0] : ''} alt="Animation" fill + sizes="(max-width: 768px) 100vw, 50vw" className={cls.animationImage} />
diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss index b3a377c76..69c9bd7a3 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss @@ -3,7 +3,10 @@ flex-direction: column; gap: 2rem; padding: 2rem; - + box-shadow: 0.3rem 0.3rem black; + border: 2px solid black; + border-radius: 10px; + background-color: var(--base-card-background); } .block { @@ -14,7 +17,6 @@ box-shadow: 0.3rem 0.3rem black; border: 2px solid black; border-radius: 10px; - margin-bottom: 20px; padding: 20px; } @@ -33,13 +35,18 @@ } .author { - font: var(--font-sw-m); + font: var(--font-sw-l); +} + +.socialsContainer { + display: flex; + margin-top: 0.5rem; } .description { font: var(--font-dm-m); - color: #faf9f6c0; - margin-top: 1rem; + color: #faf9f6; + margin: 0.5rem 0; } .framesContainer { @@ -64,10 +71,10 @@ position: relative; border-radius: 8px; overflow: hidden; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); flex: 1 1 0; aspect-ratio: 16 / 9; - width: 300px; + width: 374px; + height: 246px; min-height: 180px; } @@ -83,11 +90,11 @@ border-radius: 8px; position: relative; overflow: hidden; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); aspect-ratio: 16 / 9; - width: 500px; - height: 300px; + width: 720px; + height: 472px; display: flex; + max-width: 100%; justify-content: center; align-items: center; flex: 1 1 0; @@ -101,6 +108,47 @@ object-position: center; } +.noAnimationsFoundContainer { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2rem; + background-color:var(--base-card-background); + box-shadow: 0.3rem 0.3rem black; + border: 2px solid black; + border-radius: 10px; +} + +.noAnimationImageContainer { + position: relative; + width: 160px; + height: 160px; + margin-bottom: 1rem; +} + +.noAnimationsImage { + width: 160px; + height: 160px; + object-fit: contain; + margin-bottom: 1rem; +} + +.noAnimationsTitle { + font: var(--font-sw-l); + font-weight: bold; + margin-bottom: 0.5rem; + font: var(--font-sw-l); + color: #faf9f6; +} + +.noAnimationsText { + font: var(--font-dm-m); + color: #faf9f6; + text-align: center; +} + @media (max-width: breakpoint(md)) { .framesContainer { width: 100%; @@ -131,6 +179,10 @@ height: 100%; } + .animationContainer { + width: 100%; + } + .buttonWrapper { width: 100%; flex: 0 0 auto; From 6633a92238e5a15e5d48ae524fdd0e358ba98829 Mon Sep 17 00:00:00 2001 From: eleino Date: Thu, 16 Jul 2026 13:46:04 +0300 Subject: [PATCH 8/9] added dropdown filters for Gallery --- .../ui/FilterDropdowns/AuthorsDropdown.tsx | 60 +++++++++ .../FilterDropdowns.module.scss | 123 ++++++++++++++++++ .../ui/FilterDropdowns/FilterDropdowns.tsx | 73 +++++++++++ .../ui/FilterDropdowns/SortByDropdown.tsx | 57 ++++++++ .../ui/NavigateGalleryTabs.tsx | 4 +- .../ui/PictureGalleryPage.tsx | 30 ++++- 6 files changed, 341 insertions(+), 6 deletions(-) create mode 100644 frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/AuthorsDropdown.tsx create mode 100644 frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.module.scss create mode 100644 frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.tsx create mode 100644 frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/SortByDropdown.tsx diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/AuthorsDropdown.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/AuthorsDropdown.tsx new file mode 100644 index 000000000..4c97416c1 --- /dev/null +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/AuthorsDropdown.tsx @@ -0,0 +1,60 @@ +import cls from './FilterDropdowns.module.scss'; +import useSizes from '@/shared/lib/hooks/useSizes'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; + +export const AuthorsDropdown = ({ + selectedAuthors, + setSelectedAuthors, + authorsList, + authorsOpen, + setAuthorsOpen, + dropdownsOpen, +}: { + selectedAuthors: string[]; + setSelectedAuthors: (authors: string[]) => void; + authorsList: string[]; + authorsOpen: boolean; + setAuthorsOpen: (open: boolean) => void; + dropdownsOpen: boolean; +}) => { + const { isMobileSize } = useSizes(); + + return ( +
+
+ + {authorsOpen && (!isMobileSize || dropdownsOpen) && ( +
    + {authorsList.map((author) => ( +
  • + { + if (selectedAuthors.includes(author)) { + setSelectedAuthors( + selectedAuthors.filter((a) => a !== author), + ); + } else { + setSelectedAuthors([...selectedAuthors, author]); + } + }} + /> + +
  • + ))} +
+ )} +
+
+ ); +}; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.module.scss b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.module.scss new file mode 100644 index 000000000..aaa5c4475 --- /dev/null +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.module.scss @@ -0,0 +1,123 @@ +.dropdownContainer { + display: flex; + gap: 0.25rem; + justify-content: flex-end; + width: 100%; + @media (max-width: breakpoint(md)) { + background-color: var(--base-card-background); + flex-direction: column; + align-items: center; + justify-content: center; + box-shadow: 0.3rem 0.3rem black; + border: 2px solid black; + border-radius: var(--border-radius-figma); + gap: 0; + } + + label { + padding-left: 0.5rem; + font: var(--font-dm-m); + } +} + +.dropdownTitleContainer { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + // .dropdownTitle { + // font: var(--font-dm-m); + // } +} + +.divider { + @media (max-width: breakpoint(md)) { + background-color: var(--primary-color); + height: 1px; + width: 100%; + } +} + +.sortByDropdown { + width: 200px; + display: flex; + flex-direction: column; + @media (max-width: breakpoint(md)) { + width: 100%; + justify-content: center; + align-items: center; + } +} +.sortByDropdownContent { + width: 100%; + display: flex; + flex-direction: column; + align-items: flex-start; + @media (min-width: breakpoint(md)) { + background-color: var(--base-card-background); + box-shadow: 0.3rem 0.3rem black; + border: 2px solid black; + border-radius: var(--border-radius-figma); + } +} + +.sortByOptions { + list-style: none; + accent-color: var(--primary-color); + padding: 0 1rem 0.5rem; +} + +.dropdownTitle { + font: var(--font-dm-m); + color: var(--primary-color); + background-color: var(--base-card-background); + padding: 0.5rem 1rem; + cursor: pointer; + border: none; + display: flex; + justify-content: space-between; + align-items: center; + border-radius: var(--border-radius-figma); + width: 100%; + @media (max-width: breakpoint(md)) { + width: 100%; + border: none; + font: var(--font-sw-m) + } +} + + +.authorsDropdown { + width: 300px; + display: flex; + flex-direction: column; + @media (min-width: breakpoint(md)) { + } + @media (max-width: breakpoint(md)) { + width: 100%; + justify-content: center; + align-items: center; + } +} +.authorsDropdownContent { + width: 100%; + display: flex; + flex-direction: column; + @media (min-width: breakpoint(md)) { + background-color: var(--base-card-background); + box-shadow: 0.3rem 0.3rem black; + border: 2px solid black; + border-radius: var(--border-radius-figma); + } +} + +.authorsOptions { + list-style: none; + accent-color: var(--primary-color); + padding: 0 1rem 0.5rem; +} + +.hidden { + display: none; +} diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.tsx new file mode 100644 index 000000000..2daf3db82 --- /dev/null +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.tsx @@ -0,0 +1,73 @@ +import { PhotoObject } from '@/entities/Gallery'; +import cls from './FilterDropdowns.module.scss'; +import { useState } from 'react'; +import useSizes from '@/shared/lib/hooks/useSizes'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; +import { SortByDropdown } from './SortByDropdown'; +import { AuthorsDropdown } from './AuthorsDropdown'; + +interface FilterDropdownsProps { + selectedAuthors: string[]; + setSelectedAuthors: (authors: string[]) => void; + sortBy: 'date_asc' | 'date_desc' | 'title'; + setSortBy: (sortBy: 'date_asc' | 'date_desc' | 'title') => void; + photoObjects: PhotoObject[]; +} + +export const FilterDropdowns = ({ + selectedAuthors, + setSelectedAuthors, + sortBy, + setSortBy, + photoObjects, +}: FilterDropdownsProps) => { + const [dropdownsOpen, setDropdownsOpen] = useState(false); + const [sortByOpen, setSortByOpen] = useState(false); + const [authorsOpen, setAuthorsOpen] = useState(false); + + const { isMobileSize } = useSizes(); + + const authorsList = [...photoObjects] + .map((photoObject) => photoObject.author) + .filter((author): author is string => !!author) + .filter((author, index, self) => self.indexOf(author) === index) // remove duplicates + .sort(); + + return ( +
+ {isMobileSize && ( +
+ +
+ )} +
+ + +
+ ); +}; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/SortByDropdown.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/SortByDropdown.tsx new file mode 100644 index 000000000..b3f98626e --- /dev/null +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/SortByDropdown.tsx @@ -0,0 +1,57 @@ +import useSizes from '@/shared/lib/hooks/useSizes'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; +import cls from './FilterDropdowns.module.scss'; + +export const SortByDropdown = ({ + sortBy, + setSortBy, + sortByOpen, + setSortByOpen, + dropdownsOpen, +}: { + sortBy: 'date_asc' | 'date_desc' | 'title'; + setSortBy: (value: 'date_asc' | 'date_desc' | 'title') => void; + sortByOpen: boolean; + setSortByOpen: (open: boolean) => void; + dropdownsOpen: boolean; +}) => { + const { isMobileSize } = useSizes(); + + const sortByOptions = [ + { value: 'date_asc', label: 'Date (oldest first)' }, + { value: 'date_desc', label: 'Date (newest first)' }, + { value: 'title', label: 'Title' }, + ] as const; + + return ( +
+
+ + {sortByOpen && (!isMobileSize || dropdownsOpen) && ( +
    + {sortByOptions.map((option) => ( +
  • + setSortBy(option.value)} + /> + +
  • + ))} +
+ )} +
+
+ ); +}; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx index 86683771c..6e946c09b 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx @@ -56,7 +56,9 @@ export const NavigateGalleryTabs = ({ }; const tabs = categories.map((category) => ({ id: category.id, - label: (category.name || category.id).charAt(0).toUpperCase(), + label: + (category.name || category.id).charAt(0).toUpperCase() + + (category.name || category.id).slice(1), })); return ( diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx index 3c3480d28..e7874a4bb 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx @@ -15,6 +15,7 @@ import { useParams } from 'next/navigation'; import { useFilterPhotoObjects } from '../model/useFilterPhotoObjects'; import { NavigateGalleryTabs } from './NavigateGalleryTabs'; // import { useGetDirectusGalleryImages, getLanguageCode, getCategoryTranslation, } from '@/entities/Gallery'; +import { FilterDropdowns } from './FilterDropdowns/FilterDropdowns'; export interface Props { title: string; @@ -103,17 +104,36 @@ const PictureGalleryPage = () => { alternate={true} searchVisible={false} /> - + {isBigDevice && ( + + )}

{t('picture-galleries')}

{t('info-text')}

+ {!isBigDevice && ( + + )} + +
+ +
Date: Fri, 17 Jul 2026 14:35:20 +0300 Subject: [PATCH 9/9] cleaning up unused gallery items, added designer box, small fixes --- frontend-next-migration/package.json | 1 + .../picture-galleries/[category]/_getPage.ts | 57 ------- .../picture-galleries/[category]/page.tsx | 6 - .../(helper)/picture-galleries/_getPage.ts | 3 +- .../src/app/_styles/variables/global.scss | 1 + .../api/filterAndTransformImages.test.ts | 118 -------------- .../Gallery/api/filterAndTransformImages.ts | 51 ------- .../src/entities/Gallery/api/galleryApi.ts | 2 + .../src/entities/Gallery/api/mappers.ts | 15 +- .../api/useGetDirectusGalleryImages.test.ts | 133 ++++++++-------- .../api/useGetDirectusGalleryImages.ts | 4 +- .../src/entities/Gallery/index.ts | 4 - .../entities/Gallery/model/mockImages.test.ts | 61 -------- .../src/entities/Gallery/model/mockImages.ts | 111 -------------- .../ui/ImageWall/ImageWall.module.scss | 20 --- .../ui/ImageWall/ImageWall.stories.tsx | 26 ---- .../Gallery/ui/ImageWall/ImageWall.tsx | 50 ------ .../src/features/NavigateGalleries/index.ts | 2 - .../ui/GalleryNavMenuAsDropdown.tsx | 106 ------------- .../ui/GalleryNavMenuAsSidebar.module.scss | 47 ------ .../ui/GalleryNavMenuAsSidebar.tsx | 134 ---------------- .../PictureGalleryPages/index.ts | 6 +- .../model/useFilterPhotoObjects.ts | 20 +++ .../ui/FilterDropdowns/AuthorsDropdown.tsx | 48 +++--- .../FilterDropdowns.module.scss | 70 +++++++-- .../ui/FilterDropdowns/FilterDropdowns.tsx | 22 ++- .../ui/FilterDropdowns/SortByDropdown.tsx | 10 +- .../ui/NavigateGalleryTabs.tsx | 11 +- .../ui/PictureGalleryPage.async.tsx | 3 +- .../ui/PictureGalleryPage.module.scss | 21 +-- .../ui/PictureGalleryPage.tsx | 34 ++--- .../src/shared/appLinks/RoutePaths.ts | 3 - .../i18n/locales/en/picture-galleries.json | 14 +- .../i18n/locales/fi/picture-galleries.json | 14 +- .../ui/TabNavigation.module.scss | 28 ++-- .../ui/TabNavigation/ui/TabNavigation.tsx | 9 ++ .../src/widgets/SectionGallery/index.ts | 2 +- .../ui/SectionGalleryV2/SectionGallery.tsx | 14 +- .../SectionGallery2.module.scss | 144 +++++++++++------- frontend-next-migration/tsconfig.json | 1 - 40 files changed, 384 insertions(+), 1042 deletions(-) delete mode 100644 frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/[category]/_getPage.ts delete mode 100644 frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/[category]/page.tsx delete mode 100644 frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.test.ts delete mode 100644 frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.ts delete mode 100644 frontend-next-migration/src/entities/Gallery/model/mockImages.test.ts delete mode 100644 frontend-next-migration/src/entities/Gallery/model/mockImages.ts delete mode 100644 frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.module.scss delete mode 100644 frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.stories.tsx delete mode 100644 frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.tsx delete mode 100644 frontend-next-migration/src/features/NavigateGalleries/index.ts delete mode 100644 frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsDropdown.tsx delete mode 100644 frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.module.scss delete mode 100644 frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.tsx diff --git a/frontend-next-migration/package.json b/frontend-next-migration/package.json index 2fb40b27b..c38c6e772 100644 --- a/frontend-next-migration/package.json +++ b/frontend-next-migration/package.json @@ -9,6 +9,7 @@ "dev": "next dev -p 5173", "build": "next build --no-lint", "start": "next start", + "start-dev": "next start -p 5173", "test": "jest", "test:ci": "jest --ci --config=jest.ci-config.ts", "test:ci-retry-failed": "jest --ci --onlyFailures --config=jest.ci-config.ts", diff --git a/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/[category]/_getPage.ts b/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/[category]/_getPage.ts deleted file mode 100644 index 129c0989a..000000000 --- a/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/[category]/_getPage.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { createPage } from '@/app/_helpers'; -import { PictureGalleryPageProps } from '@/preparedPages/PictureGalleryPages'; -import { getServerTranslation } from '@/shared/i18n'; -import { AppExternalLinks } from '@/shared/appLinks/appExternalLinks'; -import { getRouteGalleryCategoryPage } from '@/shared/appLinks/RoutePaths'; -import { baseUrl, defaultOpenGraph } from '@/shared/seoConstants'; - -const toAbsolute = (src?: string | null) => - !src ? null : /^https?:\/\//i.test(src) ? src : `${baseUrl}${src}`; - -export async function _getPage(lng: string, category: string) { - const { t } = await getServerTranslation(lng, 'picture-galleries'); - - const name = t(`categories.${category}.name`, category); - const desc = t(`categories.${category}.description`, t('head-description')); - - // Routes & SEO - const relPath = getRouteGalleryCategoryPage(encodeURIComponent(category)); - const path = `/${lng}${relPath}`; - const title = `${name} — ${t('picture-galleries')}`; - const keywords = `${t('head-keywords')}, ${name}`; - - // OG image: default only (no category-specific image exists) - const defaultOg = defaultOpenGraph.images?.[0]?.url ?? null; - const ogUrl = toAbsolute(defaultOg); - const ogImages = ogUrl - ? [{ url: ogUrl, alt: `${name} — ${t('picture-galleries')}` }] - : (defaultOpenGraph.images ?? []); - - return createPage({ - buildPage: () => ({ - title, - infoText: t('info-text'), - socialsText: t('socials-text'), - socialMediaLinks: [ - AppExternalLinks.igPost1, - AppExternalLinks.igPost2, - AppExternalLinks.fbPost1, - ], - videoLink: AppExternalLinks.previewVideoYoutube, - }), - buildSeo: () => ({ - title, - description: desc, - keywords, - openGraph: { - ...defaultOpenGraph, - type: 'website', - title, - description: desc, - url: path, - images: ogImages, - }, - alternates: { canonical: path }, - }), - }); -} diff --git a/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/[category]/page.tsx b/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/[category]/page.tsx deleted file mode 100644 index e95bf93ce..000000000 --- a/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/[category]/page.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { PictureGalleryPage } from '@/preparedPages/PictureGalleryPages'; -import { withMetadataGenerator, withPageData } from '@/app/_helpers'; -import { _getPage } from './_getPage'; - -export const generateMetadata = withMetadataGenerator(_getPage); -export default withPageData(PictureGalleryPage, _getPage); diff --git a/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/_getPage.ts b/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/_getPage.ts index b084dd8a6..9c4b00410 100644 --- a/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/_getPage.ts +++ b/frontend-next-migration/src/app/[lng]/(helper)/picture-galleries/_getPage.ts @@ -1,5 +1,4 @@ import { createPage } from '@/app/_helpers'; -import { PictureGalleryPageProps } from '@/preparedPages/PictureGalleryPages'; import { getServerTranslation } from '@/shared/i18n'; import { AppExternalLinks } from '@/shared/appLinks/appExternalLinks'; import { getRouteGalleryPage } from '@/shared/appLinks/RoutePaths'; @@ -7,7 +6,7 @@ import { defaultOpenGraph } from '@/shared/seoConstants'; export async function _getPage(lng: string) { const { t } = await getServerTranslation(lng, 'picture-galleries'); - return createPage({ + return createPage({ buildPage: () => ({ title: t('picture-galleries'), infoText: t('info-text'), diff --git a/frontend-next-migration/src/app/_styles/variables/global.scss b/frontend-next-migration/src/app/_styles/variables/global.scss index 66b396a2a..1a152ab0f 100644 --- a/frontend-next-migration/src/app/_styles/variables/global.scss +++ b/frontend-next-migration/src/app/_styles/variables/global.scss @@ -167,6 +167,7 @@ --content-primary: #FFA100; --base-card-background: #1E3544; --drop-shadows: #121212; + --white-text: #faf9f6; // border-radius diff --git a/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.test.ts b/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.test.ts deleted file mode 100644 index f4a89c2ed..000000000 --- a/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { filterAndTransformImages } from '../api/filterAndTransformImages'; - -describe('filterAndTransformImages', () => { - const mockPhotoObjects = [ - { - id: '56789', - category: { - id: '1', - translations: [ - { - id: 'category-56789', - language: 'en', - name: 'Category 1', - languages_code: 'en-US', - category_id: '1', - }, - ], - }, - versions: { - preview: { - id: '56789', - image: 'https://upload.wikimedia.org/wikipedia/commons/e/e0/PlaceholderLC.png', - width: 350, - height: 350, - altText: 'preview picture 1', - }, - full: { - id: '56789', - image: 'https://upload.wikimedia.org/wikipedia/commons/e/e0/PlaceholderLC.png', - width: 200, - height: 200, - altText: 'full picture 1', - }, - }, - }, - { - id: '12345', - category: { - id: '1', - translations: [ - { - id: 'category-12345', - language: 'en', - name: 'Category 1', - languages_code: 'en-US', - category_id: '1', - }, - ], - }, - versions: { - preview: { - id: '12345', - image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTOwRConBYl2t6L8QMOAQqa5FDmPB_bg7EnGA&s', - width: 350, - height: 350, - altText: 'preview picture 2', - }, - full: { - id: '12345', - image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTOwRConBYl2t6L8QMOAQqa5FDmPB_bg7EnGA&s', - width: 200, - height: 200, - altText: 'full picture 2', - }, - }, - }, - ]; - - it('should transform and return full version objects correctly', () => { - const result = filterAndTransformImages(mockPhotoObjects, 'full'); - expect(result).toEqual([ - { - id: '56789', - image: 'https://upload.wikimedia.org/wikipedia/commons/e/e0/PlaceholderLC.png', - width: 200, - height: 200, - altText: 'full picture 1', - }, - { - id: '12345', - image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTOwRConBYl2t6L8QMOAQqa5FDmPB_bg7EnGA&s', - width: 200, - height: 200, - altText: 'full picture 2', - }, - ]); - }); - - it('should transform and return preview objects correctly', () => { - const result = filterAndTransformImages(mockPhotoObjects, 'preview'); - expect(result).toEqual([ - { - id: '56789', - image: 'https://upload.wikimedia.org/wikipedia/commons/e/e0/PlaceholderLC.png', - width: 350, - height: 350, - altText: 'preview picture 1', - }, - { - id: '12345', - image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTOwRConBYl2t6L8QMOAQqa5FDmPB_bg7EnGA&s', - width: 350, - height: 350, - altText: 'preview picture 2', - }, - ]); - }); - - it('should return an empty array for an empty input array', () => { - const result = filterAndTransformImages([], 'full'); - expect(result).toEqual([]); - }); - - it('should return an empty array for an invalid version type', () => { - const result = filterAndTransformImages(mockPhotoObjects, 'thumbnail'); - expect(result).toEqual([]); - }); -}); diff --git a/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.ts b/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.ts deleted file mode 100644 index ab6587b7b..000000000 --- a/frontend-next-migration/src/entities/Gallery/api/filterAndTransformImages.ts +++ /dev/null @@ -1,51 +0,0 @@ -// import { PhotoObject, PhotoVersion } from '../types/gallery'; - -// /** -// * Filters and transforms photo objects into an array of photo versions based on the specified version type. -// * -// * This function processes a list of photo objects and extracts either the "full" or "preview" versions, -// * transforming them into a standardized array of photo version objects. If an error occurs, it logs the error -// * and returns an empty array. -// * -// * @param {PhotoObject[]} photoObjects - Array of photo objects to filter and transform. -// * Each photo object contains metadata and version details. -// * @param {string} version - The version type to extract, either `"full"` or `"preview"`. -// * -// * @returns {PhotoVersion[]} An array of photo versions filtered and transformed based on the specified type. -// * If an error occurs, the function logs it to the console and returns an empty array. -// */ - -// export const filterAndTransformImages = ( -// photoObjects: PhotoObject[], -// version: string, -// ): PhotoVersion[] => { -// try { -// // Only allow the two supported versions -// if (version !== 'full' && version !== 'preview') { -// return []; -// } - -// // Filter out entries with missing versions or missing selected version -// const valid = photoObjects.filter((po) => { -// const v = po.versions; -// return !!(v && v[version]); -// }); - -// const images: PhotoVersion[] = valid.map((po) => { -// const v = po.versions![version]!; // safe due to filtering above -// return { -// id: v.id, -// image: v.image, -// width: v.width, -// height: v.height, -// altText: v.altText || '', -// }; -// }); - -// return images; -// } catch (error) { -// console.error('Error transforming and filtering images: ', error); -// const images: PhotoVersion[] = []; -// return images; -// } -// }; diff --git a/frontend-next-migration/src/entities/Gallery/api/galleryApi.ts b/frontend-next-migration/src/entities/Gallery/api/galleryApi.ts index 5d31bd39d..c6945d28c 100644 --- a/frontend-next-migration/src/entities/Gallery/api/galleryApi.ts +++ b/frontend-next-migration/src/entities/Gallery/api/galleryApi.ts @@ -9,6 +9,8 @@ const client = createDirectus(directusBaseUrl).with(rest()); /** * API service for fetching gallery data from a Directus backend. + * Defined an endpoint for fetching photo objects from the Directus `photo_object_v2` collection. + * @returns DirectusPhotoObjectV2[] - An array of photo objects with their associated data. */ const galleryApi = directusApi.injectEndpoints({ endpoints: (builder) => ({ diff --git a/frontend-next-migration/src/entities/Gallery/api/mappers.ts b/frontend-next-migration/src/entities/Gallery/api/mappers.ts index 3d95ef5b0..c2e1c7d1b 100644 --- a/frontend-next-migration/src/entities/Gallery/api/mappers.ts +++ b/frontend-next-migration/src/entities/Gallery/api/mappers.ts @@ -2,7 +2,14 @@ import { envHelper } from '@/shared/const/envHelper'; import { DirectusPhotoObjectV2, PhotoObject, PhotoObjectLink } from '../types/gallery'; import { getPhotoObjectTexts, getTranslation } from './translations'; -// for mapping DirectusPhotoObjectV2 to PhotoObjectV2 +/** + * Maps an array of DirectusPhotoObjectV2 to an array of PhotoObject. + * Maps the fields and translations, assigns urls to images, sanitizes links, + * and generates an url-safe anchor id from the author's name. + * @param directusPhotoObject - The array of DirectusPhotoObjectV2 to map. + * @param lng - The language code for translations. + * @returns An array of PhotoObject. + */ export const mapDirectusToPhotoObjectV2 = ( directusPhotoObject: DirectusPhotoObjectV2[], lng: string, @@ -33,10 +40,10 @@ export const mapDirectusToPhotoObjectV2 = ( const { title, description } = getPhotoObjectTexts(translations ? translations : [], lng); const mappedLinks = [ { name: 'website', url: sanitizeLink(website) }, - { name: 'github', url: sanitizeLink(github) }, + { name: 'facebook', url: sanitizeLink(facebook) }, { name: 'linkedin', url: sanitizeLink(linkedin) }, { name: 'instagram', url: sanitizeLink(instagram) }, - { name: 'facebook', url: sanitizeLink(facebook) }, + { name: 'github', url: sanitizeLink(github) }, ].filter((link) => link.url !== undefined) as PhotoObjectLink[]; const mappedFrames = mapFrames(image, image_2, image_3); @@ -72,7 +79,7 @@ const mapFrames = ( const imageWidth = 800; const imageQuality = 80; - // insert image url and image id into frames + // insert image url and image id into frames, id can be used for fetching original image for example if (image) { frames.push([ `${directusBaseUrl}/assets/${image}?format=auto&width=${imageWidth}&quality=${imageQuality}`, diff --git a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.test.ts b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.test.ts index ae6931f6a..35418d165 100644 --- a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.test.ts +++ b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.test.ts @@ -1,12 +1,11 @@ import { renderHook } from '@testing-library/react'; -import { useGetPhotoObjectsQuery, useGetPhotoVersionsQuery } from '../api/galleryApi'; +import { useGetPhotoObjectsV2Query } from '../api/galleryApi'; import { useGetGalleryCategoriesQuery } from '../api/galleryCategoriesApi'; -import { getPhotoVersionTranslation, getCategoryTranslation } from '../api/translations'; import { useGetDirectusGalleryImages } from '../api/useGetDirectusGalleryImages'; +import { getPhotoObjectTexts, getTranslation } from '../api/translations'; jest.mock('../api/galleryApi', () => ({ - useGetPhotoObjectsQuery: jest.fn(), - useGetPhotoVersionsQuery: jest.fn(), + useGetPhotoObjectsV2Query: jest.fn(), })); jest.mock('../api/galleryCategoriesApi', () => ({ @@ -14,8 +13,7 @@ jest.mock('../api/galleryCategoriesApi', () => ({ })); jest.mock('../api/translations', () => ({ - getPhotoVersionTranslation: jest.fn(), - getCategoryTranslation: jest.fn(), + getTranslation: jest.fn(), getPhotoObjectTexts: jest.fn(() => ({ title: '', author: '', description: '' })), })); @@ -33,12 +31,7 @@ describe('useGetDirectusGalleryImages', () => { }); it('returns empty arrays when no data is available', () => { - (useGetPhotoObjectsQuery as jest.Mock).mockReturnValue({ - data: null, - isLoading: false, - error: null, - }); - (useGetPhotoVersionsQuery as jest.Mock).mockReturnValue({ + (useGetPhotoObjectsV2Query as jest.Mock).mockReturnValue({ data: null, isLoading: false, error: null, @@ -52,7 +45,6 @@ describe('useGetDirectusGalleryImages', () => { const { result } = renderHook(() => useGetDirectusGalleryImages(mockLanguage)); expect(result.current.photoObjects).toEqual([]); - expect(result.current.photoVersions).toEqual([]); expect(result.current.categories).toEqual([]); expect(result.current.isLoading).toBe(false); expect(result.current.error).toBeNull(); @@ -60,98 +52,98 @@ describe('useGetDirectusGalleryImages', () => { it('transforms data correctly', () => { const mockCategories = [ - { id: '1', translations: [{ language: 'en', name: 'Category 1' }] }, - ]; - const mockPhotoVersions = [ { id: '1', - image: 'image1.jpg', - width: 100, - height: 100, - translations: [{ language: 'en', altText: 'Alt 1' }], + translations: [ + { id: '1', languages_code: 'en', category_id: '1', name: 'Category 1' }, + ], }, ]; const mockPhotoObjects = [ { id: '1', - category: { id: '1', translations: [{ language: 'en', name: 'Category 1' }] }, - preview: { - id: '2', - image: 'preview1.jpg', - width: 50, - height: 50, - translations: [], + category: { + id: '1', + translations: [ + { id: '1', languages_code: 'en', category_id: '1', name: 'Category 1' }, + ], }, - full: { id: '3', image: 'full1.jpg', width: 100, height: 100, translations: [] }, + translations: [ + { + id: '1', + languages_code: 'en', + photo_object_id: '1', + title: 'Title 1', + description: 'Description 1', + }, + ], + author: 'Author 1', + website: 'https://example.com', + github: null, + linkedin: null, + instagram: null, + facebook: null, + image: 'image1id', + image_2: 'image2id', + image_3: null, + animation: null, + date_created: '2024-01-01T00:00:00Z', }, ]; - (useGetPhotoObjectsQuery as jest.Mock).mockReturnValue({ + (useGetPhotoObjectsV2Query as jest.Mock).mockReturnValue({ data: mockPhotoObjects, isLoading: false, error: null, }); - (useGetPhotoVersionsQuery as jest.Mock).mockReturnValue({ - data: mockPhotoVersions, - isLoading: false, - error: null, - }); (useGetGalleryCategoriesQuery as jest.Mock).mockReturnValue({ data: mockCategories, isLoading: false, error: null, }); - (getPhotoVersionTranslation as jest.Mock).mockImplementation( - (translations) => translations[0]?.altText || '', - ); - (getCategoryTranslation as jest.Mock).mockImplementation( + (getTranslation as jest.Mock).mockImplementation( (translations) => translations[0]?.name || '', ); + (getPhotoObjectTexts as jest.Mock).mockImplementation((translations) => ({ + title: translations[0]?.title || '', + description: translations[0]?.description || '', + })); const { result } = renderHook(() => useGetDirectusGalleryImages(mockLanguage)); - expect(result.current.categories).toEqual([ - { id: '1', translations: [{ language: 'en', name: 'Category 1' }] }, - ]); - expect(result.current.photoVersions).toEqual([ - { id: '1', image: 'image1.jpg', width: 100, height: 100, altText: 'Alt 1' }, - ]); + expect(result.current.categories).toEqual([{ id: '1', name: 'Category 1' }]); expect(result.current.photoObjects).toEqual([ { id: '1', - category: { id: '1', translations: [{ language: 'en', name: 'Category 1' }] }, - versions: { - preview: { - id: '2', - image: 'https://strapi.altzone.fi/assets/preview1.jpg', - width: 50, - height: 50, - altText: '', - }, - full: { - id: '3', - image: 'https://strapi.altzone.fi/assets/full1.jpg', - width: 100, - height: 100, - altText: '', - }, - }, + category: { id: '1', name: 'Category 1' }, + title: 'Title 1', + description: 'Description 1', + author: 'Author 1', + anchorId: 'author-1', + links: [{ name: 'website', url: 'https://example.com/' }], + frames: [ + [ + `https://strapi.altzone.fi/assets/image1id?format=auto&width=800&quality=80`, + 'image1id', + ], + [ + `https://strapi.altzone.fi/assets/image2id?format=auto&width=800&quality=80`, + 'image2id', + ], + ], + animation: undefined, + date_created: '2024-01-01T00:00:00Z', }, ]); }); it('handles loading states', () => { - (useGetPhotoObjectsQuery as jest.Mock).mockReturnValue({ + (useGetPhotoObjectsV2Query as jest.Mock).mockReturnValue({ data: null, isLoading: true, error: null, }); - (useGetPhotoVersionsQuery as jest.Mock).mockReturnValue({ - data: null, - isLoading: false, - error: null, - }); (useGetGalleryCategoriesQuery as jest.Mock).mockReturnValue({ data: null, isLoading: false, @@ -165,16 +157,11 @@ describe('useGetDirectusGalleryImages', () => { it('handles errors', () => { const mockError = new Error('Test Error'); - (useGetPhotoObjectsQuery as jest.Mock).mockReturnValue({ + (useGetPhotoObjectsV2Query as jest.Mock).mockReturnValue({ data: null, isLoading: false, error: mockError, }); - (useGetPhotoVersionsQuery as jest.Mock).mockReturnValue({ - data: null, - isLoading: false, - error: null, - }); (useGetGalleryCategoriesQuery as jest.Mock).mockReturnValue({ data: null, isLoading: false, diff --git a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.ts b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.ts index a6aeb1028..1816e48de 100644 --- a/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.ts +++ b/frontend-next-migration/src/entities/Gallery/api/useGetDirectusGalleryImages.ts @@ -1,7 +1,7 @@ import { useGetPhotoObjectsV2Query } from './galleryApi'; import { useGetGalleryCategoriesQuery } from './galleryCategoriesApi'; import { mapDirectusToPhotoObjectV2 } from './mappers'; -import { PhotoObjectV2, PhotoCategory } from '../types/gallery'; +import { PhotoObject, PhotoCategory } from '../types/gallery'; import { useMemo } from 'react'; import { getTranslation } from './translations'; @@ -20,7 +20,7 @@ export const useGetDirectusGalleryImages = (lng: string) => { })); }, [cData, lng]); - const photoObjects: PhotoObjectV2[] = useMemo(() => { + const photoObjects: PhotoObject[] = useMemo(() => { if (!poData) return []; return mapDirectusToPhotoObjectV2(poData, lng); }, [poData, lng]); diff --git a/frontend-next-migration/src/entities/Gallery/index.ts b/frontend-next-migration/src/entities/Gallery/index.ts index fc88dd33c..88aabe5d2 100644 --- a/frontend-next-migration/src/entities/Gallery/index.ts +++ b/frontend-next-migration/src/entities/Gallery/index.ts @@ -10,11 +10,7 @@ export type { export type { ParentDirectory } from './model/galleryApi'; export { useGalleryCategories } from './model/useGalleryCategories'; -export { mockImagesFull, mockImagesPreview } from './model/mockImages'; - -export type { GalleryCategoriesWithModalSliderProps } from './ui/GalleryCategoriesWithModalSlider'; export { GalleryCategoriesWithModalSlider } from './ui/GalleryCategoriesWithModalSlider'; -// export { ImageWall } from './ui/ImageWall/ImageWall'; export { useGetStrapiGalleryImages } from './api/useGetStrapiGalleryImages'; export { useGetDirectusGalleryImages } from './api/useGetDirectusGalleryImages'; export { useGetGalleryCategoriesQuery } from './api/galleryCategoriesApi'; diff --git a/frontend-next-migration/src/entities/Gallery/model/mockImages.test.ts b/frontend-next-migration/src/entities/Gallery/model/mockImages.test.ts deleted file mode 100644 index c1f44267e..000000000 --- a/frontend-next-migration/src/entities/Gallery/model/mockImages.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { generateMockImages, baseImage1, baseImage2 } from '../model/mockImages'; - -describe('Base Mock Images', () => { - it('should have correct properties for baseImage1', () => { - expect(baseImage1).toHaveProperty('id', '56789'); - expect(baseImage1.category).toEqual({ - id: '56789', - translations: [ - { - id: 'category-56789', - language: 'en', - name: 'All', - languages_code: 'en-US', - category_id: '56789', - }, - ], - }); - expect(baseImage1.versions.preview).toHaveProperty('altText', 'preview picture'); - expect(baseImage1.versions.full).toHaveProperty('altText', 'full picture'); - }); - - it('should have correct properties for baseImage2', () => { - expect(baseImage2).toHaveProperty('id', '12345'); - expect(baseImage2.category).toEqual({ - id: '12345', - translations: [ - { - id: 'category-12345', - language: 'en', - name: 'All', - languages_code: 'en-US', - category_id: '12345', - }, - ], - }); - expect(baseImage2.versions.preview).toHaveProperty('altText', 'preview picture'); - expect(baseImage2.versions.full).toHaveProperty('altText', 'full picture'); - }); -}); - -describe('generateMockImages', () => { - it('should generate the correct number of mock images', () => { - const result = generateMockImages(baseImage1, baseImage2, 6); - expect(result).toHaveLength(6); - }); - - it('should generate unique IDs for each mock image', () => { - const result = generateMockImages(baseImage1, baseImage2, 4); - const ids = result.map((img) => img.id); - const uniqueIds = new Set(ids); - expect(uniqueIds.size).toBe(4); - }); - - it('should alternate between baseImage1 and baseImage2', () => { - const result = generateMockImages(baseImage1, baseImage2, 4); - expect(result[0].id.startsWith(baseImage1.id)).toBe(true); - expect(result[1].id.startsWith(baseImage2.id)).toBe(true); - expect(result[2].id.startsWith(baseImage1.id)).toBe(true); - expect(result[3].id.startsWith(baseImage2.id)).toBe(true); - }); -}); diff --git a/frontend-next-migration/src/entities/Gallery/model/mockImages.ts b/frontend-next-migration/src/entities/Gallery/model/mockImages.ts deleted file mode 100644 index f136820f3..000000000 --- a/frontend-next-migration/src/entities/Gallery/model/mockImages.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { PhotoObject } from '@/entities/Gallery/types/gallery'; - -/** - * Base mock photo objects for Storybook usage. - * - * Represents a photo object with predefined category, versions, and localized alt texts. - * There are two different templates for generating mock photo objects. - */ - -export const baseImage1 = { - id: '56789', - category: { - id: '56789', - translations: [ - { - id: 'category-56789', - language: 'en', - name: 'All', - languages_code: 'en-US', - category_id: '56789', - }, - ], - }, - versions: { - preview: { - id: '56789', - image: 'https://upload.wikimedia.org/wikipedia/commons/e/e0/PlaceholderLC.png', - width: 275, - height: 275, - altText: 'preview picture', - }, - full: { - id: '56789', - image: 'https://upload.wikimedia.org/wikipedia/commons/e/e0/PlaceholderLC.png', - width: 275, - height: 275, - altText: 'full picture', - }, - }, -}; - -export const baseImage2 = { - id: '12345', - category: { - id: '12345', - translations: [ - { - id: 'category-12345', - language: 'en', - name: 'All', - languages_code: 'en-US', - category_id: '12345', - }, - ], - }, - versions: { - preview: { - id: '12345', - image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTOwRConBYl2t6L8QMOAQqa5FDmPB_bg7EnGA&s', - width: 275, - height: 275, - altText: 'preview picture', - }, - full: { - id: '12345', - image: 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTOwRConBYl2t6L8QMOAQqa5FDmPB_bg7EnGA&s', - width: 275, - height: 275, - altText: 'full picture', - }, - }, -}; - -/** - * Generates an array of mock photo objects by duplicating and modifying two base images. - * - * The generated array alternates between `baseImage1` and `baseImage2` with unique IDs - * for each photo object and its respective versions. The number of mock objects generated is fixed at 12. - * - * @param {PhotoObject} baseImage1 - The first base image template to duplicate and modify. - * @param {PhotoObject} baseImage2 - The second base image template to duplicate and modify. - * @returns {PhotoObject[]} An array of 12 mock photo objects, alternating between the two base templates. - */ - -export const generateMockImages = ( - baseImage1: PhotoObject, - baseImage2: PhotoObject, - length: number, -): PhotoObject[] => { - const mockImages = Array.from({ length: length }, (_, i) => { - const baseImage = i % 2 === 0 ? baseImage1 : baseImage2; - return { - ...baseImage, - id: `${baseImage.id}-${i + 1}`, - versions: { - preview: { - ...baseImage.versions!.preview, - id: `${baseImage.versions!.preview.id}-${i + 1}`, - }, - full: { - ...baseImage.versions!.full, - id: `${baseImage.versions!.full.id}-${i + 1}`, - }, - }, - }; - }); - return mockImages; -}; - -export const mockImagesFull = generateMockImages(baseImage1, baseImage2, 12); -export const mockImagesPreview = generateMockImages(baseImage1, baseImage2, 4); diff --git a/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.module.scss b/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.module.scss deleted file mode 100644 index ce3bb8e0f..000000000 --- a/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.module.scss +++ /dev/null @@ -1,20 +0,0 @@ -.Item { - cursor: pointer; - width: 100%; - height: auto; - position: relative; - border-radius: var(--border-radius-custom); - background-color: var(--transparent-bg-dark); - overflow: hidden; - pointer-events: all; -} - -.Image { - width: 100%; - height: auto; - object-fit: cover; - &:hover, - &:active { - transform: scale(1.1); - } -} diff --git a/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.stories.tsx b/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.stories.tsx deleted file mode 100644 index 91b0725d9..000000000 --- a/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.stories.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { StoryObj } from '@storybook/nextjs'; -import { ImageWall } from './ImageWall'; -import { mockImagesFull, mockImagesPreview } from '../../model/mockImages'; - -const meta = { - title: 'entities/Gallery/ImageWall', - component: ImageWall, -}; - -export default meta; - -type Story = StoryObj; - -export const Full: Story = { - args: { - images: mockImagesFull, - version: 'full', - }, -}; - -export const Preview: Story = { - args: { - images: mockImagesPreview, - version: 'preview', - }, -}; diff --git a/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.tsx b/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.tsx deleted file mode 100644 index 6e6f2c192..000000000 --- a/frontend-next-migration/src/entities/Gallery/ui/ImageWall/ImageWall.tsx +++ /dev/null @@ -1,50 +0,0 @@ -// 'use client'; -// import cls from './ImageWall.module.scss'; -// import Image from 'next/image'; -// // import { PhotoObject, PhotoVersion } from '../../types/gallery'; -// // import { filterAndTransformImages } from '../../api/filterAndTransformImages'; -// import Fancybox from '@/shared/ui/Fancybox/Fancybox'; -// import { Border } from '../Border/Border'; -// import { MasonryWrapper } from '@/shared/ui/MasonryWrapper'; -// import { AppLink } from '@/shared/ui/AppLink/AppLink'; -// import { useEffect, useState } from 'react'; - -// export type ImageWallProps = { -// images: PhotoObject[]; -// version: string; -// }; - -// export const ImageWall = ({ images, version }: ImageWallProps) => { -// const [filteredImages, setFilteredImages] = useState([]); - -// useEffect(() => { -// const filteredImages = filterAndTransformImages(images, version); -// if (filteredImages) setFilteredImages(filteredImages); -// }, [images]); - -// return ( -// -// -// {filteredImages.map((image, index) => ( -// -//
-// -// {image.altText} -// -//
-//
-// ))} -//
-//
-// ); -// }; diff --git a/frontend-next-migration/src/features/NavigateGalleries/index.ts b/frontend-next-migration/src/features/NavigateGalleries/index.ts deleted file mode 100644 index 0976d5395..000000000 --- a/frontend-next-migration/src/features/NavigateGalleries/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as GalleryNavMenuAsDropdown } from './ui/GalleryNavMenuAsDropdown'; -export { default as GalleryNavMenuAsSidebar } from './ui/GalleryNavMenuAsSidebar'; diff --git a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsDropdown.tsx b/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsDropdown.tsx deleted file mode 100644 index 117cef62a..000000000 --- a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsDropdown.tsx +++ /dev/null @@ -1,106 +0,0 @@ -'use client'; -import { useParams, useRouter } from 'next/navigation'; -import { - NavMenuWithDropdowns, - NavMenuWithDropdownsProps, - DropDownElementASTextOrLink, -} from '@/shared/ui/NavMenuWithDropdownsV2'; -import { getRouteGalleryCategoryPage } from '@/shared/appLinks/RoutePaths'; -import { getLanguageCode, useGetDirectusGalleryImages } from '@/entities/Gallery'; -import { useEffect, useState } from 'react'; -import useSizes from '@/shared/lib/hooks/useSizes'; -import { useClientTranslation } from '@/shared/i18n'; - -interface GalleryNavMenuProps { - openByDefault?: boolean; - className?: string; -} - -const GalleryNavMenuAsDropdown = (props: GalleryNavMenuProps) => { - const { openByDefault = false, className } = props; - const { isMobileSize, isTabletSize } = useSizes(); - const isTouchDevice = isMobileSize || isTabletSize; - const params = useParams(); - const router = useRouter(); - const lng = params.lng as string; - const currentCategory = params.category as string; - const language = getLanguageCode(lng); - const { categories } = useGetDirectusGalleryImages(language); - const allCategory = lng === 'en' ? 'all' : 'kaikki'; - const [selectedCategory, setSelectedCategory] = useState(currentCategory || allCategory); - const { t } = useClientTranslation('picture-galleries'); - - useEffect(() => { - if (currentCategory) setSelectedCategory(currentCategory); - }, [currentCategory]); - - useEffect(() => { - if (categories) { - const matchingCategory = categories.find((cat) => cat.name === currentCategory); - - if (matchingCategory) { - const translatedName = matchingCategory.name; - - if (translatedName && translatedName !== currentCategory) { - const newPath = getRouteGalleryCategoryPage(translatedName); - router.replace(newPath); - setSelectedCategory(translatedName); - } else { - setSelectedCategory(currentCategory); - } - } else { - setSelectedCategory(allCategory); - } - } - }, [categories, lng, currentCategory]); - - const dropdownItems: DropDownElementASTextOrLink[] = [ - { - link: { - isExternal: false, - path: getRouteGalleryCategoryPage(allCategory), - }, - elementText: allCategory.charAt(0).toUpperCase() + allCategory.slice(1), - active: selectedCategory === allCategory, - }, - ...categories.map((category) => { - const translatedName = category.name || ''; - return { - link: { - isExternal: false, - path: getRouteGalleryCategoryPage(translatedName), - }, - elementText: - translatedName.charAt(0).toUpperCase() + - translatedName.slice(1).replace('-', ' '), - active: translatedName === selectedCategory, - }; - }), - ]; - - const navMenuWithDropdownsMobileProps: NavMenuWithDropdownsProps = { - title: t('category-menu-title'), - openByDefault: openByDefault, - dropdownItems: dropdownItems, - }; - - const navMenuWithDropdownsDesktopProps: NavMenuWithDropdownsProps = { - title: t('category-menu-title'), - openByDefault: openByDefault, - staticDropdown: true, - dropdownItems: dropdownItems, - }; - - return ( -
- - -
- ); -}; - -export default GalleryNavMenuAsDropdown; diff --git a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.module.scss b/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.module.scss deleted file mode 100644 index b53e2ec6f..000000000 --- a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.module.scss +++ /dev/null @@ -1,47 +0,0 @@ -.Arrow { - display: inline-block; - position: absolute; - top: 45%; - color: var(--secondary-color); - font: var(--font-dm-l); - right: .3em; - cursor: pointer; -} - -.Box { - width: 100%; - position: relative; - background: black; - border-radius: 10px; - transition: width 0.3s ease-in-out, opacity 0.3s ease-out; - - &.Hidden { - width: 0; - } -} - -.Category { - padding-left: 1em; - width: fit-content; - cursor: pointer; - - &:hover { - color: var(--secondary-color) - } -} - -.Text { - padding: 1em 0.5em; - font: var(--font-dm-l); - overflow: hidden; - transition: opacity 0.3s ease-in-out; - - h2 { - margin-bottom: 10px; - text-align: center; - } - - &.Hidden { - opacity: 0; - } -} diff --git a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.tsx b/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.tsx deleted file mode 100644 index 3a423b0ff..000000000 --- a/frontend-next-migration/src/features/NavigateGalleries/ui/GalleryNavMenuAsSidebar.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { useParams, useRouter } from 'next/navigation'; -import { getRouteGalleryCategoryPage } from '@/shared/appLinks/RoutePaths'; -import { getLanguageCode, useGetDirectusGalleryImages, PhotoCategory } from '@/entities/Gallery'; -import { useEffect, useState } from 'react'; -import { useClientTranslation } from '@/shared/i18n'; -import cls from './GalleryNavMenuAsSidebar.module.scss'; -import { classNames, Mods } from '@/shared/lib/classNames/classNames'; - -export interface SidebarProps { - sidebarVisible: boolean; - setSidebarVisible: (visible: boolean) => void; -} - -const GalleryNavMenuAsSidebar = (props: SidebarProps) => { - const params = useParams(); - const router = useRouter(); - const lng = params.lng as string; - const currentCategory = params.category as string; - const language = getLanguageCode(lng); - const { categories } = useGetDirectusGalleryImages(language); - const allCategory = lng === 'en' ? 'all' : 'kaikki'; - const [selectedCategory, setSelectedCategory] = useState(currentCategory || allCategory); - const { t } = useClientTranslation('picture-galleries'); - const { sidebarVisible, setSidebarVisible } = props; - - useEffect(() => { - const category = findCorrectCategory(categories); - - if (!category) { - setSelectedCategory(allCategory); - } else { - setSelectedCategory(currentCategory); - } - }, [categories, currentCategory]); - - useEffect(() => { - const category = findCorrectCategory(categories); - - if (category) { - const translatedName = category.name; - - if (translatedName && translatedName !== currentCategory) { - handleRouteChange(translatedName); - } - } else { - setSelectedCategory(allCategory); - } - }, [categories, lng]); - - const findCorrectCategory = (categories: PhotoCategory[]) => { - if (!categories) return null; - const category = categories.find((cat) => cat.name === currentCategory); - return category ? category : null; - }; - - const handleRouteChange = (category: string) => { - const newPath = getRouteGalleryCategoryPage(category); - router.replace(newPath); - setSelectedCategory(category); - }; - - const mods: Mods = { - [cls.Hidden]: !sidebarVisible, - }; - - const getCategory = (category: PhotoCategory, index: number) => { - if (category && sidebarVisible) { - return ( -
handleRouteChange(category.name ? category.name : allCategory)} - className={cls.Category} - style={ - selectedCategory === category.name - ? { color: 'var(--secondary-color)' } - : {} - } - > - {category.name - ? category.name.charAt(0).toUpperCase() + - category.name.slice(1).replace('-', ' ') - : ''} -
- ); - } else { - return ( -
- {category.name - ? category.name.charAt(0).toUpperCase() + - category.name.slice(1).replace('-', ' ') - : ''} -
- ); - } - }; - - const getList = ( -
-

{t('category-menu-title')}

- -
handleRouteChange(allCategory)} - style={selectedCategory === allCategory ? { color: 'var(--secondary-color)' } : {}} - > - {allCategory.charAt(0).toUpperCase() + allCategory.slice(1)} -
- - {categories.map((cat, index) => getCategory(cat, index))} -
- ); - - return ( -
-
setSidebarVisible(!sidebarVisible)} - > - {sidebarVisible ? '<' : '>'} -
- {getList} -
- ); -}; - -export default GalleryNavMenuAsSidebar; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/index.ts b/frontend-next-migration/src/preparedPages/PictureGalleryPages/index.ts index e53474048..622b812a2 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/index.ts +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/index.ts @@ -1,7 +1,5 @@ // todo fix it to not jump on loading -// export {default as PictureGalleryPage} from "./ui/PictureGalleryPage.async" -export { default as PictureGalleryPage } from './ui/PictureGalleryPage'; - -export type { Props as PictureGalleryPageProps } from './ui/PictureGalleryPage'; +export { default as PictureGalleryPage } from './ui/PictureGalleryPage.async'; +// export { default as PictureGalleryPage } from './ui/PictureGalleryPage'; export { default as cls } from './ui/PictureGalleryPage.module.scss'; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/model/useFilterPhotoObjects.ts b/frontend-next-migration/src/preparedPages/PictureGalleryPages/model/useFilterPhotoObjects.ts index 46d3245b2..c4af4f104 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/model/useFilterPhotoObjects.ts +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/model/useFilterPhotoObjects.ts @@ -2,6 +2,11 @@ import { useMemo, useState } from 'react'; import { PhotoCategory, PhotoObject } from '@/entities/Gallery'; import { useClientTranslation } from '@/shared/i18n'; +/** + * Custom hook for filtering and sorting photo objects based on various criteria. + * @param photoObjects - The array of PhotoObject to filter and sort. + * @returns An object containing filtered images, current filters, and functions to set and reset filters. + */ export const useFilterPhotoObjects = (photoObjects: PhotoObject[]) => { const [searchQuery, setSearchQuery] = useState(''); const { t } = useClientTranslation('picture-galleries'); @@ -58,6 +63,17 @@ export const useFilterPhotoObjects = (photoObjects: PhotoObject[]) => { }); }, [photoObjects, currentCategory, searchQuery, selectedAuthors, sortBy]); + const resetAllFilters = () => { + setSearchQuery(''); + setCurrentCategory({ id: 'all-categories', name: t('all-categories') ?? 'All' }); + setSortBy('date_desc'); + setSelectedAuthors([]); + }; + const resetSelectionFilters = () => { + setSortBy('date_desc'); + setSelectedAuthors([]); + }; + return { filteredImages, filters: { @@ -72,5 +88,9 @@ export const useFilterPhotoObjects = (photoObjects: PhotoObject[]) => { setSortBy, setSelectedAuthors, }, + resetFilters: { + resetAllFilters, + resetSelectionFilters, + }, }; }; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/AuthorsDropdown.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/AuthorsDropdown.tsx index 4c97416c1..b7f2235a0 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/AuthorsDropdown.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/AuthorsDropdown.tsx @@ -2,6 +2,7 @@ import cls from './FilterDropdowns.module.scss'; import useSizes from '@/shared/lib/hooks/useSizes'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; +import { useClientTranslation } from '@/shared/i18n'; export const AuthorsDropdown = ({ selectedAuthors, @@ -19,6 +20,15 @@ export const AuthorsDropdown = ({ dropdownsOpen: boolean; }) => { const { isMobileSize } = useSizes(); + const { t } = useClientTranslation('picture-galleries'); + + const handleAuthorChange = (author: string) => { + if (selectedAuthors.includes(author)) { + setSelectedAuthors(selectedAuthors.filter((a) => a !== author)); + } else { + setSelectedAuthors([...selectedAuthors, author]); + } + }; return (
@@ -28,31 +38,25 @@ export const AuthorsDropdown = ({ className={`${cls.dropdownTitle} ${isMobileSize && !dropdownsOpen ? cls.hidden : ''}`} onClick={() => setAuthorsOpen(!authorsOpen)} > - Authors + {t('authors')} {authorsOpen && (!isMobileSize || dropdownsOpen) && ( -
    - {authorsList.map((author) => ( -
  • - { - if (selectedAuthors.includes(author)) { - setSelectedAuthors( - selectedAuthors.filter((a) => a !== author), - ); - } else { - setSelectedAuthors([...selectedAuthors, author]); - } - }} - /> - -
  • - ))} -
+
+
    + {authorsList.map((author) => ( +
  • + handleAuthorChange(author)} + /> + +
  • + ))} +
+
)}
diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.module.scss b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.module.scss index aaa5c4475..3a00f4df9 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.module.scss +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.module.scss @@ -8,15 +8,15 @@ flex-direction: column; align-items: center; justify-content: center; - box-shadow: 0.3rem 0.3rem black; - border: 2px solid black; + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); border-radius: var(--border-radius-figma); gap: 0; } label { padding-left: 0.5rem; - font: var(--font-dm-m); + font: var(--font-dm-s); } } @@ -26,9 +26,6 @@ justify-content: center; align-items: center; width: 100%; - // .dropdownTitle { - // font: var(--font-dm-m); - // } } .divider { @@ -56,8 +53,8 @@ align-items: flex-start; @media (min-width: breakpoint(md)) { background-color: var(--base-card-background); - box-shadow: 0.3rem 0.3rem black; - border: 2px solid black; + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); border-radius: var(--border-radius-figma); } } @@ -83,11 +80,10 @@ @media (max-width: breakpoint(md)) { width: 100%; border: none; - font: var(--font-sw-m) + font: var(--font-sw-m); } } - .authorsDropdown { width: 300px; display: flex; @@ -106,18 +102,66 @@ flex-direction: column; @media (min-width: breakpoint(md)) { background-color: var(--base-card-background); - box-shadow: 0.3rem 0.3rem black; - border: 2px solid black; + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); border-radius: var(--border-radius-figma); } } +.authorsOptionsContainer { + @media (max-width: breakpoint(md)) { + background-color: #2B516A; + margin: 0 1rem 0.5rem; + padding-top: 0.2rem; + border-radius: 4px; + outline: 1px solid var(--drop-shadows); + } +} + .authorsOptions { list-style: none; + width: calc(100% - 1.4rem); + max-height: 200px; accent-color: var(--primary-color); - padding: 0 1rem 0.5rem; + padding: 0 1rem; + margin-bottom: 0.5rem; + overflow-y: scroll; + scrollbar-width: thin; + scrollbar-color: var(--primary-color) #2B516A; + &::-webkit-scrollbar { + width: 8px; + } + &::-webkit-scrollbar-track { + background: #2B516A; + } + &::-webkit-scrollbar-thumb { + background-color: var(--primary-color); + border-radius: 4px; + } + @media (max-width: breakpoint(md)) { + width: calc(100% - 0.3rem); + scrollbar-color: var(--primary-color) var(--base-card-background); + padding: 0 0.5rem; + margin-bottom: 0.2rem; + + } } .hidden { display: none; } + +.resetButton { + background-color: var(--primary-color); + color: var(--drop-shadows); + width: 250px; + border: none; + margin: 1rem 0; + padding: 0.5rem 1rem; + border-radius: var(--border-radius-figma); + cursor: pointer; + font: var(--font-dm-m); + transition: + background-color 0.3s ease, + color 0.3s ease; +} diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.tsx index 2daf3db82..db2be8de8 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/FilterDropdowns.tsx @@ -6,6 +6,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; import { SortByDropdown } from './SortByDropdown'; import { AuthorsDropdown } from './AuthorsDropdown'; +import { useClientTranslation } from '@/shared/i18n'; interface FilterDropdownsProps { selectedAuthors: string[]; @@ -13,6 +14,10 @@ interface FilterDropdownsProps { sortBy: 'date_asc' | 'date_desc' | 'title'; setSortBy: (sortBy: 'date_asc' | 'date_desc' | 'title') => void; photoObjects: PhotoObject[]; + resetFilters: { + resetAllFilters: () => void; + resetSelectionFilters: () => void; + }; } export const FilterDropdowns = ({ @@ -21,12 +26,14 @@ export const FilterDropdowns = ({ sortBy, setSortBy, photoObjects, + resetFilters, }: FilterDropdownsProps) => { const [dropdownsOpen, setDropdownsOpen] = useState(false); const [sortByOpen, setSortByOpen] = useState(false); const [authorsOpen, setAuthorsOpen] = useState(false); const { isMobileSize } = useSizes(); + const { t } = useClientTranslation('picture-galleries'); const authorsList = [...photoObjects] .map((photoObject) => photoObject.author) @@ -47,12 +54,12 @@ export const FilterDropdowns = ({ setDropdownsOpen(!dropdownsOpen); }} > - Suodattimet + {t('filters')}
)} -
+
+ {isMobileSize && dropdownsOpen && ( + <> +
+ + + )}
); }; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/SortByDropdown.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/SortByDropdown.tsx index b3f98626e..a47bd4b47 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/SortByDropdown.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/FilterDropdowns/SortByDropdown.tsx @@ -2,6 +2,7 @@ import useSizes from '@/shared/lib/hooks/useSizes'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; import cls from './FilterDropdowns.module.scss'; +import { useClientTranslation } from '@/shared/i18n'; export const SortByDropdown = ({ sortBy, @@ -17,11 +18,12 @@ export const SortByDropdown = ({ dropdownsOpen: boolean; }) => { const { isMobileSize } = useSizes(); + const { t } = useClientTranslation('picture-galleries'); const sortByOptions = [ - { value: 'date_asc', label: 'Date (oldest first)' }, - { value: 'date_desc', label: 'Date (newest first)' }, - { value: 'title', label: 'Title' }, + { value: 'date_desc', label: t('date-desc') }, + { value: 'date_asc', label: t('date-asc') }, + { value: 'title', label: t('title') }, ] as const; return ( @@ -32,7 +34,7 @@ export const SortByDropdown = ({ className={`${cls.dropdownTitle} ${isMobileSize && !dropdownsOpen ? cls.hidden : ''}`} onClick={() => setSortByOpen(!sortByOpen)} > - Sort by + {t('sort-by')} {sortByOpen && (!isMobileSize || dropdownsOpen) && ( diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx index 6e946c09b..93c623a27 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/NavigateGalleryTabs.tsx @@ -2,12 +2,13 @@ import { useMemo } from 'react'; import { PhotoCategory } from '@/entities/Gallery'; import useSizes from '@/shared/lib/hooks/useSizes'; import { TabNavigation } from '@/shared/ui/TabNavigation'; +import { useClientTranslation } from '@/shared/i18n'; interface NavigateGalleryTabsProps { categories: PhotoCategory[]; setBackgroundColor: (color: string) => void; currentCategory: PhotoCategory; - setCurrentCategory?: (category: PhotoCategory) => void; + setCurrentCategory: (category: PhotoCategory) => void; } export const NavigateGalleryTabs = ({ @@ -21,6 +22,8 @@ export const NavigateGalleryTabs = ({ () => categories?.findIndex((category) => category.id === currentCategory.id), [categories, currentCategory.id], ); + + const { t } = useClientTranslation('picture-galleries'); const categoryColors = [ { tabColor: '#97C459', sectionBG: '#527259' }, { tabColor: '#5DCAA5', sectionBG: '#0C5450' }, @@ -33,7 +36,7 @@ export const NavigateGalleryTabs = ({ categoryColors[0].tabColor, color: 'black', }; - const mobileTabStylesList = categories.map((category, index) => ({ + const mobileTabStylesList = categories.map((_category, index) => ({ border: `2px solid`, borderColor: categoryColors[index % categoryColors.length]?.tabColor || categoryColors[0].tabColor, @@ -51,7 +54,7 @@ export const NavigateGalleryTabs = ({ categoryColors[selectedCategoryNumber % categoryColors.length]?.sectionBG || categoryColors[0].sectionBG; setBackgroundColor(sectionBGColor); - setCurrentCategory?.(selectedCategory); + setCurrentCategory(selectedCategory); } }; const tabs = categories.map((category) => ({ @@ -64,7 +67,7 @@ export const NavigateGalleryTabs = ({ return ( (() => import('./PictureGalleryPage')); +const PictureGalleryPage = dynamic(() => import('./PictureGalleryPage')); export default PictureGalleryPage; diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss index d4132bfce..782531cbd 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.module.scss @@ -1,5 +1,4 @@ .Wrapper { - display: flex; flex-direction: column; min-height: 100vh; @@ -28,9 +27,9 @@ } .Header{ - background-color: #1E3544; - box-shadow: 0.3rem 0.3rem black; - border: 2px solid black; + background-color: var(--base-card-background); + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); border-radius: 5px; margin-bottom: 2rem; padding: 20px; @@ -47,16 +46,7 @@ margin-top: 10px; display:inline; font: var(--font-dm-m); - color: #faf9f6; -} - - -.galleries{ - display: flex; - gap: 30px; - justify-content: center; - flex-wrap: wrap; - + color: var(--white-text); } @media (min-width: breakpoint(md)) { @@ -83,11 +73,8 @@ .short { width: 17.5rem; - @media (max-width: breakpoint(lg)){ margin-inline: auto; - } @media (max-width: breakpoint(md)){ width: 100%; - margin-inline: 0; } } diff --git a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx index e7874a4bb..16a408636 100644 --- a/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx +++ b/frontend-next-migration/src/preparedPages/PictureGalleryPages/ui/PictureGalleryPage.tsx @@ -1,6 +1,6 @@ 'use client'; import React, { useState, useMemo, useEffect } from 'react'; -import { AnimationGallerySection } from '@/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery'; +import { AnimationGallerySection } from '@/widgets/SectionGallery'; import { getLanguageCode, PhotoCategory, useGetDirectusGalleryImages } from '@/entities/Gallery'; import { Container } from '@/shared/ui/Container'; import cls from './PictureGalleryPage.module.scss'; @@ -8,23 +8,11 @@ import { useClientTranslation } from '@/shared/i18n'; import useSizes from '@/shared/lib/hooks/useSizes'; import { SearchBar } from '@/preparedPages/DefenseGalleryPages/ui/SingleDefensePage'; import { PageTitle } from '@/shared/ui/PageTitle'; -import { classNames } from '@/shared/lib/classNames/classNames'; -// import buttonImg from '@/shared/assets/images/gallery/Frame 526.png'; -// import { SectionGalleryV2 } from '@/widgets/SectionGallery'; import { useParams } from 'next/navigation'; import { useFilterPhotoObjects } from '../model/useFilterPhotoObjects'; import { NavigateGalleryTabs } from './NavigateGalleryTabs'; -// import { useGetDirectusGalleryImages, getLanguageCode, getCategoryTranslation, } from '@/entities/Gallery'; import { FilterDropdowns } from './FilterDropdowns/FilterDropdowns'; -export interface Props { - title: string; - infoText: string; - socialsText: string; - socialMediaLinks: string[]; - videoLink: string; -} - const PictureGalleryPage = () => { const { t } = useClientTranslation('picture-galleries'); const { isDesktopSize, isWidescreenSize } = useSizes(); @@ -39,7 +27,8 @@ const PictureGalleryPage = () => { useGetDirectusGalleryImages(languageCode); // filters - const { filteredImages, filters, setFilters } = useFilterPhotoObjects(photoObjects); + const { filteredImages, filters, setFilters, resetFilters } = + useFilterPhotoObjects(photoObjects); // add "all categories" to categories const allCategories: PhotoCategory[] = useMemo(() => { @@ -125,15 +114,14 @@ const PictureGalleryPage = () => { /> )} -
- -
+ = { [AppRoutesLinks.PICTURE_GALLERY]: '/picture-galleries', [AppRoutesLinks.COMICS_GALLERY]: '/comics', - [AppRoutesLinks.PICTURE_GALLERY_CATEGORY]: '/picture-galleries/:category', [AppRoutesLinks.MAIN]: '/', [AppRoutesLinks.ABOUT]: '/about', @@ -116,7 +114,6 @@ export const getRouteOneHeroDevPage = (slug: string) => `/hero-development/${slu export const getRouteComicsPage = () => '/comics'; export const getRouteGalleryPage = () => '/picture-galleries'; -export const getRouteGalleryCategoryPage = (category: string) => `/picture-galleries/${category}`; export const getRouteGameArtPage = () => '/artGame'; export const getRouteMyClanPage = () => '/clans/myclan'; diff --git a/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json b/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json index aef8a3993..e2fc1f322 100644 --- a/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json +++ b/frontend-next-migration/src/shared/i18n/locales/en/picture-galleries.json @@ -15,5 +15,17 @@ "all-categories": "All", "picture-galleries-title": "How We Made the Graphics", "no-animations-title": "No Results Found", - "no-animations-text": "Please check your spelling or try a new search." + "no-animations-text": "Please check your spelling or try a new search.", + "loading": "Loading...", + "error-text": "Error loading gallery.", + "filters": "Filters", + "date-asc": "Oldest first", + "date-desc": "Newest first", + "title": "Alphabetical", + "sort-by": "Sort by", + "authors": "Authors", + "reset-filters": "Reset", + "page-planner": "Page designed by", + "image-alt": "image", + "animation-alt": "animation" } diff --git a/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json b/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json index a3dc69922..f90b2a852 100644 --- a/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json +++ b/frontend-next-migration/src/shared/i18n/locales/fi/picture-galleries.json @@ -15,5 +15,17 @@ "all-categories": "Kaikki", "picture-galleries-title": "Näin teimme grafiikan", "no-animations-title": "Ei hakutuloksia", - "no-animations-text": "Tarkista kirjoititko oikein tai kokeile uutta hakua." + "no-animations-text": "Tarkista kirjoititko oikein tai kokeile uutta hakua.", + "loading": "Ladataan...", + "error-text": "Gallerian lataus epäonnistui.", + "filters": "Suodattimet", + "date-asc": "Vanhin ensin", + "date-desc": "Uusin ensin", + "title": "A - Ö", + "sort-by": "Järjestä", + "authors": "Tekijät", + "reset-filters": "Tyhjennä", + "page-planner": "Sivun suunnitellut", + "image-alt": "kuva", + "animation-alt": "animaatio" } diff --git a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss index 8e796d8b0..a39c9a9b7 100644 --- a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss +++ b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.module.scss @@ -1,8 +1,8 @@ .tabNavigation { display: flex; background-color: var(--base-card-background); - box-shadow: 0.3rem 0.3rem black; - border: 2px solid black; + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); border-radius: var(--border-radius-figma); flex-direction: column; } @@ -14,19 +14,26 @@ align-items: center; width: 100%; flex-wrap: wrap; - gap: 0.5rem; @media (max-width: breakpoint(md)) { - padding: 1rem; + padding: 1rem 1.5rem; + gap: 0.5rem; } } +.tabsTitle { + font: var(--font-sw-xl); + color: var(--primary-color); + display: flex; + align-items: center; + justify-content: center; + padding-top: 1rem; +} + .tab { padding: 12px; - min-width: 150px; - max-width: 200px; + width: 250px; height: 50px; display: flex; - flex: 1 1 0; justify-content: center; align-items: center; text-align: center; @@ -38,17 +45,18 @@ @media (max-width: breakpoint(md)) { border-radius: var(--border-radius-figma); - font: var(--font-dm-bold-m); + font: var(--font-dm-m); + height: 35px; + width: 140px; } } .tab:hover { text-decoration: underline; - outline: 2px solid black; } .activeTab { - outline: 2px solid black; + outline: 2px solid var(--drop-shadows); color: black; background-color: var(--primary-color); } \ No newline at end of file diff --git a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx index 6bc1ba561..e06b6e341 100644 --- a/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx +++ b/frontend-next-migration/src/shared/ui/TabNavigation/ui/TabNavigation.tsx @@ -10,6 +10,15 @@ interface TabNavigationProps { activeTabStyles?: React.CSSProperties; } +/** + * TabNavigation component renders a navigation bar with tabs. + * @param tabs - An array of tab objects containing id and label. + * @param tabsTitle - The title displayed above the tabs on mobile devices. + * @param activeTab - The id of the currently active tab. + * @param onTabClick - Callback function triggered when a tab is clicked. + * @param tabStylesList - Optional array of styles for each tab. + * @param activeTabStyles - Optional styles for the active tab. + */ export const TabNavigation = ({ tabs, tabsTitle, diff --git a/frontend-next-migration/src/widgets/SectionGallery/index.ts b/frontend-next-migration/src/widgets/SectionGallery/index.ts index 6ef7469b8..a528008dc 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/index.ts +++ b/frontend-next-migration/src/widgets/SectionGallery/index.ts @@ -2,4 +2,4 @@ export { SectionGallery as SectionGalleryV1 } from './ui/SectionGalleryV1/SectionGallery'; // Version 2 (with ImageWall) -export { AnimationGallerySection as SectionGalleryV2 } from './ui/SectionGalleryV2/SectionGallery'; +export { AnimationGallerySection } from './ui/SectionGalleryV2/SectionGallery'; diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx index 646decc93..56cb3e272 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery.tsx @@ -16,7 +16,7 @@ export const AnimationGallerySection = ({ animations, backgroundColor }: Animati if (!animations || animations.length === 0) { return (
@@ -31,12 +31,15 @@ export const AnimationGallerySection = ({ animations, backgroundColor }: Animati

{t('no-animations-title')}

{t('no-animations-text')}

+
+ {t('page-planner')}:Sanna-Kaisa Mastokangas +
); } return (
{animations.map((set, index) => ( @@ -66,7 +69,7 @@ export const AnimationGallerySection = ({ animations, backgroundColor }: Animati > {`Frame Animation
))} +
+ {t('page-planner')}:Sanna-Kaisa Mastokangas +
); }; diff --git a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss index 69c9bd7a3..8032375af 100644 --- a/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss +++ b/frontend-next-migration/src/widgets/SectionGallery/ui/SectionGalleryV2/SectionGallery2.module.scss @@ -1,10 +1,10 @@ -.AnimationGallerySection { +.animationGallerySection { display: flex; flex-direction: column; - gap: 2rem; - padding: 2rem; - box-shadow: 0.3rem 0.3rem black; - border: 2px solid black; + gap: 3rem; + padding: 3rem; + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); border-radius: 10px; background-color: var(--base-card-background); } @@ -12,16 +12,16 @@ .block { display: flex; flex-direction: column; - align-items: start; - background-color: #1E3544; - box-shadow: 0.3rem 0.3rem black; - border: 2px solid black; + align-items: flex-start; + background-color: var(--base-card-background); + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); border-radius: 10px; padding: 20px; } .textBlock { - text-align: start; + text-align: flex-start; max-width: 800px; width: 100%; } @@ -45,7 +45,7 @@ .description { font: var(--font-dm-m); - color: #faf9f6; + color: var(--white-text); margin: 0.5rem 0; } @@ -57,6 +57,7 @@ justify-items: center; align-items: center; width: 100%; + margin-top: 1rem; } .frameRow { @@ -115,9 +116,9 @@ align-items: center; justify-content: center; padding: 2rem; - background-color:var(--base-card-background); - box-shadow: 0.3rem 0.3rem black; - border: 2px solid black; + background-color: var(--base-card-background); + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); border-radius: 10px; } @@ -140,58 +141,89 @@ font-weight: bold; margin-bottom: 0.5rem; font: var(--font-sw-l); - color: #faf9f6; + color: var(--white-text); } .noAnimationsText { font: var(--font-dm-m); - color: #faf9f6; + color: var(--white-text); text-align: center; } @media (max-width: breakpoint(md)) { - .framesContainer { - width: 100%; - } - - .frameRow { - width: 100%; - display: flex; - flex-direction: column; - gap: 1rem; - align-items: stretch; - } - - .imageWrapper { - width: 100%; + .framesContainer { + width: 100%; + } + + .frameRow { + width: 100%; + display: flex; + flex-direction: column; + gap: 1rem; + align-items: stretch; + } + + .imageWrapper { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + aspect-ratio: auto; + height: auto; + } + + .frameImage { + object-fit: contain; + object-position: center; + width: 100%; + height: 100%; + } + + .animationContainer { + width: 100%; + } + + .buttonWrapper { + width: 100%; + flex: 0 0 auto; + aspect-ratio: auto; + min-height: 0; + } + + .textBlock { + text-align: center; + } + .author { + text-align: center; + } + .description { + text-align: flex-start; + } + .title { + font: var(--font-sw-l); + } +} + +.footer { display: flex; justify-content: center; align-items: center; - flex-direction: column; - aspect-ratio: auto; - height: auto; - } - - .frameImage { - object-fit: contain; - object-position: center; - width: 100%; - height: 100%; - } - - .animationContainer { width: 100%; - } - - .buttonWrapper { - width: 100%; - flex: 0 0 auto; - aspect-ratio: auto; - min-height: 0; - } - - .textBlock { text-align: center; } - .author { text-align: center; } - .description { text-align: start; } - .title { font: var(--font-sw-l); } + background-color: var(--base-card-background); + box-shadow: 0.3rem 0.3rem var(--drop-shadows); + border: 2px solid var(--drop-shadows); + border-radius: var(--border-radius-figmadesktop); + padding: 20px; + text-align: center; + font: var(--font-dm-m); + color: var(--white-text); + + span { + color: var(--primary-color); + margin-left: 5px; + } + @media (max-width: breakpoint(md)) { + flex-direction: column; + } } diff --git a/frontend-next-migration/tsconfig.json b/frontend-next-migration/tsconfig.json index 7c7498ef3..b7f166da3 100644 --- a/frontend-next-migration/tsconfig.json +++ b/frontend-next-migration/tsconfig.json @@ -15,7 +15,6 @@ ], "allowJs": true, "skipLibCheck": true, - "ignoreDeprecations": "6.0", "strict": true, "noEmit": true, "esModuleInterop": true,