TSG CTF 2024 | Re


Misbehave

题目分类:

< 随机数 > <自定义memcmp>

题目信息:

Author: mikanami

There’s something strange about this binary file…

Hints for beginners…

The attached file is an ELF executable for x86-64 Linux. Running it and entering the correct FLAG will display Correct!. Use tools like Ghidra or IDA Free to get an overview of the process.

Use gdb to observe its behavior while running. You don’t need to fully understand every single process. Sometimes, it’s enough to identify the inputs and outputs.

misbehave.tar.gz

题目总览:

file查看文件信息

image-20241215225702771

扔IDA看逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int __fastcall main(int argc, const char **argv, const char **envp)
{
_DWORD v4[12]; // [rsp+0h] [rbp-40h] BYREF
int v5; // [rsp+30h] [rbp-10h]
int v6; // [rsp+34h] [rbp-Ch]
int i; // [rsp+38h] [rbp-8h]
char v8; // [rsp+3Fh] [rbp-1h]

v8 = 1;
v6 = 4;
input_flag(v4, 48LL, envp); //flag有48位
init(11447LL, 34LL); //初始化v4
for ( i = 0; i <= 11; ++i )
{
v5 = gen_rand(); //生成随机数
v4[i] ^= v5; //与随机数异或
if ( memcmp(&v4[i], (char *)&flag_enc + 4 * i, v6) ) //加密后与答案比较
v8 = 0;
}
if ( v8 )
puts("Correct!");
else
puts("Wrong...");
return 0;
}

看初始化v4:

1
2
3
4
5
6
7
8
9
10
11
char *__fastcall init(__int64 offset_target_23B7, __int64 offset_source_22)//这里修改传参名称,结合以下函数功能,23B7和22是main函数传入
{
char *result;

state = 0xFEEDF00DDEADBEEFLL; //初始化state
result = (char *)&loc_1381 + offset_source_22;
*(_QWORD *)((char *)&loc_1381 + offset_target_23B7) = (char *)&loc_1381 + offset_source_22; //强制类型转换,将字节指针转换为指向 64 位数据的指针 //这里解释了main中检查密文只循环了12次
//!!!!******这里!使用init函数内地址loc_1381的相对偏移量将uint64_t值写入该地址。重写的地址是memcmp@got,重写后的内容是函数13A3,也就是说,main函数调用的是23A3函数,而不是memcmp函数!!!!!***********

return result;
}

随机数生成函数,因为v5的变化在检查循环内,所以每个循环都会更新state的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
__int64 gen_rand()
{
int j; // [rsp+1Ch] [rbp-24h]
int i; // [rsp+20h] [rbp-20h]
unsigned int v3; // [rsp+24h] [rbp-1Ch]
unsigned __int64 v4; // [rsp+28h] [rbp-18h]
unsigned __int64 v5; // [rsp+30h] [rbp-10h]
unsigned __int64 v6; // [rsp+38h] [rbp-8h]

v6 = state & 0x1FF;
v5 = ((unsigned __int64)state >> 9) & 0x7FF;
v4 = ((unsigned __int64)state >> 20) & 0x1FFF;
for ( i = 0; i <= 31; ++i )
{
for ( j = 0; j <= 30; ++j )
{
v6 = ((v6 >> 4) ^ BYTE1(v6)) & 1 | (2 * (_WORD)v6) & 0x1FF;
v5 = (BYTE1(v5) ^ (v5 >> 10)) & 1 | (2 * (_WORD)v5) & 0x7FF;
v4 = ((v4 >> 11) ^ (v4 >> 10) ^ (v4 >> 7) ^ (v4 >> 12)) & 1 | (2 * (_WORD)v4) & 0x1FFF;
}
v3 = (v5 & (unsigned __int8)v6 | (unsigned __int8)(~(_BYTE)v6 & v4)) & 1 | (2 * v3);
}
state = v6 | (v4 << 20) | (v5 << 9); //<---这里变化
return v3;
}

