PK\.project_instructions.md# Lib — Project Instructions ## Overview "Lib" is a passport/ID photo scanner & editor web app with a freemium model. UI language is **Spanish** (source language). Always respond to the user in Spanish. ## Visual Style - Red / white / gray color scheme. - 3D buttons via `components/button-3d.tsx` (`Button3D`, variants: primary / dark / light). ## Key Pages / Routes - `/escanear` (scan), `/editor` (editor), `/imprimir` (print), `/cuenta` (account). ## Technical Patterns - **Global auto-translation (i18n)**: DOM-based engine, NOT per-string keys. Translates the entire app into any language via LLM. - `lib/i18n/languages.ts` — LANGUAGES (32), SOURCE_LANG="es", RTL_LANGS, COUNTRY_TO_LANG, helpers. - `app/api/translate/route.ts` — POST endpoint, LLM (gpt-5.4-mini) via ABACUSAI_API_KEY, Spanish→target, returns {translations:{original:translated}}, identity for es. force-dynamic, maxDuration=60. - `components/i18n/i18n-provider.tsx` — I18nProvider + useI18n(). Detection: localStorage `lib-lang-manual` → browser lang → IP geo (ipwho.is) → fallback es. TreeWalker DOM translator, caches in localStorage `lib-trans:`, batches of 50, MutationObserver (120ms debounce), restoreToSource() before switching non-source langs. Skips `data-no-translate`. - `components/i18n/language-switcher.tsx` — dropdown (data-no-translate), flag + native name, spinner while translating. In site-header. - To exclude content from translation, add `data-no-translate` attribute. - **Custom photo sizing**: `lib/presets.ts` has CUSTOM_PRESET_ID="custom", CUSTOM_MIN_MM=10, CUSTOM_MAX_MM=200, clampMm(), getEffectivePreset(id, customWidthMm?, customHeightMm?). Store (`lib/store.ts`) holds customWidthMm (35), customHeightMm (45), setCustomSize(). Editor & print views have "Personalizado" button + mm width/height inputs. Stage/editor/print derive aspect ratio from preset dims, so getEffectivePreset flows through automatically. ## Rules - Edit only within `/home/ubuntu/lib_app`. yarn only. Next.js 14. - LLM access (ABACUSAI_API_KEY) is the only API; never ask user for keys. - Translate API is the sole LLM consumer currently. PKʇkkPK\.abacus.donotdeletegAAAAABqNaLPTC61BFJ8Sfk7jrk8cp2M0pRihUqTZ8yrgWIaiQ4SNoMFWCHTTbd3QAYmM49w5ipLdJbgT7ktNzF96g9zJ5Pw-h7Nkrt2dSUyuoZ-qTx9q321KrFmktMZugzOXSTJFg8luUr1Ev1-0PFHC08TfI9xADg71uXnUBBplyRotVE3HHxiC1eh9JFv9HcMaBQILlycLWHBJPtb9YKP7xuBFBIhtKZjUhu_T2QHdy39SALxa5DSO_8jUD0Lb7AzcHV9GRRTFaXhYd4niIOVolCf1soxhiD27_Z39zzMykMJ0dkUQQYC715HQ5za529zGsxpzmzqW2ns_UMqmC1lf4yNUiUqA-fnbX4E1_h4zQuLeImQZ6j8RKTz2yYafKNI8Qx5ax2U1_jdcg6wVNZDp84NFHzz81NMdFTqOFOsXj4Gcuwc9f478H4sOo-99BcA5Lj5TWtO0RJukKnkOv1YHag-mlkqWAcf5cImvyWd9qyISf7nSG9qkx9Xx_aSpGlhFT9AtzFUK_Ctr58Ipx3oAlaXLVUraa_9qqGGTS2wROClSTvTMP2JB87mM2Gel-b2rpFFE0E5cQKnFyQRJWnsG2rpRk2CHTds63jSnRPJh110fXjRoqZQpH9XCHdWiGETqyljUr0tk3BXvXgsFcXBVYIsXz6zO5j7IR4iek6ByoIylcEyIRyWshZZ86gouFSbezPhLULRRcB061bEBjsHgp4aRkLszoOas6LmGCyB2Ks3G24k3Kkm91KZpLfolDot6TIEuKE_Wz15Q3Uw2w_vWfpov5b30WP03rlgFJ08FnTYc5gQ1YEDBqSQyi2dFzp2VPYLDnBUVTx1SuJRDiDrDWqJdTrgwxN_CrEaSPAUfvDrsMixOyPelGk4KkwfOObb0M3ZiRHkaS0XCK2fndoZ2PzXyPDGknsi9QLQQh55IVKj7v_lHsXqbHvC9CxY1bB1xPHbIazsd3YP3B7ewHNff6cYO5lIfymUJCgTnM5KsgAmQGcamZuwu0NZM5YYq9eY5whBGwq9_hjzHq5llI9H9bqaU7fKv3pJfKDR3PS1tvN9CM7quQ0faUgYHxe2r-VGADryiaDMp2hu2s4jpkzkSUmdc0wyFrrEw4N7GLpWo043M9OKg-_qSv3g6f-EwSaUMNTyADbKi1rAjVLYwyXz7GFFiVvE3JDTVCFzH2t8Chna8zdZ5rcyRdNZPx3EGAWxsCcQJRSkd_9t1MNtvwwUFcL4qPHWDDEMVfdHloPXAvI6LNAdpzDlZhPk52e-l-VkqjbvdfA_FAnw5zF6FvGVbVaw933tAUnVQQzCm0za0C9dGINCDMkI04eXM7MzNhp2VG5S0obRd6yU1dNmh0o7jh-QUanZJrVosHbR8N2bBRnvCfvZi7kZyrz80V1ZtvfIdKoVVDI8ryx3-wL9MiuGQOcPPKlhYjratdAhkllYuFnUjTvTPXdLPCkLAo_92v3bX24cxczVmmPmQJqzXNqNdVUu866aoH50rtpgZFvpFo47DMkO1b97GFzzcvoNGTe9JSgWEwaMzW9ZRjY2FosS10ZSKlDLIq2-AdG2D-aeGZBQsDHwOwejoPe-HwpuP_3l6Xy9qwMK6AhRS4AnooF-m5WUpZcTpIUGymTYrAsqFGt5CyF_tu-v4m4aLaLSIT4R25JgDpaVVIuZGCEoqUuu1s59n4paNik-Y8VQwRdfO8iGiZ8jBH12WK1oOj0c5qGVAWu7VYXxj_NRdjU0jSmGr1lEanVsPoMYaXkTXvS9cx4eFbFEK92sRAVJcT6CQ35q2Kaen3VNsVQiSHhiVmEWfOUExoCbVa72PEeF4NdoSUo2miGm9BqvY69DOwJz7wdkN6Q-OU73_-twTbmxmy1BtgJk2xaNv9LVNLf9QStnOq7HNgEeToomTuKVgE9DioomzBh7yYeSVsbMHo0iT14Ol84dQCOKZY8qYOR71epiHl-vqpE-3XRbND3legnrH-it78aOvLEFlq_-fsXi9SPBLtHDqFjU4DmjoSj0baXkanb0mPfHrwPHAxSwOqd7MuBY3tVD0LiAfYmy7mZSsN25VStiCdOldkTVW69FHSA8BxxUwoQg3LcNq7Yc_l4T7fPkFhxcgsHuwOpdrbmZ2bptma-p7hApK2Oben1lkngrobrWZnar1_qZsioy9ZiBjzoSKrrvx9mWIk7MVZGFijHFimYYa4-kJhorGxGelx76TKxrGii6_-VYTblH1SNah4WusKuzTUKuEbq64w-FscP0Fo8kc1dZORVxleCOrlhHaqoMAVe7p-2wXEKsJ_wcq0tleOopRF9XJ1LEjJ0VW5N2D-MwwUWQ0sLJKznQew8kEjejL9dpLbpTiRI8vz2a6fZJRRLR7Onq5LDC-uaSDglmUgJKCdrIN12Pkrut6pdhHIUjuK7KPS8PYE9soZIr_0-Pd3qdIYA1ij6FvFyg11ahbdCXCt8ALHYQgZ0Te-iAsdBkxg8jjl8g7o6hQhs_6I3_1HNHEJ7_TsEg5CDGAfrX3-lZyVigJGwa3WPou7rWFWNsH8zXGOmNY_urHC_-NDNoGHX6qof8aBRpoT6BXErbhspjznVgp7dDFn7VOZoOApnv8L3A9OtQorLLadeRvpztqIJjSCCyWl9vtSjCuEJsyTZ3nF7UfxVypxt9uEimW6xgawa0HehYCqWJYwdX8OJf6vcNPdcIQEBIGz8NhOPdVUsQzSIoxhIzqAIKBGCgPfxn8djookv4NPf4V-PjS7vcMxvh6lxo6NPUCf8H223ZxiP5iCP26pI61HRUFM1lk5Kaa05dTX_i7HayHuXeEB7bk_Km_IEvxVEyoO7JlON225qFW3FtmcbJfo0tR_tVyuKLXnQ8cD-31tb43lGc4gbZYxrElLnywEmhstsObyFy6uUzzkUE08kjtlQjCxprGjXTWHbYvemuAGH5wMvwaOaueI1Zl1Ue8qrs5UHscLd_BoVvYfxWWAEge1yWMtcpm_DcikkJHT8ZDylE9emKdIpRbQnTVG69v7nB4Yahc1Kqlo7kPhmuiD959YFFHAM5EZZR0TOXzZUZb1UWQbsYDuFPaVk0gsTmbl9I1zbAKim6mEodekFyKaMjMkD8V8mZjV92xoUJ2OJSK_UB2uoa6u193gMEmVBnOdPcTiMtklJhw2TaS05Y8i0kL6fzMN-RzYdDmgRp1qHxhbRSQVVQsol7ZhAbFuAMFPy7jGbHzMEY7T2gzqUvCkkpyJiDEPzALgYXggis5c469Z32cn_NB9vcHzK3k-hqsDO0EaNRBuAuwxWSOQ3qtj5IZLEsDmM-Z4jldAjeWD9IyLK2XMYX_HQpn_VERLiUocGPSXtgoMjHOHolgsczgvWIYoa7bNkyyCfrg4zCHpvSLAAqxH89ehRkIlsxNzVBasLxPj4T1kyXQ-2EwGMVICllFg0IveZfOVuA4WuDOLPZjUghtDIeMOHy30Ryh_YZMRvLwKDTTxeIAS8aGYhYLRtwDReSR34rxzgkFQbRC7HrBdTWxXoXBoI5-_80mLJBECftEg1pmmdMnzipJqMu7_0HtuyxalLfoEhp0Ixn1Z7vLvS3LaPJXQwMjyKNgXzzpPAX5FlPpYg4uslG2_Hnyd928W759m5lkQWvXGV3Lo87QJYAb1iSFv91Ip86QeCbDntLlP-j8I0IWY-ZNSJoRbARyqmUNbr2VUSsCtXFJMKANKUZv1F8fEuhVF6fR5oQL9UBeAhW-aQY5CeQRTxQ3Fif4Aq51MrpFHWGAsBRq5zxTuMligQfuqhE6cM8bqtq5Ich_Lfsqo75TD-msrnEReQzkaFWpGB2caHLYUI0bDpaViA46YWzEcNAHC2M4QtzG_pXSEu8i6LJMvCP330jwqZxVX_4u0IWHhrkTfcMtKChR-KBWsD7lS9yYjoHdRgCXeoIicVsG15gEsctiHrQTM7rLep_zcgyFLzAEeITa7htcoJOVZn7JQ8J0ZQZVsUkYAjW-GWqjpQ7B68TXThzmsjTkbA_WaxKDkfbKbiAyYjOZ0qgi8GeOQUUq7kQCZOpT_USssCrqqQTfMCkmTIoPhCt6xu-UuoVqxXR_UEehmMKPs4a4hLthqGDrdVT1GPDBi2TA6kJQL8YnNZpd1iiV7Cjk3scjA5Q4Y-B3tAfkzTTo6S8r46UkqXENvpsXeDanh1hyybJrB5GxwCTGSNsDtDc6rvByzl1MvHzFP4V5mgzE7TzkHdL9Fbp5p_MFt7BP6AuyI_bqCfE6qoj7dWFNBzNk29aofCyGv3hYbiy0sLUHnkwAYsAFUPGnoCsYy6M3JWdI1Uxl5bNUiaHM3hRbF4a1Ixg_K6C6u8AE4s5RAZgoMIS46SqGdSopCH_bQhyQyPkeJyw72hkFHK0CCPD3qbdN5YLl3lSOG_OW166AthfFM3cduMF3k8f_mzBaMQ3dTBOAPd2R1MZJUz2Q1oZ3XXENRYEh7Dq79HFBWuLi8lRv2fYqZrAzqGML7iR_kPW1oWWuyRcDcAHddUf2npom6tHQRk4I5rdA632RBavEymlHNnssKNGMDG5mbbo1roYO4g7_-X-fJ0FkFXQH_yDX_JkPIVuyL6nZU8-39N-674N4WedZzYAjOpj96G8CxCU_T_u7soxgtmR78RUhGObgIK0oHbVug1mN13ydTV66LK7An9qdHgQbflhwgRNlGiCTXd45e9x3C8vkzfcEdc-zO70HK96WGkZeZFjZtcxiRXLud0Hn74iI9MQJ_rHVBhNX72MSJ6PAmhETMV0GZiWc97QmUK9qHO303qjbbS0bEl6rkPbWld72l6ouyRxWN6xDU-A9eIypzOTOkNU00B9FdtKhFGsif42ZLrSeJ_f7KjZqU5U4qVYgKlg-GQSHgRNsGEwemg7TMHrjsWmkZ3_CBFrpmqieSlenpGW-pmQF_ftMBBW--0Ecw7yIzp75KdVyWYanhcFSO3CXr9kHLn9cmxaekP6lcM3DRV_Zyt5niCqBlLRL8JUB_h94j0zHuJosj-6oC1R_Gk9sHGopbonGNhI3_3WAKOZhU6DJyLoTV3Bykjqti9mx8Gmoht02uV2mMsEoRNj8u85X3kercoylT8o9V9WXIJoLzTKrwdcbzQxDR5qTum1DNW2sD2XSVtsmgmLY06DwUxpCXc8SeaigSlebsFEAN1kVNQEAPeM4qnmnsah8iKP-aKGODd82JYuLpIeWkg6qXKvvriHwkDvOxftqVCHdjLcRa9q_UJk0Ue8vCee_ohLQiSunos1C3mAhsPd__u0xsx-RB1cfOaVzV6ZPinE0z4uRcDVTEhfbuYXAtJjaoXbKlQrMlFE45aFHXl67sO1DIqf9yLlzY4ozwRdSPuNWSdsr0oPSVZ15KyCaZ1firIUbzyLSkYcgHSYOkOU6exs4vajHboQUfNHLwG6cYVodfl0kNPE0WuIuYgB5_nTPEj6Lb1olB2j0LhiJrdZ9wvkeORqKDjG74Vx0Xufagh_c6PeyAukG17O_u_g8QkV31fmCOAUuUrx0TUxENGS5d_j3W9wd9aNxZeKEOQj5eoaSXnGu_cGZTZzBobsVsQEmo9JkoElHoXlHJaYR1F_T1_DFWSKqePZ2N8tdwndYOmlWtMUm5eQ_mh4-g9MAKt4F750jcqEfFvyCurcqSmHgJGKgPcRHUb7IJIxMWGwJBnwoabTlTeOYh2gF_zZLYq8pZm2IvrP1drpMkanmmyZAwIb7O_t3RDFcQjQodZJkLsnLAspftIk3AZQQjqe7WjveMtmRoirsJV3sy21LoZZrczM7XOs9EczLhjMOCBwMWhj9s9mKIen9Fa2gjWHHr4Okr_EIN7IgJIXwKO441mcjMT8WxhuKwUjpxhz55vV1Qj3ST7E0kbviAz-CZPEQ90fF_7AxdCnFNl2J7veavhZ8PYoUUv39noMDUNYC0sAi-gPTIpthgwvjnstYtmOrV48b1i1FwNpl1TzGujD5EsosDIM94zFHC3BAqlgwWUI_SlEJLy9uqF1NXBrxUaVF3u3dvpINjRrFyQuQ1NWUhYkAt9E5mp4C6xxGfOsapkrUtkxLP8Aq7ST9mdjO-ruazSMk3DQu-t1R9W28nB6JJcE1HEpd9nJ25zfA8VBkpToxsWLPvhn8CmDeUUyWxjCKY_scFAOyigzBMFATbAXbNGCLUm30P9eBcDVwETy0WeokO_yL6bfNN-PpdouXCQ2_LxM1re6AujvaOcaXbxRnkD_nt8kvqrrie7cSLmCtizAxljEe8bwZ5KJO9XCyInlibKAawPbOkKR1QaJZg0De24FwvaDOskYaGj6K97f9Bw3Hk9SsSiM8e_CsqhjwP_Wi37Z0e1-3EuP19t9quIGPyRpZjD1ayfD6HAddgcxo8QambgvzqDmoFViM-sjwY5C-CGATh-Zko7iOnWL26TkyguFyTNKUanRICbSvnflqzwp2wQRiUW5WWMHMpgmL00LmP4atL2faSDO54aynnqBlHbyrxOAh_x5sUztYaZ_oSOfUthAKvLdPWv6l0Tj2c6-6cZ15ZzGsXPmcMpoJ4xlUsYlaFOc3_J4d-m4vLMc-fXy_z3Csx2HV5Ws8RI2bNBeFTCZ82PwIw4A0ArLJK1Viiu4aI4LVr9jgNEZFtoACCwme5Z0Kd2KjNFN0GgKAnJhE5Et90qJAqq4X1rS879gSd8VRpxfQ6GR6Uya4203954r8P2kyw6wuXB5KSlsolM61-YnMaMFBIMXix5z1USX5T0XZsF_JzpixugJeF8A4CG7wvd4J5MoGbZO3bCVmoqP1Yds9TzmiEpA7BhaxFcHKxq8Uu0Oc2fEiyDLMCNSfaSswomK9uIjvT776AyBQD9FiTknKQg5LZo8NSWrci0dmtQGhsFatPE2n4lqffdhKDmFjoF_ngjpxoGUt3b_Ufpj8zGUihAe629S3H0Qxx4pxop6gXAy_rleWRTm-ECCM28-CSXnpadoZd7c--4yKThD0xbR7KeWgyPFzW2TqZKonupcqbyKOB3rPiSjfB9xJ_Dh0MyH43etV-P2r_VG40PtA4oyaxZKJzJNiQxeds1_BD1U-bMzegwgwL1kvmfWF6vW7n3sgRiVwm75cWfBn-hHOlla3VKtHLe_Ff-M55wirEuu7WwVSQNicNs8tHGlKjDmjL8QwWxMYYOgOl6-mJ5x4EVUwYPlREdbZkVq3TkrLTOx8u36v97fTSil4ETKHzW1_tIXvGbC32MCBOaIJ_-WgMdqhlBKyfbWJ87opCl_FTf7wFem-QSczfzndk5e6-OiT2P-sE9q6TaZnNCtGBy4tZZLCaZV0cuUdpozJ1CiTOv07Vgy6srSuBg83aoqjgoPrb-mS1Sytni75TYSgzxzGeinahXiGa4KU79zcpF5PnkBxg5donrPHbNJLo-TfCHFZ7usB7Q2FUu3oWfyySo04Fhgew04Hh-ubS8SPv7zkFXaH9Xmrdm9a6Juu_Camx6rjQNyqesO-U-dai9F7VI50Mq8s__IhpEk4wco-SC1J_U8aPnHtqhUYQgCbEPXG7UHQxHziVPDPUKPImhC96AaYBN1QQ_7oMDGStWr0vNa6G7TwIMh6BVpHqf9pubx0cGkSPP9PfyH00ZeB79-D5tuJoADv3QVQlLSpSE7EGHlWxXV8IjHR_F99DWaL8RSh34_vvaQrUn8FjmTy8Pba16Pto_hqkreTmxACi1heklOgOPKO2F0hSjcWNvTgav6I2ysTzRNF5WYAgeoOGTCt_46RF-rtylqDmHKYQ5wyCsDLkt9zvJh6_AX8vpjbrL0aWFpvOkoIrhmkUAh9TLsze-EUcpCugKu2N3Joc7L6Ad_sVaASd0lxoG2SzOuRNKTMJMVUlzBiCh5lW7Z7YLetj8XEoVIQhOGWlSdYis-JmdxYTnpBhycDNTviImYSRADkiENu4UVJ5FIiizG3LsFSMq96pEAap9t-zEi6RLJ70bEkiXgtsUl0EDVb5813cSxGzvm39kRXBhQx5RlU7kJEoOOzc7_fxSHB9KpQcne7f6inj9Ii4pya60Hqcfy46r1t72Rt2DtEsD2AUxnnAEzorHxXjXL7EvHuFL3E7rUl8a1kctJNFpIP5gzlkRzomfbg5HWzTj5mhZdasxKD0B1whTmXU5IofpDJ7gUQUMZ4k_VXJ_ggv2VkIpuBlQMDYsbXQpd_8fL8TRS22ILk7xDLowhr5vUfMOKedJlGd6BfwL6_BN589fmLLHlsxoYGHgapD9iV58l6ejnM1kZGNwMZX_F5T8JaP-f2RKe1nwBMzAKe4mkLJ-giqVnG6C6yo0h5G0xNlzIT6VTKrjahv2m1c_I58kbQTQuoBp7pA_7LSOdsGm0D-9LhCo8sjHqMFY9veK1EdOXkbWY1rINCUaUWT4JUbb4UBnqvK3QCrhZ7UByQDb-RCUNXBtcF4mgudgHhJMVAbQJwLQioZvHJDKAnKT3n_wk7r9IRIItWJ6OdamNgCZXJhZt6uaTUYHEy-LbJcmhFCFye2uOwPFjKNBb6zRHc48J0XP3K4GHnYoHIkGpAwIGcKZH9BmRYb4mev2uKfJWC3wXm35Civ72IoaGFDD_CkpCvV1lmkDEOgd8z6m5R2sYDUZpjfsDaQzKRtN6x5t33d6FGQ2Slkfyj_xC6esB9Nqc55mhFI2Lru7N9xFZ0VRJq2Kz6F7bD3u3zYY9hB4KIiUB6HYHQR68Umn4ldg3U1F3krq0CtlUuLlJDgjumUxoxQi0-ownw3tcxO2fPgQf9pt3feFlWZPyusRjM4gdrD-_RZl6T8BQ7-yGdfCP7IfsFyJM4fEC5e3fRXp-V710i4i741-nPMVe9a9IS6vqlmtrUvKg4-RW0HKgkBa-08GWG5QBGGln4jJ4O9BrDnlqV8FW0NtbsP0GzAM7sEBGQKIVRQq3pM_4XmCnBMWRe6hEF8cWUS5M73rOHDN7Z6isQAyZ5IOoy1MxBAqK3LZnJSt4XzjKHdI7IY0xziZztwaH_1OxcWz3u1bmlhq-QV-fMbTAHgd19DuprDv3dJwtH_xaqK7hAjXtKsjtXigicjv5G8M9jCD-Dt2UhCaEIgDVVyAwwjo7ekUa0CJ9nVmo1wGvdyORAjI6_BKM4W0u8L0K6BU3TxEG2YljyyNSOLgZARsntU5srF3gDQS1Dobzd8lWsK1M2NgYBeM-YhfZV3MIzlRFE6P_TEgL9VDgM0J-AtBP3pq7z2xssX680NrWxSE1f7Q-wywYgNyd78mziI-QuAUSnUjreSrgYU9tOiU7dR7uMfnKvXkz84jue1jXJ6G0SYBvzwneakouVZdwMtxKXEf03JeycFeR8urTjyquqVI_hluUzA6CHvq4XfjtDmBmcuTUdWvEpqT9ruaWvejgn6kPBBHEdtTm5c4FE0jyZMPHjoxko6ivSMr9zVbG6R-23T-QUdGscD_rcxq6NfuEO05uSRZf-bTqxJB9sA4U26fpIYJW12IZAzKJM1BOB0-hHCPvZJet0ru2H26XDLvu9rHgx5qVKv_P9kiR8nI0jnDVqahoUsl2wn5QVZwxTJamlDRxo-TuDuQg0FucpvKuQMjGFm3DMb_AwCUtd4aMsTcNALsBw6IDdIRWSem2vIj3FSlaWXebQRzpgpTV7_KRRC68qLq31E0D8AB_gRJR3pA9LRVRt0idy8n7_KrGxCJo5ZDjb-O4RMcHC6lGiNKzKgXhvw9Lg46toObqlA-1q4h6AcBw7omiFy05KAoifaMg3gvblSQdyxHxlx08-2K4xH6xQ95_3ztJ3yZgR9nFmnzSTfoPV2GPbVTxlAL9A-tzMeM9eqcxYyIW4zjBfEhSe-wwojnruLtJUTW-0J7M9MUrvadTLZeWRxT-sAOV0pjiudtQ1ZxtTKYc8AStp1V25luY-z_UK3O3naCxVMu50Q6SuD-Wnnf62YGR58nHYhPRoV9U5vUYtDdaDk8j2Y89XjmMqwfdgNhDpyUX34RRxcgEm-Va6KHM7m39rWfxEkSaFlwPWnM-AihcRbAHfOo6MUfk3dVNCZ9kgCiGsf2mzrWuDXnN_RAlJQvZ_k830DS0gm0zu_JsBI8W3RXe-1JZjNX4gEzIzaq3TqhbqK2Umj10amPletT8XIS1RIXFwrBZXTMgRkWdX0eS1Le738eowGSAAdb6G5yCHI6uhd1nWjFw3CSoz74qeIyuh4A_vyfGtV5orwta1mLblJD29jfCj0HSpRUpj5KeCLvavhLySYhVF9GxdhJ5jAi1gjY2EPb2v3o_XZ7TM5DgTzvUYb9NllOAJMCAiln3h97QzWbyP955TW6dV1HUI_VrbCfNkJr41363jAuH3avc9vsnxnmwA8VyYaSy-39zuaT_RO2Kn8jZD4qVfnj9jbl0axjWIcKmvGiqvVLrKVC4wUWEalfM2AOQtWO3xGENozthtW5nxmmoBNPeYsvQauHDYJWQJi47RK5VzEd-MJky7RQUmVA2URH2d-4_CmjZlIyAuFFrPVVvB9Y4JGXXkZ5OWPgqMkHsPZJ1O13c0B9jDnIun2uC15WzaS5cnTFtBCx4pkbgEv7bWFuyl9X3HdQKqO1od_gAuzBz0cKZI4q9uNCvOoxRc6gojv7VC5bD7SZ3aDhVu6VoFbhI_1wbXCPsh3dX8djrsCpzPNNMQv52wBqxM-zRcsxKEpM_8IG9hwkXnlE3T2f-9Sf9AXi70_HpM_7GSGNxj1HRuEXSGrojrCvj0gr3k8ovBL6ruLcUi-gF-ct9T8qoc76ESiC7BO0xvgMJpFja6cICOVFy9vxFBaiw3G-fTWZH41kR3xM_82i7PuYo3qksOxGkhA4oMfUitvrmmXWzwt2psvJniwMBOWHen4udo_Oq8bWW_WE0q5WYnJ3kRzzbPj95edGGoPPIHRRSgJlPPMsi-dBTBidpo6ZoD_VpM7zt2zCnshZtjSPgesHF9FS1koPQJt-p4NA4Kw9cmBSzq5UH69N0dhPbOzsHLRYxWOrFEsGUA8ZKQStmC5orFmEJnMRQyyaPWCqso-3dAfp3p_0ZCagLKYp7svkBMIR1nNzdnnZsLlH6BGfZbmfXpXQvOgSukjvBlvTlOYL8yX2FqDEGqkPQhXsNnwBUdm0e-s0s0Ja_YGgZgu_g8jf__RXHZY9ts9U33dx4j2TTHpuLnPZYGkXwPYSEQGLiXpurugyDsSuEOMzSs28JGONQjZ1nFpTxdl4fUuzqzubrTnTjPvJtsresm4D2OifkWaeehOxRc9coxW5wRkqd6cpV1nN47ETtpafqf-wUE9TzXJK5WIZrh1X_8vsgJ7UM-6mE2Zo3P69td7UZRGZI04goZYCFPFC0X4Az4wfUUqYnZ9UinyZcFTTaQi_gEo2Myp-_STZbYvrwbov5NCpWUvrxB0jIZpq60_ssl5rlREm90u33XHKn3VEdUIlcoJM4dyubGLw0q0IthS2afkm23M7DofegB9rP1aeShyy8AH1KnQ3sqnInsHU_VHMLFoU1pBZSYMBUOC2j8nZnxgdCGNsSXCScW-bqQMCiU98_xqtEyD1rDa4FrVY_9AifButdh5L7XEdTedtkkM-T4hcm3eJ7oSGSkGcZ5fzwgcculTpoj8zMRKvxTiqPASZMHFpCUA_w0-KtnovZnhl_A1Q51NEwqKVYF7yZfYRj-ap5BFdyVO4wBPRmhyNWkYL31uvnPkIQiKNncBMUR9Ro14xacOh_b2lnME4tmumXOA6MBs8EV4GNp5vQfXwVcqDG03LnNn04pOV0yJuYo9L0y9ilov2NQthwj4zjshCoD3xceSXpxaoAoZynjXdC3ONX6gVKJ_w6ROtgJRSef1pSTcmwz5tcAXRvsVcElkWmJ441elhCTXqqTTOFd998uHNQlXtVSJcfPEnYUXzVAT6Hng69O8TjyvMbuKB9o3ZYn02erys-IZod-kEVVcq2xypB06HH01EFOPVj8gEpiQv6oT0_NG1XDVmtCphtuKrx32sgrdl2qeo2t6b_tpDrKAoXdzMABdQTypaMmYmalHsb52M7YLYkzIGqjAf7G1X9Bv62_X7mv4nSSrA3wbONey-w2DOHd8J2OdnuOJjgDHFBeblYuH32NXF-8DuBB-AtcQCwVSD30_BRFdfSs26SWra9G5sAd2NDNq_hy0rsmaVGU5pwsHfw89fJKKQdWo9sF9jNE0xG3wZic_V8AY4Ugh7te6e7bhvDgdkrAAhGsSWyKLzdhW9dB4zLqdnrUyGE12sy2O7NspybwlxI61QWJKS5q7emF6ldyP7uCJFlpc3US_kwhx7Lky-or5IiTP2wDVDDmeGj2m02x7pwLynUyRdSC2Jsda60I_sSc9CygSKTUWqC_XP4Hrz9-iUuNr2boBWX7zdzt0SVm8SxHPnTBXqrkhP-zPTCn4tVo8Chq4Hl54abABXyEJWW-gw-GluPm_6J4wKKD7VyzrNULFyUmKSD849cWamXRg7jGKM08GN31mVFm2c1HbsOpAJc9a3JQKVWstlgvUdy8i7qePho-ua63VeZRw1XUUQFiLRyzzN8W53E5un3env7wlY5pWUEps-R3Xkaj0HjTJ-W1ljYzBZv0vqXXPsvbymgbTgK1_JYcHJLdJAhAuuJgpsHtdcM69Ih4sz_iNQhsPnEAgUqe_wgNWIgWyLKx0Z9WcclEXJkjQN_vghKah5rgCy0q83OtHasaPMVJNsCuT1f2VIzHMBaFigDLV8T8O7_1maGmj-ifrLFAWjViGbmAD0oYunWJKd9N-z9scdC1t_R2CzRkxsm881CBlmFeqNAOLN8UBOt03DHO0k3YtcJHhwsMxUVcY83uRE_aTwx5pIrq-vGP2Mi3uLc2ZqoXyW3EtxWLumsWQywre3cZr5TzDUKnufsnanImlov2TnlgV60g0_axed_OkgC-oo-vBdNbPpKxdy8alYlP7yMh-v4pAl2wkO3C7F_Cg69SooS0qbn1YDIwXprBzjYJGWPmm0CgKco9Mnt7VYrl5SOzafGYXNHujYsSEXYDmixjV0jyxXpdgSoBlVeWG-c0pd8J4OSBeKdKn-g1pH7MIt7FMZuwgN-5ZJ_tQ13i3UP4mieuve8kUi_qzRQROuOJAgLa7O3ciaiMoTBdvaoOwM9RU7DU65Dd53oqHY-T84MYaPtR90wN08AoIJQ5VYDiHVMFGDqcBiK7r9kHiltC6kbbKQcdohE4Hym-bSRu-30-BekJVNUECO_FU2HxpiMdb96GVvWdiGvNwnXvOXGmZbx9oifczllOJIPGWQ-0dQSK5UkJZSbYRaOP0TjLF5FvWTrFm5nK4yVaCwiF5309RtiZCn_NRqVVki0OrNHi3ypqmh1ZDfq2kB0LLQpx5Pdb7-tr1A5NN8Kr2RyUtiIyaMETFEVWLnNgW_vRsRFfmNjz02RFU_8VSBfHE3ABTe6zRh6hh4T9gCGALHcZbngeo3chLvoLIpk3KEomRLybBws4ipmO3BJR9hX-SARAgUA8qcSaotIIkZtcPsDkjF7OPHJH1puPn14XnyFw50YhIFcUEoAhdmeB9LMPyGSk17jB5fc1CT0lqNq9sZXBSdm8hxbDAXWJLCKRQwZkWqO-KluPhMkOCi0LgsyOt4peG0-g-pLv0LlF3QgGY7pgbe52HUYbp9EvfaRe51-S6Llekyn9A-7IbzSMfB02Dyk6pNuS5GpRADnrwFHMonG8-sOR9RcU9mofqTNAQS5uHCLSbR3lhllxjbw9B607UP-qTbMvwmPxPr9BqPLMT0fW17hPEwxZ7Kr5PyPjhoTJ1qkgj-8kdRp5tOExTe7al9iLLolX-p4te7X5v9_CSJyFYX48_zDFEGfKxTXUwIQe4qUpQLRDAwgxkAO8yQE1u-eCMQzhVJU8xnu1w7hMWnQx5q2Kjq_kmp3_rROXe8PHgSHwh7MS07CxnHi0j7BDSz0zAqM3Jj9scQCgne8_u1aH5i4ti2PL-0gWs991ulG8OX33RtmQ9up2yDXLaLB2FsJWqlsEWIxi0CbEQ9vf3GdC_xXQZg_Ts3MEJko_kza0ALM7W4pBpUbv2fnSMX6IAx_XARKFCnwZHErKlHhpurZjlMvr2cHiWFbjw24_1FftjsnQjczcuVpWyfcJivJNp7eoyJ-msh08ptXpM1KMWrNkIpLlfSR_6kb9xrPK_RBiqefQVDwe2eAfw6yeCUg76gwSLyn-LOqLv-KcT-4mMk-npFfVAcjcbNOGhqhaLxMZcdEBe0o991TOH4Zkjwuv8rymhXOTAHC6fJ9yb2EnTT17vFhLf7b1XRU9godkKdW6MlzteSatCgo1xRNtoSwJkN5OxzwqMVWkn_rIfSFBnNIzMUbWmE_jgB3mmhpBz1NoxAGRqA_8DlgCwVV4vv8b3Mw7eOe1GbOTxaN4jEr6tfaZM4vhRJ35vMpA6SNAi7yLh2aFJF0J9cW9Cv6rnSqXOh3R6rsibBLqIbMouBbtR5BkdPgYGF4H6JGtgACHq2RoF0K2xfJPNCUx8FlRqRYvCs0aQWm5-FriAtvRXYwgQzqzlbTI2L6LrIKmCNNXBRnsc_h6mMZk-c9XR6UD83RiYqXb77zs_O_Qf1rpkkIbdthp2VrqOtOT7B3V_lWwYJvDJqO7-8OQ1lXUnHJz4vwYsdn_eJF9urb9ilEzreEm0Y8qHaegUHB7aPzudfMb8O45HFo-gicf3HYgbKrfc9iC8LTynFQGFP3q6iqRRa3SDd_SuPANGKarmZ3V4Z-FIBDZny0ucmzVhp4DTB7LkqOqfxIOFTarqEUQG8jf4i8THG61zgMbZXrvrW8G2z_MZLXsDV7VAw0SY5UobsOwiLhGQwpxL1IF5-UZd27riT2UIxVUtQz-TgPfs65NgiVPb3uo1K2BiCEfwk1kisweDguWCoM_CNmbZxcav_qbA7dJLeanVnARssW5bPGvurupioATC0vu2LUStTDR06_MYhYPh5MZPtD27MAMPd_rNFJiIT2nebdIzrsYEGbr8G-TGdRQ2kSV_5kwaMWew89Q0h95JjMed7BpitaRh2uqYgLZfdbhzW0m6Oz5h04gCuQbgMLUKTMGq5A4a0-VDQXX54J_JeBypplel4bcIakM3VOU_sP4ATlDYGfjTp43cg95USBbEzK8jVi_QUnZ8X9Wol-4BqUR1T_GL7SxmXWXIJUrB9aKIadhRQ2uPeekntq81A3a3d5XTeOMPhE9LOvlr5SruNwIvqHaGnWro6nfOL6rftL44l0XPYzqJY0vuHiavSEeYyRnEhLxtEflUuQFU3Lcec409IuYXsW5EASQmCrLRi2dbMTH5iK7NBz9I8FFTLt2aXiphur7TA4vU-1PG4PJfpJTJ8VUsRcZIOSXL8UW3Daau8L0m9fefkrjeq1Su7QPJgKaG1KEYMsnfTiAm4kH-00Jv_P0858WM5txmpN6lDQ6pxKkxK_WxxTbWWQPdd5bG4wMavdXNiHSQFjBpd5TQhdQ-NGl_KJs3V2NxQ4mP1aJ8348H0N_QQlB7-bq-gkMePTtPnIWhF-clHABpxcpGTBJ9O9TUhtvEIpfVoluF6G96X-hUiZ_iMkm5dx3fBdpMpM4cFabiEff_qjpthNbAy96uAQxj5_glZITinn0MBmRtND8XBQR8CQa1jSIIZ5xF96-F--hR0gmIcOotCcPzQTVc85iFfBxMGrVkXy-Y4W0zQHOt1dEfs5cS4A0-dqWxh53M99qcFJ3yTTrpt6FSKBzIUdgoZl2DHKTVxgwSPxpGNtwUQTzgC4j9_iCfUHj9IQPV-9S2_TwqN7qQiU7nlVVMLcqMpXEQaLvwNikE-UN6CQ7hAgHCJfrzaJIL6ZuGtlCWYBvkJz54MmVtN9HRE_oclgxn5sTLRbFGRf4_euW7hwRPGG0vR2yqCBDIF14BmK7Xt84CtxeT9nltunIKvzjPYnj-_h8tW87Xz1lbcGh4HwF0YGZTxO08d95xDessen0uHba98IvAo1MfYAZbjjAQxsIWjtZyptrh1OpEzC0hKvUy77kdlvlgaVDFLzhzJzMGGQYyJor6jx-KflMCALTSMmER6yKWleRAsfVgXCd61LL2niPUwqZ44KNawvxnoLVA4r1O5gRgFHPgafybNi43Q34Eqg9aWMx8ylDEw8HSi_XPWz8rGPKSoGfNrekHZevAz09bubOBUz76fYHG0EtlNCEOOZud4kzHG9EaC93MgVC5KsusK4DMA_7g673W5hSbOGhfevHIL7baUoBOkEtBqUqbhxx_ZrFxijR9YPG9A1sH3gq4YgpW47Pw0y0sovuQkFC1Fku1Vjj0Kl8-gDoZgNVbPRO0fjbU4XvV873IyXqMoj1L9KArXCwCqSbiQ8pif5UfZHx63JYkGXflLSLqhN3KTht1B7nAoaBEhjIcHvL__48AY7OgUDKqcfa-dYzGWbxn7wZNRN56pNbB-yNSmracUHVONG7w5j7gjijN2aVNPhjviGWmREPLPPWakedfo0LHEPYtn7Kvamwq4sRCTX_ytTcZAFYAG8mx4yZ2Ivp5jCAjofdS4aoGH4zC2Ix8b3_84TkPMitx3vQo1mcIm7v5ozSX2ul9x3MukCe-2r4rfVnnhbANCMZlv_Ys-6akN1xsR4-nh82FT5s0RohrwBGrYOExGBy3ZJbYp0BCZVpTzSnK1uIYFd_Y3x6oq2i9oNWbwQZIOTSSTdr4hJVD-8F0LWQH60AQXaGrHTOlp8Qbhycsyozpo4szbLjj4tUj3L0beHjNZbgT8oRjuGepxaxleaKHd9sfnPKRb1anrqO-XUmyWjDL0XtQ_T23Fvps0l9J8OXhQvBu6Ng8XFW8s5-CTg8TpPhOGSPvMYmFme_7d8H65vgyl9abvMrRUx3rEy60X4KHwpJZrMQXIB59PekSI50NeHjgb79wFezIfx4slfKQ5kPWp1dY9hKqZbUN62hH6poeNhBvBwItbaMiNhkjnWmvAZBLbvdXeVprFDyTkJUfgBRcw-caTgtez1dhaHl-_vAVIn1BgRYKqZCnQu8GC4vRefL40yoaAJ320aEsDxouckVcpBZQTIyldCAlGGDKaP5_yp-5Gbf9nvKhCbVP9ekW04bx6ZZgx1HjjoXBWu2A6fXfbRIDy9x3HAqpcHKPRgngj4xMNbkhnXfxVbBWGBdk0LNqhrO7z1glvAWUWJfBzkE83JlSzh1aOLnkTHzV0_GuuL1W9kcbvvHh0jc2j2FuxxNMnfDF1gsrux8bk4DHMUXW25B2HG6AG_9gRmxxp2_jOV7Hhe9Z8xAuVmsfUjAD1MvbO99b78seM1_wUOJfCqNa3ljVU3-B34e0wdF6AEgOSH_2cYDopG93dMReKeMy-hpn1NUGUOW6bk_4YulTwgK_1IIyshWRRoXA4m2iyNY3jmlpKie3QexCVOGQEPCU_rM20wt8p9WpMZHlD72dl5USgm1D7Wu0ac0RXJWsKCuiYohaMgSfCiBpYfR1wM_m0lFXUdAsdiig1dV3FFiGpRJ3q4lBAYGqZ3mnc6UWVzbo9qLkrevXiI8b5_kYKAe8Z3yVfW96-lk07Sc_DF3_XyLcg2MdllcNwzLynKl8Mbge8pwSUpPFuBxzbJVGxO2pymE7d98lLzKF78CbtPHCphu_WEO81bcQSDDK7UGZwFGe1RzMoFEwiExt6Smhi8sRRl2wSKskk9ft4QS4L-G6VMcy5duwCHNWlYocDoFwFpeKEa_UvvvnRupqyisxY7zv99rx6rWqvmMEhs2dqjFUBf4JNSAhckQOGxySZAyIXx2wqrvAGe2FQ_ga9NxqvyG0rEMmQhfwRM3C4ZRO1FkSbD549BhhpCWVIV1alHXlYYGJHpVIIouQP89XbXPJTm6xQTTkUnPJHRJOkNVwKZP4wwGrQw4ppVXHR0WOn6ldWBbneC-pxk4oIxYp3UR2r-lFZUP8vp5eT6VfbaA2m_3aKJk1x-7xTtdUI7zu6UY8YuY3pqQmB0GrPlfP7E9sxW9HIpi-4aOmP6FC1A0JCISAAmAsWMWrlmdUvLIGcE4jTY_BUWWqipPqHr8j3kxsx3c9aYwdup8Pu8olWahZscu0TyCBQyjQKwBHKhtYbGoJJ9vSdn1E0i065jComuib7MkmOXUfBq_sudQiOfwh-InfF_v4A3kgHAmSPgnQyCnB13DA2qMDHvoaBgAvNDGnEBN4-0YdmaVcD8rxLKpWyLMBlU7wfY9biMNGwSOK8qzzwlaYjldbSphM5W1xIs5TrM9GDIex5brR1W9KN-Q_-YZm9epO2cpo4ScPlUPIzlPmxGvhKac5Lt_-sITSxhqqsqDgH2eZtAS5L5A_pMaKNzdjHhMsHiuIWRjq5krkvD5ZjVgjDr0-JoUWaFcN6zLUfNqIRVmOf4rD5hRRgSuSvnnxhunD0cK2Shyl5q7uSy7qg0JvtpNOIzF6pRVxGbJ_iN_0XShIQz5j2AqWdpVwmuYcI5kqGQ0uBLRGOBYvB6Nr89GU9OLxvo9NADYvcoVNcq2fadcb1eZODP60v5RlIPKu0Kb-K47Qk8aOwkx8Z3_zpaUyH6nbq58axK-AeXw3W1q_xgPCwheQgE7sCeRqAaUBZuwf_vhIop5E-me4cvrxgnsuADKgQx5hklPlwGwYoVhFg0CYL2Fr3nxNGHiLQCemMxJsF_N_bf7p_Y5M9l8H-Uqlo7yrM_gQ7AeLJHQKnYtSCNvNg5fgy9QQk5h3szf-l60RoAxMy4F-Iw1r5fFdMMSnw88v0_6nx9xZ-Gxo474zmW0X0CwivqgmO_xCbm-Ix-avLAcH0VJzr3Rf_Uv46j9NqyvDmEqkUlpW5tVY9fOERLIlpbq53AlZreVLJ4-oyocORCCE6TBXh2XMqbkmVzN0BDKco0NlQ8SIAbsARfgRk_sRp9u4d7uopK8r8zEpEQvng6z28njI9owjh1gmeNowvOJyMKuRi4x4Wu4qdPxc9YhX4VfwlbU6ujPj7-DqqBMLK6TB4c2obfweLTU0NoVB2nKVFy3YModaM4CG5HaWd7IWTpohREiCanpTcvgePxI9jVAwXtqizOrsr03jmSmzzi9cywZfiZmuT-Vn9I3lKergO53nnh78GxvlCI70HxSCpWom4WnigRAHBYmRsnqFS9vu52rC-u87BJcbnIimCF9DI-esS_Fl_N6RsiNSw3EVaQIEeLodzBup_cWVx8LhmbJ4WdxRcwagOyrbNwaSPwwlmKBTU63P2QEAHUo84t6uaq0TDWLsNBnJR_Iyysj6obJN-d7bHM-e_WTEMD0N7QrtyUKNNf5pizFcWOm6UJFJJL6v7tBDzhAvwNSKrRA-4kVzqN7TwcFbSyRE-XKk0Q1CrMhE1QrCfaI2XKtNQF7dRJX5ghV-A_0IwBOwIZ7d9cu-43WEBH43ujuO1USskWEzFKrpn5I7o4iBQQh_kpvH-K99oNXbeGXqAUfaNIoGlKrO-rTM6lFbVCirlOlG4a11N31-73t4EC73chNP2eHomh2kpJIausBEeSPVuL6i61BpxnR3didMFKHXmxzmEiRhahWaoAauWYa3gNhljgq_CfD9ZC2W39EqI5Qv3hLNxHO64wqEUqrsSP2X4aZ-RCb3ILI47KjG4m2dj9-qIYCqGI_9y3JfXUr1xz1bwG-Py2Va3O2QnZ6J_HNlpBSUWa5MOKz_5xdQdk9eczBRaM8lRwEJO6vmQJ7GeSat_Nuj34DhBwlZRhSwVi5zKQ3n6nmjeiVN997VDCWUGE4GTmevffgdDeDfFBhsvLL5a_4bD5qd_Wbphf30znab18Rt5mRltQBEpaPwr8W28D95bNNAUxcsWvOdUm8S-l5pMrgeklNMVMgcahjY5mSHlDFq3UVYU1l3gv3gUd1Fsu1VlvLkf9OiKvzoG4bX_FFL7dbByoLrTqRullF_8Eahu0t4YV1iV8JmvE8hhyxJNDw5xJw04GRuo_l11pHuY3Q_Rk0f2mmTqNMQJrUjlE6fLijmk6eMGGp-gJp35YySo4KPVKzkezb9TTuQqpAQ0fYvPl9svF0LemfQqzYmhBLLD8ECzXka2muj7xS7NrDIoLKBzJyUC-qWNZF-fV0O_p-yoyD5vYUWRouc3BZU6kQYE9jV_WL-oO6euHoesGD_92DnI7ms8EpkcUIF_XQ70ITFXZ3sPzpM3VLZX37bXj8DFpD4U_dTCDZpU7GBg0tL23touRLI5uNMwNjnVuqkVsvYTA10enwR_bGyhbYP2mM_KN1H938RJt4y0SZ8cd3fuk3GiC3s7mVbVEXXdkoo115bGbt-j-KkkMMWokxJIVNX4n_Oiemq0YAKBJTY_tR_un8pO9cz--RrpoyMVHLIz9UQUJiMJ3LcqIWRwRjcp48oqR9Vdx37vvbIPDlP8e3hThbGosEDXeui3G4klam1Uhj2uz5hyZo3pSU3edlx5cCxbCUm32rVZ6Mpu85iC8_52n4C_AJhY4yIaA-KVRxOuAeJ-NN6EN1lDdtF0E75y5YXroUOUwkg7lP2nSFqLvH5Eh129k7TrB7UyezidTHttqFbQV1XF1ze_R_CxtuHROQvMTRz3joqBhQ1htLuffiUbNzEogT5SDya62FhorE9O-I4kUAd8JcYHi2tA1WobF2AUxvJRWAgffCbPp_mnDf0FUxK7XgFzue9N1d8BkZpNfvN6qWR5P9X7W0_czi9I2kn8ARuLYe1qz-9TfbCjmgH2-gWnDwO_rVriGjy0tWTsOTRKOGAgdiyaChV8bhmpUZ-axMn4WiJzS_0GBqPn4LUDrf180dXkWVPWhYZmNFUyk-lGiDRvGayw0YW3TCJJCNMswERy26sMrx5JjDPoZXEBsvxZsq6lQkmWjb50c_vORk9858BxT3Nx7vC6CT2jVVV6dSZRvwUx6V9dfYoOnI6rZBLkO3CW5-VKJohWdhGhRPO-tAAHSyx-wI3_0EKE3SvCxbmKmh0fCqBy5cpkx6IdkLuWG--nQIREb5H2-Ar7WDdhgl5e2jRqZ-4B12yt3bK5aAN-rpTPSs1zvu9gQ7uZNnkMN-JbVQN8rf6w1HjY8C1To840pnzc3Ic3D9wQVEAPBUakxy4yc5qADcbklKxQJ_60KZaNmcAq8JxdXYnui0AaphNcUfE5e2lnn8ljsr9bHF1fGYMb7g-L_LeexYb8pKQ7CdXH-rIqvELD5QS-xDg0nhHcLOXovRHVANMXaHpyWYqzmcB5eUH0io4wuwuJPbfllqr-MMsP2zl3dq2e-y7F3rZGwv-C1ZtmmfPD7pBzFnJkpLRygf0yVGzES5CrJiC8OYMvAax_pg3wH-HludEoZgMTzKIK637yAQQ9oT8ttphnVtvSkDw-CqjNMcXO_azuFz52teTTP8Z0fIf_DNy519Yy3ml0ROibAMuJC4B63DBVrcXtPuPVx-ARGhU46e_1GSq92Y08T2BgezQR2CA0eA2cABjf_oCKRXCqS0ICJ_Rp6bGp20K8ZLm_ck41oEZEm7R3cjeW9YkUXkaw9dqmXsP_DyZNyU91ZkLvSPQ6jAyVKYrEgrgfrAzdA-rtxUHRZ_fqa7b8P_d7hQe0K0Y72PI1BbB7EIb8Ktq_YS6jRFvfzorR-NQ9QbJ6OejmYQTwvziZJBR9UIrs0W3cxIffX5h6MwXI_6OzqUYV4pkJg00SbWwZgaMWM3kFgJtAzEt9lzt79kVMSFVIzAp9YGgNBfzh9EmCIhteLa23ozDVfei67nYm7lyRtaNYmPVZsZcvDG4N52_zDe1aQWUqwR9lEPcEuay5plnuzCZlk41Imgrx3Y5S2DTwdhvlHXof6vCB8FUQBHdzLoEBsIAK0wWF6-8iiwPRfB91iig6amRdpkuNhNkyuayD6qUyquqSoqUPmDG-Hb5dmqCwResps4RzPVrkvbMCmHvmHEKjOygondSpmeRTzycHPdckClnTHdlDV_lKHYkiSUfypLOPb0qg0qvnON_CzZ9AYUiJmwRopBJf0JrcXRNjdkOvnX4UvykHUbX3GFoninyjAybngFSnF2ghuZyKM8MYuLisa1moZ-KCxwasgCu-RpgnwqIBhX-xt6Iv06ZEOR4l9GX7h4ofv7Ze04IGfqpvzuu7YVgYlf6CFOE179NmG34O10vcxbAx7HRYsRmzcwu5Gj1enBtKVw_RIIbTetXoadtZVyPud6g41RBSJhZlrj-CvK56ZUba6pjSS4EkkqMFBSdEQqNRPNTH68_7E0JnX39sL2-seXRDEzTURwKw5SoRgspxHt0KklxYmbXwMAdFNc3-vzcfsq44a7MuP8C-mdmT1SpvXffpGbABMIkdqrnbb4oUAtFsG4P14EHVQBoTmA2j4kx2k_Bx-UNW2EDEW2JvOh2vDDvT2QYN1JldVro9sDRQPO7VS6Vx-CamtnTu8AgRWIKmMJiLggZbMzZzNvZEfHp5Ji-B8-5EZei4iquE8Zr5t8jfGQyMg6_BpILmiUpNrFZ-AxfAUHvqefjjHAcrN-EOAjPrzSdh3LBsKqeBaOdgjfFyjD0OEhCk6oekmZyG3fNgnI09fOWs7cAXOhK7lAMrqthmXiZiQkVIENqY4eLaPfheChYfk_PBe8LrWSoyPHiu_lshbxgedS0Aj76Mb-L9LXUcTBtCuaEekBDfqqMQuvp-LZIH_NyS7U9yyAggkrkfaJuedJ6YSO5v4S0XMKTNMg_wpA47CX3FWnEwKlZp6JpgS83S3dx69_fA4nvaKAfaHMoSjFt7czX_UlUh4CW7siQXJzCz26suiBjEd1e8Ydd-kaIFIh86GEFZLMRn7hqS93pkFN4Le6Jcw-Ih-2o-qfS8cvpDzmteOCjXNllMVtKK7ctmHNQj43o_AIqzpZi8gxl4fW5wzj_cuUY_fRW9bs8PiavqIHbn9fpIxu1FnZvVBOl427VFI1dyvfNB_FlI9rtv3oTppZEOQat6raMfijcfhaKDuuIwJZlAv89NHRLhQUd_n052_unODH9ExpsTPSrHydnUahywcI9whxSEnWdUX5lT4YLQkOW82wRcozWrd68FsoAb_trarrXhqLS1AWJKOKBSLqOMmP55046vOF_1OLShJn9oFAC_djJwMLyxLHPkW_Ly2vSD4QXROHVaGLzpo3l-xdyjpjWuW2sN3DAdGOMQiJBhuDNS9xNfSaebX8_qT59g7yi-Iyme_a1h3XGFM3QphEqdSaSGOEYwMq7SfJRXv89NV26MRni7YxRlcgZSQnNye7AK7lJFzbHQV4hHASLeFy0zvlA7ZZ7qdomrVydeS8XgEuDXhh63HbfHBsHUhiYDaN29kHtkmCvvOSHARzPvuHkheu-0V09P_m-lp-aKVP0PCEgokhLTD2TIBbY8lOyVjSaulNsx6R3CxwXlArkSZPaxWcLbo5Oi_f5CnfjUoCgKi3cxO41FQu2O09Hz1S-3sbK4_t5LZcvKjUYDckPNmfpLBnd4z6j8BCqFTPm1aVro1Oy5Y6rKsHuJLIkNHnCEiKCVgrSq1mUDNebKDeohw5s2Xyy6iqklk0Uf3xyKbu1eaGKpNbrdMi73Mj7NS9TSO_bBOtdlaL9Q6rdncQ-cRZP9t5Wwj8wC_sLmt4P1i72i3r7hqCng1rzjabfPGEzPOPRuqY2jHEXqJ9GEugn1L0sibRIIe5izmW4h_OHAdC9s3vHF-kg6A2Mr0HGpnzO7c2PBW8Yg6-368Tibcol3XRoDl1ESl_-lhuEjmciyK6aZC0F037z25ducABI_PzE2B_HwvT2vksHvDmFkihpP8B2xkvRN5m6Par-wTrCp8X1aD0PRSr-vPb4Giwh87zyYsqagpP7TzFA5GDcEfLMmZ8Lsr01fhP9-lI8LLabBF1QjNyuQiZOsn3N9-IWtdWqM-XiFAUgr5GmhT7EerlIngTgiOjtgDzQy2yu1KNpsCb5I5ghOU43W4SOXmttw9VqPwGhY2vyjf4DniWUyXDEwZARVS61_I-5WmYHJclBB9AXkuYp6dnTExGNQJJ8SsiSxQn0wsCWostmbMCJ7ufKQbX_j20hWF0IBVzDNO293Epd3IRpRtJ7VH8ozQFNKBblAh4dMRaDSln5r5PhPDVOe4eB0bMCxvxkX0i-UCWl1C4Ky40mpXqj2XhVjBJUfVsRee1Y3uMvciDkavTQjxrLNEwcCzfAGIKu8ApEsw_miJCis5jfU3T1EBmoSIwz7gsgAkzwNEa1sOgYy2Md8KwXrH-wNfqBtmNceLHRg1HIfrAllm8etq5apTogugIaNSjEKThe-brHMNhu8bne1R5dSLNPafZHuK7Ex-bgyx9sXpnnCjfIk-tbUKPHq0LtzKGFZyBjTqo8tCFqRRy2uqltZH_dhF8utywYIFaHuUgNfIj3p0qhMbAcGJBhE5THOl7yC5S4wxrc3756OT6USiAntMZzqzt7Ka6_iZ8F_nWzK40UMcvB5eFdNorCjBmyKkxF7EWoiJ9DEmd2G4BIrVDBlQDOT1A7KcwHJvSa4b32IUp7VecP3Zr1aqdM56p5PS5M93VTfZoulEsW4m-GmYxQix83Q2pzHgQ3p8Te4yyhtSINxe49kxE2BOPNwG9tfNV6u9GeakyvHBr2drJZZYUrBVQUfINUbXi2jILu8ogbjJ339F4LZ7Rs4ZfnxYHwlYlRnSwOoFIyQTjdtTaNN8O7aNzZGRl95twAe5tM0oWkF7hMeV6uvWEuRYEvjLWxhafnEcnXLLE_VZkySZbcx73rhJ7w67BzeOiuRdI1l2KAWaqBIIDe_7VfpagjU9Dfu_vtwKRhf2993KW5NQbFHwGSa1rXsO1tocFzRxudTzBELSKaMc5gLW85mGlC5MV-zVEKv8djXs15UuQX_B0F7BoKdGFGf2p1hpUmFqWUiAgcx-kp0F3CjGh2U3WqvyPOSlarWpBulBuJPbEKccYm9rpqXTsAa-EgkPoEIK0Rt6gD4J8k0jFnOmjQEOCwS1Fga7je9R7N6pweCZWxuZk8dT4hyEYCAE3ofu0lculRrMlelv_jBCgxwyALhZe6SZYZ2zyb15gsCqng20a9fWG0RpQTpGORmAN25MFsADBYbWDeeByBDLIMpmvceG6BAXJmmA9uSjqIQ6k5Yf6mF0X0QdLqsQ6AFKlFFfluepamOJYpDRyGXdE9SRw1iipG-PIDutn1ftqrYFpxx_hunF7uKYr9OxOLL-BYX-Iv2OsbzgQVIx8k3KPS_BB78l4V_dR3YufGOTs0Am_0DyJPA1JgSIxxdOavjcaCxA5b_eEemLSoavL7chg6XdAqjLV-lYgonAm7pecgJ6Pslnji8CESWdu69zRb7cC-bXOkWn9glM4NI7IhGHUefsDx5hvKN08SH6heW1pma4A7MNqGt-lLNK-LHpe-wdlwTddPK8lkCwJgx9KAWxqQH5mcdeVn6E4i4VeGY6O9_2M0ghFUG8PSYCP-gUGbNa0VvzhaWmbvxdD7lfFgbuH75YTZTTX5DQQZqV3lNKB4ujIwYSnKbHXYDYYIQrEg6yHrqde3P20ly4lGH5tDUEd3kIWoASGCV7sNFbi2NxPQDibch6Vu7zWRa81GdT2uEtbmDkXPOVJHjLaTSIn5rZaGUTY8vtBI94cT4kV5vBUUMheCZVqMKwdO8dkT14gaV5JW83jUfbLRxUme4aXQfEBLuEqpvHujmo3Pk6iX-daBnOo37FoZ1YZejkG53G-0lQT2yY3iTkegmBONs-3UqUbtlnIawVPMCXvwHfTA2AGf9kGv8fWf01SQfgojeoOHEx8dtEw_7Wg_kfP28bqVOxVUSdwayIGyrvzSOg1x5u7OsfvtKmZUwIwRUaOW2bIOXSQp16-8N_5DZUOiWJd-Hkz5CJtR6CSfc-cet14OITXeqgFaUlsr9Mwhbia5m6q1dQxI8s0ugUEiTiahvjszUThvMlMuU8di2OgkOuRf_I0I4-L5BRGoRvSSUIAoupp6Lm-3_tEm-G4n6T1z-wU2jxKaj_Cvx1a4k4HLwNoMOOmZ-fERTolLvc_NUREbKId_mN33x9G1QRH_Az8m6sy5Z7NoiXgKAujpEZjJsl9cVqVTe8inHw4fdVNubFP_b4hR9vQukNcOKG0Ws5wtvvir8bj1k5pF0L_4fJbpBCJ6yydOqeVrco1KXtA6PwK_oFyR8b6LJqmrJZBnJsZ9jUar09tNQJK37ZYEvidcCEVUffSs6sBen0XiarFSo2-cqPAOpoRJtVb-sSzA2uCqUKr5_LDT5iP-PHTbJQgBiDOyWO2avvTTdsoL4s4wV9TxQE2pj0E4Ufe_kjAqLvP04MoH8yMEDZaL-j0zIoSi-iy6XR8qyv3GIFGZHyGEykJX4Lwyad1AkAxUi_4sZMmIE--9obVwt7zRUrEPOF9tw3-nvgq_3fzhr7Y-c6lQf79sN6A7ML3k1ZSK2MW5YDc4-gaWZUt_aWyCWY0Y8QWk7dAXVKb7QXEZ9B8caJOumCH5CzymeXzsDy9d1uAw4BIbMH1trMzFJBZQG54dTOCQKc-LSzbI-B_G5UHfUQzoM9uUl3_mpAWctHcpalumr6s2pLDDTnV-RZj_5ftjtNVRTDMZLDDqPJltCIu5OZjyz_d_CXD4uAVMgwIsWf02hxXlaZ7R2_yYX4U0RQrWg3Sdc2w_UQwKa05HfNs0QrCzEYhkBemyrXL4RM_660Yy-bbUdrOzTTs7a1UZmmtl84mqmWYamaUogzsvTORwsem3PY3sxACHqf8gSVWbEpbQG5ayHngjCtSRBT4-1-t94zNGLQaK9-ZWk4nvtEr8ZZ1g316U9ZhWU3MXqXPomwRr8QmjX2mXTa7SytlWygL5FI87zKzHm2poXr27zQdpVNthzpLiC8KDL1N4G5Ixe8q4CnehlgRWxcYg7jsu9GDX7r7ym4rLghrJWyUu6cvhwJsrDD2O3GZ5Kk92cMiC8VPiY8wvmPuvguktKsSrsjhl5jPf3RwPzUZGIlvYufd9_Fx19e8pvr-R69pvw6JrnKKOpJvfXb6hJWvvWX4iZCzQnCeJ1JUO-CkZC6eF3kiGLTsnZqIcX9Zs_cEWNbwEFX9wAMflLoRkowC1Tz8NaOQmQ7dMdWVnN5Hhxz8ToVt8Dga5yv8LilOO3Mabl6jBa-ax-UXcIwnPjznkXbB9tnqtK3_GeEnytxvY2LAO3lkTLxg1u0e-toHIGCeqWatWRuqy7j0d-XJCELRzqCY1nBIsOW-vdpVm5gkT7lwhynTfrT-edxu9wnCHa3BhB6UbwUji1JcUzjnKEdP86v4Voq-3Urm2pKLP8GOURXbG0Kh1Yepz2M171Q492-BwBfQP7BPP3HponR-Mx8C98iKMguTgzawDXeDWOQtbx_kJQdNSyE5g6pCabqBIJyENlgT5SusZufVlUhxqfMmxwa65IBeaOAvrBCdU3aDTgoGZOmTS1VvE28mUT8kOoe7v3gjUyZ3AF_0OB7ga4aQH1YbyCOd2xdlIMKlTnllqBzSRBPM5j8KlnAuPHZGAyldX7c-lpW_C3wehJ4gWgh-Mzq8sAqHdCkHLZkM3dmSAFBNYaWHM27vki5-vI-P0KAZJdT1oA0guqVebs0wCLC-L5YmdSvlebiFq0z61Gkj3h7vPfG8IALN8DJZVLmPQ1Igao2WBo9qVxGMmStA7Zm6TdD5-ioF6Q2gQ6WHL9QS1hHEo11EK6PjlOU3uODWhlDdde_zo2QcmbsOphwYC7FixVqfITTuUjMKsSmq4G0mqhsqBKG7X7qSfi5pkzdU-AboWkwmdJ6EytyVG-bzPrSn2SA48wUFVC5Yu9a5ag1cHwQPZrwz80mYUCJDOVy9nVKeC79nLmUc7n2WTSCm6AN1Cr_ApHXu0T6SKUgkb-B9oQIowNsXtFyBRNvUlR7Lfgg1NntG19L05w4l1u7ZJI7l4YuC5rYvXXzElM-xRGbQlSeEoEnlKBjDFQcBU-ia7cjH-Vyv0Q2mgha1KMg9ZYPIuq7vjN8PthnPzaAFFmyl_M6Y25WdosbF5Tzlb4b3ggWXuqlII9AFV_D10hUzT5wJu3ZEvVLHl1g5uuDxdWO3-fLbgUGj-cMjXUM3w4JzFAr-x-95wjb_t7byo_AUDmIzr6sLwKt9zNLo_xG8VFqAGIsEKF_3y9cUrxgIGukxq2yrbrGVzuzdBSvyawfIbwFUw-let662D4BQDaU-hxWVhCiO3XwvCFMdx2139Ji6D4CvFj4MdbuyRp-xMhnJdnuyjZPsE3mg-WUN3KKAV8Jzk7z63kTvHsPgK3oVPog6rjxxbPpgVU8u8GLbSvwGdalxkhvi9idUZqMxKqcNsH2-Xm0wUzR0EkERI4mXzlXHl9x-G3A53hT2XZyHkGkHYFxeRgZP66JOk3Hvbd8SgVeFJyXPa0zQtgNyqwDy2pc28pHAi8pq8gkE-hcdqaRdPryvW3Te-qK1ORJNAXG71he3nk3ejbVr7LDIxvzKbUkMbAD1REn5B3lOqUKRQP8-vLmdgdPC-ewD5kt_b9XMgtGb8uHQIaJM7bb-xp0zlUU_-ZTK-GOEdthbT80CYyJ2fK0dcYXWjFgqhRn9Ha4MmxNt3N_F7J9zqSJiVJ4vidKqtuMZUobudNbVJwUsMO4Zs2rsBu1ddi-rKU8QWNKjjm1i3HBMFdiEPnfKGnyD6NQf2WfXIb01H608vVsErWbmekrdQ8g5rbDh40jvG-zANMTSGJUj3FBbCxUuR8x5SB7bnqbCWHcr4SdvRG7sOb8OcpwArfdClfiiwo0OOMqoNpfSYKhuLlaRe2VhUHORB7unZPUvX4brps2Lc2oMaLZMEo89nVneVBjIqT9Lxn7FmXeAEX7a8Kv3cYgXPM7T5eJ3YzHSdoPuk6xAPvpUFMo3AfWgZvYpr39ZiD8k0Li9QE_jGn3dWtKhnAWbxlrzM2Cr5YJxoy6s3ZeCLiUbs3PK0zyqYp7o7MmztyAH4EMPd4wr-XZixHn3jAnf-vcMiq5c1rwOv7wJMdBHYdoS1FMOjeSkFJKokdt9Mxt9wMX_YdZcku4YsMDqjjEA6YaTApMGUpbsXJzk3QoS62IsWdL6QaPrJNyvOiuAmiJiguGm6Lz_BufQR8EjLtnqDx_o6nC812fCeWBhTLJt55XiZ4xtW3o_GOLhuUJaTjCny_oh-z6V1zg1MmvOjmYrVRtrH-roWfiAE7N15zW7DMWqXNos8I2xYgRhAwIARlvrJW3JwlOVI8VCADActsQZ2euXG_ZsdEN8X5mtLD2SDFlF9LvyyaeZYR0bgcskOe4s-pq8Vbdqhlcn1qIIa4AqZnAh2uj8Jx6heBxCnsdzcvft7SkU29_s19xuqVJymfIPxH_NKe3aKho5mwyavwja3jsKKKv45fBbl1MPg3BIenQVRi5FCDZ9KZVnYa57mr5ImgigMX9CMN01WTQu0e-jCG4uhOfUiQyNcufWKLwmAYxpe0w5x-6gsWJn9JglQZkSkS0J27fnzl6EwQpc6IxAaWR-QX5oQQyUBkefHs7qI6n9JGICMjZd3DyhVPjOqKpfdShKivP2XPdOm0WEMuQywEF91dbwexJzTsgmRLf2ZU0Mn8VRFYOyJPRALdWbaBxCW90ku-0l5BHKWwo1upj384CSZ9mK5yxEGdq9w4u7g5mIWecj1_HluyaXTidBPL0t8L1Zjsa1RzWNcd-ESZRNlAs_3H0HAxNwnZeukXmmMv1-ClnoofLwXqKDYwYQHCFDHWfKvWXip4j-J5XdfGlGNQ_4syP7OrOwg7AYaTtRoMYzujsWW2VZwjRHFLvUUNPDZk84I1rLwSNKkKdkV98FDsZ-7nHHX0ZVKpoupV8qBdEyERXJWKlvyYoObrVMT2aIDeWhd6bVgcIUt62m3impLVV1PlqmwvT9ZPdFJJx1s-BG0Mijg_-UZtGA0keHyGjPJqpF5Lc6f_kglZWiNy0c25z2HBBI-IblXrRZw7rpMIdMei6Tlmqakq0XGhOID7_Gpc9895O6VFmoidnR5xx6-C4fF-8b7ZdcG8C4TDmDDL5mIww68W00UmUDZQNOQTrsfZIiH8252BpIj5zJsdIgN3ffIZY5FKgdqX50N4VNaN76Lrw-pFJSCbpRKTPBOP1bN3D9Chk872hK15GFPoLJfCb9f0HQrjaMMO4dtol_ZcfVNa3E_nO7SIf1pAwILLgh_QUdfEBoOB90pMvCDOueakCCYrnTgttJIm2NF5X-1_KgRgtpNa2FChOiWjowFxp3IAzBP2yVOqyKw8-wPOqMzz9YIkvuxtgBEFhKIu7VB2jSFtAPTcnfN6DbJdL9jjsHk8C5spbCYY1pc6Rga9LJRXlpnKJQbuQ3Vvm08wmyV_jnzTy96-iXe9Z6xthHYzMaEvuKsDWAl_FfW5VRoI_YeBa_EMKdg3ZHmf_0C0OH6Pp1k9FwcKsilUhqTWybnBqFUuRnpL3z29ag6LelVM1Yksqz_3AI8hgr0eOGh_8kyfnggnShllZJRE-l7Bc_Xk93mpgnnkmmTqH-yr3TcBGzSjMN5_BmL7fRGfHVtKjNxrUVl74Hb3ryJZWCVrl2HsWFEP5zgtu0mQDkqcPKx0oEpwAM7DqRmY-uyVWfP5vCqa_SK8MPh0-O95xuHmyPJDdh0ZARZXI-_dbtKKBMcsM3FzzRfxVYx0_9bAXkyPDQRByoN5rs8Gyg8oYtZRK2eakcnXYRqdMtbBOnqToCb7XazzN5GmY1JXZ50YMpyn4IfekcjxbDEUST_JCCujX0KJcI5_dy8PJMbKomhTlRsGWtz0CCoJ6WFATaYj4VnCi8U9-Etj5txKe8UAfZTZHyi2AEPO3O0Ze2L2pcfFTHc_nWaIviq-ehGVtUTZN3-BvBDZx47wAN0w4liqjydjAOPf6aX3SIU8nJfTmMwqFxqAsXkIV19N4pyQQInrRv3dCatep2EQ6NE0Fz6U8nE0uhzSlbyQFQsdsZW8wvez9gNrwa0wNeZV6_-qdkHPlaj4gSg-FnNgAAbLqRrv7swmiGXDu1AfI7vKs213L5dbcdk6CPPK8dZ8bBfTVxw7R2NjcKymIYQoYuQVAMtUNgOBcnxST9ISy8GjlxvoXlBpz9Sl_Z6EeBdhnvBUkhSg0FJi-EYzBa_RRR6verFP2inphj-Q0hG3tYBBm-7PuZYRWkit5CQcUSgn2u5--n-wsREjN3z6_tJEaorF4EvfvMrfMSOIfd1mobXQa4-8tCJ8GnCnqfnJbSH5hctBJuHMabeZkmw8jAsQI__31ja1wvOSkZW73LDj6BNbXCe3r5gH71NjjgXf4aDLnYxsEx_PJ9hri-1OCcLxdX0XJlcQfdlo_4S7MHL9MHTOBtoyFS7Axh-o2I7ZbdybkMNQQzDs0VJ7miiRJsxD3Qj9d3_df1tcJbIJn2KYbAqbVf88VNRNIsQJV6UthtleMchlyxVJQY-OaG3dd7w5WIvrKDs20wcGbPuX96OL8Pjd0vqlHZ77BcDdwWwF3m1XuQUAAB3GDyJ19ip1whON-BDGpVhLvoDwmxkYydoJUcCBUBdZTItBL4BWWLBc3dKtCD0klmlaRXNvxTU2mlXL5YuxkvBEytG8CEsG1EzqRucM2YSAn1VEWuGs69CeESdE9pc_qggrt5XaGbONdzVuf7elSbp28cBTPzd_4G8piO7pokZsi7X0I0c9V7YLCmr4cPAleuJSXGMBYza2jpUDbssfRf1E2IeEkNKGr95mc3DoKm4SA2hDhlp-mZ6mu1ENmiN2j809oC3cvGt0DZTr2AKKGv9I_wJ7g2xkkSGGiKA47UpgS9L66G31nnIL-eFDMGcTyQv7aptK2NkdRfvKfwmP8OqzY4dZq5V72Qlm9RVG9FXnjH-IIffgNCJRLpGRB01d1xqmC9E-AKYwk-dZomY4QxPMB6HXYGA3V1ArlFaXyMvSz4pXfzHzCc6X5wx7AqIB_omnEUZk24-Hy_iZDXZeTb8oYmbNzGswI0DRVEbBYGCxF9oFM_RWeVIwcSVTG7tntTA1o3eXgnCYXRtBv6Xpn-GZsOoE64psQ7gd0zvHSPf4v4GwImHW6rkWDuT7KCX-Ynj9ql6wiqDws6E_A9sGRuCCmO6uvjK_0idco5ZAv-Gl2tJ8EhxkvZ2xUoy3wMxuluutT5Dyc37hvr9NTYB2eVqEJkCXDcrQzheKeM0exykG5GtUyzlgMqKLjuONUe_SnA0-lF26yzMhipxmwNpMQwRqWbjZc5CtsweK5mL4BtFiXGgTzd6sIxS62AaCifBH0213VYz7FtdO5ULes4tI_TQcVOxkuFWRluO2HTDicHYIK-rJ39bvIwUpflUIRI00YF-Yq1VO7xZfHb_moJwAucNF5ytgrykBevhXPxV6iaHka0wea6QlRocgXndrtS5u0pbeGnnXe5NywB2f5Kd6hcRQ361vtRiGtwxsUySOZVGjPrfPz23cZ5riMDuiElwBCYA4wWLkcFtmISxX19pM7Uwl3oBTR-hXoHGEfoGgW695i4XlucouAgBI6H5X5w9eAvaO_cJFZqSXG96uCpgUkNFiqKAvTsc108CLYa1NXOWH7fp1-McMxcFUOAHR7UfI4S87H4_TeZ9w68WvaCPV7zmVz7lF2B55vEZKn2Ez7KeACxwYp3QkR3bEClBLr2R1vfqNPp2uJQbG7Rub-jAlKv4038JQfj7QTYEmxUgD6llErR_ZZo9fC9KITcVyNtGNxL5V4oXb-BIPDUDcQQ4PW8hUP52QT6DBsUtFoETS9gaTjEnmdh8GY0WsV_7kHeTGWRV_bHJGLgkhzRsXNpbJayLVaLaIFAL-8Wu_YF4BCafaZneFtf99zckTvq-myOlgjUWVbqbWARdPTwq32HwsdedHjV6GEt6FfYEeAHcfW9Eblg7Igp2Hc1ziAlGarCzkf4tx4ab64hWyxsyqFtqmMYHldS2xBraI1dkk0LJLuklPp-EBZXL_Fsq6Nc2r5Jvlr974xw2WLayAaRC2SblVo9rtmfCsd1WTn1xFY4vhu69SrPzJ0AAshJH52RVkfy2IHeZ8AJtiZBFXHddlVrvM3pPEtvPGGpz6OdXbfhFdz5vAMtcvewUc7y6FlXqqUOnca-WZARkEQATqwx9bCO76FivytGGOiBQmQnK-WGGQtDjaIPmKXk9A6NEJgxxFnDfQhBkVsvybY0-Enst6qSnjWJzp_3CbzkRCkkwKn53gxRqsm9jK8ripGQjcggVpv_9T7PICbD2BUvJ0ch7lnR6H4tde8V6qxyLBs2CvAPCVGleuf7ufz0rh3TTpn-0VL2wGUTnr7LlQ45FfKYIxVP1oTMnp1Lq9J2-ODG1LpA3CRuc989YfklWPVkcn-l9AwNPMveuRuBfcAFWheNT_TBDSKfX-uYYNMmFmh9TWcwx9c4R4PO58-nplsm4JCcrYvyvICAcw7Kxdu_V2ZGxmXjVoAOTnx1uWnOurRPIir1AAlualv4tM64DjLAHtla2GJfUMzaxI36UTn1n8aMN7fu-ZC3GKSmyBzxW-jRQGe68yA_RmequUAPq1h9iQI6KuTE4d35CeEYBDDiE3LtLKpoofpHAtQ5XNN_atfCgAacLAKvQrgTLYp56AQLe8tISyHmGXKocPt_n-gMDFlY6Xcxy90RMbR6lMStOWc9Ngo5CQZJyXcssFIK4vnRrBW9M-euiM7dZ90x7bIPgPS8yAHtNd2LgdbPFkpKAGbcEz4Z7SsCkVHQBjkYfQtnwnX8NuRfbNpAaY2VbjAR8kajYrTcS3TZXeylVp4hTH9621AnezYMLhckjiODlPiaSCn74D1wBpUfjS1K3d4ilrGWwS3aZA_RWAgIKP-S2JqqVhUtPWHKuTDZf6GH3pam08BGmEnlgWOS7Bwn-t484uTCI3SH5fDDUlRhxwR3s4JjKn-pPxakf7x0VcpdBWK6GxstHQY1qr1AMIphk_cQJfI96JQ0Poq4wkvWmjnMcBtE4S4iCaSZyoITtWoieUlrfB9g5FJM9qII-zcJRwBBMTTlZo7k6scxsf2hEDlgqMlwVktkJ0ixaxWQgitsvny6JsQZxEoQWKqvPXNk1f3eDLZ9pNsLZfQNdaxYRJx7Y-y8Qo26-mIn_7-UJ9VLQ3awJ6DvYGdb3u-2T-bFUM_ojuEFcMlpEzBiLHC07DKjdVuAQloqr-loD2IwxiFxtraNRk9hNuyyNRMIME99OhliPmxc3NEwHdSy6lxN2KLWHUb5p5_08Ml1MSFiHh9FUmJvdeHtN_7aVWcLy29l_OjoA0eAYVDilgV6Hh3_wCGHph0Itv0b1SVvzDFXaZBo6dFQogbBF57Z5s8fiDyC-5lN4CeRQY5Czsvlv4P7NqqrNpIyLcDRZWGCMljKBsfF_IXYejW3aio1NF6EFfbzOngLl-oAXzlOCnUbaeYP_GBBTNt9phXUZOTyF-24jTOh3u2BCNDO5jtTu-Mrb_GGEkLw-JbeUtyPuUlt0RzMJIKlrmkgmIVYe9Uk3BuPBTYIfAIqCrXGry5jCwayU1U6u1E9eL7tFD-Bn8cXpiHQo7zl2Y-9BmUtpyV-gdxguAepIXIbEwny_-aJqmdQOaEEa5WeJWm6ULExp5wSs0-sJO7gQ6UhVFs3_rAVc4mQK3tZsIt7ufRWIt6uz2ibrknjagMsWGfR-Qk14AtfcmkcnDy_O_uxiogImq2aYdDzazmSrD2yC1JO9CZX1YEDsNEibjcWokNtxRN1ESwHXLOtbNzOwY58cvg4kdv_1K2SMCR59HKlG7cCDUUwsa3uXe00rgt0AtYbCRGBRRsrlz4_cjPUAURrjZcgpy66n-vw8C4w6K8yGP_9R71obA-YIYp7ijEVQoZRwuQ5PIu__bCA8yMXmP2Dr5BZMhultBKdhvDnjyqhrzYr6a1j5_S38rOIfLZsfSJ_6vjDnWWC0jSPgxRkfiKAKbUFbichEpTkILrdgVPDpzcXdzWFJU2pTUYiJQWXkkP2WmBEMldcMq9KiWsxXm1AgN3CCH60JrARc9LBEdmHt4KpWX749L0L4gVth9Yx8JpF_LZMojJCwx6A1svCJkSIdc3Ugvmo8DdLDfAGjK3dQLWMBwlABKVzuZVeXYxfwTZ6Mxdho1VpN5C-SB8FmQUTjX7-tiwJJoFretNSs1zeYfODyAHD6zzeUKmgUv5XYn2n9H_y-Z_Y8gAT32J9HH1FHg6GtmxfZDS_PN9iRi7XbFukXTatYwN-6JvOmK4UHfKyCn-m3E1mBei0W0nxrA3a6QJEyXYdwkbmD15bTHrz-9e1tUrltuTTSE0gSlnzHB5MqZQr4b-97ZcqAcFHzjNQ6ThegSR5wjieyv0EFLLAFQsHbf2FE5QNHdOGk_Lj57DtyUN27L1xQnmLuB3I6IWm4mCZ501R_YxJD5GiRmVHtwJdnVr6jFAdUALb75k6qxm_Nd8eSiWOkz2YYpmEI3uA8HC-qrJjAFNc5mqtSsimgKwBVp-KgN0rE3ZqHzS-WVFD7akMGphZzd71KXeAiLF3fJM5NCOx3OwF2mg3wfe-iNODCjLMUMtpximd67sbKDrbBu1aw3MkX2GzrytfDGmtjIJDcRT2oxYndm8Th7rOwHB5UmWkcaHGBlol9nR4L3Iqi129XuJTIjxPmgG7zGGLtgVeGu1ElptK-Az5oZ4wS6rIZAVebFH77c1Ht7vxplG-sX8_WeubSEWzA7D45OfjtaWXsvDpDgXD5e-GTyYqRcyaa7-Owp4dep9ZhEr5L1_8Au3DF8NwWhi1uFcPq4-GL4THYGlgbksQ5P7CPl-fm9OsBbfZbYpctb2on-1qsrbBIVy7XqpjyYFQrSUWepRxg5R7MC9G6CSwTeO_BIsaD3FjyAENYJ7jRwPaM2msTloUbQZM9Hhz1yBw8z_D7nwL_M8rW6OwKr2iPBhD37INe4d_zEjDYOeGbWHhdOU5HbErhMgzsiigHP9mLeEIg4Pb0hBj_aozLlafXBvP-PiA_B4A69QPg2EWffv1irfi9JKHVWfQ5Fp4bvMsoaWgxXnRi0jbsVG9Mbn_P5oiMoD1umUr6BIUXSvdvsHhpmJ0988qaU-2-ZzTkM3JW8LPWtakl_BpJ3gUtJNNB2or5ztlcuAMgR0OnQ9JL2j81S4e-Vjv41FGCAhn7ALQlsPpDnteGC4h36fJ9n7QIaSfmr4I1FdzuolWhWbE_JhdtbA78avU2rw-_9gMm6qBLQZ4EzTphYpEX-s84H_ssDVRLtnl2BPR1_XZKN99wcFMhLzM2-bzEaI7OnPZOZrszPb8roz0yWghDgjf94LaYaHFlQrDhAe-VDkgU1t1rsK8AhQQIfV2Y9qfTA-lEmOK6JEt72XZezb8Ok0pqBlhtOekmTc2o446E0ueG2v5ky7ele-AQXV9CMhQZNJbCQtsaNe4DQWL-07JLzJituu-Fnc4nHl78krcelIIAMqHd03VSOXrGryb5aGx5sell-gzdAAaYHhqmJMavDK_lb-zLO-gVeaBH1r_q6nyZ8_tXfoIARhITUrf7oKh_feicJhq1D6YY5eqdlMb2RLscXU4pS6nKrr62gyitFF_K3M9aD6qdFUsdiIhlkEIzg4z52ifU58d92cZQCQj4d1xRtHADhqI1UxEk3dijGPMdUxus-OvgUdLs_mdqHosiK8CQrrbQbh2h9nyeQNcS1dMJsevmZcZAJxlCSQPOT43npG8CQYabblbUjwk9YsgbXTnG7OpZAnd_Ky4L6-JPgfOf5rTankTvS7OyYf1zoLAlJQfRERdRC1CLyw8OGr3ZtmOsZBYDjgbsCiBHXlRvVGMPE473flH0fwF5u4MWw-s56vVZ9scAXtt-eIWkyuEf7L89zTpNZJTSpiz4d0SLe6WbzvuZeLfKnKUppqsF2mqb8h6EpbopUVml64M6xI2JbcGVqwb9ZCrXYWAglEdlFacmhLe3I9tdhHskzm_KMvT4TVz-3cAh0pzNpfaMQzwJamxAV_pSauY9uOUliqGZgOR8NrH41-driRIoZy3pd_nSZpxveamwj0sFQidXanGtc-rpnHQdwxdZYJJNVbwWH1KU1Xlaks7ggtpQBhrtQY_jsnuGWMa8IJcsEjjpmXHMVT9Y1YYZmXNmz0ibmlNGwQ8oyEf-7f88SjG7eY2hKMYyUV5QWBcp_R5dggeuihq-qPTxmXeZHb9Tm148X_ghz8IuJl34hdhUwuMrErZLJ1qB7aQCEVcEonDwMfa4Oik3OJ6vV4BsMr6DTwoysDnBkeAuuwMMTPwuTGVV7dV17tv2fB43JFXjuBJt2gtY4OixT63KhbriN_ofbvIjcGV7HBSM6s6ve4zTIRbKm7pQMmKNT4zKNveJLFxhu_J9nm_-WeOaw299O0eOOXuaA4lkUZeEQoADtoBHn1j7LZa6GVBXIqMLCrku2k9Z5vRBfkCPtbWkp6_COoAZTfXsY48KVQTDZkEZiukEGkxLE2sOQoZhvUgj5WtMfB0PNDx5vclBCynOl1f_ZRzoJx1rt6BdqHeQ4qKrm1XISzNKulpY-ptQn5G99tpCQvotau4udizv7y2RHsmmPd188utyFimZLzChDLp-seVWCOW8DvqijsLydYKqK8K6dX0bwDng-LjVIynf9d2I1PB9yQlcy02SoERHCfDZruFT99wEKlRnlsqV7dpfYXQ73h6mUw6salX1DfBfCgsgZNLXs0Xo8uZGWM0uN4nAR-ahhXMaMvU7qCSJFnJ063aJnUGLX6BV7dPUY7m00hrBFL_o-IzFDCGP4vSh0iwilXcHF6iRezCPYf4WwSO53vjkrS5J2HHfF2eOKxCPUij5PLgLJGNrdQqAoWZ8jRgHlxtstCup-V96a4MW8-pZOQL_REVCW3TmDpiazH2k5YW2iJMhA6ZiYv2ObWC7tHBWVM1eGEHE6HDRDRrsiYt7z4IpBj9Mle-lWVyS4LmidWGYxT8mjPCZRYvKMy4SSnBfR52b7qtVNtmYF01HJHgJNvvyw43Ve4IIDlxpyIGeBz9OEBlhHP1CYAxAppHKqqDVzvvXEfUAzFVahvW9t35bL-HkjGqsjUJM2s_z8cCTq8clsP81uxSawtEwSX3kVY1bZkujcASAS3jnVhMZtQ-uA2_fpDsMTeQxGxD944L-SSbKlXUeB0UOJihGIbpqJM80XMQAEDIFdCd8DSniByyksMyoDAP_uNSdHHmHDUeIo7nUcc7MIIRK0jJ3wqTKfBtuY0MNmGcKuesAuGIdY_p_Qsvy1syzkbu61SI35wszuK69_PDK0zelhljvkFQ6iM_rI5R4aumJeORQTM34X4NWIoVweCBmFzmXiWrYtAGKnV6euqv2NjDWKtIWsjDuz-MtRG5Nk_SnJn2R1Tz2kP0EYYVtSZemvS5bGC_lmYQP69Qd-mkeqclv2_kdt5MxCEwfC_WfQmaKMcdWjA1Ot0mZ1qG-L8bHHBOB2I_O9iA7Cw662VlwzPJhsU8m2cbhDBIMjRrP0aTF4d3i6qEtwTUd5F6pDRpTLdmnlIDpXo9ewhBeveI4A9TyG46zq79diP3_3TS-driJvCN1fRPztEjDXuiYl1GlP_7-R-PWnUo73BLqF6gbQFuYiBa-bZXUchV0yp4Ocw4gvtJN6KSgzoraBOH0cwGZA4BJQo3QCY9u8hlq2jsXQYm6kwFXQ2a3xH_STakUhHe6EaV0nlz_sn51CJz83OM4m5si8LNVjfbHVjK7OdKYc7XYnF0GfO9hKDbF9O4IVqZkrSZQTWIaW7FsgdGhbExwFrKVM1Y0vvWaj6jiDTxhISY8BJxlAiqwoNBjzs8HJFrI_JTwMgUIVn9EMOIJ2INmBOYWPtRkPJAziWUczePqVLfW5uMnl4oA7VYlQLffGpG_Kme9UzqPOY_CGzW_4aUf4iw1De2k9EhuG6A-bbbmnv2jcuM4yjJ-_9s5bVYhduYyFTfCaVrAOKVG4sr1ilTFWSZweCK5OaVdMLjVVKqr6kdE3nQIgrfnVCjdGwl8qiKyB1Tb26YTNCq85oPGIZEbiCvfLfD87UCFgD-KqEksgHQwka-wew3XBkt5Y7BZ1SJ2JeWAyFMpU0Hxj8BubkVLbJowjAv1bOvGIBK87Zm-QYeZj9HqjLAIgp11jyb4oqWqe-kN3DrCaPC0IEk-I5cV9A2NCgigPutWjUG8w9uxH3IbXz34CCn8syff8xlXNGM4sOO1FowzCTgDhQV-U3pDN5SYqL979JRodgbY37tI1bJeR4PsxBRjmhDgyD3mp85VKC1qgMvheHgX6TRWimDskwhEClwjYuGCt0psKJ7V7Jrb0XXACEBZ-l-r9LMYNa-ul5ax_T7E2BoDXHLbQ4kAkKrKKXHZmMWjj7OUnz4h-BVfYPFjcR0HTrfR2fd5FEufN4ft_bxIQhSb_caX-exSinzGWgR3YMgxGsAKvXGcfurgMhjuo1YT5JllYCYIssKSPbdccXLxy2T0jE6RU6OElX116S2jF_AyQ4AUucs5o8Z2Li3u1CtNghvxCIF2QszIlcEcffKYeESh5PN4Myl7XDbSLHTttu5XP2dcewALEbuUZpRGS9g5VFVRAkMyFOTbDFxRJ851ndqZzbZOg4Rl8Qkj_hrG4_b2KYBTXo4P1QdEnYoGhstWR7aGJbP8K3rKenaoAw1Uh-aazWdEEt1GM-12oWQUryy5KGgakMgAEjU3f-Y0o1y7hhuEqALlz0b2IHQwDEWpLSkUk6caoPtQNo8Cksd6fn3owwvCO7n8cTABYqC-As4rLXinPZF-DEhqJoVQavf05BG3htPTfya-aZaCJz21UotSyHDfi8tWNx6e65W6I_6znW2WBL_rUXndafaHSnbhT5kUKEjALJM74Z8kSe60OdTdibrzz51uK41Xe_aIXZ-bZTLWE8mrWyBwTW1ro4ZipUt0wN4FgSKusFzfsnonX_nJvGVUkVeTd7ic5nj7cD6rC-Zfk45LWytBfIcTBn89AqgHt-u9Win2Y3saEm_jK-ztpDXdZLx5v51HB8ZjhH0d5SIyUDBteXhFa01DA8Bl_hgqy60NU90esQ6FVdZ-rtXVUDwIDEIPO4H-xoZ6HrKnNkiwspwpxf_jb_WKfKDqoBy7DuPH5IZ2Q64iW19Vf8awZuJOa6gDlvp7kLHRrk881toG-Rt6TcgyEThVhcfcx4_ZrUg6zwfUM5pfItuBxj8GWmFpJbzIlVZGKx0nFt2XPJjagFyAhFHO3tCouNMT8NFqxwBBTJIvt_tsx56LBtppes4ZXhIuYrJJbdvS4-v-9jUgytXo5XhJ5jswWCn5Vw2fpeHFfcBLwo0sVr69hPyVhbOQZiz_Yz28rap-rendbwfsX5Bj5-C1-0EOdfRI4SiuwykMVBtpme0HMUHox_Ve7JSCDpu0LPI6t76BMu1YBPXu6tcGBPEyIB4iT0X-iFdoj_NPxCHqI4mPhWUHAdWGUlUSk3d5KoCk1dvF9Tfu4tThxmmW6bQsJa4bqjPQG6TjlJ5DjYFy3AulMjcw_LnXyl9yCPgJlR-1oQJK8m58ng9dGdrgK5cVH_iTfTNpqtXmrhW1OO02mAPDVrgBJGwkxAtzdZOESAG3M0FnRPVrDGYgyGM01cDTu2UcQLBymIC-ifjhFvm7qiKgdlj2JaLJchyS8EefPuc8LHa8NyTqWBchehbu56K3RTJagLjp1RDUqoK1i9FDyJhyM8AET6chHyynAVFNbdAbTU0YSqhslDFwC9iAG-NkTezDdVaKRkMeedyhbW9hCxAqRSX5T8sL6G4ZrHB2VBg7U3kYFQuTvXAWl673wMJDH5c5wGHIHWCFXT54mznTY8hONGLkO2iBQcleTPDn7lfo3sk1n_-bHHkWSngiEWps1c93k9jn7g39qtcX0rtDsiiFIFMGXA2K05POyV6nLj0bfJTbxBZaxEDtJPM-JzyP1e_YuVbK9fYZYm-2mgD9K1uIWLtHNBhKe0KpDVwl6KKGPDQP1vacyhTddyvKkQtj7YudDqqU9SWf0h0-k66Ua3FJukQWo2QgtSG26WGTrrseqJEyK9KfS8A2Mf3XsYDK7vY9IIme2B45563ylHmrTnXSTKDSNYv-mFxGUS8sKnvA6ypWeqimAAkAg5ejr2dTPXuKr8Oj_Uhqk1wCT8pNBsRKxWjo6w3qaQ1YNvloiBBUa-vuMF7DLlBzLZ0wIAQBwM5L_eOOiU3gTAfOiSdE4VgQzXOyqolIOY4sNjHttadTutK2HQFQTZwaV3QCrdlS20SqVH1zODUU8_lwbY3uH4selj5ATnqRXkt2eSSeVuGEzOlvc721Pj3pBNG4TqHhnysGZkcGHoiGvjiA5Y1yWkP_lel0c2BCBnzmWpCZiSoyXa2qeBK5AwoZlHXWqbohS-VI31rUzgGDxyNNziEGeEEl1NYsfPrOPD0-HPGR4I0CFY4kIwh6pvqb3b1IL8pOpJgDKlcTKV7AMclCTllgTockNgwpxKiznYy-13bmgB52bpeZM9D40HjGt_hreCDxcjkHqYnv_Xfo0Q-L2YByxKVmtS2xEjDabvG7C2H8yNvrKkX7-Sq8D0mzzIgOWLwV2CJJkx36LdgwP6Wduu9h0zgixNYzLdnLxP3OnM7miAAcnqLuJfEXyMjuJ11e1Lb9jW5JMwhfj4ZyU7PXvDjdXvNSTpzMWWSGEb14vQh3Q_fzcQR4JgIBRUCIOKuNhNnuI-uNpk5xQFdfS-8JIqD9aT_imQP0F29B7HRcOFOIa-GpHkno9Kcq0LU5zYp_sLPuKIY1BURuXh1_kau0eK3tP4rdCK-9rjbl9ze6onXSEbKUQKJ5fSKKnwm-txr4fRk31-Vx_ThpOXTWzeunlH6vJonAdWZwoXOqRcT43TPAWi5ZRliyarNj5x1WrksZWvNt6KHXdbOBk6ztp32_yXZNiGRpwkUSB1of9fl1E9ybF820Nf73L5imxOd7BytFpWMF2viKJutaXSsPOJUk9wlEEidDMFP90BHP2mJ_0BWsUN5ejf9l4sbMn49ziwJcPSOW_L_1Z23f_Z_65KgQ8h-DzQt8ygSsU-6Dfh8x_OxO-THFMp5rxkSDNMdSCDeCAHPfRE3nDWvZqtCCgaobWutDZrlySWPNUL9rgdocq7BvUVEDCYWXT5NSAg3ukjjnX_mGSpGAN4Tqs-3yNZjAPHyzaAuLoqYZHu_TfRI4zyAWPOP6nQyxk58cuCSuZ2P1r1l--nmob3BmqV4fFPxeM6qtB-1Z0SMSufTc75Q8otuikf-jYucT68GbXo52qZ7ubHYJKc_Ab_Ah3wnuhUC7DOigJGb7jgrB-2v2wxGlnh8PsWvYNwNR28wd5KgN0x3XFqCCEAje6UCudzhzHzP-owRjBAlBZtPWZhrOMuRTplwyy6GDJ-a-df1QrIwPgxlYi5Hi6zfnZVhaXdkyQbI8g1x-xUwOx1hGsLURx90Q-XSaXE6MudjwvdNcCzTpMWtUaVR7KAa2tHcpTaDfSzhoxoYQWEOeQaXyaZVgRLJ020UvUyEXigNO4vfU9ZpJ7eR8h4R34NyzrPHO2gCUtRfZ92r1UZ0ZNPGGSc9QokNB-O9I0svalf_UE-FW3TAzik0hjrxDwNa-oEiPSZemJtq27aSrXWCz2rLyd89-haxY-fmiygF2eNNtkEJHBI0Ns68i3_N_Zy-_Mz6ycH00xw_86FFcT0Tsiq8bjH0wfu1l8GVpgK05027H_-bc9YaeIQFN7yA6_gGH-wtJXTjFzp6X5WCcmPO0xMSR754BldapRfiTgWZVvC78bOyOOYBKrweXaRPnRPvvJ1affiOF4QQC1xrcRsyPF57AHsJNopbnwb6y4OHlr4HhYcmmT9-buzFumD9VT1ZBhe5SGgi_CPa_srW1c2YKJHjONuGLo5i6dP5TB9IcFrc9ovekM6-iNwpuxYNigKuYGbAvEJj7BTqa3_i4Dx7qXjCEZ2DDC25ojAEcA8-sTbVDnuSafGcyISpgLlzg3uSGg8re2Gi3LiCpUq26X0yRKLz_7o1PwBNoMFY2YQBtxv1jINc1EnYokZVQNoE9p4_CiolL_yPfXYsc6rczUfQXzn7YrKy9t_yxlMIK0HUfgsOGycF8KvltilS6MudDSBaMZmpzSIDf-mfMa1xV22D08zn5wPNMgrZKOyiSpHqu7GJhod4X8jID6ED_dtC0VcEMEKDJ9rJUqoPg6tNrFxjA7AYEgI9ZeegIHQJ_84Q4m75Ro68pSyUZkafka9-AwF1II_sHMR9s57viGKtdyYhE-ly8PqY-URXr2JoaK4By8tBOWez-3xyEGSfrkN8_MuKCf16aknSpXjtf58foFg1dMlxsFbbdKSnhDT7TjQQji43lJ1XAXBrDMxIOiWG_zX8uZBtfxrTVPSf0BCbi0PquPE771gKEL8_Zhg7d4udpYLi67DoU4SZXPwyUVsn5gERY6sJlY_UtxvyXi6Aq1ozNcMyBZf3ujh8Mnnvr2kio62RIMrAg3jqNSEf5TZwZgN8nWZla3HfrCNjeWMLSNBeRt4ipvRzQrpFpCsvn0YQqDlsXDDy0k_psbkw4a8LZVWReBvzK_zGhytY0CavQ6Ir4tYMUUdO-1-MZIbe-Gy9xDPy0U48iRjEs744Y557iZ08xyyhycygIEkEHIZ81CcIIfxPL5IjeJxWDy_p1eg-EujJVJWr66m98jYsZRa2ykwFRIpQ4tDsbalmZe2Yf1eF0ezzkaV4nAo201frq4CGSqU6M6ZQX5wNgr8n3sZFiohExa1K7yB7hessaRF69QswWLvJR6eBYBEqTeU7aGoT0vUsx8q-Y5W3rLdTmbKajSXBu8P2LpzwqZmujypGNGqEkQXMwz1Bkxb9IIX79njp3cNGcwk9Q4_a3bvsRmNcj7hEaJ5NbUGIxP06P_QBVDDvSZf8lEh27zUwakAfpp1tpARVo49Njc4FCXkVHrxdDsiImU7lhWCW2EzpcfFfI-S-h5Plw3UuEuBJwtPHLTJWeEPsm6eBKBREI0iFmUu01lqdbsOxu-Nr5IP0POW13nR1tM-JTHvVmKYmSSbCVKmUnTloUryPsHn_N4fyMlu2mWNyaY4vhEOM-H94b6smIvT20Laoki4AClxZZsSIW8b35d4oS6AnQBoSQshSXbX1HVyAoNuZ1JKGC1TYxHqouECwRzZRUny2sFhNQzIlmkOWWwltQLGnIXyp_zNvhVrkzuzpUm-_DsOr8F49wHJw1w4ad_J-JqtpwikGYd6FA44Sni-9jO9OW3uZLowrFX_gMldJG4ZlDBCkJGxEr8VRN-8sQDsqJRysgZ7bx2Iy4flwV1ARtQM6t3rk2qkWpUnhdv6X3Z43t9UlLVbK-8SIbF7jgwArl16dSRPck99EyP6bAGCkiWOkQwPAYk1H7qoh_EMirJXsBP1Dimvs2qk4A2VEHGnJdK4fEESCgVFoOgnTBYAP42_v-ya33MTPz-8bzmTEPzMFbeswNTegJ3YCKXRhvzDSqwgYO3W3US2P835SDatmkNRjdRIG09Db-X2PJtnwOWkYnRmL_1TMqz0XPrTMC6pR7iv_uRvVUXIi87c5QyCjMRtcn_olCZ7G2I2GM4VENjciZLLkR1Zfd8Hd7O24Zr-dagveKm3g285-0Q7zRdZhFEwZ9GbI0eQTvZrmgpS7aaNYUPIQWJYc9ZJxOU4Eo-qAlx4cMg4uqM8lU0jD_7_YASbkXffTMYIMgnfOWeO-TkzTS4c856BN7OFmH22WOTJL5BUWsYkCZz4Jpj12DjJS0o-kKsnrTVEiFfq10XFPgktKUQc3U-EQ1rSXgzDyWK2f7BzVxpCZU5y1pN91Z0KWAGvkq9CNsJsdZZ4UuXW3IremtAyUXw6GiWK29Tag5DB7ZiWoRBKmhwtYMbfecPiWcDqDSczwiXiv7noPDstEsfX43jelvYUKZdfqdaBi22j801TW_nZPVIrW3eH6GjuxT9VEoaF7A4LeZYhVmFntD1gMo2tylnPOS7nyW1Hm8tbReCgqYgKTbabKZ93_iSiPxq38L_qhLgjdudQmzbSO-Yclh6hloizB7ScG_LPphRuF3uOVIhWrtMAXaCID7qoH8mmn167jjAErgyfaKqQovubjLOcmx0IoolgI9uyhcPjScL5ekE74IxfD4XJi7bOgVXlTfaPAwQhdgl-bMYyAlnwuPq7C5htT7mjGwWPSy8gMG516rjxhutl4PyL3gIoVddYOksg0FEKjhW4F8zeXKgRLRFeV-rMiylzkt7CDBob08PLecCMceTZZYlyJBIOsCL3sSyntCMp_gMFVDJubHiRY6bLHrSBOPHR86kxsluqphdABDkqGFXx-mGV3MtzRp4F_4M61UssDb8_sCGtsOA9glVtibti-RvtLYhoyB5qJpkZS8BKSKzAyI4Pzlga4e2I4NzwiSiqnxN2Ew7u_Mx4LyX8WmYeR5gpMNrnH_d0x4ZdlLpaMf_lW64ntGZRkqoEbavh431wxA2GPS2v-17e4Txehe_MwTvaBWf0AcTpdENLoHfSpFUzexLTVK1ZHKt48FnYgwSZDimW38Ab9A6J7E7TlHsIBx7DjIUlNZH747Bs7UxDNBLJaA4482lWZ9ZXki-lxLaduH8Sg2aEdvXjo8ZgYANmMCGP0h2bv1pLhzQrBUp3_euHtBN9koZKGRoTxIqTrVXoRY2yFgIpai1Vd4ArFeIkOVyZS1cBq3TLgok1NhSogInHPPND8JqOKCLR6hOEglfumbzogXBf91_wUWFtj9G14X70JSTOhm_j_OppGmBZDlSKBJQTdpdZ0SU-dAsQNvNNl3hfba8jCxzxP4tRdW-9KzPqiBTruJeEoCjTdlNZiOtAYJo3phU-7TRr7qxbN97LXoMF9a-M1jtn24VJ2xUeV8SxzkfbC5K_nlMMRhONz2LOPIGaf9o6Up0K3qYHRqs6Eqq9g-aiQbkFXjDen2yWULylVd2dYBERu4KkxGbSRktlFx5a_EG1yiglf4uAgB83PMgxz7x5gNlQfp4VCVU3vDTb_6AJKtpmNoR7PkalKSTL1-R8Zwdl3jJ2lPVfYwi15PHnZwxqOcRNIY3gYcS8j_PFkDOxH3OqPvTGs78-nzOl_tfk5peHs4qKRD0d8x8Z8eIi0PDEgUWSCSu_odD8qM2K4Gxq26yYa404c3R7stnSLS6Lyygdei31PbmZdFH52m2LbfMKCQQu_GWnMEkL3jRJ9akQ-3DJO1yfdApw5_fTaINnRE0k40rv-04pi_KcWFLHDXZ29yKc2S3YXRHunniAlPUg2MGa4aW1ODJRM8dzQLUHQa-q1X57e_ljq-pYa7mmg29CXOnDzYPLcI90qyzSyJ0OA3Ffce4kofq9LBA04sl54OSzQgBb7zZOXEMlOLvYF1deDu3kfqaTm3IrS0PZRl5MpoEOg-ciVpM-ojjsch-ZZ6ORvgxB-dcWpLUUnVY4vgH1K9bXiWx8yguvuCNYXldXY41664qXeOv4964LAbCC0ZFbcX8ZOgDZBnM_ndp5Hmuyqi0lukPNeXp813S8Ol5U-x1J3Tu8Ru1IS9cQpaIeArOPQTnR-HqzcKnoPuKChRcVwmT1mfCIESYB6ONoxPG7BUCH9gA8j6G3y9m3SXUVj5emgrT3qpDVP7L19i7hwrV686qZoKVxxhs7u7cBVlUCI432urBP7kvt-H45Z-UOarWI5XC2qInEZ_hVcyaEdU4I2Pl4dlDJ6YZ1-bpUN-dxXokppeMtzREpniOq48xHtWTCu6hvE1VE-G1PRyv5a5gV7HZutPnXD3D4vhdD_n6bdfnQTLPAve60tcC5m_TcNC-y3WtShiRNuUj6ljcuT-KMtPhszE3l46KZITABYlpjkAKYDHtqERWfg73ST6Tio8iBQGtJd3p12xkz32XI6h_IO7KWRmNDMRdfHMg3MKYfSmArzYOEYnFJHVck2k11hsb4ATQ2H8ks2o1zZEocb0m1_tjYXdGlC5C-j8Mr9RxGqG4ZTTaONRkXwxx0ycGNZ_lfs6IzW-ZEqJN3eoJ_crMYeMZZ_ZinGzHVNA_J0TWpzb-H6tXHUnAd8f96kmhmw-uZMx5Zo6yOtuqZU6dtvYM7X5hsJ_kFMyN7d5jh9lJHUHciKQpS-dtbwRVzVf18k4p_QUefA-yc2CrzgfpDL2PbKBa9jWtFHlVdGXJCT6qR6PdbP69vZ1jssuYP1JMb-8KAg89XphVdoYQADr_yngSYcg9k22v-_3VSOaE2EX1ZYH0VPSS6y6zJRgGku4u1n58pN7GPWRsbVdSoQXVV6y0_ImcTaHUHuZ94l9Np3czisnQzVrebylQhc4w47mm3FC7zqIsEOlpy1yZgVGVy7Ackhx770wL-YVhVQfmioZt3-FWKmxUYjmyKvnuuWuuu6ZTxvphxibBM9v8zpTSuaHxs5NdG6jnQ-E1K-PseEhnFDvwU7YFqjxweVXprbkD3RwKJbW9nPrdM_V78yiSocMgsc7pcHrwtYQIBTuqbU_j94JX7qkMzv0k9Q0U1O3yxCnxYYYWBYmXw8KGnWD3AcciYE9paKdRQPSlpnnXsVUZtrKc7jdf_FX0bp9KJVWmgDXiNrRJnfN_SQ0ItPPdasTdTCDRSy2hRVCt3AF1PT0n8Kom53Zc0wt3WtbTbiSjjG1Zor9muMA1haWjhurOJXl-NPFabQ2xrGOYtosuDQ4xlOnsxqlsJ5sLC9KYjIfiDZ0WmTm3rjf6S-FV_CJJUzpq_tGeNqHxD5EF3tETPB6TvXwzrn4puOTTyf3fk7kKWnowBnosBmLmJV7VGvXEjo6knoFXXv7qQB7BLSpN2eECVUYhAg5N5UXy71OXESO0fkhOYy2-dtW-iUpd5sEkSjVokCMPzuA3Z1uUt0bP8JqBjUEiDjEpwE7pXbxAJKPMOd5xBYMOJvwN6on0lmJ0GkEWT9dRFtbiz3XqgtIRHLeVOj-iy-gL-eghgIvGcG9rtqQ7EOlVDAldNVqtlePIdA4tNpsEvGTjwFgHmTRGRmQ-1PEI6a7y5_8RNORjNl3toGfaaQ5rZvHTP7xzQUHjs6j8cHrrpBtyOBP6HiwDq7gG9zidpdymT8dW6kOCPZnZ2oTnieVMLNiNyS3HE6iiOPKQqbbLDm7rKTBXXYJrdfrJIULZyVAUNQSZDn9n9EZrRRT-14vgj1TuNtIckgzn9-uUksKu1NYVohBshKRfNkzl_PKHUGt-f3ZApOnQOLIB8whU3cFfD98TzjCqJFnoFUrqCtAHaG5THERZmyeb-04k9OWDM_4NtFcSCZ2IILzexOVH7q0adaX6fih08ctX1dY6JbdMJO4_2m-v--9HNbFj2JD-21FXfVAJS4Qt-40f2lojlMCuDFGdMqvr-R4oe90iwmEsmvk7NR2UAkCunQEwI6fcrkf_T27c7pvTT53oNyViVARk3kfJDORCck-Jyqm3-RvGnOd9sYQhqXHADCZfiLAvx3muu1kSnFblFDtd7lbSymvgXyT0Nvl4fxNB3YkEvZauLwEA0r74p36ycOc0LtgizJqVofBqlj9LOFNiX3J1b0MNGT7BeUQCkVZsFAKL2dLH569QSnI3ulf8CqEb359IUJET9rj7FaZns7sjXkWxrsdXEwWD1My56DU1Q7dfS78tJCZehZkNoVJlqihxA-mmW6SVyFN7xh51eSB8isxJ5QYHUgiynXgUxWK0rDfXOEjbeNvVTE8ou7OwvbxXRsxe-ttYZULKFfGwPVfcKgd2kPAAKEKGFba2amGKZZMV9RAv_R7UFD3FBbU_vHRqcCCxVTHDbAdxIp-N294DYAkkcqjF2KILjSe1vmy4dF4r-Jmj30dRneZjIiMwjXio9y97iWtWdlfeX6uu1UW2nAX8QHVT-_C_Bim2NJ85ST1ZcqTZs8MUMnKy0C5dEsrtgMaEmG1MKuE8oiUAMbquPSjgY40Wv_zmAFLW35orgq0Zn_tOa1eQaZAX3VwARkg6GzAyYZzIeTWK-ADYitKXT5XUWqpn9bAd2M7bMTzqeTPipVzFLJAYI1k7MSxxCPXPNNm0i_ZBRpSEHegsxSyQqFpoMV65hUgHnjGR_HYQ1c7GLstL4xHr5mt9zEQs4dmwbed43_eDd218HRTNMzop_8nU3jKXjcmndv7V-luB3xTzPBoAotIfCbDHWKNTtoJltZur9FqBveAscyyL2V7Sn72zBe-3prmts2l0V761kpe8H26oy63cSNPotm62ab21YuS6wZy8Z5i3FXdkYHy_JA22Uqxou0xWf72Jv6QPQLrvGan7PSNSiBiP02n7_zCgfWkQQ6-Fr8rvSxa0AHmhGq1Xw6O7pvtBJ56MM-6x4FsVOKnnrV4-T7O88831f48SIwiUMN8C4htokVFs0JqFJitJlJ5SaRFl1CY1Fz3tqG-WHaEwMpWkyZ5JxIYqWjydHMTofE9lKsCDI_4BEDQJIk_O32MkwXcMKLkOe5Wdm3D19qkCZKIXRFOCwlx9LeFBMUnfw-M257lKJ69new9KLVER9etxZcaaCyB5CWWoiH72Y4tDpzdWn5gHIKg8X_rZrulyGYE0Fb4xnJeR45HTmBErM0h5LgOn0wib_6sQwvPoRK8qlFMSJHcfZPKoO< PK\nextjs_space/tailwind.config.tsimport type { Config } from 'tailwindcss'; const config: Config = { darkMode: ['class'], content: [ './pages/**/*.{js,ts,jsx,tsx,mdx}', './components/**/*.{js,ts,jsx,tsx,mdx}', './app/**/*.{js,ts,jsx,tsx,mdx}', ], theme: { extend: { fontFamily: { sans: ['var(--font-sans)', 'system-ui', 'sans-serif'], display: ['var(--font-display)', 'var(--font-sans)', 'sans-serif'], mono: ['var(--font-mono)', 'ui-monospace', 'monospace'], }, backgroundImage: { 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', }, borderRadius: { lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', sm: 'calc(var(--radius) - 4px)', }, colors: { background: 'hsl(var(--background))', foreground: 'hsl(var(--foreground))', card: { DEFAULT: 'hsl(var(--card))', foreground: 'hsl(var(--card-foreground))', }, popover: { DEFAULT: 'hsl(var(--popover))', foreground: 'hsl(var(--popover-foreground))', }, primary: { DEFAULT: 'hsl(var(--primary))', foreground: 'hsl(var(--primary-foreground))', }, secondary: { DEFAULT: 'hsl(var(--secondary))', foreground: 'hsl(var(--secondary-foreground))', }, muted: { DEFAULT: 'hsl(var(--muted))', foreground: 'hsl(var(--muted-foreground))', }, accent: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-foreground))', }, destructive: { DEFAULT: 'hsl(var(--destructive))', foreground: 'hsl(var(--destructive-foreground))', }, border: 'hsl(var(--border))', input: 'hsl(var(--input))', ring: 'hsl(var(--ring))', chart: { '1': 'hsl(var(--chart-1))', '2': 'hsl(var(--chart-2))', '3': 'hsl(var(--chart-3))', '4': 'hsl(var(--chart-4))', '5': 'hsl(var(--chart-5))', }, }, keyframes: { 'accordion-down': { from: { height: '0', }, to: { height: 'var(--radix-accordion-content-height)', }, }, 'accordion-up': { from: { height: 'var(--radix-accordion-content-height)', }, to: { height: '0', }, }, 'fade-in': { from: { opacity: '0', transform: 'translateY(8px)' }, to: { opacity: '1', transform: 'translateY(0)' }, }, 'fade-out': { from: { opacity: '1' }, to: { opacity: '0' }, }, }, transitionDuration: { fast: 'var(--duration-fast)', normal: 'var(--duration-normal)', slow: 'var(--duration-slow)', }, animation: { 'accordion-down': 'accordion-down 0.2s ease-out', 'accordion-up': 'accordion-up 0.2s ease-out', 'fade-in': 'fade-in 0.4s ease-out', 'fade-out': 'fade-out 0.2s ease-out', }, }, }, plugins: [require('tailwindcss-animate')], }; export default config; PKWF PK5\nextjs_space/tsconfig.json{ "compilerOptions": { "target": "es2020", "lib": [ "dom", "dom.iterable", "es5", "es2020" ], "allowJs": true, "skipLibCheck": true, "strict": true, "noEmit": true, "esModuleInterop": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "jsx": "preserve", "incremental": true, "plugins": [ { "name": "next" } ], "paths": { "@/*": [ "./*" ] } }, "include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".build/types/**/*.ts" ], "exclude": [ "node_modules" ] } PKaPK\nextjs_space/STYLE_GUIDE.md## Layout The root layout, `app/layout.tsx`, is the single place for app-wide providers and global infrastructure. **Do not remove any existing entries without a reason.** Current infrastructure in the layout: | Entry | Purpose | |-------|---------| | `ThemeProvider` | Light/dark mode via `next-themes` | | `Toaster` | Global toast notifications via Sonner | | `ChunkLoadErrorHandler` | Required — prevents known ChunkLoadError race condition bug | --- ## Typography | Role | Font | Tailwind Class | Default Usage | |------|------|---------------|-------| | Body | DM Sans | `font-sans` | All body text, labels, descriptions | | Display | Plus Jakarta Sans | `font-display` | Page titles, hero headings, section headers | | Mono | JetBrains Mono | `font-mono` | Code snippets, numeric data, IDs, timestamps | **Size hierarchy:** Use Tailwind's scale. Headings: `text-4xl`→`text-3xl`→`text-2xl`→`text-xl`. Body: `text-base`→`text-sm`. Captions: `text-xs`. Always use `tracking-tight` on large headings (`text-2xl` and above). --- ## Color System (Design Tokens) All colors use CSS variables — **never hardcode color values**. | Token | Purpose | |-------|---------| | `background` / `foreground` | Page-level bg and text | | `card` / `card-foreground` | Card surfaces | | `primary` / `primary-foreground` | Brand buttons, links, accents | | `secondary` / `secondary-foreground` | Secondary buttons, subtle highlights | | `muted` / `muted-foreground` | Disabled states, helper text, subtle backgrounds | | `accent` / `accent-foreground` | Hover states, active nav items | | `destructive` / `destructive-foreground` | Errors, delete actions | | `border` | Borders and dividers | | `input` | Form input borders | | `ring` | Focus rings | Usage: `bg-primary`, `text-muted-foreground`, `border-border`, etc. --- ## Spacing Scale Based on an 8px grid. Use these CSS variables or Tailwind equivalents: | Token | Value | Tailwind | |-------|-------|----------| | `--spacing-xs` | 4px | `p-1`, `gap-1` | | `--spacing-sm` | 8px | `p-2`, `gap-2` | | `--spacing-md` | 16px | `p-4`, `gap-4` | | `--spacing-lg` | 24px | `p-6`, `gap-6` | | `--spacing-xl` | 32px | `p-8`, `gap-8` | | `--spacing-2xl` | 48px | `p-12`, `gap-12` | | `--spacing-3xl` | 64px | `p-16`, `gap-16` | **Vary spacing rhythm** — don't use the same gap everywhere. Hero → large gap → content → medium gap → footer. --- ## Shadow Scale | Token | Default Usage | |-------|-------| | `--shadow-sm` | Subtle card lift, input focus | | `--shadow-md` | Cards, dropdowns, popovers | | `--shadow-lg` | Modals, elevated panels | These are CSS variables only — use them directly in inline styles or custom CSS as `var(--shadow-sm)` etc. They are not mapped to Tailwind's `shadow-*` utilities. --- ## Border Radius | Token | Value | Default Usage | |-------|-------|-------| | `--radius` | 0.625rem | Default (buttons, inputs, cards) | | `--radius-sm` | calc(var(--radius) - 4px) | Small elements (badges, chips) | | `--radius-lg` | calc(var(--radius) + 4px) | Large containers, hero cards | | `--radius-full` | 9999px | Avatars, pills, circular buttons | --- ## Animation Timing | Token | Value | Tailwind Class | Default Usage | |-------|-------|---------------|-------| | `--duration-fast` | 150ms | `duration-fast` | Hover states, toggles | | `--duration-normal` | 250ms | `duration-normal` | Page transitions, reveals | | `--duration-slow` | 350ms | `duration-slow` | Complex animations, modals | --- ## Layout Components ### `Container` — `@/components/layouts/container` Centers content with responsive padding. Props: `size` (`sm`|`md`|`lg`|`xl`|`full`). ```tsx {children} ``` ### `Section` — `@/components/layouts/section` Vertical spacing wrapper for page sections. Props: `id`, `className`. ```tsx
{children}
``` ### `PageHeader` — `@/components/layouts/page-header` Title + description + action buttons. Use at top of every app page. ```tsx Export} /> ``` ### `AppShell` — `@/components/layouts/app-shell` Sidebar + header + main content. The standard layout for dashboards and admin panels. ```tsx ...} header={
...
}>{children}
``` ### `AuthLayout` — `@/components/layouts/auth-layout` Centered card on gradient background. Use for login, signup, onboarding flows. ```tsx {form} ``` --- ## Animation Components — `@/components/ui/animate` | Component | Default Usage | Key Props | |-----------|-------|-----------| | `FadeIn` | Reveal content on scroll | `delay`, `duration` | | `ScaleIn` | Pop-in effect | `delay` | | `SlideIn` | Directional entrance | `from` (`top`\|`bottom`\|`left`\|`right`), `delay` | | `Stagger` + `StaggerItem` | Sequential reveal for lists/grids | `staggerDelay` | | `HoverLift` | Lift effect on hover (cards, links) | — | | `PressScale` | Press-down feedback for buttons | — | | `SkeletonPulse` | Loading placeholder | `className` (set width/height) | **Pattern:** Wrap page sections in `FadeIn`, list items in `Stagger`/`StaggerItem`, interactive cards in `HoverLift`. --- ## UI Components — `@/components/ui/` ### Core | Component | Import | Key Props | |-----------|--------|-----------| | `Button` | `@/components/ui/button` | `variant` (`default`\|`secondary`\|`outline`\|`ghost`\|`destructive`\|`link`\|`glass-dark`\|`glass-light`), `size` (`default`\|`xs`\|`sm`\|`lg`\|`icon`\|`icon-sm`), `loading` (boolean). **`glass-dark`**: for dark/vivid backgrounds. **`glass-light`**: for light/pale backgrounds. **Link**: focus uses underline, not ring. | | `Badge` | `@/components/ui/badge` | `variant` (`default`\|`secondary`\|`outline`\|`destructive`) | | `Card` | `@/components/ui/card` | `variant` (`default`\|`interactive`\|`glass-dark`\|`glass-dark-interactive`\|`glass-light`\|`glass-light-interactive`\|`ghost`). Composed: `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter`. **Interactive**: always wrap in `` or ` ) } PKwDiuuPK\4nextjs_space/components/chunk-load-error-handler.tsx'use client' // IMPORTANT: Do not remove this component. // It handles a known Next.js dev server race condition where dynamic chunks // imported by next/dynamic haven't been compiled yet and cause webpack to throw // a ChunkLoadError import { useEffect } from 'react' export function ChunkLoadErrorHandler() { useEffect(() => { const handler = (event: ErrorEvent) => { if ( event.error?.name === 'ChunkLoadError' || event.error?.message?.includes('Loading chunk') ) { event.preventDefault() window.location.reload() } } window.addEventListener('error', handler) return () => window.removeEventListener('error', handler) }, []) return null } PKcB ;PKw\*nextjs_space/components/theme-provider.tsx"use client" import * as React from "react" import { ThemeProvider as NextThemesProvider } from "next-themes" import { type ThemeProviderProps } from "next-themes/dist/types" export function ThemeProvider({ children, ...props }: ThemeProviderProps) { return {children} } PKnGGPK\%nextjs_space/components/providers.tsx"use client"; import * as React from "react"; import { SessionProvider } from "next-auth/react"; import { TrialProvider } from "./trial-context"; import { I18nProvider } from "./i18n/i18n-provider"; export function Providers({ children }: { children: React.ReactNode }) { return ( {children} ); } PKoSPK\%nextjs_space/components/button-3d.tsx"use client"; import * as React from "react"; import { cn } from "@/lib/utils"; type Variant = "primary" | "dark" | "light"; type Size = "sm" | "md" | "lg"; const sizes: Record = { sm: "px-3 py-2 text-sm", md: "px-5 py-3 text-base", lg: "px-7 py-4 text-lg", }; const variants: Record = { primary: "btn3d-primary", dark: "btn3d-dark", light: "btn3d-light", }; export interface Button3DProps extends React.ButtonHTMLAttributes { variant?: Variant; size?: Size; } export const Button3D = React.forwardRef( ({ className, variant = "primary", size = "md", children, ...props }, ref) => { return ( ); } ); Button3D.displayName = "Button3D"; PKNPK\)nextjs_space/components/trial-context.tsx"use client"; import * as React from "react"; import { useSession } from "next-auth/react"; import { computeTrial, getGuestTrial, setGuestPaidUntil, extendByOneDay, TrialState, } from "@/lib/trial"; interface TrialContextValue { state: TrialState | null; loading: boolean; isGuest: boolean; payOneDay: () => Promise; refresh: () => void; } const TrialContext = React.createContext(null); export function TrialProvider({ children }: { children: React.ReactNode }) { const { data: session, status } = useSession() || {}; const isAuthed = status === "authenticated"; const isGuest = !isAuthed; const [trialStart, setTrialStart] = React.useState(null); const [paidUntil, setPaidUntil] = React.useState(null); const [loading, setLoading] = React.useState(true); const [tick, setTick] = React.useState(0); const loadGuest = React.useCallback(() => { const { trialStart, paidUntil } = getGuestTrial(); setTrialStart(trialStart); setPaidUntil(paidUntil); setLoading(false); }, []); const loadServer = React.useCallback(async () => { try { const res = await fetch("/api/trial", { cache: "no-store" }); if (!res.ok) throw new Error("trial fetch failed"); const data = await res.json(); setTrialStart(data?.trialStart ?? new Date().toISOString()); setPaidUntil(data?.paidUntil ?? null); } catch { // respaldo: usar invitado loadGuest(); return; } setLoading(false); }, [loadGuest]); React.useEffect(() => { if (status === "loading") return; if (isAuthed) loadServer(); else loadGuest(); }, [status, isAuthed, loadServer, loadGuest]); // Reloj para la cuenta atras React.useEffect(() => { const id = setInterval(() => setTick((t) => t + 1), 60000); return () => clearInterval(id); }, []); const refresh = React.useCallback(() => { if (isAuthed) loadServer(); else loadGuest(); setTick((t) => t + 1); }, [isAuthed, loadServer, loadGuest]); const payOneDay = React.useCallback(async () => { if (isAuthed) { try { const res = await fetch("/api/trial/pay", { method: "POST" }); const data = await res.json(); if (data?.paidUntil) setPaidUntil(data.paidUntil); } catch { // ignorar } } else { const next = extendByOneDay(paidUntil); setGuestPaidUntil(next); setPaidUntil(next); } setTick((t) => t + 1); }, [isAuthed, paidUntil]); const state = React.useMemo(() => { if (!trialStart) return null; // tick fuerza el recalculo void tick; return computeTrial(trialStart, paidUntil); }, [trialStart, paidUntil, tick]); const value = React.useMemo( () => ({ state, loading, isGuest, payOneDay, refresh }), [state, loading, isGuest, payOneDay, refresh] ); return {children}; } export function useTrial(): TrialContextValue { const ctx = React.useContext(TrialContext); if (!ctx) { return { state: null, loading: true, isGuest: true, payOneDay: async () => {}, refresh: () => {}, }; } return ctx; } PKc PK\'nextjs_space/components/site-footer.tsx"use client"; import Link from "next/link"; import { Aperture } from "lucide-react"; export function SiteFooter() { return (
Lib · Fotos de carnet desde casa
); } PKǠ?UUPK\'nextjs_space/components/site-header.tsx"use client"; import * as React from "react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { useSession, signOut } from "next-auth/react"; import { Aperture, Menu, X, ScanLine, Wand2, Printer, User2, Home } from "lucide-react"; import { cn } from "@/lib/utils"; import { useTrial } from "./trial-context"; import { formatRemaining } from "@/lib/trial"; import { LanguageSwitcher } from "./i18n/language-switcher"; const NAV = [ { href: "/", label: "Inicio", icon: Home }, { href: "/escanear", label: "Escanear", icon: ScanLine }, { href: "/editor", label: "Editor", icon: Wand2 }, { href: "/imprimir", label: "Imprimir", icon: Printer }, ]; export function SiteHeader() { const pathname = usePathname(); const { data: session, status } = useSession() || {}; const { state } = useTrial(); const [open, setOpen] = React.useState(false); const isAuthed = status === "authenticated"; return (
Lib
{state?.active && ( {state.inTrial ? "Prueba gratis" : "Activo"} · {formatRemaining(state.msRemaining)} )} {isAuthed ? ( ) : ( Cuenta )}
{open && (
)}
); } PK?LQQPK©\#nextjs_space/components/paywall.tsx"use client"; import * as React from "react"; import { Lock, Check, Sparkles } from "lucide-react"; import { Button3D } from "./button-3d"; import { useTrial } from "./trial-context"; import { PRICE_PER_DAY } from "@/lib/trial"; import { toast } from "sonner"; export function Paywall() { const { payOneDay } = useTrial(); const [loading, setLoading] = React.useState(false); const handlePay = async () => { setLoading(true); try { await payOneDay(); toast.success("¡Pago realizado! Acceso ampliado 1 día."); } catch { toast.error("No se pudo procesar el pago. Inténtalo de nuevo."); } finally { setLoading(false); } }; return (

