├── .editorconfig ├── .gitignore ├── README.md ├── qqlib ├── __init__.py ├── __main__.py ├── hieroglyphy │ ├── __init__.py │ └── data.py ├── qzone.py └── tea.py ├── requirements.txt ├── setup.py └── tests ├── __init__.py ├── test_hieroglyphy.py └── test_tea.py /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.py] 15 | indent_size = 4 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | *.pyc 3 | python*/ 4 | *.egg-info/ 5 | /build 6 | /dist 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | qqlib 2 | === 3 | [![PyPI](https://img.shields.io/pypi/v/qqlib.svg)]() 4 | 5 | Python版QQ登录库,兼容Python2.x和Python3.x。 6 | 7 | 安装 8 | --- 9 | ``` sh 10 | $ pip install qqlib 11 | # or 12 | $ pip install git+https://github.com/gera2ld/qqlib.git 13 | ``` 14 | 15 | 快速开始 16 | --- 17 | ``` sh 18 | $ python -m qqlib 19 | ``` 20 | 21 | 高级用法 22 | --- 23 | ``` python 24 | def login(qq): 25 | # 不考虑验证码的情况,直接登录 26 | qq.login() 27 | 28 | import qqlib 29 | qq = qqlib.QQ(12345678, 'password') 30 | login(qq) 31 | print('Hi, %s' % qq.nick) 32 | ``` 33 | 34 | 登录时有可能出现需要验证码的情况,可以捕获到`qqlib.NeedVerifyCode`错误。这时`qq.need_verify`为`True`,需要获取验证码图片(`qq.verifier.fetch_image()`)进行处理,验证(`qq.verifier.verify(code)`)之后再继续登录。下面是支持输入验证码的`login`方法: 35 | ``` python 36 | def login(qq): 37 | # 自动重试登录 38 | while True: 39 | try: 40 | if qq.need_verify: 41 | open('verify.jpg', 'wb').write(qq.verifier.fetch_image()) 42 | print('验证码已保存到verify.jpg') 43 | # 输入验证码 44 | vcode = input('请输入验证码:') 45 | qq.verifier.verify(vcode) 46 | qq.login() 47 | break 48 | except qqlib.NeedVerifyCode as exc: 49 | if exc.message: 50 | print('Error:', exc.message) 51 | ``` 52 | 53 | QZone: 54 | ``` python 55 | from qqlib import qzone 56 | qq = qzone.QZone(12345678, 'password') 57 | # 登录流程同上 58 | login(qq) 59 | qq.feed('发一条说说') 60 | ``` 61 | 62 | 测试 63 | --- 64 | ``` sh 65 | # Python 2 66 | $ python -m unittest discover 67 | 68 | # Python 3 69 | $ python3 -m unittest 70 | ``` 71 | -------------------------------------------------------------------------------- /qqlib/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | QQ Login module 3 | Licensed to MIT 4 | ''' 5 | 6 | import hashlib, re, binascii, base64 7 | import rsa, requests 8 | from . import tea 9 | 10 | __all__ = ['QQ', 'LogInError', 'NeedVerifyCode'] 11 | 12 | class LogInError(Exception): pass 13 | 14 | class NeedVerifyCode(Exception): 15 | def __init__(self, verifier, message=None): 16 | Exception.__init__(self) 17 | self.verifier = verifier 18 | self.message = message 19 | 20 | class Verifier: 21 | url_check = 'http://check.ptlogin2.qq.com/check' 22 | url_gettype = 'http://captcha.qq.com/cap_union_new_gettype' 23 | url_getsig = 'http://captcha.qq.com/cap_union_new_getsig' 24 | url_getimage = 'http://captcha.qq.com/cap_union_new_getcapbysig' 25 | url_verify = 'http://captcha.qq.com/cap_union_new_verify' 26 | 27 | def __init__(self, parent): 28 | self.parent = parent 29 | self.sess = None 30 | self.need_verify = False 31 | 32 | def check(self): 33 | parent = self.parent 34 | login_sig = parent.session.cookies['pt_login_sig'] 35 | g = parent.fetch(self.url_check, params={ 36 | 'pt_tea': 2, 37 | 'uin': parent.user, 38 | 'appid': parent.appid, 39 | 'js_ver': parent.js_ver, 40 | 'js_type': 1, 41 | 'u1': parent.url_success, 42 | 'login_sig': login_sig, 43 | }).text 44 | v = re.findall('\'(.*?)\'', g) 45 | self.pt_vcode_v1, self.cap_cd, self.uin, self.ptvfsession = v[:4] 46 | if self.pt_vcode_v1 == '1': 47 | self.throw() 48 | else: 49 | self.vcode = self.cap_cd 50 | 51 | def get_type(self): 52 | parent = self.parent 53 | g = parent.fetch(self.url_gettype, params={ 54 | 'aid': parent.appid, 55 | 'protocol': 'http', 56 | 'clienttype': 2, 57 | 'apptype': 2, 58 | 'curenv': 'inner', 59 | 'uid': parent.user, 60 | 'cap_cd': self.cap_cd, 61 | 'callback': '_qqlib_', 62 | }).text 63 | m = re.search('"sess":"(.*?)"', g) 64 | self.sess = m.group(1) 65 | 66 | def fetch_image(self): 67 | parent = self.parent 68 | if self.sess is None: 69 | self.get_type() 70 | g = parent.fetch(self.url_getsig, params={ 71 | 'aid': parent.appid, 72 | 'protocol': 'http', 73 | 'clienttype': 2, 74 | 'apptype': 2, 75 | 'curenv': 'inner', 76 | 'sess': self.sess, 77 | 'uid': parent.user, 78 | 'cap_cd': self.cap_cd, 79 | }).json() 80 | self.vsig = g['vsig'] 81 | r = parent.fetch(self.url_getimage, params={ 82 | 'aid': parent.appid, 83 | 'protocol': 'http', 84 | 'clienttype': 2, 85 | 'apptype': 2, 86 | 'curenv': 'inner', 87 | 'sess': self.sess, 88 | 'uid': parent.user, 89 | 'cap_cd': self.cap_cd, 90 | 'vsig': self.vsig, 91 | 'showtype': 'embed', 92 | 'ischartype': 1, 93 | }) 94 | return r.content 95 | 96 | def verify(self, vcode): 97 | parent = self.parent 98 | r = parent.fetch(self.url_verify, data={ 99 | 'aid': parent.appid, 100 | 'protocol': 'http', 101 | 'clientype': 2, 102 | 'apptype': 2, 103 | 'curenv': 'inner', 104 | 'sess': self.sess, 105 | 'uid': parent.user, 106 | 'cap_cd': self.cap_cd, 107 | 'vsig': self.vsig, 108 | 'ans': vcode, 109 | }) 110 | r.encoding='utf-8' 111 | g = r.json() 112 | if g['errorCode'] != '0': 113 | self.throw(g['errMessage']) 114 | self.vcode = g['randstr'] 115 | self.ptvfsession = g['ticket'] 116 | self.need_verify = False 117 | 118 | def throw(self, message=None): 119 | self.need_verify = True 120 | raise NeedVerifyCode(self, message) 121 | 122 | class QQ: 123 | appid = 549000912 124 | action = '4-22-1450611437613' 125 | url_success = 'http://qzs.qq.com/qzone/v5/loginsucc.html?para=izone' 126 | js_ver = 10171 127 | 128 | def __init__(self, user, pwd): 129 | self.user = user 130 | self.pwd = pwd 131 | self.nick = None 132 | self.verifier = None 133 | self.session = requests.Session() 134 | self.xlogin() 135 | 136 | def fetch(self, url, data=None, **kw): 137 | if data is None: 138 | func = self.session.get 139 | else: 140 | kw['data'] = data 141 | func = self.session.post 142 | return func(url, **kw) 143 | 144 | url_xlogin = 'http://xui.ptlogin2.qq.com/cgi-bin/xlogin' 145 | def xlogin(self): 146 | ''' 147 | Get a log-in signature in cookies. 148 | ''' 149 | self.fetch(self.url_xlogin, params={ 150 | 'proxy_url': 'http://qzs.qq.com/qzone/v6/portal/proxy.html', 151 | 'daid': 5, 152 | 'no_verifyimg': 1, 153 | 'appid': self.appid, 154 | 's_url': self.url_success, 155 | }) 156 | 157 | url_login = 'http://ptlogin2.qq.com/login' 158 | def login(self, force=False): 159 | login_sig = self.session.cookies['pt_login_sig'] 160 | if force: 161 | self.verifier = None 162 | if self.verifier is None: 163 | verifier = self.verifier = Verifier(self) 164 | verifier.check() 165 | else: 166 | verifier = self.verifier 167 | ptvfsession = verifier.ptvfsession or self.session.cookies.get('ptvfsession', '') 168 | g = self.fetch(self.url_login, params={ 169 | 'u': self.user, 170 | 'verifycode': verifier.vcode, 171 | 'pt_vcode_v1': verifier.pt_vcode_v1, 172 | 'pt_verifysession_v1': ptvfsession, 173 | 'p': self.pwdencode(verifier.vcode, verifier.uin, self.pwd), 174 | 'pt_randsalt': 0, 175 | 'u1': self.url_success, 176 | 'ptredirect': 0, 177 | 'h': 1, 178 | 't': 1, 179 | 'g': 1, 180 | 'from_ui': 1, 181 | 'ptlang': 2052, 182 | 'action': self.action, 183 | 'js_ver': self.js_ver, 184 | 'js_type': 1, 185 | 'aid': self.appid, 186 | 'daid': 5, 187 | 'login_sig': login_sig, 188 | }).text 189 | r = re.findall('\'(.*?)\'', g) 190 | if r[0] == '4': 191 | verifier.throw(r[4]) 192 | if r[0] != '0': 193 | raise LogInError(r[4]) 194 | self.nick = r[5] 195 | self.fetch(r[2]) 196 | self.verifier = None 197 | 198 | @property 199 | def need_verify(self): 200 | return self.verifier and self.verifier.need_verify 201 | 202 | def fromhex(self, s): 203 | # Python 3: bytes.fromhex 204 | return bytes(bytearray.fromhex(s)) 205 | 206 | pubKey = rsa.PublicKey(int( 207 | 'F20CE00BAE5361F8FA3AE9CEFA495362' 208 | 'FF7DA1BA628F64A347F0A8C012BF0B25' 209 | '4A30CD92ABFFE7A6EE0DC424CB6166F8' 210 | '819EFA5BCCB20EDFB4AD02E412CCF579' 211 | 'B1CA711D55B8B0B3AEB60153D5E0693A' 212 | '2A86F3167D7847A0CB8B00004716A909' 213 | '5D9BADC977CBB804DBDCBA6029A97108' 214 | '69A453F27DFDDF83C016D928B3CBF4C7', 215 | 16 216 | ), 3) 217 | def pwdencode(self, vcode, uin, pwd): 218 | ''' 219 | Encode password with tea. 220 | ''' 221 | # uin is the bytes of QQ number stored in unsigned long (8 bytes) 222 | salt = uin.replace(r'\x', '') 223 | h1 = hashlib.md5(pwd.encode()).digest() 224 | s2 = hashlib.md5(h1 + self.fromhex(salt)).hexdigest().upper() 225 | rsaH1 = binascii.b2a_hex(rsa.encrypt(h1, self.pubKey)).decode() 226 | rsaH1Len = hex(len(rsaH1) // 2)[2:] 227 | hexVcode = binascii.b2a_hex(vcode.upper().encode()).decode() 228 | vcodeLen = hex(len(hexVcode) // 2)[2:] 229 | l = len(vcodeLen) 230 | if l < 4: 231 | vcodeLen = '0' * (4 - l) + vcodeLen 232 | l = len(rsaH1Len) 233 | if l < 4: 234 | rsaH1Len = '0' * (4 - l) + rsaH1Len 235 | pwd1 = rsaH1Len + rsaH1 + salt + vcodeLen + hexVcode 236 | saltPwd = base64.b64encode( 237 | tea.encrypt(self.fromhex(pwd1), self.fromhex(s2)) 238 | ).decode().replace('/', '-').replace('+', '*').replace('=', '_') 239 | return saltPwd 240 | -------------------------------------------------------------------------------- /qqlib/__main__.py: -------------------------------------------------------------------------------- 1 | import getpass, sys, tempfile, os 2 | from . import QQ, NeedVerifyCode 3 | 4 | quser = input('QQ: ') 5 | qpwd = getpass.getpass('Password: ') 6 | 7 | qq = QQ(quser, qpwd) 8 | while True: 9 | try: 10 | if qq.need_verify: 11 | fd, path = tempfile.mkstemp(suffix='.jpg') 12 | os.write(fd, qq.verifier.fetch_image()) 13 | os.close(fd) 14 | print('Verify code is saved to:', path) 15 | vcode = input('Input verify code: ') 16 | os.remove(path) 17 | qq.verifier.verify(vcode) 18 | qq.login() 19 | break 20 | except NeedVerifyCode: 21 | exc = sys.exc_info()[1] 22 | if exc.message: 23 | print('Error:', exc.message) 24 | exc = None 25 | print('Hi, %s' % qq.nick) 26 | -------------------------------------------------------------------------------- /qqlib/hieroglyphy/__init__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Decode hieroglyphy with Python 3 | @author Gerald 4 | 5 | Reference: 6 | - http://patriciopalladino.com/files/hieroglyphy/ 7 | - https://github.com/alcuadrado/hieroglyphy 8 | 9 | QZone uses hieroglyphy but changed `f` 10 | ''' 11 | 12 | # Generate mappings with JavaScript: 13 | # Run it at http://patriciopalladino.com/files/hieroglyphy/ 14 | # > 'mappings = ' + JSON.stringify('0123456789abcdeghijklmnopqrstuvwxyz'.split('').reduce((res, c) => {res[c] = hieroglyphy.hieroglyphyString(c).replace(/\+\[\]$/, ''); return res;}, {f:'(![]+[])[+[]]'}), null, 4) 15 | # Store it to ./data.py 16 | from .data import mappings 17 | 18 | class CannotDecodeError(Exception): pass 19 | 20 | def decode(text): 21 | remained = text 22 | results = [] 23 | while remained: 24 | for key, val in mappings.items(): 25 | if remained == val or remained.startswith(val + '+'): 26 | results.append(key) 27 | remained = remained[len(val) + 1:] 28 | break 29 | else: 30 | print(''.join(results), remained) 31 | raise CannotDecodeError(text) 32 | return ''.join(results) 33 | -------------------------------------------------------------------------------- /qqlib/hieroglyphy/data.py: -------------------------------------------------------------------------------- 1 | mappings = {"0":"(+[]+[])","1":"(+!![]+[])","2":"(!+[]+!![]+[])","3":"(!+[]+!![]+!![]+[])","4":"(!+[]+!![]+!![]+!![]+[])","5":"(!+[]+!![]+!![]+!![]+!![]+[])","6":"(!+[]+!![]+!![]+!![]+!![]+!![]+[])","7":"(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])","8":"(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])","9":"(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])","f":"(![]+[])[+[]]","a":"(+{}+[])[+!![]]","b":"([]+{})[!+[]+!![]]","c":"([]+{})[!+[]+!![]+!![]+!![]+!![]]","d":"([][[]]+[])[!+[]+!![]]","e":"([][[]]+[])[!+[]+!![]+!![]]","g":"[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[]))","h":"([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[+[]]","i":"([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]","j":"([]+{})[!+[]+!![]+!![]]","k":"[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+([]+{})[!+[]+!![]])","l":"(![]+[])[!+[]+!![]]","m":"[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+([][[]]+[])[!+[]+!![]])","n":"([][[]]+[])[+!![]]","o":"([]+{})[+!![]]","p":"([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]","q":"[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+!![]+[]))","r":"(!![]+[])[+!![]]","s":"(![]+[])[!+[]+!![]+!![]]","t":"(!![]+[])[+[]]","u":"([][[]]+[])[+[]]","v":"[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+[]))","w":"[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[]))","x":"[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[]))","y":"(+(+!![]+([][[]]+[])[!+[]+!![]+!![]]+(+!![]+[])+(+[]+[])+(+[]+[])+(+[]+[]))+[])[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]","z":"[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[+[]]+([][[]]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()([][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[!+[]+!![]+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+([]+[][(![]+[])[!+[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[])[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[]]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]]+([][[]]+[])[+!![]])())[!+[]+!![]+!![]]+([][[]]+[])[!+[]+!![]+!![]])()(([]+{})[+[]])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+{}+[])[+!![]])"} 2 | -------------------------------------------------------------------------------- /qqlib/qzone.py: -------------------------------------------------------------------------------- 1 | ''' 2 | QZone module 3 | ''' 4 | 5 | from . import QQ 6 | from . import hieroglyphy 7 | 8 | class QZone(QQ): 9 | url_success = 'http://qzs.qq.com/qzone/v5/loginsucc.html?para=izone' 10 | url_feed = 'http://taotao.qzone.qq.com/cgi-bin/emotion_cgi_publish_v6' 11 | url_home = 'https://user.qzone.qq.com/' 12 | 13 | def g_tk(self): 14 | h = 5381 15 | cookies = self.session.cookies 16 | s = cookies.get('p_skey') or cookies.get('skey') or '' 17 | for c in s: 18 | h += (h << 5) + ord(c) 19 | return h & 0x7fffffff 20 | 21 | def _qzonetoken(self, res, start_str, end_str=';'): 22 | i = res.find(start_str) 23 | j = res.find(';', i) 24 | assert i > 0, 'qzonetoken not found!' 25 | raw = res[i + len(start_str) : j] 26 | return hieroglyphy.decode(raw) 27 | 28 | def qzonetoken(self): 29 | self.fetch(self.url_success) 30 | res = self.fetch(self.url_home + str(self.user), headers = { 31 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36', 32 | }).text 33 | return self._qzonetoken(res, 'window.g_qzonetoken = (function(){ try{return ') 34 | 35 | def _feed(self, data): 36 | return self.fetch(self.url_feed, params={ 37 | 'g_tk': self.g_tk(), 38 | 'qzonetoken': self.qzonetoken(), 39 | }, data = { 40 | 'syn_tweet_verson' : 1, 41 | 'paramstr' : 1, 42 | 'pic_template' : '', 43 | 'richtype' : '', 44 | 'richval' : '', 45 | 'special_url' : '', 46 | 'subrichtype' : '', 47 | 'who' : 1, 48 | 'con' : data, 49 | 'feedversion' : 1, 50 | 'ver' : 1, 51 | 'ugc_right' : 1, 52 | 'to_tweet' : 0, 53 | 'to_sign' : 0, 54 | 'hostuin' : self.user, 55 | 'code_version' : 1, 56 | 'format' : 'fs' 57 | }) 58 | 59 | def feed(self, data): 60 | res = self._feed(data) 61 | res.raise_for_status() 62 | 63 | class MQZone(QZone): 64 | url_success = 'https://h5.qzone.qq.com/mqzone/index' 65 | url_feed = 'https://mobile.qzone.qq.com/mood/publish_mood' 66 | 67 | def qzonetoken(self): 68 | res = self.fetch(self.url_success).text 69 | return self._qzonetoken(res, 'window.shine0callback = (function(){ try{return ') 70 | 71 | def _feed(self, data): 72 | return self.fetch(self.url_feed, params={ 73 | 'g_tk': self.g_tk(), 74 | 'qzonetoken': self.qzonetoken(), 75 | }, data = { 76 | 'opr_type': 'publish_shuoshuo', 77 | 'res_uin': self.user, 78 | 'content': data, 79 | 'richval': '', 80 | 'lat': 0, 81 | 'lon': 0, 82 | 'lbsid': '', 83 | 'issyncweibo': 0, 84 | 'format': 'json', 85 | }) 86 | -------------------------------------------------------------------------------- /qqlib/tea.py: -------------------------------------------------------------------------------- 1 | ''' 2 | QQ Crypt module 3 | Licensed to MIT 4 | ''' 5 | 6 | import struct, ctypes 7 | import os 8 | 9 | __all__ = ['encrypt', 'decrypt'] 10 | 11 | def xor8B(a, b): 12 | ''' 13 | XOR operation between two 8B bytes. 14 | ''' 15 | length = 8 16 | arr_a = bytearray(a[:length]) 17 | arr_b = bytearray(b[:length]) 18 | for i in range(length): 19 | arr_a[i] ^= arr_b[i] 20 | return bytes(arr_a) if isinstance(a, bytes) else arr_a 21 | 22 | def encipher(v, k): 23 | ''' 24 | TEA coder encrypt 64 bits value, by 128 bits key, 25 | QQ uses 16 round TEA. 26 | http://www.ftp.cl.cam.ac.uk/ftp/papers/djw-rmn/djw-rmn-tea.html . 27 | ''' 28 | n=16 #qq use 16 29 | delta = 0x9e3779b9 30 | k = struct.unpack('!LLLL', k[0:16]) 31 | y, z = map(ctypes.c_uint32, struct.unpack('!LL', v[0:8])) 32 | s = ctypes.c_uint32(0) 33 | for i in range(n): 34 | s.value += delta 35 | y.value += (z.value << 4) + k[0] ^ z.value+ s.value ^ (z.value >> 5) + k[1] 36 | z.value += (y.value << 4) + k[2] ^ y.value+ s.value ^ (y.value >> 5) + k[3] 37 | r = struct.pack('!LL', y.value, z.value) 38 | return r 39 | 40 | def encrypt(v, k): 41 | """ 42 | Encrypt function for QQ. 43 | 44 | v is the message to encrypt, k is the key 45 | fill char is randomized (which is 0xAD in old version) 46 | the length of the final data is filln + 8 + len(v) 47 | 48 | The message is encrypted 8 bytes at at time, 49 | the result is: 50 | 51 | r = encipher( v ^ tr, key) ^ to (*) 52 | 53 | `encipher` is the QQ's TEA function. 54 | v is 8 bytes data to be encrypted. 55 | tr is the result in preceding round. 56 | to is the data coded in perceding round (v_pre ^ r_pre_pre) 57 | For the first 8 bytes 'tr' and 'to' is filled by zero. 58 | """ 59 | vl = len(v) 60 | #filln = (8 - (vl + 2)) % 8 61 | filln = (6 - vl) % 8 62 | v_arr = ( 63 | bytes(bytearray([filln | 0xf8])), 64 | os.urandom(filln + 2), # random char * (filln + 2) 65 | v, 66 | b'\0' * 7, 67 | ) 68 | v = b''.join(v_arr) 69 | tr = to = b'\0' * 8 70 | r = [] 71 | for i in range(0, len(v), 8): 72 | o = xor8B(v[i:i+8], tr) 73 | tr = xor8B(encipher(o, k), to) 74 | to = o 75 | r.append(tr) 76 | r = b''.join(r) 77 | return r 78 | 79 | def decrypt(v, k): 80 | """ 81 | Decrypt function for QQ. 82 | 83 | according to (*) we can get: 84 | 85 | x = decipher(v[i:i+8] ^ prePlain, key) ^ preCyrpt 86 | 87 | prePlain is the previously encrypted 8 bytes: 88 | per 8 byte from v XOR previous preCyrpt 89 | preCrypt is previous 8 bytes of encrypted data. 90 | 91 | After decrypting, we must truncate the padding bytes. 92 | The number of padding bytes in the front of message is 93 | pos + 1. 94 | pos is the first byte of deCrypted: r[0] & 0x07 + 2 95 | The number of padding bytes in the end is 7 (b'\0' * 7). 96 | The returned value is r[pos+1:-7]. 97 | 98 | >>> from binascii import a2b_hex, b2a_hex 99 | >>> r = encrypt('', b2a_hex('b537a06cf3bcb33206237d7149c27bc3')) 100 | >>> decrypt(r, b2a_hex('b537a06cf3bcb33206237d7149c27bc3')) 101 | '' 102 | >>> r = encrypt('abcdefghijklimabcdefghijklmn', b2a_hex('b537a06cf3bcb33206237d7149c27bc3')) 103 | >>> decrypt(r, b2a_hex('b537a06cf3bcb33206237d7149c27bc3')) 104 | 'abcdefghijklimabcdefghijklmn' 105 | >>> import md5 106 | >>> key = md5.new(md5.new('python').digest()).digest() 107 | >>> data='8CE160B9F312AEC9AC8D8AEAB41A319EDF51FB4BB5E33820C77C48DFC53E2A48CD1C24B29490329D2285897A32E7B32E9830DC2D0695802EB1D9890A0223D0E36C35B24732CE12D06403975B0BC1280EA32B3EE98EAB858C40670C9E1A376AE6C7DCFADD4D45C1081571D2AF3D0F41B73BDC915C3AE542AF2C8B1364614861FC7272E33D90FA012620C18ABF76BE0B9EC0D24017C0C073C469B4376C7C08AA30' 108 | >>> data = a2b_hex(data) 109 | >>> b2a_hex(decrypt(data, key)) 110 | '00553361637347436654695a354d7a51531c69f1f5dde81c4332097f0000011f4042c89732030aa4d290f9f941891ae3670bb9c21053397d05f35425c7bf80000000001f40da558a481f40000100004dc573dd2af3b28b6a13e8fa72ea138cd13aa145b0e62554fe8df4b11662a794000000000000000000000000dde81c4342c8966642c4df9142c3a4a9000a000a' 111 | 112 | """ 113 | l = len(v) 114 | #if l % 8 != 0 or l < 16: 115 | # return '' 116 | prePlain = decipher(v, k) 117 | pos = ord(prePlain[:1]) & 0x07 + 2 118 | r = prePlain 119 | preCrypt = v[0:8] 120 | for i in range(8, l, 8): 121 | x = xor8B(decipher(xor8B(v[i:i+8], prePlain), k), preCrypt) 122 | prePlain = xor8B(x, preCrypt) 123 | preCrypt = v[i:i+8] 124 | r += x 125 | if r[-7:] == b'\0' * 7: 126 | return r[pos+1:-7] 127 | 128 | def decipher(v, k): 129 | ''' 130 | TEA decipher, decrypt 64bits value with 128 bits key. 131 | it's the inverse function of TEA encrypt. 132 | ''' 133 | n = 16 134 | y, z = map(ctypes.c_uint32, struct.unpack('!LL', v[0:8])) 135 | a, b, c, d = map(ctypes.c_uint32, struct.unpack('!LLLL', k[0:16])) 136 | delta = 0x9E3779B9 137 | s = ctypes.c_uint32(delta << 4) 138 | for i in range(n): 139 | z.value -= ((y.value << 4) + c.value) ^ (y.value + s.value) ^ ((y.value >> 5) + d.value) 140 | y.value -= ((z.value << 4) + a.value) ^ (z.value + s.value) ^ ((z.value >> 5) + b.value) 141 | s.value -= delta 142 | return struct.pack('!LL', y.value, z.value) 143 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | rsa 2 | requests 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='qqlib', 5 | version='1.1.1', 6 | description='QQ library for Python.', 7 | long_description='QQ library for Python, based on web APIs.', 8 | url='https://github.com/gera2ld/qqlib', 9 | author='Gerald', 10 | author_email='i@gerald.top', 11 | license='MIT', 12 | classifiers = [ 13 | 'Development Status :: 5 - Production/Stable', 14 | 'Intended Audience :: Developers', 15 | 'License :: OSI Approved :: MIT License', 16 | 'Programming Language :: Python :: 2.7', 17 | 'Programming Language :: Python :: 3', 18 | 'Programming Language :: Python :: 3.0', 19 | 'Programming Language :: Python :: 3.1', 20 | 'Programming Language :: Python :: 3.2', 21 | 'Programming Language :: Python :: 3.3', 22 | 'Programming Language :: Python :: 3.4', 23 | 'Programming Language :: Python :: 3.5', 24 | 'Programming Language :: Python :: 3.6', 25 | ], 26 | keywords='qq', 27 | packages=find_packages(exclude=['tests']), 28 | install_requires=[ 29 | 'rsa', 30 | 'requests', 31 | ], 32 | ) 33 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gera2ld/qqlib/1c6417ea4d602f7a559f9bca56c7dfd86463d910/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_hieroglyphy.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from qqlib import hieroglyphy 3 | 4 | class TestHieroglyphy(unittest.TestCase): 5 | def test_decode(self): 6 | for encrypted, plain in [ 7 | ( 8 | '(+[]+[])+(+!![]+[])+(!+[]+!![]+[])+(!+[]+!![]+!![]+[])' 9 | '+(!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+[]' 10 | ')+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!' 11 | '![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+' 12 | '!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]' 13 | '+!![]+[])+(+{}+[])[+!![]]+([]+{})[!+[]+!![]]+([]+{})[!' 14 | '+[]+!![]+!![]+!![]+!![]]+([][[]]+[])[!+[]+!![]]+([][[]' 15 | ']+[])[!+[]+!![]+!![]]+(![]+[])[+[]]', 16 | '0123456789abcdef' 17 | ), 18 | ( 19 | '(!+[]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![' 20 | ']+!![]+[])+(+[]+[])+([][[]]+[])[!+[]+!![]]+(!+[]+!![]+' 21 | '!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+' 22 | '([][[]]+[])[!+[]+!![]+!![]]+(![]+[])[+[]]+(![]+[])[+[]' 23 | ']+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+([]+{})' 24 | '[!+[]+!![]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+([' 25 | ']+{})[!+[]+!![]]+(+{}+[])[+!![]]+([]+{})[!+[]+!![]]+([' 26 | ']+{})[!+[]+!![]+!![]+!![]+!![]]+(+!![]+[])+([][[]]+[])' 27 | '[!+[]+!![]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[' 28 | '])+(!+[]+!![]+!![]+!![]+!![]+[])+([]+{})[!+[]+!![]]+([' 29 | '][[]]+[])[!+[]+!![]]+(!+[]+!![]+!![]+!![]+!![]+!![]+[]' 30 | ')+(!+[]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+[])+(!+[]+!' 31 | '![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+' 32 | '!![]+!![]+!![]+[])+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(' 33 | '!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]' 34 | '+[])+(![]+[])[+[]]+(![]+[])[+[]]+(+{}+[])[+!![]]+(!+[]' 35 | '+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![' 36 | ']+!![]+!![]+!![]+!![]+!![]+!![]+[])+([]+[][(![]+[])[!+' 37 | '[]+!![]+!![]]+([]+{})[+!![]]+(!![]+[])[+!![]]+(!![]+[]' 38 | ')[+[]]][([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![' 39 | ']]+([][[]]+[])[+!![]]+(![]+[])[!+[]+!![]+!![]]+(!![]+[' 40 | '])[+[]]+(!![]+[])[+!![]]+([][[]]+[])[+[]]+([]+{})[!+[]' 41 | '+!![]+!![]+!![]+!![]]+(!![]+[])[+[]]+([]+{})[+!![]]+(!' 42 | '![]+[])[+!![]]]((!![]+[])[+!![]]+([][[]]+[])[!+[]+!![]' 43 | '+!![]]+(!![]+[])[+[]]+([][[]]+[])[+[]]+(!![]+[])[+!![]' 44 | ']+([][[]]+[])[+!![]]+([]+{})[!+[]+!![]+!![]+!![]+!![]+' 45 | '!![]+!![]]+(![]+[])[!+[]+!![]]+([]+{})[+!![]]+([]+{})[' 46 | '!+[]+!![]+!![]+!![]+!![]]+(+{}+[])[+!![]]+(!![]+[])[+[' 47 | ']]+([][[]]+[])[!+[]+!![]+!![]+!![]+!![]]+([]+{})[+!![]' 48 | ']+([][[]]+[])[+!![]])())[+[]]+(!+[]+!![]+!![]+!![]+!![' 49 | ']+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!!' 50 | '[]+[])+(!+[]+!![]+!![]+[])+(+!![]+[])+(!+[]+!![]+!![]+' 51 | '!![]+[])+(+{}+[])[+!![]]+([][[]]+[])[!+[]+!![]]+(!+[]+' 52 | '!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(+{}+[])[+' 53 | '!![]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!!' 54 | '[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+[' 55 | '])+([][[]]+[])[!+[]+!![]+!![]]+(+[]+[])+(!+[]+!![]+!![' 56 | ']+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!!' 57 | '[]+!![]+[])+(!+[]+!![]+[])+(!+[]+!![]+!![]+!![]+[])+(!' 58 | '+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(![]+[])[+[]]+(!' 59 | '+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+' 60 | '!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]' 61 | '+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+([]+{})[!' 62 | '+[]+!![]]+(!+[]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!![' 63 | ']+!![]+!![]+!![]+!![]+!![]+[])+(![]+[])[+[]]+(!+[]+!![' 64 | ']+!![]+!![]+!![]+[])+(!+[]+!![]+[])+([]+{})[!+[]+!![]]' 65 | '+(+[]+[])+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!+[]+!![]' 66 | '+!![]+!![]+!![]+[])+(!+[]+!![]+[])+(![]+[])[+[]]+(!+[]' 67 | '+!![]+!![]+!![]+[])+(![]+[])[+[]]+([]+{})[!+[]+!![]+!!' 68 | '[]+!![]+!![]]+([]+{})[!+[]+!![]]+(!+[]+!![]+!![]+!![]+' 69 | '[])+([]+{})[!+[]+!![]]+(!+[]+!![]+!![]+!![]+!![]+!![]+' 70 | '!![]+!![]+!![]+[])+(+{}+[])[+!![]]+(!+[]+!![]+[])+(+!!' 71 | '[]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!' 72 | '![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+' 73 | '!![]+!![]+!![]+!![]+!![]+!![]+[])+([]+{})[!+[]+!![]]+(' 74 | '[]+{})[!+[]+!![]+!![]+!![]+!![]]+(!+[]+!![]+!![]+[])+(' 75 | '[]+{})[!+[]+!![]]+(!+[]+!![]+!![]+!![]+!![]+[])+(!+[]+' 76 | '!![]+[])+(!+[]+!![]+[])+([]+{})[!+[]+!![]+!![]+!![]+!!' 77 | '[]]+(+[]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+(+{}+[' 78 | '])[+!![]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(![]' 79 | '+[])[+[]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])' 80 | '+([]+{})[!+[]+!![]+!![]+!![]+!![]]+(!+[]+!![]+!![]+!![' 81 | ']+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+[])+(!+[]+!!' 82 | '[]+!![]+[])+(+[]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!!' 83 | '[]+!![]+!![]+[])+(+{}+[])[+!![]]+(![]+[])[+[]]+(!+[]+!' 84 | '![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+' 85 | '!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+([]+{})[!+' 86 | '[]+!![]]+(!+[]+!![]+!![]+[])+(+[]+[])+(+[]+[])+(!+[]+!' 87 | '![]+!![]+!![]+!![]+!![]+[])+([]+{})[!+[]+!![]]+(!+[]+!' 88 | '![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+' 89 | '[])+(!+[]+!![]+!![]+[])+(+{}+[])[+!![]]+(+!![]+[])+(!+' 90 | '[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(![]+[]' 91 | ')[+[]]+(!+[]+!![]+!![]+!![]+!![]+[])+([]+{})[!+[]+!![]' 92 | '+!![]+!![]+!![]]+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!' 93 | '![]+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+' 94 | '[])+(![]+[])[+[]]+([][[]]+[])[!+[]+!![]]+(!+[]+!![]+!!' 95 | '[]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]+!![]+!![]+!' 96 | '![]+[])+(+!![]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]' 97 | '+!![]+[])+(+[]+[])+(!+[]+!![]+!![]+!![]+!![]+!![]+[])+' 98 | '(![]+[])[+[]]+([]+{})[!+[]+!![]]+(!+[]+!![]+!![]+!![]+' 99 | '!![]+!![]+[])+([]+{})[!+[]+!![]+!![]+!![]+!![]]+([]+{}' 100 | ')[!+[]+!![]+!![]+!![]+!![]]+(!+[]+!![]+!![]+!![]+!![]+' 101 | '[])+(!+[]+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])+(!+[]' 102 | '+!![]+!![]+!![]+!![]+!![]+!![]+!![]+[])', 103 | '290d56eff8b7babc1d85bd63477c46ffa89h96314ad9a783e06824' 104 | '7f9666b49f52b0c52f4fcb4b9a21798bc3b522c06a7f8c83309af9' 105 | '36b3006b833a19f5c98fd941806fb6cc588' 106 | ), 107 | ]: 108 | self.assertEqual(hieroglyphy.decode(encrypted), plain) 109 | -------------------------------------------------------------------------------- /tests/test_tea.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from binascii import a2b_hex, b2a_hex 3 | from qqlib import tea 4 | 5 | KEY_1 = b'aaaabbbbccccdddd' 6 | DATA_1 = b'abcdefgh' 7 | ENC_1 = b'a557272c538d3e96' 8 | KEY_2 = b2a_hex(b'b537a06cf3bcb33206237d7149c27bc3') 9 | DATA_2 = b'' 10 | ENC_2 = b'b56137502728e2c74bb84c6d50d21973' 11 | 12 | class TestTEA(unittest.TestCase): 13 | def test_encipher(self): 14 | c = b2a_hex(tea.encipher(DATA_1, KEY_1)) 15 | self.assertEqual(c, ENC_1) 16 | 17 | def test_decipher(self): 18 | c = tea.decipher(a2b_hex(ENC_1), KEY_1) 19 | self.assertEqual(c, DATA_1) 20 | 21 | def test_decrypt(self): 22 | c = tea.decrypt(a2b_hex(ENC_2), KEY_2) 23 | self.assertEqual(c, DATA_2) 24 | 25 | def test_encrypt(self): 26 | e = tea.encrypt(DATA_2, KEY_2) 27 | src = tea.decrypt(e, KEY_2) 28 | self.assertEqual(src, DATA_2) 29 | --------------------------------------------------------------------------------