From 582844bacf3321fc530b830fb628108a4d6774e6 Mon Sep 17 00:00:00 2001 From: kalzu Date: Tue, 4 Apr 2023 22:55:16 +0300 Subject: [PATCH] lots of improvements to pastedb01 --- pastedb/old_upload.py | 30 +++++ pastedb/pastedb01/data.json | 2 +- pastedb/pastedb01/data/__init__.py | 0 .../data/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 152 bytes .../data/__pycache__/data.cpython-310.pyc | Bin 0 -> 4398 bytes pastedb/pastedb01/data/data.py | 122 ++++++++++++++++++ pastedb/pastedb01/paste_dict.json | 33 +---- .../__pycache__/defau.cpython-310.pyc | Bin 923 -> 1500 bytes .../__pycache__/dpaste.cpython-310.pyc | Bin 839 -> 966 bytes .../__pycache__/opendev.cpython-310.pyc | Bin 834 -> 970 bytes .../__pycache__/pastie.cpython-310.pyc | Bin 722 -> 865 bytes .../__pycache__/rentry.cpython-310.pyc | Bin 758 -> 910 bytes .../__pycache__/sprunge.cpython-310.pyc | Bin 897 -> 1026 bytes pastedb/pastedb01/services/defau.py | 28 ++-- pastedb/pastedb01/services/dpaste.py | 9 +- pastedb/pastedb01/services/opendev.py | 14 +- pastedb/pastedb01/services/pastie.py | 11 +- pastedb/pastedb01/services/rentry.py | 8 +- pastedb/pastedb01/services/sprunge.py | 9 +- pastedb/pastedb01/upload.py | 54 +++----- 20 files changed, 232 insertions(+), 88 deletions(-) create mode 100644 pastedb/old_upload.py create mode 100644 pastedb/pastedb01/data/__init__.py create mode 100644 pastedb/pastedb01/data/__pycache__/__init__.cpython-310.pyc create mode 100644 pastedb/pastedb01/data/__pycache__/data.cpython-310.pyc create mode 100644 pastedb/pastedb01/data/data.py diff --git a/pastedb/old_upload.py b/pastedb/old_upload.py new file mode 100644 index 0000000..e47f5b3 --- /dev/null +++ b/pastedb/old_upload.py @@ -0,0 +1,30 @@ +import json +import os +import time +import hashlib +from services import pastie, dpaste, rentry, defau, sprunge, opendev +from data import data + +def save(data): + # Upload to the available services + paste_dict = {'name': name} + successes = [] + failures = [] + for service in [defau]: + try: + result = service.upload(data) + add_data(result["service"], result["key"], result["md5sum"] ) + successes.append(result['name']) + except Exception as e: + failures.append(f"{service.__name__}: {str(e)}") + +# Print upload results +print(f"Upload successful to {len(successes)}/{len(successes)+len(failures)} services:") +for name in successes: + print(f"- {name}") +if failures: + print("Upload failed to the following services:") + for error in failures: + print(f"- {error}") + +print(f"Your paste trace is: {name}") diff --git a/pastedb/pastedb01/data.json b/pastedb/pastedb01/data.json index c39e9ba..8a04f3e 100644 --- a/pastedb/pastedb01/data.json +++ b/pastedb/pastedb01/data.json @@ -1 +1 @@ -{"name": "Joe Chuck", "age": 222, "city": "New Jersey"} +ed566cf8f839c936bfd5582f1af6aa7d0d8457fcdd3c421d4424eedb41d5868155a6e04a291c4add0a2ec88a287d0371605d8ff9be6cbf2ba91d67097e39c0333cbf57515d9072d998d1dee110f3ecab \ No newline at end of file diff --git a/pastedb/pastedb01/data/__init__.py b/pastedb/pastedb01/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/pastedb/pastedb01/data/__pycache__/__init__.cpython-310.pyc b/pastedb/pastedb01/data/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b0bb1c53323432c7b63db83787a07ea6a56e65e7 GIT binary patch literal 152 zcmd1j<>g`kf|vF>DIoeWh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o6vSKO;XkRX;m1 zr>a!HBsI4{KRF|@#62KHzaX)=BsC=oMjIIFrzDmn>c_`t=4F<|$LkeT-r}&y%}*)K ONwotRTFe9_SQr3886r9W literal 0 HcmV?d00001 diff --git a/pastedb/pastedb01/data/__pycache__/data.cpython-310.pyc b/pastedb/pastedb01/data/__pycache__/data.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92cee8c1c6efee856b25d1edec539064cd1137b0 GIT binary patch literal 4398 zcmbVP&u<&Y72aPYmlP#gvMpOq+HT#V6;oMi0yqT-$EYi-h1*6lBDH~eVOE@>xYlx) zogG?{O7$Z5+&`cxAOXGP-{`S_!d!bwFFgcEfuKP9y_sE+lpQ&xqvvB?A53B5N3zqc{>P%ifIzPpo{T&ZxwJc^cC$?L*emgBkzulIr-(JhZ+l@>8 za;t2UtQS}Me#_VGQe5rVS~cA+$20wUt8QDo%qq-(Zk^h#S>}Xutjg!R4y&=5=U(dy ztMdhnEU;PJb9|xevw3y}Ul!Rdwt%rkezohdtL)nIQtKLe^N^ay$aS^^sq2usp=XlR zO|}fFCFbl{jW@!7yOvek?L}G8PuVc$!9b+XBF3|zJ4`wes|AWT@0 zh0mzTLKy~85`+PZv}h=ff^_dG@5r^_kqp8(OM`4U7^FgG0Z%&OXh0gZ4#qFKX*ZBP zZqyz2cv9%6rQ$SXv{obonXY$5+Q(wq!CJ738DkS+g`C(#lyu@Dtcj_0AS>ZV5@Wpxf3Sz4Kq3) zGWWsePLLh-`&^2sQ%LIbj`veo(d)yX*eKUF=~>1Av$0&Y*_+vnIU#bFZZ!*~xzqli zrOg@yr?K#RS{9DWH^hzS zfFq-}@MnRsJQ7G_?jEy7;Z}0RT5T#w86WTj&_OJb*NjnSQ{KE|6UyS_gHxUI$7c1QL_XYqg;Tu zLq-%AwdvOO()uGS1eNbtpW5Vu`S#}4#s^Ox?>^ezYX55UNy8R15E>gPs_3f47rA5^ z<9cb|5pyInGeHBYY~o&(&6#${WyMuOgKlloZ_!}3w9ahlNcYq}^Ukev`>b>hr!x1C z&a(Aq>o3lUE6cKSRyjweIPpfFbVu&8#k_mg$R0VY^a?*^S7?;L=ZU#(eh`2!R86Zt}~b>)#tRR-szjH_yof6O8ffmCjkNaax+HcDci^k`s{Mxb(-v?HdMx(sz6 zrfI7DHY9a~e}ArS*WD%CbHtl8+bK6U=|79eb&IV1ZV z0G6(JLjuMGa{#(Da?i@662bf2wymTtede5^^`XUF&+@EO7iAM5eYyX(mA!KaIr=@p zO)?EHe6N80huC2BGc+TJU;y5$bo-@h80b}1gUXKc`=YQa7(}|nUwc5OA}RM!~P%>vp9ZLpUm#!1`U<8N0bYws?q?wAsc1!Equ{% z(kNASS5--u2BMm~$f&x18L`!i(&$}i$rkabS8I;v)}1SE&7J$)sonlUyoKSZ%rHg6 z_wdz_@KYBEwI#4QvZRBabK*$n4D^eh5B$0(pxU$Q$RQ+ye!UyWCJp=eUz#sAO}YDx zDwVI~Tz&d0#nC><&(xIM(?@$jG6pLbjzb|qhn1YRXA7RT&Bt z>}g+6ic__{IPDy?v*?%$j|SX9$dsG#LxTtZ{q2XF?Tw#ps7kIA>_jx8oamXFfiQT{ zoO-zv4SHON2EJZ8a`8QkZR6JbRG*o1>7adAkE<$$pRVybR2mf56gPD-DlKtG+BrYf zPn?l+=A2t6E?CAXSSRtpF-wyiBVFLcD-tnKLU<|3@>vB8<`aYMShC8H%E3n-kWo7R zr}q7?QGhUV-Pl621&F7ecg_|ETde{Bl6ebT6DfQSH7l_z+}1O=#} zj7n~+_%3}d(GD|J#vpQ@_yNYiAa_Yxr??-IP|cu6@{gq|cXb`Bs)INL-C*bvo>cYX z4?={=nnFCkZrAKL|66x!_MGiIo-OXv5_LQpH&mtFW@)G07C)jvvP)d0$1Ob6%tXO0 z2!m?Dl;emKzP4d-t>a~WV*EEUicQd5)&G&xeGv|NM{CA<;|>ZH6G`@ZYT&H8fm^@u}n~K)IXa4x#N3OK801wadXMCG}NcZOFc+Q-2t90$=;_}T~{{yu% B=sW-b literal 0 HcmV?d00001 diff --git a/pastedb/pastedb01/data/data.py b/pastedb/pastedb01/data/data.py new file mode 100644 index 0000000..d08feda --- /dev/null +++ b/pastedb/pastedb01/data/data.py @@ -0,0 +1,122 @@ +""" +This module provides functions for managing and saving data in a dictionary object. It also supports encryption and decryption of the data when saving and loading it to/from disk. The functions in this module include: + + set_encryption_key(key: bytes): sets the encryption key to be used for encrypting the data. + add_data(service_tag: str, key: str, md5sum: str) -> str: adds data for a service to the data dictionary. + save_data(filename: str, data: dict, key=None): writes the data dictionary to disk as a JSON object. If a key is provided, it encrypts the data using the AES symmetric encryption algorithm before writing to disk. + encrypt_data(data: bytes) -> bytes: encrypts data using the AES symmetric encryption algorithm. + load_data(file_path: str) -> Dict: loads the data from a file and returns it as a dictionary. If the file is encrypted, it uses the provided key to decrypt it before returning the data. + +This module depends on the following packages: hashlib, Crypto, and collections. +""" +import os +import json +import hashlib +import time +from collections import defaultdict +from Cryptodome.Cipher import AES +from Cryptodome.Util import Padding +from cryptography.fernet import Fernet + +data = defaultdict(lambda: {"timestamp": 0, "services": {}}) + +_ENCRYPTION_KEY = None + +def set_encryption_key(key: bytes): + global _ENCRYPTION_KEY + _ENCRYPTION_KEY = key + + +def add_data(service_tag: str, key: str, md5sum: str) -> str: + """ + Adds data for a service to the `data` dictionary. + + Parameters: + service_tag (str): A string representing the service being added. + key (str): A string representing the key for the service being added. + md5sum (str): A string representing the MD5 checksum for the service being added. + + Returns: + str: A string representing the unique ID of the run that the data was added to. + """ + + # Generate a unique ID for the run + run_id = f"run-{hashlib.sha256(str(data).encode()).hexdigest()[:6]}" + timestamp = int(time.time()) + + # Add the service data to the run + data[run_id]["timestamp"] = timestamp + data[run_id]["services"][service_tag] = {"key": key, "md5sum": md5sum} + + return run_id + + +def save_data(filename: str, data: dict, key=None): + """ + Writes the data dictionary to disk as a JSON object. + + Parameters: + filename (str): A string representing the filename to write the data to. + data (dict): A dictionary representing the data to be written to disk. + key (bytes): Optional bytes representing a key to use for encryption. + """ + with open(filename, "w") as f: + # Serialize the data dictionary as a JSON object + json_data = json.dumps(data) + + # If a key is provided, encrypt the JSON data + if _ENCRYPTION_KEY: + # Encrypt the data using the key + encrypted_data = encrypt_data(json_data.encode()) + + # Write the encrypted data to the file + f.write(encrypted_data.hex()) + else: + # Write the unencrypted JSON data to the file + print("you need to set the encryption key first.") + + +def encrypt_data(data: bytes) -> bytes: + """ + Encrypts data using the AES symmetric encryption algorithm. + + Parameters: + data (bytes): A bytes object representing the data to be encrypted. + + Returns: + bytes: A bytes object representing the encrypted data. + """ + # Generate a random initialization vector (IV) + iv = os.urandom(AES.block_size) + + # Pad the data to a multiple of the block size + padded_data = Padding.pad(data, AES.block_size) + + # Create an AES cipher object + cipher = AES.new(_ENCRYPTION_KEY, AES.MODE_CBC, iv) + + # Encrypt the data using CBC mode + encrypted_data = cipher.encrypt(padded_data) + + # Prepend the IV to the encrypted data + return iv + encrypted_data + + +def load_data(file_path: str, key=None) -> dict: + """ + Load the data from a file and return it as a dictionary. + + :param file_path: The path to the file to load. + :param key: The key to use to decrypt the file. + :return: A dictionary representing the data from the file. + """ + if _ENCRYPTION_KEY: + with open(file_path, "rb") as f: + ciphertext = f.read() + + fernet = Fernet(_ENCRYPTION_KEY.encode()) + plaintext = fernet.decrypt(ciphertext) + return json.loads(plaintext.decode()) + else: + print("you need to set the encryption key first.") + return '{"you need to set the encryption key first."}' diff --git a/pastedb/pastedb01/paste_dict.json b/pastedb/pastedb01/paste_dict.json index b3ef4db..7e38601 100644 --- a/pastedb/pastedb01/paste_dict.json +++ b/pastedb/pastedb01/paste_dict.json @@ -1,34 +1,9 @@ { - "name": "1680551932-b74d72", - "pastie_blzoeg": { - "service": "pastie", - "key": "https://pastie.io/blzoeg", - "md5sum": "9fd3002da661e6ca38a2e8a49daafb1b" - }, - "rentry_QDmcP3gr": { - "service": "Rentry", - "key": "https://rentry.co/hqcohp", - "md5sum": "9fd3002da661e6ca38a2e8a49daafb1b" - }, - "dpaste_9W5AB4Y2V": { - "service": "dpaste", - "key": "https://dpaste.com/9W5AB4Y2V", - "md5sum": "9fd3002da661e6ca38a2e8a49daafb1b" - }, - "sprunge_j9uXbd_9fd30": { - "service": "sprunge", - "key": "http://sprunge.us/j9uXbd", - "md5sum": "9fd3002da661e6ca38a2e8a49daafb1b" - }, - "defau_9fd30": { + "name": "1680593168-456462", + "defau_4e062": { "service": "p.defau.lt", - "key": "https://p.defau.lt/?ExQfLnJ_aDEKYIqkpwv6cQ", - "md5sum": "9fd3002da661e6ca38a2e8a49daafb1b" - }, - "opendev_819477_9fd30": { - "service": "opendev", - "key": "https://paste.opendev.org/json/", - "md5sum": "9fd3002da661e6ca38a2e8a49daafb1b" + "key": "https://p.defau.lt/?QtZaVCSgOsVMmI1xS_ofqw", + "md5sum": "4e062894f660d3c69640129f9fd0a09e" } } \ No newline at end of file diff --git a/pastedb/pastedb01/services/__pycache__/defau.cpython-310.pyc b/pastedb/pastedb01/services/__pycache__/defau.cpython-310.pyc index 25380efbb7a042c3cebfe8707b4652d6ddfb89ee..ed3e89100a42d2d5bef94ef3309dd4a1715f4429 100644 GIT binary patch literal 1500 zcmZ8h&5zqe6rZujj^peXOA!>Q!oX!C(HIU$XjLH)+9Cu*)wWe>F4k;jvUZx-?#y_% z8#xH6a0AXr1t}{|{7ZA?)PI2k;you(QpTD$-|zk2d%x#mcQ+)^et!Ca_>~dzH!ilD z1B=g~YZQVEh@irm&;e~mXW%rWJ8*?NV1f-i;R*joGVn!91TeNlTZAwM!nsen9sVaJ zBz%x&I+_-un#f4VQI<;`jjDWTvLe@!DWWVlQt_dQE;ExxCY4dygNwZCO-!Vvy2yqy z8Wk$4%1OaRmY+vF7m<=iW%2@-!$QbN=UG`wqkCa^cdh<7yd9lOldQBPhMymGkE2s* zDh0-Qq(KKLP_k4~%iQ1s5vKJ64Ns-vs59bcMP(WsOG{`I+&D52Cb`6qu0tRZ>nm2d*2OU6MvAR)s^TIO zu+zMcMyi-@LFf<=xz>alwHqA`0OiSxGIZ1|idAmW5$rsQyFbW6* ziFf+5aHHcdqFgxHh=13XIA^Bwg4B*6g8k&&BrnJx&fKd#v-6zP4EDX>*&}kF zFammZ$9q>_Q!@7{nRU#5?LViKJR*;wvgZExzJPnn*(JRsUB5r`Dl@wMiDj73F0~A~ z@Dg3>GRty4mA17ChjpLGE9+0i$GVz!4=fw&BDbEXrlq#6ljSZB1TERqHRu-^!AD(_=4;0U|OrXvZZMdnlbt^Too&M+Fo+S59Pwsy8T@zj# z%4b7aHq~nnPM4Za)?3yqp`c8+r7-fgjkpr@L+#)iEb9`=UaAf(RU7xH+)zUyhpfM3 z{SBDww?TyT26dc68c-i*hwue-j|M+D|EhQ3_?3hs)vz}S$Hz6K{3d~P({Yn{jRqJ@;Y3!tyNg83k2_eyrmMa;}?hTI3qzY z75%>+`moHgkAx&IMPHI4&0dkAfW0O-5#4a%8}-~V?!tpR#m|i>Pwm(7F#VK#(e4gA zk>-LUwtVD3Zhs`4$-+#6N|LN#45Yr}OjT+Ul0HSd&rxlr$yCS-1XuV>Y>Anv426|u zu6CWhniGGA_yC3@XN`u3YCHygzjrbAN(qj7n diff --git a/pastedb/pastedb01/services/__pycache__/dpaste.cpython-310.pyc b/pastedb/pastedb01/services/__pycache__/dpaste.cpython-310.pyc index f6c8bb6d58ac5d85297b76c89ec32b2fd2e22834..3e8b75d06d7ead38ab24a2817e315aff2885f97b 100644 GIT binary patch delta 459 zcmYjN%}T>S5Z>8rHffrq0imT*!Gl8M4|ww;MJe927Z1fEl+X#qQfb+wiY2{y^ipyY z56w~f9`+sT6Zj5-?#4@J*l+%4XJ*Ae4R_=?7Ll|}j?iOsw+1Kk!=1a1h8nUL(qX70 zmr_T#A-?gga$9ST;~1Wnzb&jFF%M-Ucu6YHg`+?Fz!a7 zc)ah0-8kqQs)|ZrAh;Cs&NhFOa(X_Wp7t6E8|YZ5l9?X!g^|F*L@R>~7KMz=cx)wl zA`y!flIV*f+UR5y-72XNEWNX~oTN=qA|o*!*aPSJ3W(y{-1|g)FZJLRAYH<-<_aVI zf;u=UqkFp0i5w`ygj{x7C9UBa4A#=}v7R=T1GSO)Wl8y;|= xzhYm8eJ*M$Rjn+l3e*qz)_HuRTi!QsX`Vfda54-V>co+n#3Uw|z^F-W?GHo{Q@;QJ delta 342 zcmX@cew>XjpO=@50SGv>v{P;|PvnzfRGFwPYm~y=!Vtxr!Whh;$?_5;@0ZL7qM(2s zNOJ(OGY}U~0}@qslhql`8Eq!VGs-!naM!Tbu%+ed3>1QpqC<3vqL8dpNf>2$5pfn#td(^&3aLwdfMu^i z&>`w$)G_)5-a7jYBG}$69el(5-n{?3`QV?L?b^0MP+o6W#3-;AU_DsQ&R3XVLcJ#y zRdAu9<^qmMP7ltOc7~eUaV~|^ugkh|0W@~;b{WDaSOCQw3|TRMxc5dp>GfFHqlL^= z!||(K$LlxiPSvk9bXi3a3_Ol1xJ&UD)HnOVQyvPz_w12x_)HKn@j#Pgzr}FN%BXTNkeAwViGGsohD0PISB_jE;BGnXf{|d+at2Ml$zK@5gm1Cu7o_H;q?X;{fHLAI`!lIC^Axd7u4Iy7 zE-lKLJcCJZ@@XbTM)t{XnT$C2fo@sJP^38VlnV!2X+chYVha0YYi5N+CPpSkF-DF* zZ0rJzY>Z6*i*IBatBQ%ZAE?HGZ)Vo>mK OFmNz(FtRZ5FaZE;06)0^ diff --git a/pastedb/pastedb01/services/__pycache__/pastie.cpython-310.pyc b/pastedb/pastedb01/services/__pycache__/pastie.cpython-310.pyc index 2db32262ec5eb76034a076fa60fcd9ead195ceee..e19fde5aa0e7d3628a3cdaba8425532b6bc82825 100644 GIT binary patch delta 521 zcmYjN!AcxK5bc`j>FHV5RS#;25seoaqV7Q#L_}DEcraN+5pge*VSA#x?CdPvJ&MbM z7k^-wt3Ti^zmQ+Zac(*07ep}Cqli`XE4sSsRrUMh{AIOda$j)k?U@QBw zc-yvx-KK&H=Z>@;!Gw#E2{<7>|7Yr3j|-Pt57kb+J`9!aMjPFvE|N|fM+2=2_LA(F z()R{<`HDwT1Wk|*T0RuC)%?EyK%|3N1NpqwT%Nj!bf6-6)$K%q4lg{@XCY9KE{3fA zk=N^jz(3B>q$nY|{y*BUvg z{<*#_4Sl`@t1A%rv~XXi7jzKDku*XTEEWxw#(p)wf1K!iG! zHFM`OQp03`G-Yq)MU^0x{kN|Y$x7OE*iS-H&3{-Qk_uSp{E4~Kz`%Nzi&)~jau$P} tGB9I$?9=0KS5Z>7)+f8g^LD4D|L)qCrB| zwYv7*0TAuyWA%o(b|W^U@N#1(POd8H8>~&Up{K%*pXDc<0-bRT+?27tsHv#$PNggK z_$;&i+qORpJHbF@r4#=;@>O{FC%H^gJ!5rMFlY%c^rWS8E`2q`315!Cv?n`Sk?cJa zSx#Q+F^h)1z!N5Rt7QZVHq3&9SiqnL1B%YSSiS`K{+5f_1gh5PI^Nf-nukEa0Q4p4>t8-RKHq*EnNQBxWU`2?Nt``v)jvJ;0at~hae_M&2uCmpjr+6} z@$vB44`RJ{jXy`x+jME7_tgvbrO-JF35(K!fn(&P=$bCk2I_fL8Diq-P!Xo-G;&jp72Gf zpjW6}0%0Kw3Y*^qmb?|8%iO(rbkOp|e0+uV@8s1!&FNb1@pgsEB%eiPZ#L~!s;vAH4o6!*Y-9l vd(-2F$6b$G9^AtZ!}`c8sn#=H=hKJF6!L|6>VF}-hR{S)zXTUlvmXBos%~>q delta 341 zcmY+Ay-EW?5XX0RZ|^Q2cli(_5iOz^2vM(1AvWpLq_dIWoT9{>tQ*jgaM_LC-kow^_mSDwe1! zNtfHUr&0h`=|&T&i-B=B7=}g~z}lNb&(=o^IoIb0gGJ*oitlu+W)puJsd%QWzT#FVfMwh)+Bv%Rf_RapPnTczcbZYehw3Neltxb=#hIH5;ma@A%wgIEog$; qrBY9-bxNvXQL|`USW9*OV~6C*Ke|qEK8=ro)U92g&wQ|_D*gb|?n%J_ diff --git a/pastedb/pastedb01/services/__pycache__/sprunge.cpython-310.pyc b/pastedb/pastedb01/services/__pycache__/sprunge.cpython-310.pyc index 44caa4676e94945e4283de0ebe93984713affd0a..3346fdbf8435dca79cf742bb8816ea246d0fef12 100644 GIT binary patch delta 350 zcmZoZaR%aI79df=0Mx+fr^$GW#m~{#btOX)NVJG$@>(Vr z1^)EZlKA4(qO#27)cBIbbWV^iCLqDWSi}aTCRW~JEduc;$1rYV4h`~|EXouj$PN^^ z#hF!{pBJB!Sdv&IFu96JT1O5nT9lZVlAjx&nNq|L*_pO6mlowrKEM>>!VJ`Wi!-Y@KQBHdu_UpG2gK(nN-ZwP&nr&7#SPUH z4^&?y1y);>n3s~D8=sj{#0})HWGGUec*KQ+t+XH~KQV=4at^a$xGGRWldVV?NEPvd v2!0SD2_i&61W3L}8I@20a&K|i