很好的memcmp,可能当作strcmp了(x

在调试起来发现,链接了另一个函数

image-20241215232226386

image-20241215232220596

这里对state也有操作,每组数第一个数对state异或

题目解决:

state初始值:

state = 0xFEEDF00DDEADBEEFLL;

密文知道了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
enflag = [  
0x20, 0x60, 0x6F, 0x90, 0xAE, 0x77, 0x8F, 0xF3, 0xFC, 0x09,
0xA5, 0x5E, 0xDD, 0x6B, 0x39, 0x51, 0xDF, 0xFD, 0x6E, 0x5E,
0xA8, 0x60, 0x88, 0x85, 0xBC, 0xD7, 0x95, 0x52, 0x75, 0xE9,
0x82, 0xF3, 0xB7, 0xA2, 0x04, 0x95, 0x4A, 0x0E, 0x5C, 0x67,
0x53, 0x81, 0x13, 0xBF, 0x34, 0x61, 0x70, 0xC1]
整理一下:
enflag = [
0x906F6020,0xF38F77AE,
0x5EA509FC,0x51396BDD,
0x5E6EFDDF,0x858860A8,
0x5295D7BC,0xF382E975,
0x9504A2B7,0x675C0E4A,
0xBF138153,0xC1706134,
]

没有在memcmp被异或的state中间值:

image-20241215234159080

1
2
3
4
5
6
7
8
initia = '19BC7C670'
tmp = [
0xD3283374,0x74FC6DEF,
0xA03471DD,0x86BF5A2A,
0xECA0F9BC,0xDB9E9D94,
0xA47A61BA,0x5A46820B,
0xABD092BC,0x7908986B,
0x4AE82AEA,0xE73A17DB]

在memcmp自定义函数中,第i+1个state会与第i组明文异或*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
state_init = 0xFEEDF00DDEADBEEF
enflag = [
0x906F6020,0xF38F77AE,0x5EA509FC,0x51396BDD,
0x5E6EFDDF,0x858860A8,0x5295D7BC,0xF382E975,
0x9504A2B7,0x675C0E4A,0xBF138153,0xC1706134,
]
state_tmp = [ //这里还是偷懒了,直接摘出来的v5,没还原rand函数
0xD3283374,0x9BF431FA,0x6DC16DCD,0x245F34B3,
0x37599EB1,0xB1D70E98,0x21CAB3D2,0xACE4D846,
0xCA3392D0,0x1539787A,0x8822F324,0xC1701C07
]
for i in range(12):
print((state_tmp[i]^enflag[i]).to_bytes(4, byteorder='little'))
'''
b'TSGC'
b'TF{h'
b'1dd3'
b'n_fu'
b'nc7i'
b'0n_4'
b'nd_s'
b'31f_'
b'g07_'
b'0ver'
b'wr17'
b'3}\x00\x00'
#TSGCTF{h1dd3n_func7i0n_4nd_s31f_g07_0verwr173}

测试一下

image-20241216113234897

一些别的:

グローバル変数stateを初期化しています。そして、init関数内部のアドレスloc_1381からの相対オフセットを使ったアドレスへ、uint64_t値を書き込んでいます。計算すると、書き換え先のアドレスはmemcmp@got、書き換え後の内容は13A3の関数でした。つまり、main関数ではmemcmp関数ではなく13A3の関数を呼び出します!

初始化全局变量状态。然后,使用 init 函数内地址 loc_1381 的相对偏移量将 uint64_t 值写入该地址。我算了一下,要重写的地址是memcmp@got,重写后的内容是函数13A3。也就是说,main函数调用的是13A3函数,而不是memcmp函数!

4 字节 memcmp 的比较的同时,全局变量状态将通过与第一个参数的 XOR 结果进行更新。

Warmup SQLite

题目分类

< SQLite opcode>

题目信息

Author: mikitorium08

Let’s get familiar with SQLite’s bytecode

warmup_sqlite.tar.gz

题目分析

一开始没怎么搞懂readme里在说什么

1
2
3
4
5
6
7
8
9
# Warmup SQLite

`dump` is the result of `EXPLAIN <hidden SQL>` with the parameter `~~Your input is filled here~~`.

We use the same sqlite3 as SQLite of Hand, another pwn challenge in TSG CTF 5, to dump this code.

# 预热 SQLite
`dump` 是参数为 `~~Your input is filled here~~` 的 `EXPLAIN <hidden SQL>` 的结果。
我们使用与 SQLite of Hand 相同的 sqlite3 来转储这段代码,SQLite of Hand 是 TSG CTF 5 中的另一项 Pwn 挑战。

看python文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
import sqlite3
import re
import sys

res = [100, 115, 39, 99, 100, 54, 27, 115, 69, 220, 69, 99, 100, 191, 56, 161, 131, 11, 101, 162, 191, 54, 130, 175, 205, 191, 222, 101, 162, 116, 147, 191, 55, 24, 69, 130, 69, 191, 252, 101, 102, 101, 252, 189, 82, 116, 41, 147, 161, 147, 132, 101, 162, 82, 191, 220, 9, 205, 9, 100, 191, 38, 68, 253]
#for i in range(len(res)):
# print(chr(res[i]),end='')

def check(s):
return bool(re.match('^[a-zA-Z0-9_=}{"]+$', s))

def run(s):
conn = sqlite3.connect('hello.db')
cursor = conn.cursor()

with open('query.sql', 'r') as f:
query = f.read()

try:
cursor.execute(query, (s,))
for (idx, row) in enumerate(cursor.fetchall()):
assert(row[0] == res[idx])
print('correct')
except Exception as _:
cursor.execute(query, (s,))
for (idx, row) in enumerate(cursor.fetchall()):
assert(row[0] == res[idx])
print(row[0])
print('correct')
finally:
conn.close()

def main():
print('input string: ')
s = sys.stdin.readline().strip()
#if not (s and len(s) == 64 and check(s)):
# print("wrong")
# return
run(s)

main()

检测flag是否64位,且match('^[a-zA-Z0-9_=}{"]+$', s),之后对flag处理,与res比较

对flag的check应该是在db里面,

1
2
3
4
5
6
7
#sqlite3 Python library:使用 sqlite3 库来与 SQLite 数据库进行交互,并使用 EXPLAIN 获取 SQL 查询的 opcode 列表。
import sqlite3

conn = sqlite3.connect('example.db')
cursor = conn.cursor()
cursor.execute('EXPLAIN QUERY PLAN SELECT * FROM my_table')
print(cursor.fetchall())

看到文档里crazyman贴了一个:

https://www.sqlite.org/opcode.html

往下滑滑,找到一个很类似的东西,

image-20241220001558188

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ sqlite3 ex1.db
sqlite> explain delete from tbl1 where two<20;
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 12 0 00 Start at 12
1 Null 0 1 0 00 r[1]=NULL
2 OpenWrite 0 2 0 3 00 root=2 iDb=0; tbl1
3 Rewind 0 10 0 00
4 Column 0 1 2 00 r[2]=tbl1.two
5 Ge 3 9 2 (BINARY) 51 if r[2]>=r[3] goto 9
6 Rowid 0 4 0 00 r[4]=rowid
7 Once 0 8 0 00
8 Delete 0 1 0 tbl1 02
9 Next 0 4 0 01
10 Noop 0 0 0 00
11 Halt 0 0 0 00
12 Transaction 0 1 1 0 01 usesStmtJournal=0
13 TableLock 0 2 1 tbl1 00 iDb=0 root=2 write=1
14 Integer 20 3 0 00 r[3]=20
15 Goto 0 1 0 00

所以dump应该是对db文件的转储,所以问题变成了,如何将 sqlite opcade 转换为可以阅读的常见指令类型(比如右侧comment)

if SQLite is compiled with the -DSQLITE_ENABLE_EXPLAIN_COMMENTS options. (乐)

难蚌

image-20241220005920304

照着opcode一点一点写规则(?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def opcode_to_description(opcode, p1, p2, p3, p4, p5):
descriptions = {
0: f"Start at {p2}",
1: f"R[{p1}] = {p3}",
......
}

return descriptions.get(opcode, f"Unknown opcode {opcode}")

def process_opcode_dump(dump_file_path):
with open(dump_file_path, 'r') as file:
for line in file:
if '|' not in line:
continue
parts = line.strip().split('|')
if len(parts) >= 4:
opcode = int(parts[0])
p1 = int(parts[2])
p2 = int(parts[3])
p3 = int(parts[4])
p4 = str(parts[5])
p5 = int(parts[6])
description = opcode_to_description(opcode, p1, p2, p3, p4, p5)
print(description)

process_opcode_dump('./dump')

一点一点扣规则(?

最后的integer似乎是寄存器?找一些操作行为,比如Ge、add、Multiply

1
2
3
4
5
6
7
8
9
10
11
57|Multiply|30|29|24||0
58|Add|31|24|20||0
59|Remainder|32|20|21||0
89|Integer|1|15|0||0
90|Integer|1|16|0||0
91|Integer|2|18|0||0
92|Integer|1|19|0||0
93|Integer|10|28|0||0
94|Integer|7|30|0||0
95|Integer|2|31|0||0
96|Integer|256|32|0||0

根据寄存器的内容读取第 55 条到第 66 条指令时,循环了 10 次计算 ((something * 7) + 2) % 256

本想着直接爆破来着(x 下面是一个数学方法,

一些别的

ctf_writeups/2024/tsgctf/README.md at master · moratorium08/ctf_writeups

这个师傅SQL恢复的非常好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
WITH RECURSIVE
split(input, rest, idx) AS (
VALUES('', ?, -1)
UNION ALL
SELECT
substr(rest, 1, 1),
substr(rest, 2),
idx + 1
FROM split
WHERE rest <> ''
),
tr(val, idx, iter) AS (
SELECT
unicode(input) AS val,
idx,
0 AS iter
FROM split
WHERE input <> ''

UNION ALL

SELECT
(tr.val * 7 + 2) % 256,
idx,
iter + 1
FROM tr
WHERE iter < 10
)
SELECT * from tr WHERE iter = 10 ORDER BY idx;

exp:(很好的数论,让我的大脑短路)# 唉,乘法逆元。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import sqlite3
import re
import sys

res = [100, 115, 39, 99, 100, 54, 27, 115, 69, 220, 69, 99, 100, 191, 56, 161, 131, 11, 101, 162, 191, 54, 130, 175, 205, 191, 222, 101, 162, 116, 147, 191, 55, 24, 69, 130, 69, 191, 252, 101, 102, 101, 252, 189, 82, 116, 41, 147, 161, 147, 132, 101, 162, 82, 191, 220, 9, 205, 9, 100, 191, 38, 68, 253]

n = pow(7, -1, 256) # <----这里
for i in range(10):
numbers = []
for x in res:
m = ((x - 2) * n) % 256
numbers.append(m)
res = numbers

print(''.join(map(chr, res)))

TSGDBinary

题目分类

< ? >

题目信息

Author: iwashiira

Everyday Tools

TSGDBinary.tar.gz

三个文件,start.sh:

1
sudo gdb --nx -x ./tsgdbinary.py ./tsgdbinary

执行 tsgdbinary 二进制文件,同时将 tsgdbinary.py 作为 GDB 脚本加载

。。哭了

不想看了。先做点作业吧。

serverless

<\yaml><重定向>

题目分类

题目信息

Author: mikit

Experience the power of serverless computing.

The server is provided for illustration purposes only and there is no need to connect to the server to solve this task.

http://34.146.145.253:20906/TSGCTF{dummy_dummy}

serverless.tar.gz

image-20241223222322354

题目分析

不太懂是什么,可以看到后面都是格式相同的内容,把前面扔个chatGPT:写了一些注释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# docker-compose配置文件
services:
proxy:
image: envoyproxy/envoy:v1.31.4
restart: no
command: ["--log-level info", "--config-path /etc/envoy/envoy.yaml"]
ports:
- "20906:20906" # 将容器的 20906 端口映射到主机的 20906 端口。
configs:
- source: proxy.yaml
target: /etc/envoy/envoy.yaml
configs:
#嵌套在这里
proxy.yaml:
content: |
admin:
address:
socket_address: { address: 127.0.0.1, port_value: 0 }
static_resources:
clusters:
- name: redirect-cluster
connect_timeout: 0.1s #超时
type: STATIC # 静态负载均衡
lb_policy: ROUND_ROBIN #负载均衡算法
load_assignment: #配置和 redirect-cluster 相似,但是地址为 127.0.0.1:20908
cluster_name: redirect-cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 20907
- name: internal-cluster
connect_timeout: 0.1s
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: internal-cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 20908
listeners:
- name: api-listener
address:
socket_address: { address: 0.0.0.0, port_value: 20906 }
# 配置了一个 HTTP 连接管理器过滤器,route_config 定义了具体的路由规则:
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config: <------这里
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
# please decode `%7B` to `{` and `%7D` to `}` before submission.
safe_regex: { regex: "^/TSGCTF%7B[a-zA-Z0-9_-]+%7D/?$" }
route:
cluster: redirect-cluster
timeout: 1s
internal_redirect_action: HANDLE_INTERNAL_REDIRECT
- match: <-----匹配成功
prefix: "/"
direct_response:
status: 200
body:
inline_string: "ill-formed"
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- name: redirect-listener
address:
socket_address: { address: 127.0.0.1, port_value: 20907 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: internal-cluster
internal_redirect_policy:
max_internal_redirects: 2000
redirect_response_codes: [301]
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
- name: internal-listener
address:
socket_address: { address: 0.0.0.0, port_value: 20908 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
codec_type: AUTO
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
path: "/"
direct_response:
status: 200
body:
inline_string: "ok"
# 对于匹配正则表达式 ^(.*)/eq.* 的路径,进行重定向,重写路径将 "/eq" 替换为 "(w)(s)(p)/"
- match:
safe_regex: { regex: "^(.*)/eq.*" }
redirect:
regex_rewrite:
pattern: { regex: "^(.*)/eq" }
substitution: "\\1(w)(s)(p)/"
- match:
······很多个类似的结构(六行)直到结尾

image-20241224153053086

将六行匹配,写为一行的键值对,发现有以下规则:

  • 标志开头的 TSGCTF{ 中的开头括号 %7B 被转换为(/ 和 “开头圆括号 + 斜线”。
  • 标志末尾 } 的结尾括号 %7D 被转换为 a) 和结尾圆括号。
  • 将 ) 转换为 ) 和结尾圆括号。 换句话说,去掉斜线。
  • 将 _ 转换为)(/和 “闭合圆括号 + 开头圆括号 + 斜线”。
  • 将 “斜线 + 1 或 2 个小写字母或数字或连字符”(如 /eq)转换为 “圆括号内的 3 个小写字母 + 斜线”(如 (w)(s)(p)/)。
  • 将 “斜线 + 1 或 2 个小写字母、数字或连字符”(如 /6i)转换为 “3 个小写字母(用圆括号包围) + 3 个大写字母 + 斜线”(如 (s)(y)(n)RZK/)。
  • 将 “斜线 + 1 或 2 个小写字母或数字或连字符”,如 /wz/ 转换为 “1 个小写字母 + 3 个大写字母 + 斜线”,如 cDPL/。
  • 将 “大写字母 + 圆括号内的小写字母”(如 M(m))转换为空字符串。 这种组合适用于从 A 到 Z 的所有 26 个字母。
  • (有些模式会将 %7D%7B 转换为 +。 但这种情况不会发生)。

对所有模式的分析表明,斜线的位置在模式中非常重要。

  • 斜线由大括号和下划线产生。
  • /eq 等模式在转换字符串(例如
    /),并在斜线到达结尾圆括号时清除斜线。
  • 目标是重定向的结果是/。 为此,必须删除 TSGCTF 字符串。 考虑到可以删除的模式,TSGCTF(f)(t)(c)(g)(s)(t) 模式显然需要完成。

换句话说,对于字母 tsfctf,我们需要找到满足以下重定向的模式:。

  • 第一个重定向目标是 tABC/ 格式中的 “1 个小写字母 + 3 个大写字母 + 斜线 ”模式
  • 中间重定向目的地是(c)(b)(a)XYZ/格式的 “3 个小写字母括在圆括号中,抵消前面的 3 个大写字母 + 另外 3 个大写字母 + 斜线 ”模式的零次或多次重复。
  • 最后一个重定向是(z)(y)(x)/,即 “3 个小写字母括在圆括号中,取消前面的 3 个大写字母 + 一条斜线”。

/をかお えすあ <–读出来就知道是哪个表情包了)

。为什么我这么菜啊我靠啊

。。

贴一个csome师傅的exp.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
#!/usr/bin/env python3

lines = '''
"eq": "(w)(s)(p)"
"6i": "(s)(y)(n)RZK"
"g7": "(q)(k)(s)MFF"
"9g": "(e)(f)(z)EFT"
"wz": "cDPL"
"9c": "(m)(d)(v)FXP"
"wt": "(r)(v)(p)WTS"
"l0": "(d)(i)(f)YNR"
"jc": "lPZK"
"hs": "(y)(j)(m)QFU"
"al": "(m)(m)(v)WTS"
"37": "(i)(z)(x)YNR"
"gr": "(l)(t)(x)WFG"
"v4": "(s)(t)(w)FXP"
"ie": "(e)(v)(p)TQB"
"75": "(r)(f)(t)QLD"
"mo": "(o)(v)(q)"
"r3": "(i)(d)(t)DAM"
"s-": "(b)(b)(c)RFF"
"a2": "(k)(z)(p)LGI"
"f8": "dWSO"
"hz": "(z)(k)(d)EAX"
"og": "(p)(l)(u)AMA"
"d5": "(f)(e)(s)LZZ"
"o2": "(c)(h)(m)DPL"
"3i": "(u)(t)(d)ECN"
"kv": "(v)(r)(c)DAM"
"2j": "(f)(f)(m)"
"76": "(a)(g)(f)GIO"
"ol": "(q)(l)(n)TQV"
"30": "(s)(t)(n)"
"2g": "(f)(e)(s)XIU"
"b4": "(h)(q)(a)FGA"
"by": "(w)(j)(e)RBJ"
"ck": "(k)(v)(w)RBJ"
"3z": "(a)(z)(y)PZK"
"0p": "(d)(j)(p)YNR"
"o4": "wWVK"
"6b": "(k)(z)(r)GYJ"
"zh": "(u)(t)(d)QFU"
"5k": "(y)(o)(w)WSM"
"sk": "(a)(m)(q)XPF"
"sp": "(o)(v)(q)YMC"
"f2": "(k)(v)(p)DPL"
"w-": "(a)(a)(f)QLD"
"y1": "(y)(o)(w)MJY"
"7e": "(l)(v)(c)WSM"
"mn": "(s)(y)(n)QMA"
"mq": "(y)(o)(w)DTU"
"up": "hWTS"
"pg": "(b)(x)(u)CAX"
"s2": "(z)(r)(x)NGC"
"it": "(v)(a)(p)JTO"
"hg": "(v)(j)(v)XIU"
"d2": "(c)(m)(y)MJY"
"25": "(b)(t)(i)GIO"
"bi": "dFCU"
"qr": "(k)(z)(r)PVK"
"2o": "(u)(f)(q)QOH"
"su": "vFCU"
"-0": "(k)(v)(p)TDI"
"rj": "bWFE"
"as": "cQOH"
"8m": "gDPL"
"-j": "(v)(p)(e)YNY"
"dy": "(j)(h)(i)"
"qq": "(y)(a)(m)QOB"
"bk": "(n)(c)(e)LZP"
"e5": "(q)(x)(r)XTL"
"ip": "(a)(y)(h)FYG"
"h-": "(j)(y)(g)RZK"
"j4": "(s)(y)(n)GYJ"
"kz": "qCRV"
"ma": "(d)(l)(q)FBY"
"8j": "(g)(f)(w)AMA"
"pl": "(b)(q)(t)JBX"
"7h": "(c)(w)(q)YNV"
"1h": "(k)(v)(p)RVA"
"jy": "(a)(a)(f)PVK"
"iz": "(i)(g)(l)PVR"
"jb": "(q)(k)(s)"
"vv": "(j)(b)(r)EED"
"or": "(q)(l)(n)YZA"
"tb": "(e)(v)(p)ZIK"
"i8": "(o)(j)(m)TQV"
"ek": "(z)(p)(z)"
"yc": "(o)(v)(q)PAV"
"17": "lTZK"
"3x": "lFID"
"bq": "(b)(d)(v)TQB"
"c-": "fGIO"
"c8": "(c)(m)(y)CVL"
"k-": "qPVR"
"89": "eJBX"
"zg": "(y)(j)(m)LZP"
"33": "(o)(t)(f)PRZ"
"hv": "(b)(c)(e)BZC"
"ez": "(b)(l)(z)RVG"
"97": "(m)(j)(o)HMZ"
"-5": "(l)(d)(m)WSO"
"wo": "(b)(l)(z)RFF"
"ki": "uITB"
"w6": "(i)(y)(a)FYG"
"v5": "(g)(y)(f)YNR"
"zt": "kBBC"
"wh": "(g)(t)(h)"
"7b": "(v)(g)(h)ITV"
"ag": "tPZK"
"gv": "(a)(z)(y)XRZ"
"4q": "uXZI"
"uq": "(v)(a)(p)GIO"
"4t": "(j)(h)(i)SKQ"
"sz": "tBZC"
"18": "(n)(h)(m)"
"rq": "(d)(e)(e)WVK"
"w4": "(r)(f)(t)PVE"
"xb": "vSOY"
"7w": "(e)(v)(p)ULP"
"nz": "(a)(m)(q)QJK"
"z-": "(w)(h)(b)"
"np": "(b)(d)(v)URM"
"pr": "sTOW"
"kb": "(b)(b)(c)"
"gl": "(z)(p)(z)WSM"
"cb": "(w)(v)(a)OMX"
"r6": "(l)(s)(f)EKQ"
"ou": "(q)(l)(n)HCB"
"p7": "(i)(t)(d)DQO"
"b3": "iWFE"
"dv": "(o)(i)(g)STM"
"6s": "(h)(h)(e)AMA"
"7d": "(d)(e)(e)RBJ"
"n0": "(w)(e)(r)YMC"
"8v": "qVVT"
"i4": "(o)(y)(y)RFF"
"dk": "(o)(q)(d)WRO"
"r4": "(b)(b)(c)UXT"
"dx": "(s)(t)(w)XRZ"
"ss": "(s)(n)(q)YNR"
"z6": "hITB"
"e6": "(r)(w)(d)"
"wk": "(o)(j)(m)"
"dm": "(o)(q)(d)FCU"
"ld": "(a)(v)(r)QLO"
"de": "(n)(z)(l)JGU"
"0n": "(s)(z)(d)"
"dg": "(c)(g)(g)"
"qa": "(a)(y)(h)XIU"
"bt": "(i)(t)(d)ITB"
"ci": "(b)(c)(h)AIL"
"m8": "(o)(a)(a)QOB"
"0r": "(v)(p)(e)PAV"
"bp": "(h)(q)(p)ROS"
"we": "(y)(a)(m)NTN"
"js": "(k)(z)(r)IRV"
"vp": "(z)(p)(z)"
"b9": "qITB"
"zo": "(n)(t)(n)NYS"
"ay": "(c)(z)(b)GIH"
"x6": "(g)(t)(h)"
"9v": "(k)(z)(r)PAV"
"w7": "(x)(a)(e)DZS"
"cf": "(d)(e)(e)SOY"
"el": "(y)(o)(w)"
"cz": "(x)(a)(e)"
"zd": "(l)(i)(a)AMA"
"yw": "(t)(f)(e)QOH"
"c1": "(y)(a)(m)IRV"
"9m": "(s)(o)(r)WRU"
"g9": "(w)(j)(e)FXP"
"j-": "(u)(i)(x)SEF"
"ne": "(m)(i)(f)DKZ"
"w8": "(w)(s)(p)FTO"
"tx": "(v)(j)(v)UKO"
"mz": "(g)(t)(h)ULP"
"l2": "(f)(e)(s)STM"
"8a": "(m)(r)(u)CGJ"
"qx": "(u)(i)(x)LZZ"
"26": "(s)(y)(n)NTN"
"5n": "(b)(l)(z)ZIK"
"xr": "(y)(u)(d)YMC"
"xq": "bWRO"
"e4": "(o)(s)(w)UKO"
"t5": "(h)(h)(e)WSM"
"1r": "(a)(z)(y)ZAA"
"fl": "(t)(x)(u)"
"gk": "(q)(x)(r)JBX"
"c6": "(h)(i)(g)WSO"
"2m": "(b)(c)(e)TZK"
"z7": "(b)(x)(u)EFT"
"xi": "(i)(y)(d)"
"ke": "(e)(f)(w)DPL"
"ev": "(o)(i)(g)AQH"
"bl": "(p)(u)(i)"
"f5": "bBZC"
"r2": "(b)(b)(c)YYO"
"bu": "(j)(y)(g)IRV"
"iv": "(j)(x)(x)"
"x7": "(w)(s)(p)"
"co": "(l)(e)(n)IHJ"
"fs": "(a)(m)(q)WFG"
"vs": "vRUH"
"6e": "(w)(s)(p)NOD"
"7-": "(k)(z)(r)MAY"
"40": "(o)(v)(q)VJV"
"l-": "(w)(o)(t)FID"
"d7": "(p)(u)(i)JGU"
"gz": "(p)(f)(q)JBX"
"i1": "(k)(j)(q)OMX"
"9x": "hCRV"
"ng": "(m)(m)(v)"
"mb": "(d)(o)(n)MHN"
"po": "(c)(w)(q)ROS"
"b6": "(r)(w)(d)"
"lb": "(o)(t)(f)DZS"
"dp": "(h)(q)(a)LZZ"
"nm": "(o)(k)(u)ECB"
"--": "(n)(t)(n)IRV"
"-h": "(s)(y)(n)"
"nc": "(b)(o)(q)TQB"
"7o": "(v)(p)(e)YNY"
"so": "(q)(k)(e)TQB"
"1x": "(k)(z)(p)QLO"
"sg": "qGAU"
"z5": "(o)(v)(q)DTU"
"za": "(l)(e)(n)MFF"
"mf": "(v)(r)(i)QOB"
"rh": "(k)(z)(t)OMX"
"mu": "(y)(n)(y)XPF"
"n1": "(v)(a)(p)ROS"
"4x": "(a)(g)(f)AQH"
"gj": "(w)(e)(r)QVO"
"-6": "(m)(d)(v)EED"
"cs": "dWVK"
"5t": "(c)(g)(n)FXP"
"ba": "(r)(f)(t)YYO"
"cv": "(b)(b)(c)VDM"
"ab": "(i)(z)(x)AIL"
"9a": "(y)(j)(m)"
"sb": "(r)(f)(t)XTL"
"7a": "(c)(w)(q)OJM"
"gp": "(k)(j)(q)ECB"
"p0": "(w)(e)(r)PAV"
"ql": "(i)(y)(d)VDB"
"kx": "(k)(z)(r)EJW"
"8u": "(s)(k)(j)"
"zq": "(k)(i)(z)"
"in": "(r)(f)(t)"
"vk": "(b)(o)(q)XIU"
"5g": "(c)(g)(n)XRZ"
"ed": "(v)(j)(v)YZA"
"wy": "(l)(d)(m)TDI"
"hl": "(d)(o)(n)ITV"
"08": "(d)(i)(f)FYG"
"nv": "(u)(n)(a)"
"xd": "(v)(r)(i)"
"jg": "(w)(v)(a)WLM"
"9z": "(e)(v)(p)"
"au": "rBBC"
"da": "(r)(v)(p)FXP"
"6l": "fXRZ"
"ga": "jCRV"
"fu": "tQOB"
"tz": "lXRZ"
"cg": "(c)(h)(m)YNR"
"m6": "(n)(h)(m)PRZ"
"bd": "(s)(t)(n)FHA"
"0m": "(r)(w)(d)"
"mc": "bAZF"
"q5": "(z)(r)(x)PZK"
"1t": "(l)(a)(f)EED"
"ns": "(z)(p)(z)"
"52": "(x)(g)(f)"
"o7": "(y)(u)(d)"
"uy": "kITB"
"bj": "(k)(z)(p)PVR"
"u6": "(f)(z)(a)FAL"
"h9": "(d)(i)(f)XZI"
"tg": "(x)(g)(f)"
"x4": "(m)(l)(w)UKO"
"47": "(s)(z)(d)STM"
"h7": "(c)(g)(n)PZK"
"hj": "(m)(t)(s)SEF"
"qz": "(g)(v)(r)JTO"
"9d": "(o)(i)(g)XIU"
"ug": "(y)(j)(m)REW"
"7s": "(o)(k)(u)GIH"
"la": "(g)(y)(f)QNS"
"of": "(l)(v)(c)DTU"
"uf": "(b)(b)(c)OAL"
"7f": "(k)(z)(p)FXP"
"5e": "(b)(x)(u)TQB"
"gh": "(i)(y)(a)QNS"
"6m": "(b)(c)(e)OMX"
"-r": "(w)(j)(e)VJV"
"q3": "(e)(f)(z)"
"8g": "(o)(q)(d)CRV"
"dq": "(u)(f)(q)LZP"
"yv": "(j)(x)(x)NTS"
"ic": "(w)(h)(b)"
"ka": "(o)(t)(j)ITB"
"k1": "pSTM"
"gc": "(g)(v)(r)RXQ"
"mm": "(o)(v)(q)"
"3p": "(t)(x)(u)YZA"
"a8": "bAIL"
"n3": "(y)(j)(m)"
"qb": "(x)(a)(c)"
"ko": "(w)(o)(t)FGA"
"1-": "fQNS"
"8y": "(s)(y)(n)FAA"
"c0": "(a)(m)(q)MDL"
"p4": "(v)(a)(p)SEF"
"05": "(o)(i)(g)LZZ"
"5p": "(b)(c)(h)AZF"
"sl": "(l)(d)(m)XZI"
"01": "(s)(o)(r)GAU"
"k7": "(a)(g)(f)XIU"
"fg": "(n)(w)(s)PAV"
"1f": "(a)(a)(z)STM"
"gw": "(d)(o)(n)"
"6f": "(b)(b)(c)ZLB"
"eo": "zGAU"
"kh": "(u)(f)(q)YMC"
"m0": "(j)(g)(c)DYI"
"un": "(k)(z)(p)RVA"
"lp": "(p)(z)(l)PQH"
"om": "(t)(x)(u)"
"lx": "(e)(v)(p)VJV"
"vc": "(a)(a)(f)MAY"
"ih": "(g)(t)(h)QLD"
"cm": "tFAL"
"t3": "(d)(o)(n)HCB"
"7y": "qDAM"
"lh": "(y)(o)(w)TOW"
"yo": "ySEF"
"4d": "(s)(z)(d)BBC"
"-k": "(o)(s)(w)OMX"
"i-": "(p)(x)(f)RVA"
"2v": "mGIH"
"cn": "(m)(s)(w)QNS"
"vx": "(y)(u)(d)ECN"
"oe": "(z)(z)(l)GIO"
"7v": "(e)(v)(p)"
"xv": "(y)(n)(y)HLX"
"hx": "(k)(z)(r)NYS"
"tr": "(n)(c)(e)QFU"
"qn": "(c)(h)(m)FAL"
"-c": "(m)(s)(w)HCB"
"ad": "(m)(r)(u)"
"cy": "(l)(e)(n)NLQ"
"lk": "(p)(z)(l)QFU"
"ul": "cWRU"
"o8": "(o)(t)(f)ITV"
"z9": "(r)(w)(d)"
"bh": "(z)(r)(x)RVA"
"y6": "(b)(l)(z)YYO"
"tc": "(y)(o)(s)EED"
"5d": "(n)(j)(q)DTI"
"1l": "(e)(f)(w)AMA"
"m4": "gOAL"
"j0": "(w)(e)(r)"
"pa": "(m)(i)(f)EAX"
"14": "(o)(t)(f)EJW"
"qj": "(o)(t)(f)QJN"
"lj": "(o)(j)(m)SKQ"
"53": "(u)(i)(x)FGA"
"yj": "(m)(r)(u)OAL"
"ai": "vJIF"
"u3": "(v)(q)(t)ZAA"
"7u": "(y)(u)(d)REW"
"0f": "(n)(t)(n)GYJ"
"rp": "(b)(c)(e)GIH"
"10": "wDSF"
"l3": "(p)(u)(i)ZPZ"
"lz": "(o)(q)(d)BBC"
"49": "(n)(t)(n)FAA"
"4f": "(u)(n)(a)JTO"
"12": "(z)(k)(d)"
"gu": "(u)(c)(f)WRO"
"5o": "(s)(z)(d)JBX"
"ij": "(u)(r)(w)FBY"
"eg": "(d)(j)(p)QFP"
"u0": "nRUH"
"3k": "(u)(g)(j)EFT"
"lc": "(u)(f)(q)PAV"
"ow": "(n)(t)(n)RZK"
"wg": "(i)(y)(a)YNR"
"o-": "(a)(y)(h)SEF"
"85": "(n)(j)(q)EJW"
"4h": "(g)(t)(h)QOH"
"n9": "zSTM"
"19": "(q)(x)(r)WTS"
"q2": "(l)(v)(c)WOY"
"7k": "(e)(f)(z)WSM"
"kf": "(u)(t)(d)YMC"
"sy": "(p)(z)(l)WOY"
"bn": "(l)(v)(c)"
"jn": "(w)(s)(p)"
"t2": "(o)(l)(q)PVR"
"qk": "(c)(m)(y)QVO"
"3e": "zHMZ"
"ak": "(a)(m)(q)HMZ"
"2n": "(m)(l)(w)TZK"
"hi": "(i)(z)(x)WFE"
"kq": "(x)(g)(f)QOH"
"8o": "(v)(t)(i)"
"bz": "(h)(u)(r)DPL"
"4g": "(o)(v)(q)DZS"
"rf": "(f)(s)(d)XPF"
"d-": "(i)(g)(l)PZK"
"uz": "(o)(t)(j)LGI"
"g-": "(d)(l)(q)QMA"
"xo": "(u)(t)(d)"
"yu": "(u)(f)(q)HCB"
"8-": "(u)(g)(j)QOB"
"yd": "(c)(m)(y)QFU"
"78": "jAIL"
"2i": "(a)(v)(r)NGC"
"84": "(u)(a)(g)FBY"
"ew": "(j)(g)(c)DWR"
"yp": "(v)(r)(i)GYJ"
"8b": "(y)(o)(w)ECN"
"tn": "(s)(z)(d)EED"
"2a": "uOMX"
"d0": "(o)(s)(w)BZC"
"ik": "(b)(q)(t)CRV"
"h3": "(y)(j)(m)"
"1e": "(p)(l)(u)PQH"
"me": "(z)(r)(x)QLO"
"a4": "(m)(s)(w)GAU"
"nf": "(o)(k)(u)WSO"
"ee": "(f)(y)(u)MDL"
"8l": "(u)(i)(x)AQH"
"to": "(o)(t)(j)OJM"
"2h": "yXZI"
"ac": "(u)(n)(a)XTL"
"2-": "(s)(o)(r)FBY"
"le": "fFCU"
"m3": "(s)(z)(d)XPF"
"hh": "(n)(j)(q)NOD"
"m2": "(t)(f)(e)ULP"
"wq": "(v)(r)(l)RBJ"
"ra": "(u)(g)(j)ZPZ"
"jw": "(i)(y)(d)BHW"
"u5": "(j)(b)(r)FAL"
"4p": "(a)(h)(f)YZA"
"aj": "(a)(v)(r)LGI"
"fi": "(s)(z)(d)FGA"
"ln": "tAQH"
"s8": "(s)(o)(r)DEE"
"zw": "aFYG"
"xa": "(m)(t)(s)GIO"
"2b": "(e)(f)(w)QNS"
"8c": "(l)(i)(a)WFE"
"1k": "(v)(g)(h)"
"lv": "(e)(v)(p)"
"iy": "(i)(y)(a)AMA"
"gm": "(g)(v)(r)FGX"
"pw": "(k)(z)(p)NGC"
"p3": "(r)(f)(t)"
"vl": "(s)(z)(d)RUH"
"ob": "(o)(y)(y)"
"bb": "(d)(e)(e)LRV"
"b2": "(d)(i)(f)AIL"
"20": "(x)(l)(h)VVT"
"j5": "xLZZ"
"dr": "(f)(e)(s)ITB"
"7q": "wFCU"
"1o": "(d)(e)(e)FAL"
"ni": "(v)(g)(h)RXQ"
"6g": "(u)(t)(d)HCB"
"jk": "(v)(j)(v)DSF"
"e1": "(b)(b)(c)TFR"
"v6": "(t)(d)(x)FHA"
"hb": "(n)(j)(q)KZP"
"n-": "(p)(x)(f)PZK"
"e9": "(l)(d)(m)QLO"
"io": "(c)(m)(y)VDM"
"8i": "(b)(d)(v)"
"0h": "(u)(i)(x)ITB"
"65": "(q)(k)(s)"
"sr": "(b)(q)(t)RBJ"
"y8": "(k)(z)(t)QJK"
"s5": "(c)(m)(y)VJV"
"0k": "xROS"
"w9": "(o)(l)(q)LGI"
"x5": "rQLO"
"wn": "(t)(d)(x)"
"fo": "wDQO"
"77": "(h)(q)(a)XIU"
"t1": "(b)(q)(t)DZS"
"nk": "(l)(a)(f)AZF"
"32": "(l)(d)(m)RVA"
"46": "(n)(h)(m)XTL"
"q0": "(z)(m)(h)FBY"
"ir": "(b)(l)(z)PVE"
"v9": "iPVR"
"9s": "(w)(e)(r)QFU"
"u2": "(n)(j)(q)"
"xe": "(f)(s)(d)HLX"
"c2": "(j)(h)(i)MFF"
"7x": "nXIU"
"vf": "(o)(j)(m)IHJ"
"xg": "(y)(o)(s)WVK"
"1n": "(c)(h)(m)QLD"
"v1": "(o)(t)(j)YNY"
"x9": "vQLO"
"4b": "(v)(j)(v)STM"
"1c": "bDEE"
"ii": "(t)(x)(u)YYO"
"g3": "lGAU"
"p8": "(b)(x)(u)MHC"
"i0": "(c)(g)(g)"
"5i": "(l)(t)(x)VMM"
"az": "(o)(i)(g)SEF"
"3t": "(b)(l)(z)MDL"
"ec": "(a)(a)(z)EHH"
"gd": "vPVR"
"3s": "(y)(j)(m)YMC"
"gi": "(l)(v)(c)DUY"
"ov": "gBBC"
"ro": "(o)(k)(u)BZC"
"os": "(a)(m)(q)AQH"
"2q": "(y)(o)(w)QVO"
"79": "(o)(y)(y)DZS"
"l8": "(a)(q)(t)JGU"
"hk": "(w)(e)(r)MJY"
"nh": "(c)(h)(m)AQH"
"-i": "qQWC"
"81": "(b)(d)(v)DWR"
"gg": "(i)(y)(d)ULP"
"xm": "(n)(z)(l)"
"4r": "(m)(m)(v)LZZ"
"uu": "(f)(s)(d)YNY"
"xw": "rROS"
"1w": "(j)(y)(g)MAY"
"xl": "(d)(j)(p)ECB"
"dl": "(u)(n)(a)PJD"
"kc": "(n)(h)(m)PSW"
"zv": "(q)(k)(e)YZA"
"wu": "(y)(u)(d)CVL"
"a-": "(q)(k)(e)"
"s0": "(b)(b)(c)"
"9h": "(v)(q)(t)EPV"
"oc": "(w)(o)(t)RXQ"
"1v": "(i)(y)(d)JKS"
"ib": "(z)(k)(d)"
"q4": "(v)(n)(y)WRU"
"0e": "(r)(v)(p)PZK"
"cp": "(b)(c)(e)AVW"
"bx": "dWFG"
"dd": "(x)(a)(c)EKQ"
"pj": "(g)(v)(r)ZIK"
"-7": "(s)(t)(w)PVR"
"wi": "(m)(r)(u)DWR"
"43": "tWFG"
"ym": "(y)(j)(m)QVO"
"nr": "(o)(q)(d)TDI"
"at": "(i)(y)(a)WFE"
"u4": "(b)(d)(v)BHW"
"uh": "(u)(f)(q)EHH"
"ps": "(f)(e)(s)FGA"
"rd": "(l)(a)(o)GAU"
"v-": "(h)(i)(g)TZK"
"ku": "(a)(h)(f)"
"rg": "(l)(a)(f)SOY"
"zm": "(p)(u)(i)EKQ"
"e7": "(x)(m)(o)BZC"
"yq": "wUKO"
"5y": "(v)(g)(h)PSW"
"8e": "(n)(t)(n)"
"69": "(a)(g)(f)LZZ"
"6d": "(w)(e)(r)WOY"
"r-": "vSEF"
"ft": "(e)(f)(z)TQA"
"ry": "(y)(a)(m)GYJ"
"ls": "(a)(v)(r)FXP"
"z3": "(l)(i)(a)WFG"
"07": "(f)(y)(u)NTS"
"av": "(i)(y)(d)SWN"
"4e": "(h)(q)(p)ITB"
"74": "(s)(t)(w)LGI"
"m-": "zDSF"
"i7": "(o)(t)(f)HGV"
"6r": "(i)(y)(d)CGJ"
"pp": "(z)(r)(x)PVR"
"8d": "(x)(a)(c)AAO"
"g1": "(j)(x)(x)XDT"
"sa": "(n)(w)(s)JKS"
"o6": "(y)(a)(m)RZK"
"03": "(z)(r)(p)YZA"
"f1": "xAZF"
"5r": "(r)(w)(d)"
"te": "(h)(q)(p)"
"2s": "cROS"
"vm": "(p)(x)(f)LGI"
"6h": "(v)(r)(l)SOY"
"x8": "(o)(a)(a)"
"q7": "(f)(y)(u)XDT"
"wb": "(e)(f)(z)UXB"
"-n": "(a)(a)(f)QMA"
"ws": "(g)(y)(f)WFG"
"vq": "zXPF"
"an": "(b)(c)(h)"
"jt": "(p)(z)(l)ECN"
"b-": "(e)(f)(z)IUP"
"9q": "(m)(d)(v)BBC"
"id": "(o)(l)(q)PZK"
"go": "(b)(c)(h)AZF"
"4v": "(d)(j)(p)TDI"
"8s": "(n)(j)(q)MHN"
"jf": "(m)(i)(f)UYF"
"-s": "(p)(u)(i)EFT"
"x-": "(d)(e)(e)AZF"
"l1": "(b)(l)(z)"
"4u": "(x)(a)(e)DZS"
"3-": "(p)(z)(k)HYA"
"oy": "(o)(j)(m)TOW"
"ny": "aXRZ"
"oz": "(v)(r)(i)FAA"
"fp": "(a)(z)(y)WLM"
"-a": "(i)(t)(d)PJD"
"22": "(j)(x)(x)ANU"
"yr": "dDAM"
"yb": "(b)(t)(i)XIU"
"73": "(o)(k)(u)QJK"
"yt": "(t)(f)(e)"
"qm": "(a)(z)(y)NGC"
"jx": "(m)(i)(f)"
"06": "(m)(d)(v)LGI"
"oi": "(w)(s)(p)VMM"
"vb": "(j)(x)(x)FIM"
"45": "(n)(h)(m)"
"o5": "(f)(y)(u)HTG"
"9-": "(m)(i)(f)HTG"
"km": "(u)(t)(d)"
"38": "lLZZ"
"qh": "(n)(c)(e)"
"l6": "(u)(n)(a)"
"fd": "(k)(z)(t)GIH"
"s3": "(b)(c)(e)QJK"
"oq": "(n)(h)(m)EJW"
"51": "(a)(g)(f)SEF"
"re": "(i)(y)(a)WFG"
"0a": "(f)(s)(d)QFP"
"y0": "(f)(z)(a)WVK"
"rx": "(l)(a)(o)LRV"
"96": "(f)(f)(r)"
"rv": "(n)(w)(s)"
"br": "tRBJ"
"hc": "(z)(z)(l)SEF"
"ep": "(h)(o)(q)SOY"
"-w": "(p)(x)(f)NGC"
"rn": "(c)(h)(m)AYI"
"uo": "(i)(z)(x)AYI"
"cx": "(q)(k)(s)ULP"
"hp": "(w)(o)(t)TDI"
"rs": "tDSF"
"ll": "(g)(y)(f)RUH"
"kr": "(c)(g)(g)HYA"
"j9": "(g)(t)(h)MHC"
"0v": "(a)(y)(h)DTI"
"-l": "(c)(g)(n)WTS"
"u1": "(o)(s)(w)GIH"
"x2": "(f)(s)(d)VVT"
"2y": "xGIH"
"5c": "(o)(v)(q)ECN"
"kg": "(d)(i)(f)RUH"
"6p": "(m)(i)(f)"
"2t": "wVVT"
"bc": "(f)(e)(s)AQH"
"df": "(o)(y)(y)"
"ix": "(f)(z)(a)LRV"
"ve": "(l)(d)(m)HMZ"
"6z": "(o)(v)(q)WOY"
"ty": "(c)(h)(m)AIL"
"0l": "(c)(g)(g)"
"qs": "(o)(s)(w)ECB"
"dt": "(n)(c)(e)QVO"
"si": "(e)(f)(z)JTO"
"95": "(u)(n)(a)EAX"
"m7": "(f)(i)(j)WRU"
"11": "(e)(f)(z)LZN"
"d6": "(m)(s)(w)YNY"
"cr": "(o)(a)(a)"
"t7": "(v)(a)(p)AIL"
"fx": "(m)(r)(u)PQH"
"k5": "(j)(b)(r)LRV"
"3y": "(f)(f)(r)ZIK"
"tl": "nLRV"
"3o": "(h)(h)(e)TZK"
"on": "(z)(r)(x)LGI"
"b8": "(v)(r)(i)NTN"
"3j": "(z)(r)(p)ITV"
"xk": "pAZF"
"gy": "(a)(v)(r)PZK"
"q-": "(h)(q)(a)GIO"
"9t": "fITB"
"am": "(u)(g)(j)PAV"
"nn": "(y)(o)(w)LZP"
"h5": "(c)(m)(y)"
"04": "(t)(f)(e)"
"y2": "(v)(t)(i)KZP"
"xs": "(m)(r)(u)JKS"
"23": "(l)(v)(c)QVO"
"tk": "(l)(v)(c)MJY"
"c5": "(g)(t)(h)DZS"
"36": "(g)(v)(r)"
"vo": "eYNR"
"kn": "(u)(a)(g)DEE"
"0t": "(g)(v)(r)"
"6y": "(a)(q)(t)EKQ"
"gf": "(y)(u)(d)QVO"
"fz": "(t)(x)(u)FGX"
"g5": "(t)(x)(u)RFF"
"6c": "jPZK"
"ys": "(x)(a)(e)QMA"
"w3": "(b)(l)(z)PJD"
"xz": "(u)(f)(q)MJY"
"sw": "(y)(u)(d)MJY"
"na": "(m)(r)(u)DTI"
"yy": "(m)(r)(u)ULP"
"7i": "(c)(g)(n)QLO"
"ox": "(v)(j)(v)OJM"
"mg": "(w)(v)(a)ECB"
"8p": "(h)(q)(a)SEF"
"yz": "(y)(u)(d)DTU"
"ej": "(w)(j)(e)AVW"
"lu": "uWVK"
"oj": "(l)(v)(c)YMC"
"lr": "(w)(e)(r)DUY"
"34": "(a)(a)(f)IRV"
"sq": "(w)(o)(t)AMA"
"p9": "(g)(t)(h)FHA"
"n8": "(u)(f)(q)QVO"
"-t": "(h)(o)(q)PVK"
"vd": "zAZF"
"87": "(h)(o)(q)QWC"
"5u": "(s)(y)(n)JTO"
"7p": "(b)(x)(u)TQA"
"lo": "iHMZ"
"y-": "(k)(z)(r)FAA"
"-o": "(b)(l)(z)GGC"
"p1": "(t)(d)(x)QOB"
"zr": "(b)(c)(e)UKO"
"ut": "(p)(l)(u)WSO"
"a9": "(b)(t)(i)FGA"
"im": "(l)(e)(n)MJO"
"fj": "zOJM"
"kd": "nSTM"
"6a": "fWLM"
"gs": "(z)(z)(l)ITB"
"nw": "(h)(i)(g)QJK"
"yn": "(m)(t)(s)ITB"
"ht": "fVDM"
"mp": "(l)(d)(m)ULP"
"61": "(u)(t)(d)QVO"
"pb": "(r)(w)(d)RXQ"
"fw": "(p)(z)(k)"
"bf": "(a)(h)(f)JTO"
"jr": "(p)(x)(f)XRZ"
"ur": "(k)(v)(p)MHC"
"58": "(l)(e)(n)TQV"
"35": "(z)(z)(l)FGA"
"pz": "(m)(t)(s)AQH"
"x1": "(s)(o)(r)OJM"
"wm": "(v)(g)(h)EPV"
"j1": "(m)(s)(w)AZF"
"68": "(k)(j)(q)WSO"
"-8": "(l)(a)(o)PZK"
"9b": "(a)(a)(f)"
"mw": "(v)(r)(l)FAL"
"1g": "(d)(j)(p)EPV"
"fa": "(h)(h)(e)SEF"
"vt": "(t)(x)(u)"
"qo": "(i)(d)(t)BBC"
"md": "(l)(d)(m)RBJ"
"2z": "(r)(w)(d)MDL"
"zp": "(u)(n)(a)EPV"
"xp": "(i)(y)(a)RUH"
"88": "(t)(x)(u)PVE"
"hm": "(o)(t)(j)"
"98": "(n)(h)(m)NOD"
"5l": "(b)(b)(c)ZIK"
"eu": "(o)(l)(q)XRZ"
"93": "(n)(c)(e)WOY"
"yf": "(h)(q)(p)WLM"
"tq": "mAZF"
"fk": "(y)(o)(w)YMC"
"zs": "(u)(t)(d)"
"em": "(g)(y)(f)DPL"
"-z": "(o)(y)(y)PVK"
"od": "(n)(h)(m)JTO"
"2u": "(b)(d)(v)JKS"
"rk": "(l)(a)(o)HYA"
"ud": "(n)(w)(s)"
"-u": "lPVR"
"ya": "(l)(e)(n)"
"8t": "(c)(g)(n)LGI"
"-y": "(s)(y)(n)"
"vw": "(p)(z)(l)REW"
"1q": "(k)(z)(r)"
"er": "pYNV"
"m9": "(w)(s)(p)KZP"
"1p": "(j)(y)(g)NYS"
"pt": "(r)(v)(p)LGI"
"v7": "(m)(t)(s)XIU"
"72": "(u)(c)(f)CRV"
"zk": "(a)(v)(r)XRZ"
"ca": "(o)(a)(a)DTI"
"wx": "(c)(z)(b)WSO"
"3h": "(u)(c)(f)DAM"
"2l": "(e)(f)(z)"
"xy": "(v)(t)(i)"
"tp": "(m)(d)(v)EJW"
"k4": "(b)(q)(t)JIF"
"7m": "(a)(a)(f)"
"tv": "(f)(p)(x)VVT"
"pd": "(e)(v)(p)"
"ue": "(b)(x)(u)OAL"
"ef": "(h)(q)(p)XZI"
"ok": "(j)(y)(g)NTN"
"tw": "(r)(f)(t)EHH"
"8f": "(b)(t)(i)LZZ"
"-": "(m)(l)(w)QJK"
"0": "(n)(h)(m)ITV"
"u": "(n)(h)(m)KZP"
"i": "(z)(r)(p)HGV"
"8": "(b)(x)(u)IUP"
"e": "(c)(z)(b)UKO"
"z": "(o)(t)(f)PSW"
"v": "(z)(r)(p)KZP"
"w": "(p)(z)(k)NOD"
"k": "(p)(z)(k)PRZ"
"d": "(n)(j)(q)HGV"
"5": "(b)(x)(u)JGU"
"p": "(k)(z)(t)WSO"
"m": "(a)(q)(t)ZPZ"
"o": "(o)(t)(f)MHN"
"h": "(d)(o)(n)QJN"
"2": "(x)(a)(c)FSL"
"c": "(o)(s)(w)WLM"
"a": "(e)(f)(z)ZPZ"
"y": "(z)(r)(p)QJN"
"x": "(k)(j)(q)TZK"
"4": "(k)(z)(t)WLM"
"j": "(w)(s)(p)ITV"
"q": "(o)(t)(f)KZP"
"l": "(o)(s)(w)QJK"
"t": "(v)(n)(y)JIF"
"7": "(w)(v)(a)QJK"
"s": "(p)(z)(k)HGV"
"1": "(x)(m)(o)QJK"
"g": "(m)(l)(w)ECB"
"3": "(s)(o)(r)HMZ"
"6": "(v)(g)(h)MHN"
"r": "(d)(o)(n)PRZ"
"b": "(x)(m)(o)TZK"
"f": "(w)(v)(a)UKO"
"9": "(o)(t)(f)NOD"
"n": "(v)(g)(h)PRZ"
'''

import networkx as nx

def parse_edge(right):
if 'a' <= right[0] <= 'z':
assert all('A' <= i <= 'Z' for i in right[1: ]), right
return right[0], right[1: ]
assert right[0] == '(', right
assert 'a' <= right[1] <= 'z', right
assert right[2] == ')', right
assert right[3] == '(', right
assert 'a' <= right[4] <= 'z', right
assert right[5] == ')', right
assert right[6] == '(', right
assert 'a' <= right[7] <= 'z', right
assert right[8] == ')', right
start = (right[7] + right[4] + right[1]).upper()
if len(right) == 9:
return start, ''
assert len(right) == 12, right
assert all('A' <= i <= 'Z' for i in right[9: ]), right
return start, right[9: ]

G = nx.DiGraph()
values_dict = {}

for line in lines.strip().splitlines():
left, right = line.split(': ')
left = eval(left)
right = eval(right)
start, end = parse_edge(right)
if start not in values_dict:
values_dict[start] = {}
values_dict[start][end] = left
G.add_edge(start, end)

def get_input(char):
path = nx.shortest_path(G, char, '')
out = ''
for i in range(len(path) - 1):
out += values_dict[path[i]][path[i + 1]]
return out

flag = []
for i in 'TSGCTF'[::-1].lower():
flag.append(get_input(i))

print('TSGCTF{%s}' % ('_'.join(flag)))

参考资料

https://tan.hatenadiary.jp/entry/2024/12/16/013044


文章作者: W3nL0u
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 W3nL0u !
  目录