sceutils 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sceutils/__init__.py +57 -0
- sceutils/__main__.py +57 -0
- sceutils/axfs.py +308 -0
- sceutils/decrypt_cpupdate.py +136 -0
- sceutils/emmc_extract.py +231 -0
- sceutils/extract_idstorage.py +27 -0
- sceutils/find_imported_by.py +35 -0
- sceutils/keys.py +57 -0
- sceutils/keys_external.py +333 -0
- sceutils/keys_internal.py +121 -0
- sceutils/keys_proto.py +137 -0
- sceutils/module_info.py +138 -0
- sceutils/pup_fiction.py +379 -0
- sceutils/pup_info.py +100 -0
- sceutils/scedecrypt.py +52 -0
- sceutils/scetypes.py +692 -0
- sceutils/sceutils.py +94 -0
- sceutils/self2elf.py +242 -0
- sceutils/selfinfo.py +249 -0
- sceutils/ud0_extract_pup.py +42 -0
- sceutils/unpack_bootimage_new.py +19 -0
- sceutils/util.py +72 -0
- sceutils-0.1.0.dist-info/METADATA +106 -0
- sceutils-0.1.0.dist-info/RECORD +31 -0
- sceutils-0.1.0.dist-info/WHEEL +5 -0
- sceutils-0.1.0.dist-info/entry_points.txt +3 -0
- sceutils-0.1.0.dist-info/licenses/LICENSE +21 -0
- sceutils-0.1.0.dist-info/top_level.txt +2 -0
- unarzl/__init__.py +25 -0
- unarzl/__main__.py +29 -0
- unarzl/arzl.py +497 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import binascii
|
|
2
|
+
|
|
3
|
+
from .keys import KeyStore
|
|
4
|
+
from .scetypes import KeyType, SceType, SelfType
|
|
5
|
+
|
|
6
|
+
ENC_KEY = binascii.a2b_hex('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')
|
|
7
|
+
ENC_IV = binascii.a2b_hex('AF5F2CB04AC1751ABF51CEF1C8096210')
|
|
8
|
+
|
|
9
|
+
SCEWM_KEY = binascii.a2b_hex("AB7097356FDD49D83878540167F0C4AD")
|
|
10
|
+
SCEWM_IV = binascii.a2b_hex("85537C5A56BD15DF0EB5F7F0D9E276E6")
|
|
11
|
+
|
|
12
|
+
SCE_KEYS = KeyStore()
|
|
13
|
+
SCE_KEYS.register(
|
|
14
|
+
KeyType.METADATA,
|
|
15
|
+
SceType.SPKG,
|
|
16
|
+
0,
|
|
17
|
+
'23F1D525244266E6DA7A52DA9446318301EE8CC58D54901AE94D93010F7DEE6B',
|
|
18
|
+
'3721F7C05DE5F55ECC39BDDB4A6C585D',
|
|
19
|
+
0x00000000000,
|
|
20
|
+
0xFFF00000000,
|
|
21
|
+
SelfType.NONE
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
SCE_KEYS.register(
|
|
25
|
+
KeyType.METADATA,
|
|
26
|
+
SceType.SELF,
|
|
27
|
+
0,
|
|
28
|
+
'AED9D76EE1E29290002BFF32D4B0656EEE40FBDA4F8B55BE5BE0ED83530F27D2',
|
|
29
|
+
'DB50912F2416B54F7F36227169ECE500',
|
|
30
|
+
0x00000000000,
|
|
31
|
+
0xFFF00000000,
|
|
32
|
+
SelfType.SECURE
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
SCE_KEYS.register(
|
|
36
|
+
KeyType.METADATA,
|
|
37
|
+
SceType.SELF,
|
|
38
|
+
0,
|
|
39
|
+
'9D3F28DE30DED1D503DB6FA762A571C422A88D0F361899EF36D357059C72EC43',
|
|
40
|
+
'30E43CFB57D418A5A0D32A9939D23501',
|
|
41
|
+
0x00000000000,
|
|
42
|
+
0xFFF00000000,
|
|
43
|
+
SelfType.BOOT
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
SCE_KEYS.register(
|
|
47
|
+
KeyType.METADATA,
|
|
48
|
+
SceType.SRVK,
|
|
49
|
+
0,
|
|
50
|
+
'EAB14F9BE15EAEC1603BE63C9FCDE4099D601FB0E9FC4DF250B8DEC635987A1C',
|
|
51
|
+
'30B9E61707993B635D0E182446DB0B8D',
|
|
52
|
+
0x00000000000,
|
|
53
|
+
0xFFF00000000,
|
|
54
|
+
SelfType.NONE
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
SCE_KEYS.register(
|
|
58
|
+
KeyType.METADATA,
|
|
59
|
+
SceType.SELF,
|
|
60
|
+
0,
|
|
61
|
+
'74F6D2A1D2A093AE32B83337E0AE4AD2E6D93B034F5BF3B68DB77131883310D4',
|
|
62
|
+
'926AB55BDADC45DBB610E90E56A0368C',
|
|
63
|
+
0x00000000000,
|
|
64
|
+
0xFFF00000000,
|
|
65
|
+
SelfType.KERNEL
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
SCE_KEYS.register(
|
|
69
|
+
KeyType.METADATA,
|
|
70
|
+
SceType.SELF,
|
|
71
|
+
0,
|
|
72
|
+
'322D706CB6EBEA14DEF7BFE45F812971347DC95CD7697C16A71EA4B2A1E12C0D',
|
|
73
|
+
'31FA2E606031EDF39665B5616E9F937D',
|
|
74
|
+
0x00000000000,
|
|
75
|
+
0xFFF00000000,
|
|
76
|
+
SelfType.USER
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
SCE_KEYS.register(
|
|
80
|
+
KeyType.METADATA,
|
|
81
|
+
SceType.SELF,
|
|
82
|
+
1,
|
|
83
|
+
'DA3BE69B77B3A857EA4F6CDC73C0AB0590C0A95E145B8D55D2D3A6447C247F46',
|
|
84
|
+
'A0385383AB31497E3AFB7CCDDB30CA5A',
|
|
85
|
+
0x00000000000,
|
|
86
|
+
0xFFF00000000,
|
|
87
|
+
SelfType.USER
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
SCE_KEYS.register(
|
|
91
|
+
KeyType.NPDRM,
|
|
92
|
+
SceType.SELF,
|
|
93
|
+
0,
|
|
94
|
+
'C10368BF3D2943BC6E5BD05E46A9A7B6',
|
|
95
|
+
'00000000000000000000000000000000',
|
|
96
|
+
0x00000000000,
|
|
97
|
+
0xFFFFFFFFFFFFFFFFFFFFFF,
|
|
98
|
+
SelfType.APP
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
SCE_KEYS.register(
|
|
102
|
+
KeyType.METADATA,
|
|
103
|
+
SceType.SELF,
|
|
104
|
+
0,
|
|
105
|
+
'AAA508FA5E85EAEE597ED2B27804D22287CFADF1DF32EDC7A7C58E8C9AA8BB36',
|
|
106
|
+
'CD1BD3A59200CC67A3B804808DC2AE73',
|
|
107
|
+
0x00000000000,
|
|
108
|
+
0x16920000000,
|
|
109
|
+
SelfType.APP
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
SCE_KEYS.register(
|
|
113
|
+
KeyType.METADATA,
|
|
114
|
+
SceType.SELF,
|
|
115
|
+
1,
|
|
116
|
+
'4181B2DF5F5D94D3C80B7D86EACF1928533A49BA58EDE2B43CDEE7E572568BD4',
|
|
117
|
+
'B1678C0543B6C1997B63A6F4F3C8FD33',
|
|
118
|
+
0x00000000000,
|
|
119
|
+
0xFFFFFFFFFFFFFFFFFFFFFF,
|
|
120
|
+
SelfType.APP
|
|
121
|
+
)
|
sceutils/keys_proto.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import binascii
|
|
2
|
+
|
|
3
|
+
from .keys import KeyStore
|
|
4
|
+
from .scetypes import KeyType, SceType, SelfType
|
|
5
|
+
|
|
6
|
+
ENC_KEY = binascii.a2b_hex('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')
|
|
7
|
+
ENC_IV = binascii.a2b_hex('AF5F2CB04AC1751ABF51CEF1C8096210')
|
|
8
|
+
XXX_KEY = binascii.a2b_hex('992EF70868DE1B219EC3618FA79DAEC39067FE5638116C29FC0FF7E2A58FBD9E')
|
|
9
|
+
XXX_IV = binascii.a2b_hex('00000000000000000000000000000000')
|
|
10
|
+
|
|
11
|
+
SCEWM_KEY = binascii.a2b_hex("BFD5EA9F91AE9AF23565E534C4823B72")
|
|
12
|
+
SCEWM_IV = binascii.a2b_hex("CE16937E97A3349F143C8FB6AA219528")
|
|
13
|
+
|
|
14
|
+
SCEAS_KEY = binascii.a2b_hex("6B0AF9E48DD54E4BBD9F2FDA1063082A")
|
|
15
|
+
SCEAS_IV = binascii.a2b_hex("001B362DA54268E97000B83B90118E54")
|
|
16
|
+
|
|
17
|
+
SCE_KEYS = KeyStore()
|
|
18
|
+
SCE_KEYS.register(
|
|
19
|
+
KeyType.METADATA,
|
|
20
|
+
SceType.SPKG,
|
|
21
|
+
0,
|
|
22
|
+
'FA88E5B5CBB49603DF689F139045E7C3C9C7E33B5923DF54E4C5FE5298B4FD32',
|
|
23
|
+
'5EAA69AB35E737EC22C721A916E00263',
|
|
24
|
+
0x00000000000,
|
|
25
|
+
0xFFF00000000,
|
|
26
|
+
SelfType.NONE
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
SCE_KEYS.register(
|
|
30
|
+
KeyType.METADATA,
|
|
31
|
+
SceType.SELF,
|
|
32
|
+
1,
|
|
33
|
+
'B982589B568CDD4055433747DF19644A8D1B479B17CA44ECE5E82694550FEC74',
|
|
34
|
+
'BECEDF96543939032CC4DD7D95E47720',
|
|
35
|
+
0x00000000000,
|
|
36
|
+
0xFFF00000000,
|
|
37
|
+
SelfType.SECURE
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
SCE_KEYS.register(
|
|
41
|
+
KeyType.METADATA,
|
|
42
|
+
SceType.SELF,
|
|
43
|
+
1,
|
|
44
|
+
'9EE16CA4AADD77F53BEE0F4AE3D45326D009806D2DE9942CE0836E43DC5DD1CE',
|
|
45
|
+
'CFBA84A87EE29C9A521CA20691485E45',
|
|
46
|
+
0x00000000000,
|
|
47
|
+
0xFFF00000000,
|
|
48
|
+
SelfType.BOOT
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
SCE_KEYS.register(
|
|
52
|
+
KeyType.METADATA,
|
|
53
|
+
SceType.SRVK,
|
|
54
|
+
0,
|
|
55
|
+
'A603AA68753CEE3E186C81900A862DCDB13505D39FC59C62BBFAD94C526B8A06',
|
|
56
|
+
'352F596CFB513A148B95F9D78E57E755',
|
|
57
|
+
0x00000000000,
|
|
58
|
+
0xFFF00000000,
|
|
59
|
+
SelfType.NONE
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
SCE_KEYS.register(
|
|
63
|
+
KeyType.METADATA,
|
|
64
|
+
SceType.SELF,
|
|
65
|
+
1,
|
|
66
|
+
'61E7E786BB6F67570A71FC92E73885439CD16B96BC7C37C200EF11D3446FCF69',
|
|
67
|
+
'99E8B68EE784FDAFC3294B8E55F0C529',
|
|
68
|
+
0x00000000000,
|
|
69
|
+
0xFFF00000000,
|
|
70
|
+
SelfType.KERNEL
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
SCE_KEYS.register(
|
|
74
|
+
KeyType.METADATA,
|
|
75
|
+
SceType.SELF,
|
|
76
|
+
0,
|
|
77
|
+
'DA3BE69B77B3A857EA4F6CDC73C0AB0590C0A95E145B8D55D2D3A6447C247F46',
|
|
78
|
+
'A0385383AB31497E3AFB7CCDDB30CA5A',
|
|
79
|
+
0x00000000000,
|
|
80
|
+
0xFFF00000000,
|
|
81
|
+
SelfType.USER
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
SCE_KEYS.register(
|
|
85
|
+
KeyType.METADATA,
|
|
86
|
+
SceType.SELF,
|
|
87
|
+
1,
|
|
88
|
+
'8D355E70736EF7AA508D640D8D382B19D9C8747C4A8273A6D5707F227F49592E',
|
|
89
|
+
'BEB4819878915F3025978538693B3EBB',
|
|
90
|
+
0x00000000000,
|
|
91
|
+
0xFFF00000000,
|
|
92
|
+
SelfType.USER
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
SCE_KEYS.register(
|
|
96
|
+
KeyType.METADATA,
|
|
97
|
+
SceType.SELF,
|
|
98
|
+
0,
|
|
99
|
+
'AAA508FA5E85EAEE597ED2B27804D22287CFADF1DF32EDC7A7C58E8C9AA8BB36',
|
|
100
|
+
'CD1BD3A59200CC67A3B804808DC2AE73',
|
|
101
|
+
0x00000000000,
|
|
102
|
+
0x16920000000,
|
|
103
|
+
SelfType.APP
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
SCE_KEYS.register(
|
|
107
|
+
KeyType.METADATA,
|
|
108
|
+
SceType.SELF,
|
|
109
|
+
1,
|
|
110
|
+
'4181B2DF5F5D94D3C80B7D86EACF1928533A49BA58EDE2B43CDEE7E572568BD4',
|
|
111
|
+
'B1678C0543B6C1997B63A6F4F3C8FD33',
|
|
112
|
+
0x00000000000,
|
|
113
|
+
0xFFFFFFFFFFFFFFFFFFFFFF,
|
|
114
|
+
SelfType.APP
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
SCE_KEYS.register(
|
|
118
|
+
KeyType.NPDRM,
|
|
119
|
+
SceType.SELF,
|
|
120
|
+
0,
|
|
121
|
+
'C10368BF3D2943BC6E5BD05E46A9A7B6',
|
|
122
|
+
'00000000000000000000000000000000',
|
|
123
|
+
0x00000000000,
|
|
124
|
+
0xFFFFFFFFFFFFFFFFFFFFFF,
|
|
125
|
+
SelfType.APP
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
SCE_KEYS.register(
|
|
129
|
+
KeyType.NPDRM,
|
|
130
|
+
SceType.SELF,
|
|
131
|
+
1,
|
|
132
|
+
'00000000000000000000000000000000',
|
|
133
|
+
'00000000000000000000000000000000',
|
|
134
|
+
0x00000000000,
|
|
135
|
+
0xFFFFFFFFFFFFFFFFFFFFFF,
|
|
136
|
+
SelfType.APP
|
|
137
|
+
)
|
sceutils/module_info.py
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import sys
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
|
|
5
|
+
from .scetypes import (ElfHeader, ElfPhdr, SceModuleImports, SceModuleImports2, SceModuleInfo, SceModuleLibaryExports)
|
|
6
|
+
from .util import c_str
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class LibraryImport:
|
|
11
|
+
name: str
|
|
12
|
+
nid: int
|
|
13
|
+
functions: list[int]
|
|
14
|
+
variables: list[int]
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class LibraryExport:
|
|
18
|
+
name: str
|
|
19
|
+
nid: int
|
|
20
|
+
functions: list[int]
|
|
21
|
+
variables: list[int]
|
|
22
|
+
|
|
23
|
+
def read_module_info(fin) -> tuple[SceModuleInfo, list[LibraryImport], list[LibraryExport]] | None:
|
|
24
|
+
ehdr = ElfHeader.unpack(fin)
|
|
25
|
+
if ehdr.e_machine == 0xf00d:
|
|
26
|
+
return None
|
|
27
|
+
segment_num = (ehdr.e_entry >> 30) & 0x3
|
|
28
|
+
info_offset = ehdr.e_entry & 0x3fffffff
|
|
29
|
+
fin.seek(ehdr.e_phoff + ElfPhdr._size * segment_num)
|
|
30
|
+
phdr = ElfPhdr.unpack(fin)
|
|
31
|
+
fin.seek(phdr.p_offset + info_offset)
|
|
32
|
+
module_info = SceModuleInfo.unpack(fin)
|
|
33
|
+
|
|
34
|
+
import_list = []
|
|
35
|
+
fin.seek(phdr.p_offset + module_info.importsTop)
|
|
36
|
+
imports_off = module_info.importsTop
|
|
37
|
+
while imports_off < module_info.importsEnd:
|
|
38
|
+
fin.seek(phdr.p_offset+imports_off)
|
|
39
|
+
size = int.from_bytes(fin.read(2), "little")
|
|
40
|
+
fin.seek(-2, 1)
|
|
41
|
+
if size == 0x24:
|
|
42
|
+
imports = SceModuleImports2.unpack(fin)
|
|
43
|
+
elif size == 0x34:
|
|
44
|
+
imports = SceModuleImports.unpack(fin)
|
|
45
|
+
else:
|
|
46
|
+
raise Exception(f"imports wrong size {size}")
|
|
47
|
+
imports_off += size
|
|
48
|
+
|
|
49
|
+
library_name = hex(imports.library_nid)
|
|
50
|
+
if imports.library_name > phdr.p_vaddr:
|
|
51
|
+
fin.seek(phdr.p_offset + imports.library_name - phdr.p_vaddr)
|
|
52
|
+
library_name = c_str(fin.read(32))
|
|
53
|
+
|
|
54
|
+
functions = []
|
|
55
|
+
variables = []
|
|
56
|
+
for (entry_table, nid_table, num, arr) in (
|
|
57
|
+
(imports.func_entry_table, imports.func_nid_table, imports.num_functions, functions),
|
|
58
|
+
(imports.var_entry_table, imports.var_nid_table, imports.num_vars, variables)
|
|
59
|
+
):
|
|
60
|
+
if entry_table == 0:
|
|
61
|
+
continue
|
|
62
|
+
entry_table_offset = entry_table - phdr.p_vaddr
|
|
63
|
+
nid_table_offset = nid_table - phdr.p_vaddr
|
|
64
|
+
fin.seek(phdr.p_offset+entry_table_offset)
|
|
65
|
+
entry_data = fin.read(num * 4)
|
|
66
|
+
fin.seek(phdr.p_offset+nid_table_offset)
|
|
67
|
+
nids_data = fin.read(num * 4)
|
|
68
|
+
for i in range(num):
|
|
69
|
+
nid = int.from_bytes(nids_data[i*4:(i+1)*4], "little")
|
|
70
|
+
addr = int.from_bytes(entry_data[i*4:(i+1)*4], "little")
|
|
71
|
+
arr.append(nid)
|
|
72
|
+
import_list.append(LibraryImport(library_name, imports.library_nid, functions, variables))
|
|
73
|
+
|
|
74
|
+
export_list = []
|
|
75
|
+
fin.seek(phdr.p_offset + module_info.exportsStart)
|
|
76
|
+
exports_off = module_info.exportsStart
|
|
77
|
+
while exports_off < module_info.exportsEnd:
|
|
78
|
+
fin.seek(phdr.p_offset+exports_off)
|
|
79
|
+
size = int.from_bytes(fin.read(1), "little")
|
|
80
|
+
fin.seek(-1, 1)
|
|
81
|
+
if size == 0x20:
|
|
82
|
+
exports = SceModuleLibaryExports.unpack(fin)
|
|
83
|
+
else:
|
|
84
|
+
raise Exception(f"imports wrong size {size}")
|
|
85
|
+
exports_off += size
|
|
86
|
+
|
|
87
|
+
if exports.libname_nid == 0:
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
library_name = hex(exports.libname_nid)
|
|
91
|
+
if exports.libname_ptr > phdr.p_vaddr:
|
|
92
|
+
fin.seek(phdr.p_offset + exports.libname_ptr - phdr.p_vaddr)
|
|
93
|
+
library_name = c_str(fin.read(32))
|
|
94
|
+
|
|
95
|
+
functions = []
|
|
96
|
+
variables = []
|
|
97
|
+
|
|
98
|
+
entry_table_offset = exports.addrtable - phdr.p_vaddr
|
|
99
|
+
nid_table_offset = exports.nidtable - phdr.p_vaddr
|
|
100
|
+
fin.seek(phdr.p_offset+entry_table_offset)
|
|
101
|
+
num_nids = exports.nfunc + exports.nvar + exports.ntlsvar
|
|
102
|
+
entry_data = fin.read(num_nids * 4)
|
|
103
|
+
fin.seek(phdr.p_offset+nid_table_offset)
|
|
104
|
+
nids_data = fin.read(num_nids * 4)
|
|
105
|
+
|
|
106
|
+
for i in range(exports.nfunc):
|
|
107
|
+
nid = int.from_bytes(nids_data[i*4:(i+1)*4], "little")
|
|
108
|
+
addr = int.from_bytes(entry_data[i*4:(i+1)*4], "little")
|
|
109
|
+
functions.append(nid)
|
|
110
|
+
|
|
111
|
+
for i in range(exports.nfunc, exports.nfunc+exports.nvar):
|
|
112
|
+
nid = int.from_bytes(nids_data[i*4:(i+1)*4], "little")
|
|
113
|
+
addr = int.from_bytes(entry_data[i*4:(i+1)*4], "little")
|
|
114
|
+
variables.append(nid)
|
|
115
|
+
|
|
116
|
+
export_list.append(LibraryExport(library_name, exports.libname_nid, functions, variables))
|
|
117
|
+
return module_info, import_list, export_list
|
|
118
|
+
|
|
119
|
+
def main(argv = sys.argv):
|
|
120
|
+
if len(argv) < 2:
|
|
121
|
+
print(f"Usage: {argv[0]} (filename)")
|
|
122
|
+
sys.exit(1)
|
|
123
|
+
with open(argv[1], "rb") as fin:
|
|
124
|
+
info = read_module_info(fin)
|
|
125
|
+
if info is None:
|
|
126
|
+
print("f00d binary")
|
|
127
|
+
return
|
|
128
|
+
module_info, imports, exports = info
|
|
129
|
+
info = {
|
|
130
|
+
"module_name": module_info.module_name,
|
|
131
|
+
"module_nid": hex(module_info.module_nid),
|
|
132
|
+
"imports": [asdict(item) for item in imports],
|
|
133
|
+
"exports": [asdict(item) for item in exports],
|
|
134
|
+
}
|
|
135
|
+
print(json.dumps(info, indent=2))
|
|
136
|
+
|
|
137
|
+
if __name__ == "__main__":
|
|
138
|
+
main()
|