From 2e998545fe592883e5634729f669a2efddd3d935 Mon Sep 17 00:00:00 2001 From: ammar-faifi Date: Sat, 18 Nov 2023 03:22:32 +0300 Subject: [PATCH] partially ready to register --- notifier/banner_api.py.bin | 2 +- notifier/schema.py | 1 + notifier/utils.py | 129 +++++++++++++++++++++++-------------- telegram_bot/utils.py | 15 ++--- 4 files changed, 90 insertions(+), 57 deletions(-) diff --git a/notifier/banner_api.py.bin b/notifier/banner_api.py.bin index 7a7c79fd..d3f1596e 100644 --- a/notifier/banner_api.py.bin +++ b/notifier/banner_api.py.bin @@ -1 +1 @@ -gAAAAABlTnJbUR4Al2V0pPo3vFTVIPtBeuj2gF40yM8LbItZhFWZgWjxjQ5t56Bk_i0kv_oEvs_cBivL8iBINh6PPXiZjFKl8yczAYQT4njZRxr1Wee0Ps9l5pVIcXJQYVLH5vesqCimVVOOEuYuXz9OcV3QeSHCdNfFvJcNhRAmiGY_SXFZSIuir3uN4hRmpP2FVZ2cKeRkPx2jyhE44R6OcW8g2b5UgANp4OQYUHZsB6_4EOloFknPV9VYTOefg30O3M45F2Bi3YcF7CgPd_U1rxgCsvMzqJdZuspTG-6RhJwDn_mfWdTE1QiUz_6KHu1XxugleFGKE7RTUgBMosp-EKMVXUEwD-tpTQZImkv1jpSPc_wJjHcxuFiq-Zcc18PbaIzSyqmBlF5hEPj4pJdJAOPzbynnCQ-oF70b5YpLkjITSHgeY7uZakw6BZG9lMeoiJ6Zr_fd1EhaVsBpRdIUO4ixHvSERch1LnNlUAtWTmI9wx-eEc8mbpFljsCtfUQdfwgFvnPp4pb-0lSXoEp7J285QFeCkLqPYjCGGKkBYmk_GK0oAA0VYCjJrTv2wVw-n9wmXMHczfaTYPKnjygUmdIrwOjbELv_qT0nlWzsNwDbjWN7iccgRbUzKMCCC8cyC8KQUt7BNNbacaVBY5MciJLzzY0PSLE6z7SQRoop5gyx2flJZ5PqK_b7feqEL2gak3cyLRW4Ae-PPQupGucR2ZLSOczXfluaoSxkI9daoUnHL1S6HRsF5NH7viXpv1xbx5J_pYph5hNRDSiTgkYhBBhUeV3bTjbr4c33ewal8idiTa408RePpo5yYwhqLEpVw1QmUmS694ckkEaWx0pVWPxcU2siDdZabhwGaKVX89hptJDXh30HRrSflinCUOLS3jxbItDEk9zlUzSy14n-ieQEruclQ-J_7DkDNCCEqbkzTu8PBUrBY_Hl-p2fOIpDZuU1OsCZ0RrslIZwT4Y2eVQUrIHx6dr536ED43eUaf5QuYuzJqLsb2Bo-GnaQQFMwJgBcAyeF2QPTTxtZhlF5sbP7AKtSKAyNKJjZgMdRr4jTJKWoqf9AH2mstnOBI8U7uF55wGYa_3_n_SJK_9LCnNsSXMJ3vwscSGUzz9Q5KPKE6ne0n20Kfg9lUyDK1aGm38j7gFVwdP4wZZ1MYkjSr2USLTh-w8omEY9t9Sw6Yxt6oxAjc3ENveIP9Rfe6ruyWkITm3F9aFeyOJESF5lQzD-MwSDKW6EZwRekrrTjCgg4qpA6YWbGvC8Uq3nTq0R3D3fXYveZ8YvGxvacQi3E7z6J1KsbgQPIshYCbcx2BBv_G6ChUe13fvcczSRM5SKyUYOk2G90yDcQBp_j4TvAc_-b3vVX8tbDUObHCn41U8wSfUn_IQPHb6v6hnyFHobezsLgGE3VtX8Ut9UJc5by5uH6xDt2sdGS1tr9QC5TCvlxgKJ8mwKMiedbDbKW-rompI3vbwAJtO3BuvTDJUVqUt_cQpwOMZV0UmVTHxbZWInu0KlyEYTitC7HzYaLCbZ3PCEJQp87OM9D1MtuqLMm0EaiCWy3v5vPGIhwPnoIakJ6w-chAY9Mvvo2u89TYaQWK3m6SMuwIwjv9pA9nM_R7cqxIFg7ubp6N5jnu_emRQdZljraFSmF4PJUvAy-FX0dutIrFAgHvZ2u1q7ZmEgrvB0Bt4isRWHtoSEv1HRvChXHfI5ArJaEIQo0oetMnRUKRPBD2GZe3dalYumd-CIzlME7y3fpH_1schR8d5q-TxyE6nK1ioQkd5Tzp-Ft3au_qXHxZLkMo56uWdt3fEN_KBLxmSE6-wodzLW66q2aURiKfP5doPdJdUOXvrsfgNMYrOjouVr4DR0BHbTineCPvZvrcmzYyQ_oYzG9o11T0lCx-3z9Epkb6D90Vgny2BE8yzej7xUthCsN3maW86_aB-ELQ0XlKOQGUr1ZJfVQHeZsMaYcELAos5_cXi6fyryGyfLRBAZNRKvMOf1jPyiK7xvIraINE__b9oLOuhaTxtEHGzq8UGIx2jufFCI8xNYVzAYOrDRbV0tkb_pxpdMtVQJDoZetFUv5TjAXJad8VDC8PprF2jpMIdKQOtCNNuA9BabbPAbiYEXcBDaxp6xjE8DeXZOMNm1lfDklzHeAMLGmSRhQWlHTP5DrQKG5vnVihwlhkQlymRTf3Pq52iopIZiCwMHE3aXbzgtfp0nhcTJ6hAoM2E7DC1LE-_QHnatk7SaQACmixkLC5iFeq4_r7IuNnMxat2AlA4iav-F98zNELzW8OR2P_-rx5Y7xXxc2mMW7AHJy5AQ-gRUlSuh1hHyAnOqLcbWfNcdiNxxJGaPBbAmRDbrFB6tMnBqaeXky5iODHzfpH763rKrLkUcoLPiumIiHN8vAMttdCczFerFS_UF_IaXB1a5vY3M3_KExBu-_iMF_L1v1g-IWUOdh9ZD2KZffQtY56h8YNKFb4HvbXoEYpWqw99kgpJbz2eVKg76HJB_e_UjDVp0TnXqrRMGEVpLJDI4YJz5e2l_Nr38q8FqooRUT994MFjQpAJYMUJTcNAOTeG8ZLlJ_URVLDwgH05jASZvvQghyWv9sGRjFgVl3XHNrnIGPjRiizZ9qlAKRnjjMDR-mFQVIun34bn5MqPlz4CnoQgv1QWkBM_R8ioLg9cYsZh3g7Ed_xgZIKJ1lS3jfZCjtmhKkOPNIQVSO-Vlbt6v-KqxJeP09BJiA3mi_-wZN34rhx2Zy8hc47hlQ48fxv_KNf7pPyNSdO7p8NqkeoUH8wGV_bbko6gqDzg3tfabMZzJZcZ4fnfIgkWyBQ-zNXeNNI__OFPCpk5pIrHMZmwvXarFW66Ju1ByPUVH-8tgJC_OgSvex9EMsgVz11Td2YiKRfo9D6rbZkjKpCN-PjzgppfUrytZ2KND-9peDbCug-GwC0mOWzqWs25tJ_7rqZHgqZhRccmy3hfR2PnvGwrcpLLLxf4qipptK7lJQXiL4oMrFyZlNpXLgiPjZA7r3EvOWZZ_ZQnQndH-H-EBim3dU2qRr7JOqF18tg7cEaUSQ8pqV3m3MMHqN-H2caowF2rmhejkEtdg917zLhmOrRWQ_hn6zP3r8Y7lcmK6J-gnK3sDujMSTkaLWhPWL2zWlWUMVWEhqeXyEClxsgR2Yy329ft0HugPviLLK3EDVkq65-v1SNPH138r_OWzB-S7lsO_G2izV7gX-cSHEw5HCACVRivhaQbeTTMoOZKcIj843aYuKVib2OTzb4CdljVmstk5BLsXymy0-FE0sd8It4TPsAzDxf_VgYhl3dFjG-xynRjopOW5h2UP0OO_LXc92CvgkR-dWIzB2cIKMvJZU8htNn4xjZL4lU-OwOpcjf_ZaFSaWMqnSfKJuloLfoVizdM_iIFlQLN-dffUgKO_pPZHWhIjGkaJ-oPd9JaL5PpyYr42vV5pZVMmLblcbFA6vgbmDUuPP9TXkkH243srPtJtGAew2Zd3oazSS0osVpAYJXbjGQo6oO9GgvuYQwIghwfowIp-KcAfCxaKfPDeHMubMlF0F3-LLDQZsGXyGGFLDB7t-1IUuhp-ImaX6Ia7NekKBfVxRuul_QCi-S6HVgAsQl20ZFGjwO6GzUT4oGWwbvD5wu3Ell7QxL4wveK2uktXDUzsQUHBeHPmm6QrIcYVfR9xUbJOGbq1UtlZAdTp6GzM1B4YHHlQ4fpVQuHWdrgtRBNUnfgBWvA_Hf95IWdXlKfEMtn1lY7FhMBt3xEZi2cZ68eOsv9czPdUNuAaBhrQITM6M1b5DPTV_N2epV7N_dkYN8dq86LsqvGi7IP-09mCrUfVqKNMYt_cKkalwBfn4l5G9taYo8V1-BBvV70Cu1r0NQI5lo9apERsx75UiarBSNX4Gm-UhcRL39JEmn1Okx9ggZPkdKJU8I78OvspqtlgTqLvxQwR_r35i5gSuKaSDyVfVZB4hPFa-gi6zpCgfh3WqE92H8kvkcL84yC5llzeaw0Ep8uZBG9r1jzPrYLF4vp8u_KT5V-DBa9RDdhqxN4ZDKJ59566DDUG4vumIwgFQNYXiL4XpRVPfD8tP2cTBztfahkkg_NJ-jY7JAytiUcoWZfw7KFWRJe1D-TA3vWyeJrEKWSCsNI8ttM3Nv8IkCfJftzht8CanfDZBtL4AFZaZzNHYza_DANRRRA0mU0bPqde-mievHmmygnHE4o4PqGKP3BXSO9wuLuQy9lZ_XbmSSoJQF4H9gs6MHtQKlG7o6UnhIhTxTY_dWIm_OkzhWKc2Dy1bb4k9nzrsHLb8zdxCuSZvkG3SnpnUfIu9wjktdjr1PYq2j9rv0OwTHIZZEM3eVosK_3W_oLnpRUzL7lFMAJNPzzx_s4Yk_TPf3ZyRWfvRhBxGgHLVVGtvzeenG_8WstPgdi59_FfwNt-wl7zXU6i_tG-PaXcaHKU-52XxQHhfKXbnG-K8Jy85vv4GRmsKQbWfBSb7_g3K2-On1AdNSFXdhW-RX8IYGtHAIxqs0I_r78cE2AHfRwGDWdjwCJacqz12Jy4lJx-XrmJIiNT5N6Y3fkjMOyIojMyT05pbWINklBioJeJGswuPPK2A70Z0FoiMdL7ufukkuo97_xc_R-yoJxTd0wFYLAUHjtlJUUEprihW4w6jUG9N_DKMk67Usprd0YweZHBsPMNBgheMk3UTnKHWP8Pz5pTrlHY3xHajwsB9U31hvmmiAwBXEN8tSAaDdgyAm0k8DCSK8JwrrZkOTorSnt7mJndPslpXf4IYwoErRaJWjObkaeCEkr65wVTtDFdw6aGtoid1NhK9gEuIOoYd3nrRXBZewkZA0j1s7EFs7w0hyvBbvVvOnhsiYIP7EE2X3_OOFx3DIZPslRcpjrFvANLJI4YdNIGv04IfUbJxCn6B3Bf1b0rqZW3onDnaXzgy7YvLOIjA6ym7RW_nJXYC11Iu3xyi5ljQSDnlsI9I_P6RZowMZnlGPojpxbGf_sVHDxT8m_vxlfToI6MSG6U4QMlkYKswXdLUCO5YBiv5UELQ4hHKa1cSKpUiqWcxce-Olrj9rTshligKLbz4i-Mt7X3w5X6Pfqn822UNuQQI_6P6sBUpGKrNJg2uxEyrLUmsq53As43742OBeChfH1wkqAmlFxjfpP0SJRzSc5NXqpZcwiEZiNUpY0mCdEbrCyrh9GNIYtAh9vsnMupRAvMytErEul_br82Fd7hcbAqF2Fd7jwHs0OFw-XvpXpI4ACM0aXiW8MoT9M5psawZ2alEJjLbMJZhCH9pIAZ_tiGk7LyWdyTo3X4WeB9BvqNtkqITcR0BX3_r28E-Vgtj5XryZKMZK0mbjzNMDHPWfK6JYbZO6k7KwzMxITehsiHBBuqBam7Ic2D1Nqy8iPoMNZjwRebPeTcUE4MgUte6HWfTGgDDe9q2sKM34CcVU6GBIBFV1Wr3STY5uJHyyKIzdRBZXnqW20nWHcBomgNCf9iXb2oFdFKwbegPx76eTpEFNOevySM4eIESIoQh0A9etjDq7z5eogogRTBZniAPTxd4rWFBy6dBGnxZlk-TVboQlh7B-o4EfUQa-ZI573ayquHwRQAGhZ7wBS4z6Lvu7Ip232r5zSg29PZHWx0mXQ-jJsCBdh4iueOpWcJFOUs_x-DG0eSoBoTYkLZdEA5FXmRjOqslZWilGmkWxp-TzE63KrFA54VuZ8ZwwEeaYIlXjZ_lK92VLYdsuzqfdmU6Eua3Jm-po36oSOFSc9Y-TCx6UAnM1iLksD9LUC6J0tn8N1yofwVa8w4p3OBl8TSoGrmjfFluuR2rRNE6vghNKansIBBL0NLPPwpB12GnStmPcWInhO2mqMdsOviqM3qxRkebgc1VIBZrOU5Bm_qGwMWd5ktHG7cr_Vserm7KIAmXzHn_ehg7SQ06AdGaS7XKyDeOxnZ_m67QWoKpG7mTOozQzJ1jk8RrI462aUw_O6N4uG6tEDL4QTwx7jhu19o7IwXtspmHX74OOBvf4D--BNuWt17lB8cWK05oUwRGmMi6TxuuQ9QAVQc96RtdEXTZ-dCQsFBDJ7nz5p8uZQ4dcyzTZ1b3M6b-8FHs-K9Vudidp6lcVLg-x_6AJZyrlp4vBrqFant0YIFIj-m1abdWgDPBw0Nkdv0FzuW15rnnq7sU-xV4khdClIFOuErnHrJubJ0b-SzrX13-Gv14f-xVY-6hpNqo0xjx289ZF-95WVMVzw7zO_-8qwVQ_4KgX0T5-7v6V7ieH9VaFIyN_kWcWUyAWY__lLhzQUxgUiUlbZ3kZ2zND05ikFRNUZm5RPIy1hXq9owOwI6Yuo5tkTX4-rtP_kqgqZx7tBQQGUebnu6N0YUmopeRcjvIKx2wdngbeVk5eSZZe0m6bpdxNPCrMMqTR6b2wpkUfRE9XHermwbtVCZV-dSgw6b1c_IJgqhNZ9Zk3cWp4e2XwhN0hlN7RmHga0kMAV_M8M4N-dDU09d9sSKJT9ryaqAK1XkUg2iH8twJAYa44sTyjRmK-gmGO-S9u2Otov6YA64LbH_CWbGjJf1GLMNvF7K9tjlpCxsSFbDx5ibAKh7JcfWqPAjSUCnvZF6T5lgcDhzGthnszUKegT0f94K_QcqVKPffipnJPNySnOS2mZXgNtMEzCSRSfnVnGV9NODCmQFXBkUsGWDgNZV592pKY0jC-_Kya-4UZ5u1PCLR2hwoEzxyhHypmW5NEGmFJ96nCXhMXp_l5hvW9NZ7SV-woT7MbZfIIJEW3DPWVxlX_w7VXr5k28VApq1sHnv5jyb6y7X9atzGixA6dAJe3bjxBaJPxGwaT6aUL86r6A7T9CyJwwqTU5d5Vao7lZB7_1_nEdkMxWjJ0MFeMWk_He86uuXiH41q6hLafERjOfQ-FqdAeWmARdzqzdqUoEJOVNOaD6hV9dA332FrvFTu5tkOCdpSFPk0WSvirg6CZwbIEeSPt8xMdxas94_S4Ho9_-df3IB8-NXueYMkIl-bfK5ZJezZ-n1tjmlIRjBabhcA236iU2Ya96Oguq-iN4cqfYwIt7WbWIf5oxrAmNWZcUlhWpYimkvFPXO9893IeBGZb0DISlI0_qlKvlaixwDQMr7s5kynYDaqoLAd-1INdZIjkRKbCOWYOBZsGmZ5-3HCrXqNZk-2mLgvQWyshB-0QCJdp_xHpUlC4sLVoYCTEBRcdVeMyzQ3pF2gJhuvt4pacW6bGkjt20_miz0uMrVD5SfbdVeWyN2NRPvbxLuXeURNRw9YuhXHE2_v9nfhyUjo1SYIl_JnPyN6_W6d32jX442Yr0jX3SH0LQP0KUdpFAYK2LGJuY57-MhZARaJfdb2Jwj_11c4F-6Q31DrkaJNoWVe1QpIpH7PrMdXnaq7Uc-WWOPhMtVFVuHxKroVJWVLuVpufUqF7pizjtNT1mwey-JCvc568lpV25E2j-MX9iDRP6LQnchV6gYgQGGh-_Ld1_Ofg3Gsp9AU74NS7XIkJWLINk05RzYo0mLKtfj3Ky7SJe-0hHqxKlK-mbxbGnRrbjuTWT2zPAAo2BIWaz7ch4-h1ZUVQArhZkSv9_KN4wjDPKhTJkMBzrzRsKjOn3xFvIsjYuBO4jxj4P2bLJTpMgp_O9UoNcmoZgIETwj6w82R0ilo4gTxanIpQ45TtWOAuVdwktfns5Me9qU8Q5MvI8cyClqoYLnI_CeBECt-BpE6xWv9JYh6iNVQGtzOBwBB2ceY2m02ys2TQ19yB-QFUnJg4hf41ICH0lBw26xJ8GB6_U4OpEGGSk2Jv0q1sb_g0Kt_8rNO78XPF1l7BVoU-SQhqRo8XSXuGofQ1TQEiwUlyJCLZXFwcnJWMPOCET8CK9A9OEFwImYntnuARgk9OH5tqSmXKZTUXxz30ywUfTqxCoupqUvAPDq05QHFOG_VCyETaKvGtHcxoB-n2CoyJKTISYFpuOmPbXxS6qJtr0UlP2pQf58nBxJPH9JeRVnFE1ql9SZBYsE7d8Xgfd0h52GjVpt8m_cx_BOJQbtcnOFM6CcskgVRuUWFn6hAxwN1SDf3KNLZ1SL7pnyg-B7i4aE6Wm4r85OEZ69qPVKAKAMhLh_UI_3D97E8Ou-6maNOQL7Q5RlxfZSNmkAMHiKxVuybFWIi5xd8t_owqyjWpjjyM-Mobm4vPvXns85FvGP1K3LixQc-0AQAFm_TBe_93ppv9N9RQlmzgIVGpwFe8zWySVsag-JcPTgs41Y_l_zHvnp9beZ3EwbrZ11yaVcRXCUrc8WU8_mE6Cv3m5msBugeD4bTMH358BHqzJqEM9YuKOzJphE0jxQh2HvuqKaxTWIDqatloJGWM1dyJnTxAZkbWS0MIflS0NHPo_2kmOKpKSUSGjtky_D3XficQc88nAApnlBT3rC6WCWa69v8kW_K3m6IQ90wdalB7ArqqrY0RKKTcpyOn6cX7dayhag45ROjG5w4SO1w0rxI09ggN0ft_EOErQLv-2U7jAu4_qW1T58O1prqwrFvPSi99WFzC_6xIEFMwtLKwTHGsyOKFkZOBwjjX3qETeIulm8iD-La_8166ELiET6ibo5DmhhewCpIpEduHb2Y--tGgWK7SSW7sIbX1ph-AOSG5qZCzi8Z_bZ3m6gDNy4xdk2IVWD7j03F7i8WGJ30hCgIlxJGt4Ax7CwYg5VZWrIuHXSdVqJGnrFOgIzagGyAfqoWjPBdTug5Tyw9HIhMfYEv6flwqTC7R44DMnfmvoWVMSWyhSVvVS47U7KjHoOZGLLUv3H64mC6xNOUdHJZWP_gPRIESuY2TjG-wkmLTN_Mzwl8essXDUil_htYjh1nA7RuR_5htkD0cAAapCgFm3kxnqId8llaxe0dNARC5oUrIlx8wD5kdC4IzCe-3T1Bih75YaVlpaHMnuu8_EhvqFuiBGa199KXodld-LPdqkfmoXv4m69uDVAh3vDt23rGaLdaAP6S3TauIIRD3FcXoYLyu3gU3jn0u5hzjIBvxv7ofZ3AHmtMvq8tbQMyM0ou_keto6mBX8Jx5HaavlQ9j-r9ZSIWpljIebLW9CX733Iow4G9-QFzg3y9GXg3pccTOPDRky7b0NI_fwhssddBw_Atby1R5jQ2CUfOhQ6iM3VGcjZWUQJ8AmzQqD0xzdn3uCqeN-HvFXVg48bTg4O0DDLz-EGit6pg33e2J0Fw48XXk6I_Prtm4QgN1vpsSAix17WzKk7ImYqgsRdyo30RQqIV7oGCpaYFAVWCen1tofFZVsLj7mfor2PcbphNlz5JZpTKXhBN9c_xxNnlOSYp9iCnbC2WYrSRaL5EgJLIXQGvsZqNRmNgPX-NIo3voUNUsQMpfIUWV6B6KlXR5uBMJkYlXdWYv9hO14J2Tic9H8xfn8fQRVfr_5-cyNXHFkRajYqNguikPHKbSje0Ks8skeZVjmm5FoLGbDkklXzZji0oINl-UdhdSHEf4jB_-eXeeIBJMuyuOstHaZQrZ5paLJY35vRPdMuog5tjCcpUmPKHL7vQIPW41xFJWe7rEDRMl_-Pppeg7IQ0AGnoGBJDlvp6wdC5hy7smBC4jrOyIg845v7fHLKPrYX5js7atUaSWRaBSh1S-4ujO1r3F2-h8CytZjNnIDhw1mLMF5_yxnUhs-DQNBByQ-dcSXOr1WsOD8Bv_E9oiF5rHSD1tPFglce3U5yY09OtGBPDMsl4wptQwVbbRthAiYhLPR3n2yvcYF6qcTWRnT2CN1_ipezt4m9yZF99jJBlJlfTltgXlVFhHXxcUDhMNXb9nGgSMXKAlGUlf0RM7AlaiO6mYu2q-4GBafmuPUbaPZAHMX0BTXQgaJL7w5G8nRLyqv5tbkmQ3pxZQ8z14afgy8tiMMhXeKSOermTzwMVgfTqCz0lPQEblHP0WjQOJJVyUhDYtvT6bZ8KRVflNcwtmq4ljsCfjwIPjintcegP5XBHHfKuJshDe_gLNCxqHBCkfsEDiuJfy5bID6gmkOl0oRWxIS14sb4AQhj-oH4Sf5grzevcJb_ILsa2BbdPXNkB2AJLcNxv-RllEuNOij224jna3LpOl8CeaISMq8iUtJttL_yFji_Iy6eS2hD3Im6y8f2B0yCvDhKZ-qb7uNUKWdd9MMrxa1SOwC-Iv1RNXP_vojPKlG7Rr9GYMQztRViBQkKQqgEyyZoWSns5LEGdAA-bZiRcDPK7KY0hzr-dZuvvHtNbGELBHlU0VDghcu-kRJ2ByVKv6V8PALVZfTj4RFSu6YgioU0v574Z8DapGdk3CbNPWnTLl7q0Ey23ghmXE97_gn4_pVotw4112Kun3jzFxzvXfvb0JJyX5qWFmaFL851G4q7rfqW1qQRPBv0bsTSH8azokIdgw4zbKt1aTyEPXJpDoWUq_c4VhlhELYU8gboCp-jGjc1G9SQmBdw97nGkYAulkc7EkkP0KJlnqjvNOGoDxJLfMs413bNJUZ4hq2nQMhZZygWD1Md3jPbH5d8XDh1KBOrHZtBPdoidRoQViPVtMsUfEmBcLAw7ma54SA_o9ifWptQJZQ-Yprdbf_rAIjjEPdjpE7vZBCklUrKUCxSDa_7AEiL9K5PhvW7pCJDtwoQrcta_27koJOFHo1V6uE4JOd7X7X5zbTKpZJzmy2AlJgfZyM6GnzFjIxHKZpuiv4VXrfVsdo7GfMlmrpr5SoPIdvhcBveyVjkeSBI-pfrt7BIO_EHOQcgIm3FrBKUKMwV1mzKaEsVzkVf3xp-zZh3a_czgzvOuv_O0QAUnku3Ye3JxRET7BaF-VStiGmeoD11So-4u2KKbbnfHKgWspUc8vH29eaHv9tImsUunYqXmMIFAIOjD-1SU3RMVYA4lp2Ja6ZhFsDOUynLEVqpSH3TH9FAyTFwxAoAAUXN6HwXU0jZf3WWpnCWSsX8k2uT9NR7V-XVi3TY9MDp3h3fnvF-nHNGL_Fca0HKAu5TijcVsxAHGvLjrd2N4lYBvbUBoRQ5JqLCuvifi3T_g4b_ehb07dkZXpNzqflx8HExEWW84UojOL9nLjd8aCq63xNFnj7AD4zetC-bih1DBeL7fwiePIGCWqNffWwPcCINXYWyRlZ2lVuGCgQg8RTYAHJ0MfcItCHdXLJCw4KbUd3aQLGmVbMOMXES_TVRgfxbydKdvti825Yt4sTEEjodtj4TcFOgFKNWuQA1Yeh7xtQ0BLDQQdrUikJ_G8arTRisQD6G8_JDNSDToKt47rec06FB3S-DjQ-msZCba4JGG3jqa0i2UBv3sJe-oG3EOj0TYkC1BYSG-R_cBDIc65VhWyLJTcL8BgRsy6oq5uCIGt8weGz3rMUdDtKUrrC6krTwIIB1Gh7hdzuaSN612OC42XCXhiCOfRZ4-XNdk2Y-qDzY8P69m9d_aRgIVyrZ2_HwyPu55Psf4keYJoT4FeNTdtDgdZkf6Zvt0XSBb4rDR_Kqa0XEEuUpHyjItKM72X9SLRRPPmFgRYpMwIQxyWLoMZROaEj29EP-CP14YOWy32ACUatJMn19eFglFI4IBSDjBomOMbwkIoF-Aj1aWdfB-f2HQA-71bCLL4lwfwZeyrhMjcA05i6f0_DgnJnHHcL-GhAErKDLprvKwavecvO0pxgkiszE6x5sJMlQYctKlwn9PGzQ8rwKnETTU3O4DCw0IganbofLLGHb_VPipEMXwhN7qGhgZ58l9rhgyoGjwMPbf3MUBsJFggbADvUjE6FlqtOw_GZk1ZPz6pW6XXQvH6I2LoBkRKw_A14v3nQ3-kinqVupAaCQvw1PHZ3QNiIOzsLHsrQu7Z0MjkCabiiGhGoXrkXjYT6Apr1R271WNWBWW2euo40np1J0xgjzlCXEbI_8vJ8N1vT2VdA3ojizfFOApuUtQz9XqXrkCXNbbffy5O77Vo_RBo-9PuHo9ufD_nsvKdGS4-EOa_bABYiG8v5g-RnGaY7ciQmJkfH5zCtLbar3lAeeuiIkr1eZOPToqP0TSvJlaUoHvad_fzBYfIwDFJF8dYmROaLsR9rYUTFcSfqOI5tTn63vTSlzjhobQlLPsX7UD7Fw5TZ_OBw0O5h-3T1Q3g4LsqRPMnUcYXNDyYJ-wfdbUQb-NLJU6vC3OUS7X2i_HerImvnC_1M6h3VPUNslIUGdPWc7uetXV-E9HMdWh7FtuSzadTIhYuIXLEzzv4cPtf9YjolYI9QGbsLk9VwIMHEOonWdBhubcpk1gnxY-A_lx6fhhC9I0gL06ZrrJYE34ubWshPdjXwIvHo6s1MTo7ItKUO3KOlUKriIyzosRQH7zawMf2ovL-B4Z_sPuSdD_Mzoalod1jCi_K_Ir9JsXtvx5cI5hKzsvF0PFeEaNLcq7OKWbhnIXUu7gakf68D9d8PRLpm1JAE3s6Pl0ZCcqRezttAa_leW8YEHZntSYTdppRCOxlZuSU6aeySGS9himtyncQXpoOL92zo6OLtfWYEtXM4EzPVr7Of5ub17gRNKEgD239BQaRUdynXohkP7TsW6Z44WPtbmIeSNuVUd7WByhNB9fa3H_rJV5RDNSbVRMVG-C3U2h1pM_duLNHrLXQBYi7U5u6iJ0GocIKOgt61O9jTlPJkj9zcgMweFkvy4kt1nJQsqpUvBdnTcCITu09AbDQvVqkkFbzzw9P2mzGVkaSI79hdZc8b2hMwEO-2dc8wDsjCHaQgZe7qACV632YP2IRYCPJ838v6sUp0zwSaLEdfTS3jVjwPgZ5DfaY4Vl3rkKgzIxb7pW_ZdpK7r7ECYJSuLNkL5bVI_TgRNeMNyerr8TD9eoW6YON2ksUiavpNVOSWf8Rl7fDyQpd9-mkY0an6LLTN1K3KMd-1_uszipMazH1FR6ghj4C8vKEp61Gmv8PkZ2fgZZL72tYw_g8PzF0u3fOzxNsjTHs7H2FUFaN-3FXGiZP9lHBdINwSZe3SujgnDwM0HNEpNYWrJbAz6IN3H3HydZviSMzovPW51eZ4zFxZgLm7FyZyEW2IwqwWo-LdQ \ No newline at end of file +gAAAAABlWAOd7n4zFrmsmo6vRDLxMC-v7bl9HkLa1aQDaAcXc_J8s4f76M6PhTbR7UV9eYhwMVGLyxppuuMYkCobOPeecSqrPN3KEFzNFhThq5JElS4J22c7NtRfPT5p6cpZn6fl376-U1c4ZsuYbApBeI71D2_ntXEgXbZtOzh211SWyM4nsr1QpOzYTALjYWamPteKBqlZzhUJG0O9FvuOKzadYLupGCHS0mY1spTnh6yr_NuocweeLIST_dKI7jEPDQC9YpYyqrC3ZIJ2hnIvzVgawux4zC74_XjT8YGaZAkrf_syBcTZMolGAGkqzmfWFEmnJQgmgkieK5qpNpRKqRy7pfmCFne-kAEe9lhEvfyvDcZ4CrM9Cd9tVyxLarP18mkHm2DszrcDrn0sF3ueizg3Tt-hShVd1dh6LroXGipwVGh3HsikMwgXn5eLyn1szb7Gr_nlF35iA91ypxPctw_cgu8id-pvBrwC0GekoBGA5N3XT_OS_Fy4OkRXfzbIa8_PhOsdGhfMLCa8ajaicBOX_0iQTDhWL6G9na0PJAFzHbsrDU-DdnZG0PJrvi4XhZsVwaeVKYZpZL1efBtwYMuwxdErrd2SM8bVX8GExJ0mjrPWyqaWGmmzSCY49fcbCLYfRelVlTAuaa0yB5Jxlg35aE2nUDipj2uAUcdd7N4VZwcMsdqE-V92IK4qVxBTqD9izCh9nYpCDF1hSnJmbGOdHbc0SSgMeLxHgYbzE_jd391tp51P-X3RWU5yVmGouEYUyyQbUJUC0ADG4gUujA_FUK1qVvptGJfsJ5PTitPewtm3abBmWm6XI6CBy272MmSg0xBu-tyeJtfexVSNCipn6qzFDyEJ00UwnjV9hxOouBfZlIwKN6Omw9oUHx9hQVnnad-GicdAQOfgn7icFcr_KhaZ8kmXmtgD1GquZ9p-a-n-B6LfOsBXK9hlhpZcxspZunwGmjTvlYTj2f-Y6QpKBEpsk8J-3_kDhg17rgi1HFbW7YtHmD8TgXoCKmiQ--xFvkjT8KQ-XSecWfmUuDuGk9GYH2H-ydvVOGDLyAWj7YuA8jSXNsw7RoS5UZ7nVtDAqefPBLv_WiPtRvn6jC8eSBW12wBcKids6ic43Z7OqRp1ePYrGXhZEiOxrYKPI6GnkUyOOO-1BHBY-tw_LxM-kaVi9WQz0H9GUPP2UAWz-OWBaqmAiaQrvMwef5U4w1RQYCrnMr1n38bj-mtX1V0pG5EISKi6y7LUlmesd-wi-tKZW_qqeEnDSePKMhSxBV5gH0gN2D5HbMLPvFoBCsEBDnKOUCeCSQHBGfDS7YAOgGiXrEHMl0J699F4pEHTGI0ll6gqUkWHtk3CZY2mYmejXnQ8wCxxSdb4U5_tp0bwRD25ICivvABMUgEN8eXGejRtli9FHpR4ubZ-hdl1lqE-E5qc9lznifbdSY8NwdIjDyn34KvnjbtfScD1GFAMRgc_JmQzw5DB6vcyvZGGptRjOGMaEcnfLvbWynA6GkbTdOIKimy-N7FxB1b5v8zuaUKI1CRyfrqeMCPJdCbd5Y9D4zUNrKo9IR5_G81sxb6q3vfrcvwRGfD4rnxlU8uERDm2y1epRjKKk_upGKfDPjSLMwNw3sIGQDcXSrtir7VOa65A04qrTrRedFdrCMbaTqz_7Wq5lVc2-MwcfCJn95cG5Iubsb7zH760maiYgs2SIR3stfCj-ojT0_9WJrgHe0SLFP66Te_6DLkPAPPxNyN5XgzJrJf4WpR1O8FNw0VrgSE9rNMyz07bmH08SDzBt_fzt0ujLOrO490HYOiAotZsHh2NoyenkTi4BjOBH6pNiwo8LDsGOdXpNaJMFFZQBdkJMaQ95q-umzAN580IZBs1bB8vQF4RkR2aXWTMDzT9xTD8JXALTupxqIpYIyrE9-2ibri9hK6KRXXVrBMIXn69EJhITZm2yfiLxrtM_VcREw4hQDHm0NMuNNmdE71hQw3tFWA_Ei0cMn8bPahYD4NtRvvrbL_xGs3W3yyqdZjBwDH-1hvBlMPNraYWWaP7Zh5whNHgvXgooY6VAPlFNeqe1Y2TA5GhEysGAAu3m7DgFajq5R5BnBQ3KKCmEg1yibjQkMUgZYyHwMIiyVCxzsnD32KvAWCel4au8jdibdQZJnPb8b2M3yu-usD4LAsnUHPmoB32Woy8PXyAWFuxolNuHIL1NMvNRasQFFZVQf7IpldGsz_yMySOyuv5QUaesadZtQC1UA9-VCB4Mbo8n3w0m3zPSBfOZFi71ffv_gUQUBefUtMh4tZzJY9qiQM3DPPbIL04mBJqi9_TGuOChc87pKcuzl1cF9UUJm-w3derpbmnLY433HdJoYbqUFAg2OdCD6l3vSBToNKJg-nHod7dzKVzLyIIxeQqIKyrk72l8OU95o7nBVnOdgaerxlzf6lT-dosrYuSXGea4L_wmw025cYkv9m_LovDzVpqGTU2iD3exY5N9E-T-tTep6B-0o8_mbhGYhDWbfPqw6fcK-AqQ6rgwQSCMtyFT6ALjmG8hqUvYq2EC6p8xg-o--NM4q1oYyIIWjgTaVherWzSHeq5wvrK_XMmrOa6OYOFknRyk-YNTNhCtmnVXSX_NSopIaYxe_PZE4404bKTtee6v5dm950QGGUaNtM5fbNf9i2v6OoMBlolRRfyQiJLU8asleVwVfuTT_rSNNh4lcK7owiTLxgobubnqsJF_Mmoj2UD93S4Qnupk3tv-ZSDEYxW2v0CNnrb2YVrbgtA5wNmjD1N8wYTpnlxhySS8fk4dcTpF_8_DNIJctLqy3Zkn8pW2-9q7Okjszq5uLGrA2KkjcgpZ_Wc6VT8pWIJpAlFuBysFvITSUFRQniVTHwTxx8A3clf29I9LuVohJYZq6dAkWWXwgB2hszGduha3uVvhvjk85nUE_yA9KaWjjX4UL9JN2HU5cJC8SQXUO6TyxllTjKr0DOhuRwE9ntmBhlcWBxQ_n3pL06Zth3Ofz64rwVcVN1ef_LLUKo0yzCn1YdaDPOyosmwO4sNZXr04AYfYx1H2AAMZRleU3WKMwPnkl5Zex5ZuipMzMAg4Ty1PwhB0ljaNMmtwXQRMLZnhpbBuL2C9XELJaQRgvCD2atJoWOJcbHEQzCQ9MyeO08akKcntDA_XzbU-AIVs5jQve3-vltgC2KU7ghtScFUTJ4zjdAkJwDAO4ZvaHweWRtDBT2USIkFzOY3BL-wJGTHeMT33g0rrhh90UAhLrZUOJ2alMR-y1yjDoNmGFOd4RgMWnmJHcIuNNsI6ac4s007P0I9cpBRIaoIlaiBUoy5NVar4iOTcvE_UJ6jmCUGZeGr0dRO_VvscgXZu-6g0u55Ztwkg8B_6hgnVmn9rQNPCc9G6Xu_qTabGrRl5Eosl1ROLc3PXsKiGQOfbd8Oj3DEpNkema1mad-tuLk-FBNJAZ4UixqvyopSh0NmR0YdRtP_oixtC_3FMVr6DPYbCCCzJd7IGPnqTFlPdJrGqOqlgVRCvuKIsevzGlTwCj1OD3XwABaSFK2TwKhj_4gJs2KZg3-GiXlR81_JQzImr1mQCzEDOBjB0pJk6_l164_Xe9PreMLlK3Y5ylWh_ujiZj2GqqMZoD1H5jH8gr6cWO9Hx31krgL4O45KTwKZkAD6p0Cx9uh1Kef__JC8DFZeOraG9Ei19uMcRy1YYhqr0rvcJjLzyjL2PocVR9YJMOA8-8850RnlgCSjuv9pdP7L4nwvPlyunFp4eFGfUZ1TXLqvR5S5FxRL38YkFI1GDi7OcfnGH90G-4PNWE9tQq0V8hPZCFhk5-SU7VVUpxxG6kdmTWyimJCKkP6qOKTf9Q7uQNabE7_W3sVnbjf-fOr-qwlow70KcHPmNRX-I6bt75h7XGOvWJs1QjiM0NbWzShRKEZCjfCf_ORESgBQs-kZaGVCpqlO5d1qFvCNZNPpSWfAriaclxuhEdKY8Gg4j7ex4nL6rIw9iCnDjx2JjdtrsbYptoaNMF7vSj0qHPFjMEtYOtD_ztWzk8CZnCMkR-v5jtfwaeHTvcxBXQjJH0uC97QC2wLtIx6-ewqZhIceTX_iRsHZ9dzQQrFOzMbZXL3x9wlCsAG2q5ZWD7IDykc0WL-LuZCzJh9ymEDj61RnsB0v6x2uda6VymmZHAZS4RU5pv_4bGTELQmPueoSfRx4J87ltthSK8bpAYQ7riw4r1p5CMgj6qfrRPHUznxncavfZtxb1qjwD2-Fbvxh-y5Ln_qSX35hYkocb_NRfGl6yAihPAkNDIMf7Nl0veZMCgs3x8AJpxXO1JXPDNE-f-Su4_MnJlTJD8wRT7SaPJyoLzkP18IHwleeUol1MEPJq3LgYSpxJp0U9HP1xkfnRzdo8MQ7h8aCVGNRgAoMfvDAkgy4dI0ZS67vWel2jjHHpVHkwNJDP7R5XSu4e1nn6rucZaHKP4rUImw6gl3Xtt8rKJLvXuS0WD7f9N4M1nDLjyk-R0sPe3fWGczguzzvIkyFh5-MkdzhRhz_sMNABYXfx0aHGPslXg8BCfa_j_NXosVPGvXtnwANm2BJEXLcoZ4BtTKkhIeFFxb6KDDLs8L8qS1gZK4n9krmK_VCmYXgdFzdrjhBwuuM015lqoRgAvJxlGqlOZwhkqnAZJ9zI9UtfLJuYFST1o144ONC1eDSlToHi4B4UZ625fqefzdmWx7lHfIOTjczC3W8ZcjLSuJhi8E5MewL_KLwkBwM9ZvfjEGI4KJMrCYcoFjtkm2fTkduOteeUNklLilGy2fN7hHFw5HzM8eKWW4YTdcZAbRZl6mlj9JvIgoa45ouAro6yV1Z_OHSYMmqpRwfFgNfVDkjXewtmWz6rr-ELqQvVu1ae0n2N94_URtIS0TRR30kbCygaEj9BRV8K4IxG3lc1jPMq6oGS-sPEpmUAUNqe60uoD9YVkmBQtHRE-ORJX1y4u5hfHSsAWtkrgAEURE5eb70_zn7DfBs2C94ynI9zSV9SbFeIv1p7-T-VOTkZStNCeERCOJwSE_EAwn5pd7iFC3UUMNv1ltYklQnLjfSZhtiJyLDGuyFBJ82hab9eq1QvJ55x3PcS47E_E_qflHgzrm6hf44e3hn8t4kgdDggbnjxBI6rRxBJx9_uA4sAare7JHEIpDQLJQdYUZbWfMZaKUo2T81bZ4ukASEUxyjLtDJ6NKWf_3a5XTWjyfsQ39w6gU3CshAd32v5KKF-HC9EBTyXhUn_tVZwdzFtg9cztHp27OBuhFtQOQUrZI5Me3KSzRaX8Lgf6o9gITSvS1n7NTj3zAbxHY4DQjVb8ugf6RRdXeMhle2lSQgCDOXuBlPsTsf5dP4vofotnn1CmkIa6bTDKydDaAGWAZCtOsY1KbeNwFFkAKIgVtKbmHZE0GTYp7d1ijk9DfWVIA7wXXNao7V5cB9cuMSl_a0nvh6sBGz2463hdXKu4l_aPa6u0FexfSxchlIBmt9-lEhvAgL1QUDFbGNoQ1DldwFrrqB6NNFHnkuCUQ1OFqtng2HeyJi_bkgAwUPOn1UDwSxlStrWgGxFyULqdgMe0wTKrlq7sQwjYsO5Yq47P7MTm0NbniA_3J2xUR337YN9WFzgkrHBLxF1v5cAJZSlz8sqG_3kUwCPxOBv1O5sglhpEYTaydgZJ415SKNZfWFM7H4WMyzBDCQltsohp8vpTOHgavVD-ditfzzI-Bdu_TxdYy9YuKYMFpmjXGHv1KuoGwPzXDM3zvDht0kt7Jp9Dt5Ou3nuVXuXPgy23afZIXKYfbi8zSTljwq2pw0-aUamAUgOvwMC0ljKln9g1AeEl-FAxAfTVnklbcg10PtKuKZFB3cwMg32d_Q543myEHOpXFWqpywQOngYVYWmW4iYO02i-wy4Z0DmtEcxf3H1o4pzEOhuKOC_DHOZQCShp1-jLEjN5EjGmu1CRWu2wYlUZNyvEhlOGr1m2rvo8FX89uJIq6_li5XG8cvOEu1ZLBk86UHkQKm6SAq_ez18yi8edn5PzjlvWPwjewUamPsxDgnungl8WA6L5pPHvWEKGk8x0xtuodHWsditFD01lcH22SmvftuOPV6iXQ57GErZh50bQzldWwwstbH66gXiWeDlwHP3RBpf9bQAdbjbSrH1an1lsnArXeuPlpAABCxwnBd98TXpllrSuBKkk0VgBcOuRm6yNQ8U3qiFImqjI1FfeXEAkQwAiPgJBEZnUIAII6ftbj7-JmMR9HSFruRXUOz8FUkcD-SoswEscDrs1iuGG5h8yCUWgrrY87-1Saz0VSBWCqSE6BMkuZZVLD_IOJg3POKtXx065JLoTCDy9tBdIXmQ1xDgQ6i_-kIGRNQnMaBcgm7CgiE4wzI0PDatYTW77irpJ0x_EFdVWYhcCmDRlKTUnbxKPqoSQuiAuyPZ-9Q_q7nzbNZ-in9VJS4kZAcknWGMU0PQXh_I5P3sLRCcIaCceOxQybmm6v3mib-s8-jWagiY3NTediWDnOW8gGNpTeM4yXD-1TmQa61Rf_CagQzwi96rqF1JCoTXIjZ4B0oPFLCGJblWBwRrtRulVrnrulNtUlcH_ZrOuBLpDQa1rNsV0hftJllIee3DRfk0tUZw7UuPsjg_ZqZN_HlMzltuB_ax1-wV1w4Ah_obT9WcorVuAyxBzw2x7t80fl0yPE12Oa2XasZMB5GAyQgZya8MrRJ_ijzX87kEt9grqbpOPUcskzcfKVpjoS3BzPtH2WJzjqejy26cutHCYvYamyTW9BbkE5Sh7vGe8xZWk7ziPT3pZsY-i4E1OdovcIpWYK1Wfgm8417MONGpPtncrBoGojOyxgW4dq54br_rJZ_ccNcvj2oHdSM0p6edb_qNt7eTxUMuusLiLiLSahkIeWtrHXttPhvrC_zvWgVvg02NyBW_XrMklYb7KMpSnsGF2dTY5AOexD4HaMztZp7c47fwm7LxUHVzqKmOPY_dVAGtG5DVyii6plHf0313yMcqCY7zXQn1zwuuXKnVQqImC-bnuc6p6c-qScpPPaaZ_7sK-_pMvbr3C5i7UTDiLzTIfLbvgWk3beJ5NSzR3NLnOj8RtfNOUp32K32yJ2jxruF2kuO9jITwUtWP1Wr92XXJxqW3BKCpU6ieRS05BJiKLdVlULpfBbGaR5T69-QSEdQL9K-a_TRs8idCcbXEDVCIB5DV3gNCp8BmwBKzoOD2wDz1pVydGWbb_HD2_r1qrbvC5NJ_K1oT9ReHc6uzuxWj8wMXX-vSdCKaDARdcN-JzBgUA3SsNreAsC-NsJUk_wU1H-lufoDMTC45oJ9WHUdyKk7VTcpGrYoG67xJUj_PZGotlZcD7HA7T3vZG6gaimiI-9qiY-C7T1OM2y1JWb7MCqLWnDXSWiBwvQTOVa-RG4yy6JQs1t7V7V6Ku-4ea3o9KpHoDIzbJb2REyqXRQPNs5Skqq_AsucI-8ftKgPq_vX17JaQhV6xau5E8yA5Gl0qrempMnqZaB209fKd9tcquGuWS_lo-caqtIM3FZBLtmr4Sro4MS_rEGvM7csiye1kcFnkXM0rNjP4xgsRS78gRibq7OUEUuFgmNL8q_A7wLaULwyKANIw8GZ3fzTjvpFGmSLEov8OllfZUjVumtO_0pVUo1EotbTnqSHqHslUa1ZpAduUD8iyzvDq2t9qaQ0YzWd4RryO1OCNVpD5-xa0vAknrd8uGy2-zDk9WgzR6-o3PvvJSX8udAG5ckjHighGVOqk8igggGE2WOHEtOWtQEXOeRyKnvyWGHik02NB6XYm2-yELTsnf9Xam6_F6gYS-a2FthGEJcJ9LpHo_8vahlM3arZ4FO21v6NKaCibzsmwM6E5IHLktLLT78kx3EGDljMPODR1KEc6lJIuGI4Toq1cfJbLoEx9CjHlRk4Y0LI1rs8fUzg_LilEvQkin1ES6hB9u4a4lwQPPrmtxtzxnmigqIxRxEpSxGGQFZGzLNSULjg9Gx3dEYLzMx8pEzRJ1CTC_QImW8SLG9QHwiqz98igjjwcOqDtu864o4Zg-3-UZ8jnIIiMsgtIYT7qm2tz3NZ71VmYD4ZnR12o2QPh7bKWBP0AGCCSOjwUeFI33QsAMYLHXT2J66yJFX5CAwxrULUepxtA1R_414Gwrc_9y90TBt93MLDoNWXiIlazK-2Hf0ihR2kj6NS0QZBeCcjaen4i6K9KBA-kISY6RWIImyoRWks4ne2SqOzD0PmeNO6vhJPATEUC4honaEespDg0_Q5bK0V-YW4OjVJuKqD8ppX7w1DNtSFNFbzrnEmCeOXsPPCpJzaA1yW3Hl0ypYei7Bo8BcjmUGph0CInElzOzgiWbvXFsoVzvBJ_0uZM8_HxHs_nkceRUnaphajiLpW2VEpTmqElSqX1Ba_9vaGt1RCDDBAyh4S80kyQN8an_T1UFioAdgByW_5qXyz3ZDNSD4SrMh8Y51anlG8MKerQxJKApgh2DJ6C1sXQ6BDs14YZHxas5sBvXw2hQ5RWG8uhRuRb0zzkO99PaBVLJDf3yTSZYarSAFC09DPkxK2e9vErsKAPELD9whRv64vmdVP0HUFhb12mghkDuEf3LQ8dQMWnHHTvPtpIlSyBvbrR6LdF37Try4ygUSqvQ3vsM-m6XgpU70O9uba6I3qJG07e6v0cp2dx1BAbRh5QPM10a_07GI58a7B8d2s6BYQWLmyt-spFtaZJAvxEKrhaDNfY7EPw5L6HM_pXDHlfVKFHIDUp9JT6dQ-4Tg984PU1MgKnFkLSAn4-7aPy-XtdZNzgcJzDV9uFohbcJOvksAev7Gr_2PbatvdNN8S-8x55jtO5peySh7ydjhnxiE_S-jyUJEh4a4zJBIem4SWUPnkpj1H2dPPWvok0DKLCCyIjTaYxJqB-thYTcVOwWSU_2Qf3JeUe_djkbc2jbR7FnF5AxDyMMKnMBhM96_VpUP_oRUcMrLM1kd3cARtV0ops-GpOujP04q_2nru6AM69ZgdkBXfgIK5KKt9Q607Q0rLaHGJumYJ_akXSnUU5QQ6o0KqpKiEzsbbdunXCiJAE0mkFMwSxlYzoCV2mVPZ6rcPDZYuKQ2_aBI-Z1g-vX8tSGPMIJuYbje5TuvKFSTAyX3j3X0-CTDyJXrGLizXQkb5ijpU0kFRrD4QCaNFp1k18Ud8wz0dkTriMTjJFEzo4tNuOanbdGptp2-lC11hVHa-DtyLAJC645H9yM7RQcZLcIsztlPc0Lc_CX661R-5EjGzbT1uOyKbA_0hRFfZGvmPwdQzPearw-MxWjyhoNmek6JhfazAIzwGdyfpfyGY_jBTrRNR7z1a6ero9mTBQQyuyTGHU2QgEYd7sLNjA_Z5DLw0zD7Hl-FOWX6JQPqhwAe022DzbrqjsDKJSAIluCBza9XChbpRuKD3RcjTJmIGDCsVtaeonhuf_9UFgLdrgL9CSdV9CjUF1WED3FmyGlbZwh6ZczRKuvSaBScgkKUviqRQE8pSoCIoHwNxJItHd-NSJ_LfFIw6NV0k6ya3Z6Iz03w2AuJ-ZlNnLw-UYZcP9flAzpK_4EHq64wlR8btZGUt9w3A0TAn_xcb5x7h1ioqLm8k_LClRB6rq7rRrsLzngKSrMzo4KS5Zvxt7ZU8QlxRDN_8ZDTSOLkbGwlFs6JevH7sahDGtyAuQ_AwEEOIVPVY6iOdZ2mB8OB-p1sLQh2NgKkpfwFHUPGV7KHOhZjgKYD6yNeUETvfZjDtMqfjU_cICVlpKKC4ji6TBHtlod8g18ly5kowfsNWfE4jnpPmNYar3v5RCMWPMTRX-mB4ptIc6qkhWJzvsNsfYEae_pVZ9Y-1ckv86Nm0JwDZTYQaqnw9cjbsib5FBi3x-td7MPPK-cIswb13LYHCf3Q5e3pGdug7pteeXKhJT3qnMXzrYP4JpZmCjo8SBr9pRk780qsUbi3mE35bV0DSRwsyg9Dxusb9WUNgJzJkVsDkP755aZabq75-nd2PJ4-RVNARSaLXQLpLkOmJ2JNKdHgJ-bKgGz_9dov2M00bzE42dBU1UtANlO8sQ6cqORLVDnoH8xKheVj2ZeVISaGIf8hrE_Uu3A-kkHGl9t_HGuijp0B6xztCGI79T8-8AkVfD4F0Tfq7wNMSGTtybeEV91HDldKn1knZDIwIhrBmNfQ2qy6ARtJ0zvEyNislY602wYKau6CVXLKNeErRX7Z6UljDFdGNC9rvJYYpqXAPzzfSa6b2eZH-5azJqOXTKzt6Cjq8sBEKIrJ9KhafOWa97gufIEuFwUa2JP40Fi6UrgaiUwnOB65R1SVZgww46Zsz2k3Ildmjvidcd2g-9390U6a7Ed7GbuTDOAHq7rlsDgVTD05aPhrA6mE9CxhZocfIAG7a1cygDSUdlz5IuRlxOhWQQjg4HdVdsDzu66FRrOzHIfmtOahEd5uewZWZ-KtCMnWPRKPVOTjy9TE5rxIUkXIuQiSGPnXpHZOxcbyPsJT-YXpKbxCyy9OrjK4jE2OwuaHDxAIhkkW0FYKqr5WWPp2f3NEGaoq9_ph5j8GsMLL0hyKncmEi2auAESrbk9-3OsqIue2oEkNBAebeCvfnUXqi677BegM563aVkhrGtdzwEIsZCjPDpfCJMsNuFe4X3dv0GfBBmXhNVA1vCjEDmkNgYLUMSqBZE4hI1HKkWmgsAfsizOvfA1xctywjW2Y6eyxxVxJtpHLXOJlr4F4GSmrdcTdRKTmDwWuVMLXlzEe8KfxKihVd7cEkmXzfxT_1cxynjeskbcj3A84V78j1SNI0V86ITiS3tXj3wekFhpQLkU6KhrjQSCjEqccr_Cy9o2IVMigWh8z-HJ0SEBlOEsppb3DA2AuvhjDmBO8aY3jP4inzlzN0xItJWaqyB3sS1MEMc1fqUmaq0NNvCsD91dyrEDR9nDARQcsgl87vUWzd-Hw-csYAthxXFf3bXRoRCzNhNNt2sspWt1c5RF-vpdeZbGYXDMrAX-44woEC78jxNhGkgO0odtZidmpY551_jiCnEqL4SEB4JvPtj0fLba9iUnQqabWl2P-lePNi2x0HCjlVQdoitEwUTHmzBt-01PlYOXLlP6mgrEnOMSl6WH2rEYVnIhljCP4CuCr6V9aJK0wtv0fgHfzMrv7_3nxC-Gz-sjGAXuTJgkG0yT3EWsuZiIj8eFO0meewoY2GvG80bLrJ5YWkqQov7JpQ8vKXx8bG2Y7Z3FYDCWTW8Dx7r8_svAjGC6QCqyV6yN2MGGjZ_IEK2ulEnqyQQsFnGk7DC0iV0DAXUlQVXixv7X9srgVsTP9vN-s6od4kWHMm49LhuY62b9P0KOaxMH4tmL4xPxjmpnfucJHh-6Dyw6YSsPMLZ8a3EOR2COUseQnRG-aqZG0x4Lh01BcHqQqspk6xH6yF9UUL7A3vLIKqJt3-g_y7xuP_qM-mQjrrCs3vv-wjhQIEo0yDuBS4KnjFmttDrF5MoUevqJPg6oJSeWgIsH2nIzGO7IjYQoS67f-zYSagkgNGFrFFVaYnaHqM9eEgAHobjemVnwqBPOsyruU2IZLgjjTUXhmOlHx9aoiDgJ9HsstvAm1f9Ezxl55gB9u8kwKX2uTUKf_y5h7552OtGXOd7XnQiiKtKmWbZbz5eKsMCtRmbB2DziYQVPnVXEW4j6PtshiZip_KItGnf34PY0ps6T3Tx9tISpKQl8Uus7QlEIylgUH_tZqBC_lrh1kgV3lWbKFSonCbgWlR193naDvuqvZHdoB9_pK5L5FPqABk6FrpzX0HHizMJB5hMaKDEpaGc8sRKHjK0aeTtZ1Yp4Gt-YYlAZAooEE2-Ap7onN-t6M0B5hsjE-f6SYB6Gz2fM-6cXx-4eE8AjctLMELAcO20EY87Y6uekGirvYBdhE__Wo1iFH3gxtKPTw1cN4HBZA7NazJOHWesltbDGtKperaCPtAB6PszkOMYn_FrZHHgc3fzdl4j4FxZ9pT5I0NOpJE3ycU14Rqp8V26OdzYCKj4GASMm8r6mri-BvH8tRAtjuELa1w3eA7aciaqvhJ7sgWfJruvsKiRCPkg4qIdaYM8L3FnCKoNawB6VItlZuX-UxwvBYAsXHNwVAqUrVOeWEMDFnKCZ5q_h8AIyUQGoxyqdwWwfB8ELY0wf5eiFeXOIw6cVEpcQ4FOY-FFtvlmd0zw-Q1Cylg7X9sy07EoagkDJYX7cEF3gOfnTwIIKmI4lTADjGzFSDf7IX7S3cT99O0NI74Z5Uam74S6zKAOJcM8NmiBphTi0kf-VqV16WKlejbn8nEfN-4Xd9PqT9vnN8MvVryXQF_LaDMtQ08DvYoBohWGukT63zYOFuA1ygoQjdMV_S2_T9buHK6uGhqrg36z2nngBdQFMqomZ4NkhLwckvOMR1V3LBMBBDyW5Ukr0Ws90brDDppiOHo5BTD-iuZp8s49NZAs4ktWtuWQ0vTYCts60jGHG5IeNxnxkPlYINCDYsBVcSs0JleXqiQ4iBcV3edfie4hC89ht_zU5fqLGASt8JdTr-13c0NJD4QbRQmCcm0OtcgsF5AWUlzkcYzEO0VQ-dDcmI2KK6l8NeH-ETmyJbaRiwVmDApZoc_vCO498kSU7L7oh6OuJylZTkqXiXt4NaJA4CAo6su8Hhk1fzfEl9PFB68urMpm0rHNXlyPDUuOzTETeEsPnYhrbTZLkGSVjk8UU3qfzr-Ey4aZa1FbIixPAxc3vGU2DCbHGbiDjFtMn_CwH4AmgBhgc6BDaKFVkDcU15fcXYwiyA3Zt4gDhBFSAsAJG-PQtqwv7Tn42jdz3IrYxYykBG2CmWRQGA_Q9D7tdncYv3vKgXy64ekvGTaZKdo_hhTntgqtaz8AA1EB8L_PR0V-capEHR9iaEhhQe5Vk_7o_ZW2PGd6kD8EEFqjEi004ke77Se-nRJO8QokGrN8E9dwqmznYAoDjiaKHOOKaVAuPAWnDdxe48edc-q2LY6ZF_oxY4j65N8CXaYsIuR3mbnnukTUNq7Op7YgwVJpRk5h5cz_x2qLLTfKNW6d3yb0juu15C-ydxl5FdNlBfTzZkqZmn3DqsXjnHRA-PcsAs_zTBSiSxClXomIUlEdTlo_f3mhP76Vc8Zkm6pqcbpu52NlUj9hUmTAspvJD6L69xhP2Pjgfj6o6to0ZJJOsLNGjBczfUffONDEJwLXXmlyYnw-mKPTqpf79WYP2WkRkE4Su38EEcDYevCrAH-yzdb-43-Fylst3re_54rYIMPvfYUx2XuERJs89jEJUx1-uXVS-1Ub5ggLNa9kuLOwQ1gXuGQuoit-1foqRkggmln9xUtXG_k4hfWqbcUQdubRjDPcRXklAeVnKYAE1k4Oj8yZ6LBJKP-IMGxlKGy4JHAsIgV6w_S_V4FwDdiV7NL6bQoIku1vg== \ No newline at end of file diff --git a/notifier/schema.py b/notifier/schema.py index da1d7363..397bac63 100644 --- a/notifier/schema.py +++ b/notifier/schema.py @@ -297,6 +297,7 @@ def update_tracking_list(self, info: Info, courses: List[CourseInput]) -> bool: ) try: + # TODO turn `register` off for each removed course # get all `Course` objects or create them new_list = [] for course in courses: diff --git a/notifier/utils.py b/notifier/utils.py index a341a5c7..29e1385c 100644 --- a/notifier/utils.py +++ b/notifier/utils.py @@ -3,77 +3,92 @@ from the KFUPM API """ -import os -import sys +import html import imp import json import logging -from typing import List, Dict, Tuple - +import os +import sys import requests as rq -from django.db.models import Q +from typing import Dict, List, Tuple + +from cryptography.fernet import Fernet from django.conf import settings +from django.core.mail import send_mail +from django.db.models import Q from django.template import loader from django.utils.timezone import now -from django.core.mail import send_mail from django_q.tasks import async_task +from telegram.constants import ParseMode from django.contrib.auth import get_user_model -from telegram_bot import messages -from telegram_bot import utils as bot_utils +from data import DepartmentEnum, SubjectEnum from evaluation.models import Instructor from evaluation.schema import crete_global_id from evaluation.types import InstructorNode -from cryptography.fernet import Fernet - from notifier.models import Cache -from data import DepartmentEnum, SubjectEnum - +from telegram_bot import messages +from telegram_bot import utils as bot_utils -# from . import banner_api -from .models import ( - TrackingList, - Course, - ChannelEnum, - Cache, - Status, - StatusEnum, -) +from .models import Banner, Cache, ChannelEnum, Course, Status, StatusEnum, TrackingList -logger = logging.getLogger(__name__) User = get_user_model() -ENC_KEY = os.environ.get("ENC_KEY") +logger = logging.getLogger(__name__) +assert (ENC_KEY := os.environ.get("ENC_KEY")), "You must provide `ENC_KEY` env var." -if ENC_KEY: - # with open('notifier/banner_api.py', 'r') as file: - # file_data = file.read().encode() - # f = Fernet(os.environ.get('ENC_KEY').encode()) - # dec_file = f.encrypt(file_data) - # - # with open('notifier/banner_api.py.bin', 'wb') as file: - # file.write(dec_file) +# with open("notifier/banner_api.py", "r") as file: +# file_bin = file.read().encode() +# f = Fernet(ENC_KEY.encode()) +# enc_file = f.encrypt(file_bin) +# +# with open("notifier/banner_api.py.bin", "wb") as file: +# file.write(enc_file) - # decrypt the python code into a module - with open("notifier/banner_api.py.bin", "rb") as file: - f = Fernet(ENC_KEY.encode()) - code = f.decrypt(file.read()).decode() - import imp +# decrypt the python code into a module +with open("notifier/banner_api.py.bin", "rb") as file: + f = Fernet(ENC_KEY.encode()) + code = f.decrypt(file.read()).decode() + import imp - banner_api = imp.new_module(code) - exec(code, banner_api.__dict__) + banner_api = imp.new_module(code) + exec(code, banner_api.__dict__) + + +def register_for_user(user_pk, term: str, crns: List): + banner, created = Banner.objects.get_or_create(user__pk=user_pk) + + if created or not banner.cookies: + bot_utils.send_telegram_message( + banner.user.telegram_profile.id, r"You did not clone your Banner session" + ) + return + + res = banner_api.register(banner, term, crns) + print(res) + if res is not None: + bot_utils.send_telegram_message( + banner.user.telegram_profile.id, + "We tried to register your courses here is the result\n\n" + f"
{html.escape(res)}
", + ParseMode.HTML, + ) + else: + bot_utils.send_telegram_message( + banner.user.telegram_profile.id, r"We could not register your courses\." + ) def check_session(user_pk): """This uses user's Banner session to check for its health.""" - user = User.objects.get(pk=user_pk) + banner = Banner.objects.get(user__pk=user_pk) - if user.banner.cookies: - if banner_api.check_banner(user.banner): + if banner.cookies: + if banner_api.check_banner(banner): return # TODO notify user about this change - user.banner.scheduler.delete() + banner.scheduler.delete() def fetch_data(term: str, department: str) -> List[Dict]: @@ -86,7 +101,7 @@ def fetch_data(term: str, department: str) -> List[Dict]: request_data(term, department) obj = Cache.objects.get(term=term, department=department) - return obj.get_data() + return obj.get_data() # type: ignore def request_data(term, department) -> None: @@ -219,14 +234,15 @@ def check_changes(course: Course) -> Tuple: "It's deleted." ) + # renaming keys for back compatibility info = { "available_seats": course_info["seatsAvailable"], "waiting_list_count": course_info["waitAvailable"], } increased = ( - info["available_seats"] and info["available_seats"] > course.available_seats + info["available_seats"] > 0 and info["available_seats"] > course.available_seats ) or ( - info["waiting_list_count"] + info["waiting_list_count"] > 0 and info["waiting_list_count"] > course.waiting_list_count ) @@ -272,8 +288,9 @@ def collect_tracked_courses() -> Dict[str, List[Course | set[User]]]: def send_notification(user_pk: int, info: str) -> None: """Send a notification for every channel in `TrackingList.channels`""" - user: User = User.objects.get(pk=user_pk) - channels = user.tracking_list.channels + tracking_list = TrackingList.objects.get(user__pk=user_pk) + user = tracking_list.user + channels = tracking_list.channels # deserialize the dict back info_dict: List[Dict] = eval(info) @@ -317,6 +334,24 @@ def send_notification(user_pk: int, info: str) -> None: except Exception as exc: logger.error("Couldn't send email: %s", exc) + # After sending notifications, let's try to register (if enabled) + crns = [] + register_courses = tracking_list.register_courses.all() + for c in info_dict: + if c["course"] in register_courses: + crns.append(c["course"].crn) + + # TODO there might be different terms + if crns: + async_task( + "notifier.utils.register_for_user", + user_pk, + "202320", + ",".join(crns), + task_name=f"register-{user_pk}", + group="register_crns", + ) + def formatter_md(courses: List[Course]) -> str: """helper method to create a formatted message for each course in the tracking list""" diff --git a/telegram_bot/utils.py b/telegram_bot/utils.py index 679be075..0b1d44de 100644 --- a/telegram_bot/utils.py +++ b/telegram_bot/utils.py @@ -42,12 +42,13 @@ def escape_md(txt) -> str: @sync_to_async def get_user(user_id: int): - return TelegramProfile.objects.get(id=user_id).user + async def has_tracking_list(user: User) -> bool: return TrackingList.objects.filter(user=user).aexists() + async def user_from_telegram(user_id: int, update: Update) -> User: try: return await get_user(user_id) @@ -79,7 +80,9 @@ def format_courses(courses: List[Course]): @async_to_sync -async def send_telegram_message(chat_id: int, msg: str) -> bool: +async def send_telegram_message( + chat_id: int, msg: str, parse_mode=ParseMode.MARKDOWN_V2 +) -> bool: """Useful to send one-time message. To make this method as sync @@ -91,11 +94,7 @@ async def send_telegram_message(chat_id: int, msg: str) -> bool: """ async with Application.builder().token(settings.TELEGRAM_TOKEN).build() as app: try: - await app.bot.send_message( - chat_id=chat_id, - text=msg, - parse_mode=ParseMode.MARKDOWN_V2, - ) + await app.bot.send_message(chat_id=chat_id, text=msg, parse_mode=parse_mode) return True except error.Forbidden as exc: @@ -119,7 +118,6 @@ def mass_send_telegram_message(chat_ids: List[int], message: str) -> None: logger.error("Couldn't send to Telegram: %s - %s", chat_id, exc) - @async_to_sync async def send_telegram_changes(chat_id: int, msg: str): """Sending the changes notification. @@ -409,7 +407,6 @@ def construct_reply_callback_grid( ) else: for i in range(int(len(input_list) / row_length)): - result.append( [ InlineKeyboardButton(text=el, callback_data=el)