Tu acceso ha caducado

Disfrutaste de 2 días gratis. Para seguir escaneando, editando e imprimiendo tus fotos, renueva tu acceso por solo{" "} {PRICE_PER_DAY} € al día.

1 € / día
    {[ "Escaneo con cámara y subida de fotos", "Recorte automático a medidas oficiales", "Vestuario digital y cambio de fondo", "Impresión y PDF en alta calidad", ].map((f) => (
  • {f}
  • ))}
{loading ? "Procesando..." : "Pagar 1 € y continuar"}

Pago simulado con fines de demostración. No se realiza ningún cargo real.

); } PKcDnb b PK©\%nextjs_space/components/protected.tsx"use client"; import * as React from "react"; import { Loader2 } from "lucide-react"; import { useTrial } from "./trial-context"; import { Paywall } from "./paywall"; export function Protected({ children }: { children: React.ReactNode }) { const { state, loading } = useTrial(); if (loading || !state) { return (
); } if (state.expired) { return ; } return <>{children}; } PK6.]55PK©\(nextjs_space/components/trial-banner.tsx"use client"; import * as React from "react"; import Link from "next/link"; import { AlertTriangle, Clock } from "lucide-react"; import { useTrial } from "./trial-context"; import { formatRemaining, DAY_MS } from "@/lib/trial"; export function TrialBanner() { const { state, loading } = useTrial(); if (loading || !state) return null; if (state.expired) { return (
Tu acceso ha caducado. Renueva por 1 €/día
); } // Aviso suave cuando queda menos de un dia if (state.msRemaining < DAY_MS) { return (
{state.inTrial ? "Tu prueba gratuita" : "Tu acceso"} termina en{" "} {formatRemaining(state.msRemaining)}.
); } return null; } PK]]PKH\$nextjs_space/components/count-up.tsx"use client"; import * as React from "react"; import { useInView } from "react-intersection-observer"; export function CountUp({ to, duration = 1400, suffix = "", prefix = "", decimals = 0, }: { to: number; duration?: number; suffix?: string; prefix?: string; decimals?: number; }) { const { ref, inView } = useInView({ triggerOnce: true, threshold: 0.3 }); const [value, setValue] = React.useState(0); React.useEffect(() => { if (!inView) return; let raf = 0; const start = performance.now(); const tick = (now: number) => { const p = Math.min(1, (now - start) / duration); const eased = 1 - Math.pow(1 - p, 3); setValue(to * eased); if (p < 1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [inView, to, duration]); return ( {prefix} {value.toLocaleString("es-ES", { minimumFractionDigits: decimals, maximumFractionDigits: decimals, })} {suffix} ); } PKA/;;PK\#nextjs_space/components/scanner.tsx"use client"; import * as React from "react"; import { useRouter } from "next/navigation"; import { Camera, Upload, RefreshCw, CircleDot, ImageIcon, AlertTriangle, SwitchCamera, } from "lucide-react"; import { Button3D } from "@/components/button-3d"; import { useEditor } from "@/lib/store"; import { toast } from "sonner"; type Mode = "camara" | "subir"; export function Scanner() { const router = useRouter(); const setPhotoSrc = useEditor((s) => s.setPhotoSrc); const [mode, setMode] = React.useState("camara"); const [facing, setFacing] = React.useState<"user" | "environment">("user"); const [streaming, setStreaming] = React.useState(false); const [error, setError] = React.useState(null); const [dragOver, setDragOver] = React.useState(false); const videoRef = React.useRef(null); const streamRef = React.useRef(null); const fileInputRef = React.useRef(null); const stopCamera = React.useCallback(() => { const s = streamRef.current; if (s) { s.getTracks().forEach((t) => t.stop()); streamRef.current = null; } setStreaming(false); }, []); const startCamera = React.useCallback(async () => { setError(null); stopCamera(); try { if (!navigator?.mediaDevices?.getUserMedia) { setError("Tu navegador no permite el acceso a la cámara."); return; } const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: facing, width: { ideal: 1280 }, height: { ideal: 1280 } }, audio: false, }); streamRef.current = stream; if (videoRef.current) { videoRef.current.srcObject = stream; await videoRef.current.play().catch(() => {}); } setStreaming(true); } catch (e) { setError( "No se pudo acceder a la cámara. Revisa los permisos del navegador o usa la opción de subir una foto." ); } }, [facing, stopCamera]); React.useEffect(() => { if (mode === "camara") startCamera(); else stopCamera(); return () => stopCamera(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [mode, facing]); const usePhoto = (dataUrl: string) => { setPhotoSrc(dataUrl); stopCamera(); toast.success("Foto cargada. ¡Vamos a editarla!"); router.push("/editor"); }; const capture = () => { const video = videoRef.current; if (!video || !streaming) return; const w = video.videoWidth || 720; const h = video.videoHeight || 720; const canvas = document.createElement("canvas"); canvas.width = w; canvas.height = h; const ctx = canvas.getContext("2d"); if (!ctx) return; if (facing === "user") { ctx.translate(w, 0); ctx.scale(-1, 1); } ctx.drawImage(video, 0, 0, w, h); usePhoto(canvas.toDataURL("image/png")); }; const handleFile = (file?: File | null) => { if (!file) return; if (!file.type.startsWith("image/")) { toast.error("Selecciona un archivo de imagen válido."); return; } const reader = new FileReader(); reader.onload = () => { if (typeof reader.result === "string") usePhoto(reader.result); }; reader.onerror = () => toast.error("No se pudo leer el archivo."); reader.readAsDataURL(file); }; return (

Escanea tu documento

Haz una foto con tu cámara o sube una imagen existente. Después podrás recortarla y ajustarla a las medidas oficiales.

{/* Selector de modo */}
{mode === "camara" ? (
) : (
{ e.preventDefault(); setDragOver(true); }} onDragLeave={() => setDragOver(false)} onDrop={(e) => { e.preventDefault(); setDragOver(false); handleFile(e.dataTransfer?.files?.[0]); }} className={`rounded-3xl border-2 border-dashed bg-white p-10 text-center shadow-[var(--shadow-sm)] transition-colors ${ dragOver ? "border-primary bg-primary/5" : "border-border" }`} >

Arrastra una foto aquí

o selecciónala desde tu dispositivo (JPG, PNG)

handleFile(e.target.files?.[0])} /> fileInputRef.current?.click()}> Elegir archivo
)}
); } PKqA""PKw\'nextjs_space/components/ui/progress.tsx'use client'; import * as React from 'react'; import * as ProgressPrimitive from '@radix-ui/react-progress'; import { cn } from '@/lib/utils'; const Progress = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, value, ...props }, ref) => ( )); Progress.displayName = ProgressPrimitive.Root.displayName; export { Progress }; PK53VPKw\+nextjs_space/components/ui/context-menu.tsx'use client'; import * as React from 'react'; import * as ContextMenuPrimitive from '@radix-ui/react-context-menu'; import { Check, ChevronRight, Circle } from 'lucide-react'; import { cn } from '@/lib/utils'; const ContextMenu = ContextMenuPrimitive.Root; const ContextMenuTrigger = ContextMenuPrimitive.Trigger; const ContextMenuGroup = ContextMenuPrimitive.Group; const ContextMenuPortal = ContextMenuPrimitive.Portal; const ContextMenuSub = ContextMenuPrimitive.Sub; const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup; const ContextMenuSubTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, children, ...props }, ref) => ( {children} )); ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName; const ContextMenuSubContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName; const ContextMenuContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName; const ContextMenuItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, ...props }, ref) => ( )); ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName; const ContextMenuCheckboxItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, checked, ...props }, ref) => ( {children} )); ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName; const ContextMenuRadioItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( {children} )); ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName; const ContextMenuLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, ...props }, ref) => ( )); ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName; const ContextMenuSeparator = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName; const ContextMenuShortcut = ({ className, ...props }: React.HTMLAttributes) => { return ( ); }; ContextMenuShortcut.displayName = 'ContextMenuShortcut'; export { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuCheckboxItem, ContextMenuRadioItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut, ContextMenuGroup, ContextMenuPortal, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuRadioGroup, }; PKC~~PKs\(nextjs_space/components/ui/resizable.tsx'use client'; import { GripVertical } from 'lucide-react'; import * as ResizablePrimitive from 'react-resizable-panels'; import { cn } from '@/lib/utils'; const ResizablePanelGroup = ({ className, ...props }: React.ComponentProps) => ( ); const ResizablePanel = ResizablePrimitive.Panel; const ResizableHandle = ({ withHandle, className, ...props }: React.ComponentProps & { withHandle?: boolean; }) => ( div]:rotate-90', className )} {...props} > {withHandle && (
)}
); export { ResizablePanelGroup, ResizablePanel, ResizableHandle }; PKL.3PKs\'nextjs_space/components/ui/skeleton.tsximport { cn } from '@/lib/utils'; function Skeleton({ className, ...props }: React.HTMLAttributes) { return (
); } export { Skeleton }; PKt<PKs\(nextjs_space/components/ui/task-card.tsximport { useState } from 'react' import { Card, CardContent, CardHeader, CardTitle } from './card' import { Badge } from './badge' import { Checkbox } from './checkbox' import { Button } from './button' import { Pencil, Trash2 } from 'lucide-react' import { motion } from 'framer-motion' interface TaskCardProps { id: string title: string description?: string category: string completed: boolean onComplete: (id: string, completed: boolean) => void onDelete: (id: string) => void onEdit: (id: string) => void } export function TaskCard({ id, title, description, category, completed, onComplete, onDelete, onEdit, }: TaskCardProps) { return (
onComplete(id, checked as boolean)} /> {title}
{description &&

{description}

} {category}
) }PKi-8PKs\$nextjs_space/components/ui/badge.tsximport * as React from 'react'; import { cva, type VariantProps } from 'class-variance-authority'; import { cn } from '@/lib/utils'; const badgeVariants = cva( 'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', { variants: { variant: { default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80', secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80', destructive: 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80', outline: 'text-foreground', }, }, defaultVariants: { variant: 'default', }, } ); export interface BadgeProps extends React.HTMLAttributes, VariantProps {} function Badge({ className, variant, ...props }: BadgeProps) { return (
); } export { Badge, badgeVariants }; PKU fnnPKw\&nextjs_space/components/ui/popover.tsx'use client'; import * as React from 'react'; import * as PopoverPrimitive from '@radix-ui/react-popover'; import { cn } from '@/lib/utils'; const Popover = PopoverPrimitive.Root; const PopoverTrigger = PopoverPrimitive.Trigger; const PopoverContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( )); PopoverContent.displayName = PopoverPrimitive.Content.displayName; export { Popover, PopoverTrigger, PopoverContent }; PK PKw\%nextjs_space/components/ui/switch.tsx'use client'; import * as React from 'react'; import * as SwitchPrimitives from '@radix-ui/react-switch'; import { cn } from '@/lib/utils'; const Switch = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); Switch.displayName = SwitchPrimitives.Root.displayName; export { Switch }; PKXPKw\&nextjs_space/components/ui/menubar.tsx'use client'; import * as React from 'react'; import * as MenubarPrimitive from '@radix-ui/react-menubar'; import { Check, ChevronRight, Circle } from 'lucide-react'; import { cn } from '@/lib/utils'; const MenubarMenu = MenubarPrimitive.Menu; const MenubarGroup = MenubarPrimitive.Group; const MenubarPortal = MenubarPrimitive.Portal; const MenubarSub = MenubarPrimitive.Sub; const MenubarRadioGroup = MenubarPrimitive.RadioGroup; const Menubar = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); Menubar.displayName = MenubarPrimitive.Root.displayName; const MenubarTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); MenubarTrigger.displayName = MenubarPrimitive.Trigger.displayName; const MenubarSubTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, children, ...props }, ref) => ( {children} )); MenubarSubTrigger.displayName = MenubarPrimitive.SubTrigger.displayName; const MenubarSubContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); MenubarSubContent.displayName = MenubarPrimitive.SubContent.displayName; const MenubarContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >( ( { className, align = 'start', alignOffset = -4, sideOffset = 8, ...props }, ref ) => ( ) ); MenubarContent.displayName = MenubarPrimitive.Content.displayName; const MenubarItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, ...props }, ref) => ( )); MenubarItem.displayName = MenubarPrimitive.Item.displayName; const MenubarCheckboxItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, checked, ...props }, ref) => ( {children} )); MenubarCheckboxItem.displayName = MenubarPrimitive.CheckboxItem.displayName; const MenubarRadioItem = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => ( {children} )); MenubarRadioItem.displayName = MenubarPrimitive.RadioItem.displayName; const MenubarLabel = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { inset?: boolean; } >(({ className, inset, ...props }, ref) => ( )); MenubarLabel.displayName = MenubarPrimitive.Label.displayName; const MenubarSeparator = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); MenubarSeparator.displayName = MenubarPrimitive.Separator.displayName; const MenubarShortcut = ({ className, ...props }: React.HTMLAttributes) => { return ( ); }; MenubarShortcut.displayname = 'MenubarShortcut'; export { Menubar, MenubarMenu, MenubarTrigger, MenubarContent, MenubarItem, MenubarSeparator, MenubarLabel, MenubarCheckboxItem, MenubarRadioGroup, MenubarRadioItem, MenubarPortal, MenubarSubContent, MenubarSubTrigger, MenubarGroup, MenubarSub, MenubarShortcut, }; PKESYYPKw\'nextjs_space/components/ui/checkbox.tsx'use client'; import * as React from 'react'; import * as CheckboxPrimitive from '@radix-ui/react-checkbox'; import { Check } from 'lucide-react'; import { cn } from '@/lib/utils'; const Checkbox = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); Checkbox.displayName = CheckboxPrimitive.Root.displayName; export { Checkbox }; PKq66PK\'nextjs_space/components/ui/textarea.tsximport * as React from 'react'; import { cva, type VariantProps } from 'class-variance-authority'; import { cn } from '@/lib/utils'; const textareaVariants = cva( 'flex min-h-[80px] w-full rounded-lg border bg-background px-3 py-2 text-sm transition-all duration-fast placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50', { variants: { variant: { default: 'border-input hover:border-ring/50 focus-visible:border-input focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background', error: 'border-destructive hover:border-destructive focus-visible:border-destructive focus-visible:ring-2 focus-visible:ring-destructive focus-visible:ring-offset-2 focus-visible:ring-offset-background', success: 'border-emerald-500 hover:border-emerald-500 focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-emerald-500/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background', ghost: 'border-transparent bg-muted/50 hover:bg-muted focus-visible:bg-background focus-visible:border-input focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background', }, }, defaultVariants: { variant: 'default', }, } ); export interface TextareaProps extends React.TextareaHTMLAttributes, VariantProps {} const Textarea = React.forwardRef( ({ className, variant, ...props }, ref) => { return (