├── .gitignore ├── Pipfile ├── repack_bin.py ├── run_bash ├── run_windows.bat ├── repack_mov.py ├── LICENSE ├── README.md ├── repack_font.py ├── format_str.py ├── game.py ├── repack_lines.py ├── tool.py ├── format_img.py ├── bin_patch.asm └── Pipfile.lock /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .DS_Store 3 | *.log 4 | BakeData 5 | old 6 | *.iso 7 | notes.md 8 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | hacktools = {extras = ["armips", "cli", "graphics", "psp", "xdelta"], version = "*"} 8 | 9 | [dev-packages] 10 | 11 | [requires] 12 | python_version = "3" 13 | -------------------------------------------------------------------------------- /repack_bin.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import os 3 | import game 4 | from hacktools import common, psp 5 | 6 | 7 | def run(data): 8 | binin = data + "extract/PSP_GAME/SYSDIR/EBOOT.BIN" 9 | binout = data + "repack/PSP_GAME/SYSDIR/BOOT.BIN" 10 | ebinout = data + "repack/PSP_GAME/SYSDIR/EBOOT.BIN" 11 | binpatch = "bin_patch.asm" 12 | 13 | psp.decryptBIN(binin, binout) 14 | common.armipsPatch(common.bundledFile(binpatch)) 15 | psp.signBIN(binout, ebinout, 5) 16 | common.copyFile(binout.replace("repack", "extract"), binout) 17 | -------------------------------------------------------------------------------- /run_bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd "$(dirname "$0")" 3 | 4 | echo "Checking for python installation ..." 5 | if which python3 > /dev/null 2>&1; 6 | then 7 | : 8 | else 9 | echo "Error: Python is not installed." 10 | exit 1 11 | fi 12 | 13 | echo "Checking for pip installation ..." 14 | if which pip3 > /dev/null 2>&1; 15 | then 16 | : 17 | else 18 | echo "Error: pip is not installed." 19 | exit 1 20 | fi 21 | 22 | echo "Checking for pipenv installation ..." 23 | if which pipenv > /dev/null 2>&1; 24 | then 25 | : 26 | else 27 | pip3 install pipenv 28 | fi 29 | 30 | echo "Syncing dependencies ..." 31 | pipenv sync 32 | 33 | echo "Running tool ..." 34 | nohup pipenv run python3 tool.py --gui >/dev/null 2>&1 & 35 | -------------------------------------------------------------------------------- /run_windows.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | echo Checking for python installation ... 4 | python --version 2>NUL 5 | if errorlevel 1 goto noPython 6 | 7 | echo Checking for pip installation ... 8 | pip --version 2>NUL 9 | if errorlevel 1 goto noPip 10 | 11 | echo Checking for pipenv installation ... 12 | pipenv --version 2>NUL 13 | if errorlevel 1 goto noPipenv 14 | 15 | :sync 16 | echo Syncing dependencies ... 17 | pipenv sync 18 | 19 | echo Running tool ... 20 | pipenv run start pythonw tool.py --gui 21 | goto:eof 22 | 23 | :noPython 24 | echo Error^: Python is not installed. 25 | pause 26 | goto:eof 27 | 28 | :noPip 29 | echo Error^: pip is not installed. 30 | pause 31 | goto:eof 32 | 33 | :noPipenv 34 | pip install pipenv 35 | goto sync 36 | -------------------------------------------------------------------------------- /repack_mov.py: -------------------------------------------------------------------------------- 1 | import os 2 | from hacktools import common, psp 3 | 4 | 5 | def run(data): 6 | moviesin = data + "work_MPS/" 7 | cpkout = data + "extract_CPK/" 8 | 9 | common.logMessage("Repacking movies ...") 10 | repacked = 0 11 | for file in common.getFiles(moviesin): 12 | pmffile = file.replace(".MPS", ".pmf") 13 | # Get the original length for the PMF file 14 | pmffolder = cpkout + "exrom/" 15 | if not os.path.isfile(pmffolder + pmffile): 16 | pmffolder = pmffolder.replace("exrom", "rom") 17 | with common.Stream(pmffolder + pmffile, "rb", False) as f: 18 | f.seek(0x5c) 19 | totlength = f.readUInt() 20 | # Write the new header 21 | outfile = pmffolder.replace("extract_", "repack_") + pmffile 22 | common.makeFolders(os.path.dirname(outfile)) 23 | psp.mpstopmf(moviesin + file, outfile, totlength) 24 | repacked += 1 25 | common.logMessage("Done! Repacked", repacked, "files") 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2024 Illidan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bakemonogatari Translation 2 | This repository is for the tool used to translate the game. If you're looking for the English patch, click [here](https://agtteam.net/bake). 3 | ## Setup 4 | Install [Python 3](https://www.python.org/downloads/). 5 | Download this repository by downloading and extracting it, or cloning it. 6 | Copy the original Japanese rom into the same folder and rename it as `bake.iso`. 7 | Run `run_windows.bat` (for Windows) or `run_bash` (for OSX/Linux) to run the tool. 8 | ## Text Editing 9 | Rename the \*\_output.txt files to \*\_input.txt (str_output.txt to str_input.txt, etc) and add translations for each line after the "=" sign. 10 | To blank out a line, use a single "!". If just left empty, the line will be left untranslated. 11 | Comments can be added at the end of lines by using # 12 | ## Image Editing 13 | Rename the out\_\* folders to work\_\* (out_IMG to work_IMG, etc). 14 | If an image doesn't require repacking, it should be deleted from the work folder. 15 | ## Run from command line 16 | This is not recommended if you're not familiar with Python and the command line. 17 | After following the Setup section, run `pipenv sync` to install dependencies. 18 | Run `pipenv run python tool.py extract` to extract everything, and `pipenv run python tool.py repack` to repack. 19 | You can use switches like `pipenv run python tool.py repack --bin` to only repack certain parts to speed up the process. 20 | -------------------------------------------------------------------------------- /repack_font.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import json 3 | import os 4 | from hacktools import common, psp 5 | 6 | 7 | specialchars = { 8 | 0x2015: 0x30af, # ― 9 | 0x2018: 0x30b0, # ‘ 10 | 0x2019: 0x30b1, # ’ 11 | 0x201c: 0x30b2, # “ 12 | 0x201d: 0x30b3, # ” 13 | 0x2026: 0x30ae, # … 14 | } 15 | 16 | 17 | def run(data): 18 | fontin = data + "extract/PSP_GAME/USRDIR/rom/font/ESC_HGPMB.pgf" 19 | fontout = data + "repack/PSP_GAME/USRDIR/rom/font/ESC_HGPMB.pgf" 20 | fontout2 = data + "repack_CPK/rom/ID08360.bin" 21 | fontbmpin = data + "work_FONT/" 22 | fontconfin = data + "fontconfig_input.txt" 23 | fontconftemp = data + "fontconfig_temp_output.txt" 24 | 25 | common.logMessage("Repacking font from", fontconfin, "...") 26 | with codecs.open(fontconfin, "r", "utf-8") as f: 27 | section = common.getSection(f, "", "##") 28 | common.copyFile(fontconfin, fontconftemp) 29 | with codecs.open(fontconftemp, "a", "utf-8") as f: 30 | for char in section: 31 | glyph = json.loads(section[char][0]) 32 | char = char.replace("<3D>", "=") 33 | if ord(char) > 0x7e and ord(char) not in specialchars: 34 | continue 35 | glyph["width"], glyph["height"] = glyph["height"], glyph["width"] 36 | glyph["left"], glyph["top"] = glyph["top"], glyph["left"] 37 | glyph["dimension"]["x"], glyph["dimension"]["y"] = glyph["dimension"]["y"], glyph["dimension"]["x"] 38 | glyph["bearingx"]["x"], glyph["bearingx"]["y"] = glyph["bearingx"]["y"], glyph["bearingx"]["x"] 39 | glyph["bearingy"]["x"], glyph["bearingy"]["y"] = glyph["bearingy"]["y"], glyph["bearingy"]["x"] 40 | glyph["advance"]["x"], glyph["advance"]["y"] = glyph["advance"]["y"], glyph["advance"]["x"] 41 | glyph["bearingx"]["y"] = -10 42 | charcode = ord(char) 43 | if charcode == 0x20: 44 | newchar = chr(0x3005) 45 | elif charcode in specialchars: 46 | newchar = chr(specialchars[charcode]) 47 | else: 48 | charcode += 0x3020 49 | if ord(char) >= 0x70: 50 | charcode += 2 51 | if ord(char) >= 0x72: 52 | charcode += 13 53 | newchar = chr(charcode) 54 | if "vertwidth" in glyph: 55 | glyph["width"] = glyph["vertwidth"] 56 | fontdata = json.dumps(glyph) 57 | f.write("#" + char + "\n" + newchar + "=" + fontdata + "\n") 58 | psp.repackPGFData(fontin, fontout, fontconftemp, fontbmpin) 59 | common.makeFolders(data + "repack_CPK/rom") 60 | common.copyFile(fontout, fontout2) 61 | os.remove(fontconftemp) 62 | common.logMessage("Done!") 63 | -------------------------------------------------------------------------------- /format_str.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import os 3 | import game 4 | from hacktools import common 5 | 6 | 7 | def extract(data, writeid=False): 8 | infolder = data + "extract_CPK/rom/" 9 | outfile = data + "str_output.txt" 10 | 11 | common.logMessage("Extracting STR to", outfile, "...") 12 | with codecs.open(outfile, "w", "utf-8") as out: 13 | for file in common.showProgress(game.strfiles): 14 | common.logDebug("Processing", file, "...") 15 | with common.Stream(infolder + file, "rb") as f: 16 | out.write("!FILE:" + file + "\n") 17 | strnum = f.readUInt() 18 | for i in range(strnum): 19 | strlen = f.readUInt() 20 | utfstr = game.readString(f, strlen) 21 | if writeid: 22 | out.write(common.toHex(i) + ": ") 23 | out.write(utfstr + "=\n") 24 | common.logMessage("Done! Extracted", len(game.strfiles), "files") 25 | 26 | 27 | def repack(data): 28 | infolder = data + "extract_CPK/rom/" 29 | outfolder = data + "repack_CPK/rom/" 30 | fontconfig = data + "fontconfig_input.txt" 31 | infile = data + "str_input.txt" 32 | chartot = transtot = 0 33 | 34 | if not os.path.isfile(infile): 35 | common.logError("Input file", infile, "not found") 36 | return 37 | 38 | glyphs = game.readFontGlyphs(fontconfig) 39 | common.logMessage("Repacking STR from", infile, "...") 40 | common.makeFolders(outfolder) 41 | with codecs.open(infile, "r", "utf-8") as input: 42 | for file in common.showProgress(game.strfiles): 43 | section = common.getSection(input, file) 44 | common.logDebug(section) 45 | chartot, transtot = common.getSectionPercentage(section, chartot, transtot) 46 | # Repack the file 47 | common.logDebug("Processing", file, "...") 48 | size = os.path.getsize(infolder + file) 49 | with common.Stream(infolder + file, "rb") as fin: 50 | common.makeFolders(os.path.dirname(outfolder + file)) 51 | with common.Stream(outfolder + file, "wb") as f: 52 | strnum = fin.readUInt() 53 | f.writeUInt(strnum) 54 | for i in range(strnum): 55 | strlen = fin.readUInt() 56 | check = game.readString(fin, strlen) 57 | newutf = "" 58 | if check in section: 59 | newutf = section[check].pop(0) 60 | if len(section[check]) == 0: 61 | del section[check] 62 | if newutf != "": 63 | if file in game.wordwrapfiles: 64 | newutf = common.wordwrap(newutf, glyphs, game.wordwrap, default=16) 65 | game.writeString(f, newutf) 66 | else: 67 | game.writeString(f, check) 68 | common.logMessage("Done! Translation is at {0:.2f}%".format((100 * transtot) / chartot)) 69 | -------------------------------------------------------------------------------- /game.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import json 3 | from hacktools import common 4 | 5 | 6 | # A list of all the files that contain strings to translate 7 | strfiles = [ 8 | "ID08373.bin", "ID08374.bin", "ID08375.bin", "ID08376.bin", 9 | "ID14266.bin", "ID14267.bin", "ID14268.bin", "ID14269.bin", 10 | "ID14270.bin", "ID14271.bin", "ID14272.bin", "ID14273.bin", "ID14274.bin", "ID14275.bin", "ID14276.bin", "ID14277.bin", "ID14278.bin", 11 | ] 12 | # A list of the files that contain game lines that need to be wordwrapped 13 | wordwrapfiles = [ 14 | "ID14268.bin", "ID14269.bin", 15 | "ID14270.bin", "ID14271.bin", "ID14272.bin", "ID14273.bin", "ID14274.bin", "ID14275.bin", "ID14276.bin", "ID14277.bin", "ID14278.bin", 16 | ] 17 | # A list of the files that contain line stats, same order as above 18 | linefiles = [ 19 | "ID14281.bin", "ID14285.bin", 20 | "ID14288.bin", "ID14291.bin", "ID14294.bin", "ID14297.bin", "ID14300.bin", "ID14303.bin", "ID14306.bin", "ID14310.bin", "ID14313.bin" 21 | ] 22 | wordwrap = 390 23 | 24 | # This is a list of AMT files that need their AMA file tweaked in order to fit the translation 25 | # The first element is the corresponding AMA file, and everything else is offset and float to write 26 | files = { 27 | "ID13756.amt": [ 28 | "ID13755.ama", 29 | # Increase texture height from 48 to 64 30 | (0x25c, 64), 31 | (0x39c, 64), 32 | (0x46c, 64), 33 | (0x53c, 64), 34 | (0x67c, 64), 35 | (0x144, -32), 36 | (0x14c, 32), 37 | (0x284, -32), 38 | (0x28c, 32), 39 | (0x3c4, -32), 40 | (0x3cc, 32), 41 | (0x494, -32), 42 | (0x49c, 32), 43 | (0x564, -32), 44 | (0x56c, 32), 45 | # Move the one at the bottom of the screen up 8 pixels 46 | (0x1d4, 205), 47 | (0x1f4, 205), 48 | # Move the centered one down 10 pixels 49 | (0x404, 140), 50 | (0x4d4, 140), 51 | ], 52 | "ID13936.amt": [ 53 | "ID13935.ama", 54 | # Change the 4th texture of Oshino's name to not repeat 55 | (0x1160, 96), 56 | (0x1168, 128), 57 | ], 58 | "ID13984.amt": [ 59 | "ID13983.ama", 60 | # Move the text close together 61 | (0x9c0, 230), 62 | (0xb10, 246), 63 | ], 64 | "ID13734.amt": [ 65 | "ID13733.ama", 66 | # Move the first half to the right, there are 2 positions since it's animated 67 | (0xb60, 364), # 353 68 | (0xb80, 334), # 323 69 | (0xe10, 120), # 107 70 | (0xe30, 83), # 70 71 | # Move the second half to the left 72 | (0xca0, 415), # 415 73 | (0xcc0, 410), # 410 74 | (0xf50, 183), # 183 75 | (0xf70, 133), # 133 76 | ], 77 | "ID14084.amt": [ 78 | "ID14083.ama", 79 | # Move episode number to the right 80 | (0x26d0, 198), # 148 81 | (0x27a0, 198), # 148 82 | (0x2870, 198), # 148 83 | (0x2940, 198), # 148 84 | (0x2a10, 198), # 148 85 | (0x2ae0, 198), # 148 86 | (0x2bb0, 200), # 150 87 | (0x2c80, 200), # 150 88 | (0x2d50, 200), # 150 89 | ], 90 | "ID13830.amt": [ 91 | "ID13829.ama", 92 | # Move the text close together 93 | (0xdf0, 206), # 180 94 | (0xff0, 274), # 300 95 | ], 96 | "ID13832.amt": [ 97 | "ID13831.ama", 98 | # Move the text close together 99 | (0x240, 224), # 210 100 | (0x340, 256), # 270 101 | ], 102 | "ID13934.amt": [ 103 | "ID13933.ama", 104 | # Move the text close together 105 | (0x410, 216), # 200 106 | (0x560, 264), # 280 107 | (0x680, 216), # 200 108 | (0x7a0, 264), # 280 109 | (0xbc0, 206), # 190 110 | (0xd10, 274), # 290 111 | (0xe30, 206), # 190 112 | (0xf50, 274), # 290 113 | ], 114 | } 115 | backwards_pal = [ 116 | "ID14154.amt", 117 | "ID14196.amt", 118 | ] 119 | 120 | 121 | def readString(f, length): 122 | ret = "" 123 | start = f.tell() 124 | while f.tell() < start + length: 125 | charcode = f.readUShort() 126 | if charcode == 0xa: 127 | ret += "|" 128 | elif charcode != 0: 129 | ret += chr(charcode) 130 | return ret.replace(" 0: 145 | f.writeZero(4 - (f.tell() % 4)) 146 | f.writeUIntAt(lenoffset, f.tell() - lenoffset - 4) 147 | 148 | 149 | def readFontGlyphs(file): 150 | glyphs = {} 151 | with codecs.open(file, "r", "utf-8") as f: 152 | section = common.getSection(f, "", "##") 153 | for c in section: 154 | jsondata = json.loads(section[c][0]) 155 | charlen = float(jsondata["advance"]["x"]) * 0.85 156 | glyphs[c] = common.FontGlyph(0, charlen, charlen) 157 | return glyphs 158 | -------------------------------------------------------------------------------- /repack_lines.py: -------------------------------------------------------------------------------- 1 | import codecs 2 | import game 3 | from hacktools import common 4 | 5 | 6 | class LineStats: 7 | def __init__(self): 8 | self.i = 0 9 | self.storyOrder1 = 0 10 | self.storyOrder2 = 0 11 | self.unk2 = 0 12 | self.alphabeticalOrder1 = 0 13 | self.alphabeticalOrder2 = 0 14 | self.alphabeticalOrder3 = 0 15 | self.alphabeticalOrder4 = 0 16 | self.index = 0 17 | self.unk6 = 0 18 | self.unk7 = 0 19 | self.unk8 = 0 20 | self.unk9 = 0 21 | self.unk10 = 0 22 | self.unk11 = 0 23 | self.unk12 = 0 24 | self.unk13 = 0 25 | self.unk14 = 0 26 | self.unk15 = 0 27 | self.unk16 = 0 28 | self.type = 0 # 0 = paper, 1 = rock, 2 = scissors 29 | self.unk18 = 0 30 | self.unk19 = 0 31 | self.unk20 = 0 32 | self.unk21 = 0 33 | self.unk22 = 0 34 | self.unk23 = 0 35 | self.unk24 = 0 36 | self.unk25 = 0 37 | self.unk26 = 0 38 | self.unk27 = 0 39 | self.unk28 = 0 40 | self.unk29 = 0 41 | self.unk30 = 0 42 | self.unk31 = 0 43 | self.unk32 = 0 44 | self.unk33 = 0 45 | self.unk34 = 0 46 | self.unk35 = 0 47 | self.unk36 = 0 48 | self.unk37 = 0 49 | self.unk38 = 0 50 | self.unk39 = 0 51 | self.unk40 = 0 52 | self.unk41 = 0 53 | self.unk42 = 0 54 | self.unk43 = 0 55 | self.unk44 = 0 56 | self.unk45 = 0 57 | self.unk46 = 0 58 | self.unk47 = 0 59 | self.unk48 = 0 60 | self.unk49 = 0 61 | self.unk50 = 0 62 | self.unk51 = 0 63 | self.unk52 = 0 64 | self.unk53 = 0 65 | self.unk54 = 0 66 | self.unk55 = 0 67 | self.index2 = 0 68 | self.index3 = 0 69 | self.unk58 = 0 70 | self.unk59 = 0 71 | self.unk60 = 0 72 | self.unk61 = 0 73 | self.unk62 = 0 74 | self.unk63 = 0 75 | self.original = "" 76 | self.translation = "" 77 | 78 | 79 | def readLines(f): 80 | lines = [] 81 | num = f.readUInt() 82 | for i in range(num): 83 | line = LineStats() 84 | line.i = i 85 | line.storyOrder1 = f.readByte() 86 | line.storyOrder2 = f.readByte() 87 | line.unk2 = f.readShort() 88 | line.alphabeticalOrder1 = f.readSByte() 89 | line.alphabeticalOrder2 = f.readSByte() 90 | line.alphabeticalOrder3 = f.readSByte() 91 | line.alphabeticalOrder4 = f.readSByte() 92 | line.index = f.readShort() 93 | line.unk6 = f.readShort() 94 | line.unk7 = f.readShort() 95 | line.unk8 = f.readShort() 96 | line.unk9 = f.readShort() 97 | line.unk10 = f.readShort() 98 | line.unk11 = f.readShort() 99 | line.unk12 = f.readShort() 100 | line.unk13 = f.readShort() 101 | line.unk14 = f.readShort() 102 | line.unk15 = f.readShort() 103 | line.unk16 = f.readShort() 104 | line.type = f.readShort() 105 | line.unk18 = f.readShort() 106 | line.unk19 = f.readShort() 107 | line.unk20 = f.readShort() 108 | line.unk21 = f.readShort() 109 | line.unk22 = f.readShort() 110 | line.unk23 = f.readShort() 111 | line.unk24 = f.readShort() 112 | line.unk25 = f.readShort() 113 | line.unk26 = f.readShort() 114 | line.unk27 = f.readShort() 115 | line.unk28 = f.readShort() 116 | line.unk29 = f.readShort() 117 | line.unk30 = f.readShort() 118 | line.unk31 = f.readShort() 119 | line.unk32 = f.readShort() 120 | line.unk33 = f.readShort() 121 | line.unk34 = f.readShort() 122 | line.unk35 = f.readShort() 123 | line.unk36 = f.readShort() 124 | line.unk37 = f.readShort() 125 | line.unk38 = f.readShort() 126 | line.unk39 = f.readShort() 127 | line.unk40 = f.readShort() 128 | line.unk41 = f.readShort() 129 | line.unk42 = f.readShort() 130 | line.unk43 = f.readShort() 131 | line.unk44 = f.readShort() 132 | line.unk45 = f.readShort() 133 | line.unk46 = f.readShort() 134 | line.unk47 = f.readShort() 135 | line.unk48 = f.readShort() 136 | line.unk49 = f.readShort() 137 | line.unk50 = f.readShort() 138 | line.unk51 = f.readShort() 139 | line.unk52 = f.readShort() 140 | line.unk53 = f.readShort() 141 | line.unk54 = f.readShort() 142 | line.unk55 = f.readShort() 143 | line.index2 = f.readShort() 144 | line.index3 = f.readShort() 145 | line.unk58 = f.readShort() 146 | line.unk59 = f.readShort() 147 | line.unk60 = f.readShort() 148 | line.unk61 = f.readShort() 149 | line.unk62 = f.readShort() 150 | line.unk63 = f.readShort() 151 | # common.logMessage(common.toHex(i), common.varsHex(line)) 152 | lines.append(line) 153 | return lines 154 | 155 | 156 | def run(data): 157 | linesin = data + "extract_CPK/rom/" 158 | linesout = data + "repack_CPK/rom/" 159 | strin = data + "str_input.txt" 160 | 161 | common.logMessage("Repacking lines ...") 162 | repacked = 0 163 | for i in common.showProgress(range(len(game.linefiles))): 164 | # Read the original lines from the respective str file 165 | originals = [] 166 | with common.Stream(linesin + game.wordwrapfiles[i], "rb") as f: 167 | strnum = f.readUInt() 168 | for j in range(strnum): 169 | strlen = f.readUInt() 170 | originals.append(game.readString(f, strlen)) 171 | # Read the translation 172 | with codecs.open(strin, "r", "utf-8") as f: 173 | section = common.getSection(f, game.wordwrapfiles[i]) 174 | # Read the line stats 175 | file = game.linefiles[i] 176 | common.copyFile(linesin + file, linesout + file) 177 | with common.Stream(linesout + file, "r+b") as f: 178 | lines = readLines(f) 179 | # This is how the game sorts alphabetically: 180 | # lines = sorted(lines, key=lambda x: (x.alphabeticalOrder1, x.alphabeticalOrder2, x.alphabeticalOrder3, x.alphabeticalOrder4)) 181 | # Get the original line and translation for each line 182 | for j in range(len(lines)): 183 | line = lines[j] 184 | if line.index > 0 and line.index3 >= 0: 185 | line.original = line.translation = originals[line.index - 1] 186 | if line.original in section: 187 | line.translation = section[line.original].pop(0) 188 | if len(section[line.original]) == 0: 189 | del section[line.original] 190 | line.translation = line.translation.lstrip("|.*‘’“”…※■―-,'\" ?!").replace("", "").replace("", "") 191 | # common.logMessage(common.varsHex(line)) 192 | # Sort the lines 193 | lines = sorted(lines, key=lambda x: (x.translation)) 194 | # Write the new order 195 | order1 = order2 = 1 196 | for j in range(len(lines)): 197 | line = lines[j] 198 | if line.index > 0 and line.index3 >= 0 and line.translation != "": 199 | common.logDebug("Writing order", order1, order2, common.varsHex(line)) 200 | f.seek(4 + line.i * 0x7e + 4) 201 | f.writeSByte(order1) 202 | f.writeSByte(order2) 203 | f.writeSByte(1) 204 | f.writeSByte(1) 205 | order2 += 1 206 | if order2 == 100: 207 | order1 += 1 208 | order2 = 1 209 | repacked += 1 210 | common.logMessage("Done! Repacked", repacked, "files") 211 | -------------------------------------------------------------------------------- /tool.py: -------------------------------------------------------------------------------- 1 | import os 2 | import click 3 | import game 4 | from hacktools import common, cpk, psp 5 | 6 | version = "1.2.0" 7 | data = "BakeData/" 8 | isofile = "bake.iso" 9 | isopatch = data + "bake_patched.iso" 10 | patchfile = data + "patch.xdelta" 11 | 12 | infolder = data + "extract/" 13 | outfolder = data + "repack/" 14 | replacefolder = data + "replace/" 15 | cpkin = infolder + "PSP_GAME/USRDIR/rom/" 16 | cpkout = data + "extract_CPK/" 17 | replacecpkfolder = data + "replace_CPK/" 18 | 19 | fontin = data + "extract/PSP_GAME/USRDIR/rom/font/ESC_HGPMB.pgf" 20 | fontbmpout = data + "out_FONT/" 21 | fontconfout = data + "fontconfig_output.txt" 22 | 23 | @common.cli.command() 24 | @click.option("--iso", is_flag=True, default=False) 25 | @click.option("--cpk", "cpkparam", is_flag=True, default=False) 26 | @click.option("--str", "strparam", is_flag=True, default=False) 27 | @click.option("--img", is_flag=True, default=False) 28 | @click.option("--font", is_flag=True, default=False) 29 | def extract(iso, cpkparam, strparam, img, font): 30 | all = not iso and not cpkparam and not strparam and not img and not font 31 | if all or iso: 32 | psp.extractIso(isofile, infolder, outfolder) 33 | if all or cpkparam: 34 | common.makeFolder(cpkout) 35 | common.logMessage("Extracting CPK ...") 36 | cpk.extract(cpkin + "rom.cpk", cpkout + "rom/", guessRomExtension) 37 | common.logMessage("Done!") 38 | common.logMessage("Extracting Movies CPK ...") 39 | cpk.extract(cpkin + "exrom.cpk", cpkout + "exrom/", guessExromExtension) 40 | common.logMessage("Done!") 41 | if all or strparam: 42 | import format_str 43 | format_str.extract(data) 44 | if all or img: 45 | import format_img 46 | format_img.extract(data) 47 | if all or font: 48 | common.logMessage("Extracting font to", fontconfout, "...") 49 | common.makeFolder(fontbmpout) 50 | psp.extractPGFData(fontin, fontconfout, fontbmpout) 51 | common.logMessage("Done!") 52 | 53 | 54 | @common.cli.command() 55 | @click.option("--no-iso", is_flag=True, default=False, hidden=True) 56 | @click.option("--cpk", "cpkparam", is_flag=True, default=False) 57 | @click.option("--str", "strparam", is_flag=True, default=False) 58 | @click.option("--lines", is_flag=True, default=False) 59 | @click.option("--mov", is_flag=True, default=False) 60 | @click.option("--img", is_flag=True, default=False) 61 | @click.option("--bin", is_flag=True, default=False) 62 | @click.option("--font", is_flag=True, default=False) 63 | def repack(no_iso, cpkparam, strparam, lines, mov, img, bin, font): 64 | all = not cpkparam and not strparam and not lines and not mov and not img and not bin and not font 65 | if all or font: 66 | import repack_font 67 | repack_font.run(data) 68 | if all or strparam: 69 | import format_str 70 | format_str.repack(data) 71 | if all or lines or strparam: 72 | import repack_lines 73 | repack_lines.run(data) 74 | if all or bin: 75 | import repack_bin 76 | repack_bin.run(data) 77 | if all or mov: 78 | import repack_mov 79 | repack_mov.run(data) 80 | if all or img: 81 | import format_img 82 | format_img.repack(data) 83 | if all or cpkparam or strparam or lines or mov or img or font: 84 | common.logMessage("Repacking CPK ...") 85 | common.mergeFolder(replacecpkfolder, data + "repack_CPK/rom/") 86 | cpk.repack(cpkin + "rom.cpk", cpkin.replace("extract", "repack") + "rom.cpk", cpkout + "rom/", data + "repack_CPK/rom/") 87 | common.logMessage("Done!") 88 | if all or cpkparam or mov: 89 | common.logMessage("Repacking Movies CPK ...") 90 | cpk.repack(cpkin + "exrom.cpk", cpkin.replace("extract", "repack") + "exrom.cpk", cpkout + "exrom/", data + "repack_CPK/exrom/") 91 | common.logMessage("Done!") 92 | if os.path.isdir(replacefolder): 93 | common.mergeFolder(replacefolder, outfolder) 94 | 95 | if not no_iso: 96 | psp.repackUMD(isofile, isopatch, outfolder, patchfile) 97 | 98 | 99 | @common.cli.command(hidden=True) 100 | def names(): 101 | tot = 0 102 | totfiles = 0 103 | for file in common.getFiles(data + "extract_CPK/rom/", ".bin"): 104 | with common.Stream(data + "extract_CPK/rom/" + file, "rb") as f: 105 | try: 106 | strnum = f.readUInt() 107 | firstlen = f.readUInt() 108 | firststr = f.readNullString() 109 | except: 110 | firststr = "" 111 | if strnum > 0 and strnum < 0x1000 and firstlen > 0 and firstlen < 0x100 and len(firststr) > 5: 112 | if common.isAscii(firststr): 113 | common.logMessage("Found names file", file, strnum, firstlen, firststr) 114 | tot += strnum 115 | totfiles += 1 116 | else: 117 | common.logMessage("Found str file?", file, strnum, firstlen, firststr) 118 | common.logMessage(totfiles, tot) 119 | 120 | 121 | @common.cli.command(hidden=True) 122 | @click.argument("text") 123 | def translate(text): 124 | ret = "" 125 | for c in text: 126 | charcode = ord(c) 127 | charhex = common.toHex(charcode).zfill(4) 128 | ret += charhex[2:4] + charhex[0:2] 129 | common.logMessage(ret) 130 | searchbytes = bytes.fromhex(ret) 131 | for file in common.getFiles(cpkout): 132 | with common.Stream(cpkout + file, "rb") as f: 133 | alldata = f.read() 134 | pos = alldata.find(searchbytes) 135 | if pos >= 0: 136 | common.logMessage("Found string at", common.toHex(pos), "in file", file) 137 | 138 | 139 | @common.cli.command(hidden=True) 140 | @click.argument("text") 141 | def translatevert(text): 142 | ret = "" 143 | for c in text: 144 | charcode = ord(c) 145 | if charcode == 0x20: 146 | ret += chr(0x3005) 147 | else: 148 | charcode += 0x3020 149 | if ord(c) >= 0x70: 150 | charcode += 2 151 | if ord(c) >= 0x72: 152 | charcode += 13 153 | ret += chr(charcode) 154 | common.logMessage(ret) 155 | 156 | 157 | @common.cli.command(hidden=True) 158 | @click.argument("file") 159 | def ama(file): 160 | import format_img 161 | format_img.readAMA(cpkout + "rom/" + file) 162 | 163 | 164 | @common.cli.command(hidden=True) 165 | @click.argument("text") 166 | def length(text): 167 | glyphs = game.readFontGlyphs(data + "fontconfig_input.txt") 168 | lookup = dict((c, glyphs[c].length if c in glyphs else 16) for c in set(text)) 169 | ret = 0 170 | for c in text: 171 | ret += lookup[c] 172 | common.logMessage(ret) 173 | 174 | 175 | @common.cli.command() 176 | def copymovies(): 177 | for filename in common.showProgress(common.getFiles(data + "movies/original_pmf/")): 178 | filename = filename.replace(".pmf", "") 179 | umdpath = os.path.expanduser("~/Documents/UmdStreamComposer/MuxWork/" + filename + "/00001/00001.MPS").replace("\\", "/") 180 | if os.path.isfile(umdpath): 181 | common.copyFile(umdpath, data + "work_MPS/" + filename + ".MPS") 182 | 183 | 184 | def guessRomExtension(data, entry, filename): 185 | import struct 186 | magicint = struct.unpack(' 0x7e 44 | bgt a0,0x7e,@@ret 45 | nop 46 | ;Add 0x3020 to the character code and tweak it for charcode gaps 47 | blt a0,0x70,@@done 48 | addiu a1,a0,0x3020 49 | blt a0,0x72,@@done 50 | addiu a1,a1,2 51 | addiu a1,a1,13 52 | @@done: 53 | move a0,a1 54 | @@ret: 55 | move s6,a0 56 | j CONVERT_VERTICAL_RET 57 | move a1,s1 58 | 59 | ;A copy of the function at 0x088ae390 to return a short character name 60 | GET_SHORT_CHAR_NAME3: 61 | addiu sp,sp,-0x10 62 | sw ra,0x0(sp) 63 | lw a0,0x50b8(a0) 64 | nop 65 | jal GET_SHORT_CHAR_NAME2 66 | nop 67 | lw a0,0x0897f380 68 | jal 0x088b58d8 69 | move a1,v0 70 | lw ra,0x0(sp) 71 | nop 72 | jr ra 73 | addiu sp,sp,0x10 74 | 75 | ;A copy of the function at 0x08833bf8 to return a short character name 76 | GET_SHORT_CHAR_NAME2: 77 | addiu sp,sp,-0x10 78 | lui a1,0x898 79 | sw s0,0x0(sp) 80 | sw ra,0x4(sp) 81 | jal GET_SHORT_CHAR_NAME 82 | lw s0,-0x70a0(a1) 83 | nop 84 | move a0,s0 85 | li a1,0 86 | jal 0x0880a504 87 | move a2,v0 88 | lw ra,0x4(sp) 89 | lw s0,0x0(sp) 90 | jr ra 91 | addiu sp,sp,0x10 92 | 93 | ;Return short character name ID 94 | GET_SHORT_CHAR_NAME: 95 | sltiu a1,a0,0xc 96 | beq a1,zero,GET_SHORT_CHAR_NAME_RET 97 | nop 98 | addiu v0,a0,0x5b 99 | GET_SHORT_CHAR_NAME_RET: 100 | jr ra 101 | nop 102 | 103 | GET_CHAR_LEN: 104 | addiu sp,sp,-0x70 105 | sw ra,0x0(sp) 106 | sw a0,0x4(sp) 107 | sw a1,0x8(sp) 108 | sw a2,0xc(sp) 109 | sw a3,0x10(sp) 110 | sw t0,0x14(sp) 111 | ;Get the font handle 112 | li a0,0x08a03e80 113 | lw a0,0x0(a0) 114 | ;Call sceFontGetCharInfo(SceFontHandle fontHandle, unsigned int charCode, SceFontCharInfo *charInfo[0x3c]) 115 | move a1,a3 116 | jal 0x0894fbd8 117 | addiu a2,sp,0x20 118 | lw t0,0x14(sp) 119 | ;advancex is in charInfo[0x30] 120 | addiu a0,sp,0x20 121 | lw v0,0x34(a0) 122 | beq t0,zero,@@advancepos 123 | nop 124 | lw v0,0x30(a0) 125 | @@advancepos: 126 | li.s f13,64.0 127 | mtc1 v0,f12 128 | nop 129 | cvt.s.w f12,f12 130 | div.s f12,f12,f13 131 | lw ra,0x0(sp) 132 | lw a0,0x4(sp) 133 | lw a1,0x8(sp) 134 | lw a2,0xc(sp) 135 | lw a3,0x10(sp) 136 | jr ra 137 | addiu sp,sp,0x70 138 | 139 | ;Center wordwrapped lines 140 | ;a1 = string ptr 141 | CENTER_WORDWRAP: 142 | ;Setup stack 143 | addiu sp,sp,-0x180 144 | sw a0,0x0(sp) 145 | sw a1,0x4(sp) 146 | sw a2,0x8(sp) 147 | sw a3,0xc(sp) 148 | sw s0,0x10(sp) 149 | sw s1,0x14(sp) 150 | sw s2,0x18(sp) 151 | swc1 f10,0x1c(sp) 152 | swc1 f11,0x20(sp) 153 | swc1 f12,0x24(sp) 154 | swc1 f13,0x28(sp) 155 | ;Calculate the length for all the lines 156 | ;a0 = current str ptr 157 | ;a3 = current character 158 | ;s0 = line length ptr 159 | ;f10 = current length 160 | ;f11 = max length 161 | move a0,a1 162 | move a2,zero 163 | li t0,0x1 164 | mtc1 a2,f10 165 | nop 166 | mov.s f11,f10 167 | addiu s0,sp,0x30 168 | ;Load one character, check for line breaks and 0 169 | @@loop: 170 | lhu a3,0x0(a0) 171 | nop 172 | beq a3,0xa,@@linebreak 173 | addiu a0,a0,0x2 174 | beq a3,0x0,@@center 175 | nop 176 | jal GET_CHAR_LEN 177 | nop 178 | j @@loop 179 | add.s f10,f10,f12 180 | ;Set f11 if the length is more than the max, store it in s0 and move on 181 | @@linebreak: 182 | c.lt.s f10,f11 183 | nop 184 | bc1t @@linebreaksmall 185 | nop 186 | mov.s f11,f10 187 | @@linebreaksmall: 188 | swc1 f10,0x0(s0) 189 | move a2,zero 190 | mtc1 a2,f10 191 | j @@loop 192 | addiu s0,s0,0x4 193 | ;Finished calculating all the lengths, check the last length with max 194 | @@center: 195 | c.lt.s f10,f11 196 | nop 197 | bc1t @@centersmall 198 | nop 199 | mov.s f11,f10 200 | @@centersmall: 201 | swc1 f10,0x0(s0) 202 | addiu s0,sp,0x30 203 | addiu a0,sp,0x40 204 | lwc1 f10,0x0(s0) 205 | nop 206 | ;Registers setup 207 | ;a0 = new str 208 | ;a1 = original str 209 | ;s0 = line length ptr 210 | ;f10 = current length 211 | ;f11 = max length 212 | ;s2 = number of padding characters added 213 | c.seq.s f10,f11 214 | nop 215 | bc1t @@copyloop 216 | move s2,zero 217 | @@padline: 218 | ;Pad the line, length is in a2 219 | ;Length to pad = (f11 - f10) / 2 220 | sub.s f10,f11,f10 221 | li.s f12,2.0 222 | nop 223 | div.s f10,f10,f12 224 | li.s f12,4.84375 225 | nop 226 | div.s f10,f10,f12 227 | cvt.w.s f10,f10 228 | mfc1 a2,f10 229 | li a3,0x7b 230 | @@padloop: 231 | ble a2,0x0,@@copyloop 232 | addiu s2,s2,0x1 233 | sh a3,0x0(a0) 234 | addiu a0,a0,0x2 235 | j @@padloop 236 | addi a2,a2,-0x1 237 | @@copyloop: 238 | lhu a3,0x0(a1) 239 | addiu a1,a1,0x2 240 | sh a3,0x0(a0) 241 | beq a3,0x0,@@copyover 242 | addiu a0,a0,0x2 243 | beq a3,0xa,@@copybreak 244 | nop 245 | j @@copyloop 246 | nop 247 | ;On line break, check the next string length 248 | @@copybreak: 249 | addiu s0,s0,0x4 250 | lwc1 f10,0x0(s0) 251 | nop 252 | c.seq.s f10,f11 253 | nop 254 | bc1t @@copyloop 255 | nop 256 | j @@padline 257 | nop 258 | @@copyover: 259 | addiu a1,sp,0x40 260 | @@return: 261 | ;Original instructions 262 | lw a0,0x0(sp) 263 | lw a2,0x8(sp) 264 | lw a3,0xc(sp) 265 | lw s0,0x10(sp) 266 | lw s1,0x14(sp) 267 | addu a2,a2,s2 268 | lw s2,0x18(sp) 269 | lwc1 f10,0x1c(sp) 270 | lwc1 f11,0x20(sp) 271 | lwc1 f12,0x24(sp) 272 | lwc1 f13,0x28(sp) 273 | addiu a2,a2,0x1 274 | jal 0x088269d8 275 | move t0,s2 276 | ;Restore stack and return 277 | lw a1,0x4(sp) 278 | j CENTER_WORDWRAP_RETURN 279 | addiu sp,sp,0x180 280 | 281 | LINES_POS_TWEAK: 282 | mov.s f20,f4 283 | mov.s f21,f14 284 | ;Move lines text (0x43d2) 285 | lui a1,0x43c6 286 | mtc1 a1,f14 287 | ;Move lines number (0x43be) 288 | lui a1,0x43b2 289 | mtc1 a1,f4 290 | j LINES_POS_TWEAK_RETURN 291 | addiu a1,a2,0x400 292 | .endarea 293 | 294 | ;This function has a list of harcoded characters that are offset 295 | ;when rendering them vertically, we just don't care about this 296 | ;Use the space after to inject some more code 297 | .org 0x088266bc 298 | .area 0x318 299 | jr ra 300 | li v0,0x0 301 | 302 | SWAP_CIRCLE_CROSS: 303 | move t0,a1 304 | lbu a1,0x5(t0) 305 | nop 306 | srl a2,a1,5 307 | srl a3,a1,6 308 | xor a2,a2,a3 309 | andi a2,a2,0x1 310 | sll a3,a2,5 311 | sll a2,a2,6 312 | or a2,a2,a3 313 | xor a2,a1,a2 314 | sb a2,0x5(t0) 315 | move a1,t0 316 | ;Original code 317 | lw s1,0x4(a1) 318 | lw a2,0x0(a0) 319 | j SWAP_CIRCLE_CROSS_RET 320 | nop 321 | 322 | ;Wrap the sprintf function by repeating the parameter 323 | SPRINTF_REPEAT: 324 | addiu sp,sp,-0x10 325 | sw ra,0x0(sp) 326 | jal 0x088cf7f8 327 | move a3,a2 328 | lw ra,0x0(sp) 329 | nop 330 | jr ra 331 | addiu sp,sp,0x10 332 | 333 | ;Cut text off taking VWF into account 334 | ;Originally text is cut off at 0x17 (horizontal) or 0xe (vertical) length 335 | ;s1 = str ptr (actually a copy, but this is what will be used and cut off) 336 | ;a1 = max amount of characters 337 | ;s2 = 1 for shorter text (vertical) 338 | CUTOFF_TEXT: 339 | addiu sp,sp,-0x20 340 | swc1 f10,0x0(sp) 341 | swc1 f11,0x4(sp) 342 | swc1 f12,0x8(sp) 343 | swc1 f13,0xc(sp) 344 | sw s1,0x10(sp) 345 | sw a2,0x14(sp) 346 | sw a3,0x18(sp) 347 | sw t0,0x1c(sp) 348 | li a2,0x0 349 | li t0,0x1 350 | li.s f10,0.0 351 | li.s f11,490.0 352 | ;Don't use the delay slot here since li.s assembles to 2 instructions 353 | beq s2,zero,@@loop 354 | nop 355 | li.s f11,308.0 356 | @@loop: 357 | lhu a3,0x0(s1) 358 | nop 359 | beq a3,0xa,@@linebreak 360 | addiu s1,s1,0x2 361 | beql a3,0x0,@@return 362 | move a2,a1 363 | @@check: 364 | beql a3,0x20,@@getlen 365 | move a2,a1 366 | @@getlen: 367 | jal GET_CHAR_LEN 368 | addiu a1,a1,0x1 369 | add.s f10,f10,f12 370 | c.lt.s f10,f11 371 | nop 372 | bc1t @@loop 373 | nop 374 | j @@return 375 | subiu a1,a1,0x1 376 | @@linebreak: 377 | ;Replace with space, or invisible character if it's the first one 378 | li a3,0x20 379 | beql a2,zero,@@notfirst 380 | li a3,0x7c 381 | @@notfirst: 382 | sh a3,-0x2(s1) 383 | j @@check 384 | nop 385 | @@return: 386 | move a1,a2 387 | lwc1 f10,0x0(sp) 388 | lwc1 f11,0x4(sp) 389 | lwc1 f12,0x8(sp) 390 | lwc1 f13,0xc(sp) 391 | lw s1,0x10(sp) 392 | lw a2,0x14(sp) 393 | lw a3,0x18(sp) 394 | lw t0,0x1c(sp) 395 | sw a0,0x354(s0) 396 | j CUTOFF_TEXT_RETURN 397 | addiu sp,sp,0x20 398 | 399 | LB_TO_SPACE: 400 | li s1,REPLACE_LB 401 | lw t2,0x0(s1) 402 | nop 403 | beq t2,zero,@@return 404 | @@loop: 405 | li t3,0x20 406 | lhu t2,0x0(s1) 407 | addiu s1,s1,0x2 408 | beq t2,zero,@@return 409 | nop 410 | bne t2,0xa,@@loop 411 | nop 412 | ;Check if it's the first character of the string 413 | lw t2,0x350(s0) 414 | nop 415 | addiu t2,t2,0x2 416 | ;In that case, set the character to an invisible space 417 | beql t2,s1,@@notfirst 418 | li t3,0x7c 419 | @@notfirst: 420 | j @@loop 421 | sh t3,-0x2(s1) 422 | @@return: 423 | lw s1,0x350(s0) 424 | li t2,0x0 425 | j LB_TO_SPACE_RETURN 426 | li t3,0 427 | 428 | REPLACE_LB: 429 | .dw 0 430 | 431 | SET_REPLACE_LB: 432 | li a1,0x1 433 | li a3,REPLACE_LB 434 | sw a1,0x0(a3) 435 | li a1,0x0 436 | j SET_REPLACE_LB_RETURN 437 | li a3,0x0 438 | 439 | ;If REPLACE_LB is set, copy a2 bytes from a1 to a0 440 | ;s4 = result from wcslen 441 | LB_TO_SPACE_LONG: 442 | sw v0,0x24(s0) 443 | li a1,REPLACE_LB 444 | lw a0,0x0(a1) 445 | nop 446 | beq a0,zero,@@retnormal 447 | nop 448 | sw zero,0x0(a1) 449 | addiu sp,sp,-0x10 450 | move a0,v0 451 | move a1,s3 452 | sw a0,0x0(sp) 453 | sw a1,0x4(sp) 454 | sw a2,0x8(sp) 455 | sw a3,0xc(sp) 456 | li t8,-1 457 | @@loop: 458 | addi t8,t8,0x1 459 | lhu a3,0x0(a1) 460 | addiu a2,a2,-0x1 461 | sh a3,0x0(a0) 462 | beq a3,0x0,@@return 463 | addiu a1,a1,0x2 464 | beq a2,0x0,@@return 465 | addiu a0,a0,0x2 466 | bne a3,0xa,@@loop 467 | li a3,0x20 468 | beql t8,zero,@@notfirst 469 | li a3,0x7c 470 | @@notfirst: 471 | sh a3,0x0(a0) 472 | addiu s4,s4,0x2 473 | sw s4,0x28(s0) 474 | j @@loop 475 | addiu a0,a0,0x2 476 | @@return: 477 | lw a0,0x0(sp) 478 | lw a1,0x4(sp) 479 | lw a2,0x8(sp) 480 | lw a3,0xc(sp) 481 | j LB_TO_SPACE_LONG_RETURN 482 | addiu sp,sp,0x10 483 | @@retnormal: 484 | j LB_TO_SPACE_LONG_RETURN_NORMAL 485 | move a0,v0 486 | .endarea 487 | 488 | ;Center wordwrapped lines 489 | .org 0x08826668 490 | jal CENTER_WORDWRAP 491 | .skip 12 492 | CENTER_WORDWRAP_RETURN: 493 | 494 | ;Cut off text taking VWF into account 495 | .org 0x08826460 496 | j CUTOFF_TEXT 497 | li a1,0x1 498 | .skip 8 499 | CUTOFF_TEXT_RETURN: 500 | 501 | ;Change line breaks to spaces for glossary lines 502 | .org 0x088263fc 503 | j LB_TO_SPACE 504 | .skip 4 505 | LB_TO_SPACE_RETURN: 506 | .org 0x088b41f0 507 | j SET_REPLACE_LB 508 | .skip 4 509 | SET_REPLACE_LB_RETURN: 510 | .org 0x0882651c 511 | j LB_TO_SPACE_LONG 512 | .skip 4 513 | LB_TO_SPACE_LONG_RETURN_NORMAL: 514 | .skip 8 515 | LB_TO_SPACE_LONG_RETURN: 516 | 517 | ;Make some more space for the allocation to replace line breaks with line break+space 518 | .org 0x08826504 519 | ;addiu a0,s4,0x1 520 | addiu a0,s4,0x2 521 | 522 | ;Handle vertical text VWF 523 | .org 0x088e4da8 524 | j VERTICAL_TEXT 525 | sw zero,0x2c(s1) 526 | nop 527 | nop 528 | nop 529 | VERTICAL_TEXT_RET: 530 | 531 | ;Convert the character code for vertical text 532 | .org 0x088e49ec 533 | j CONVERT_VERTICAL 534 | move s0,a1 535 | CONVERT_VERTICAL_RET: 536 | 537 | ;Swap date order for save games 538 | .org 0x088094a0 539 | lhu a2,0x212(sp) ;MM 540 | lhu a3,0x214(sp) ;DD 541 | lhu t0,0x210(sp) ;YYYY 542 | 543 | ;Swap order for "%sで対%s語録が|使えるようになりました。||対%s戦オススメの語録で|シングルモードでのみ使用可能な語録です。" 544 | .org 0x088cd2d4 545 | move a2,s1 546 | move a3,s3 547 | .org 0x088cd33c 548 | move a2,s1 549 | move a3,s3 550 | .org 0x088cd3a4 551 | move a2,s1 552 | move a3,s3 553 | .org 0x088cd408 554 | move a2,s1 555 | move a3,s3 556 | 557 | ;Add more space for the "Glossary n" lines 558 | .org 0x0881da9c 559 | addiu s4,s4,0x12 560 | 561 | ;Use short character names in the menu 562 | ;Original: 563 | ;4f: 阿良々木暦 564 | ;50: 戦場ヶ原ひたぎ 565 | ;51: 八九寺真宵 566 | ;54: 神原駿河 567 | ;52: 千石撫子 568 | ;53: 羽川翼 569 | ;55: ブラック羽川 570 | ;59: 阿良々木火憐 571 | ;5A: 阿良々木月火 572 | ;56: 忍野メメ 573 | ;57: 忍野忍 574 | .macro short_char_names 575 | .dw 0x5b ;暦 576 | .dw 0x5c ;ひたぎ 577 | .dw 0x5d ;真宵 578 | .dw 0x60 ;駿河 579 | .dw 0x5e ;撫子 580 | .dw 0x5f ;翼 581 | .dw 0x61 ;猫 582 | .dw 0x65 ;火憐 583 | .dw 0x66 ;月火 584 | .dw 0x62 ;メメ 585 | .dw 0x63 ;忍 586 | .endmacro 587 | .org 0x0897c728 588 | short_char_names 589 | .org 0x0897dd7c 590 | short_char_names 591 | 592 | ;Use short character names in menu headers 593 | .org 0x088af798 594 | jal GET_SHORT_CHAR_NAME3 - 0x8804000 595 | .org 0x088b2fec 596 | jal GET_SHORT_CHAR_NAME3 - 0x8804000 597 | .org 0x088b3a64 598 | jal GET_SHORT_CHAR_NAME3 - 0x8804000 599 | .org 0x088ae02c 600 | jal GET_SHORT_CHAR_NAME3 - 0x8804000 601 | .org 0x088b1128 602 | jal GET_SHORT_CHAR_NAME3 - 0x8804000 603 | .org 0x088c4d2c 604 | jal GET_SHORT_CHAR_NAME2 - 0x8804000 605 | 606 | ;Repeat sprintf parameter for these two strings: 607 | ;"%sの「中敵」語録が開放されました。|フリー対戦モード限定のCOM専用語録です。|より強力なCOMと会話劇ができます。" 608 | .org 0x088cd1e4 609 | jal SPRINTF_REPEAT - 0x8804000 610 | ;"%sの「強敵」語録が開放されました。|フリー対戦モード限定のCOM専用語録です。|最強難易度に挑戦してみてください!" 611 | .org 0x088cd214 612 | jal SPRINTF_REPEAT - 0x8804000 613 | 614 | ;Align "Achievements" header 615 | .org 0x088bc20c 616 | ;lui v0,0x41a0 617 | lui v0,0x4140 618 | ;Move Progress text 619 | .org 0x088bc2e4 620 | ;lui t3,0x43b4 621 | lui t3,0x43a0 622 | ;Move first progress number 623 | .org 0x088bbf64 624 | ;li a1,0x15c 625 | li a1,0x16c 626 | ;Move second progress number 627 | .org 0x088bbf7c 628 | ;li a1,0x176 629 | li a1,0x186 630 | ;Don't overwrite the progress position every frame 631 | .org 0x088bbf4c 632 | ;swc1 f12,0x0(a0) 633 | nop 634 | 635 | ;Align "General" header 636 | .org 0x088b8828 637 | ;lui a0,0x4260 638 | lui a0,0x4270 639 | ;Move the hour number 640 | .org 0x088bbce8 641 | ;lui a1,0x439a 642 | lui a1,0x4393 643 | ;Move the : and minute number 644 | .org 0x088bbd3c 645 | ;lui a0,0x4396 646 | lui a0,0x4391 647 | ;Move (Hr:M) text 648 | .org 0x088bbe80 649 | ;lui a0,0x4100 650 | lui a0,0x3e99 651 | ;NOTE: the stuff below runs at boot 652 | ;Move wins/losses text 653 | .org 0x088bccb8 654 | ;lui a1,0x43b8 655 | lui a1,0x43a8 656 | ;Move wins number 657 | .org 0x088bcccc 658 | ;lui a1,0x43ab 659 | lui a1,0x439b 660 | ;Move losses number 661 | .org 0x088bccdc 662 | ;lui a1,0x43c2 663 | lui a1,0x43b8 664 | ;Move lines number/text 665 | .org 0x088bd0d4 666 | ;addiu a1,a2,0x400 667 | j LINES_POS_TWEAK 668 | .skip 4 669 | LINES_POS_TWEAK_RETURN: 670 | ;Fix the last 3 Beat Character values that are set after 671 | .org 0x088bd0f0 672 | ;swc1 f14,0x438(a2) 673 | swc1 f21,0x438(a2) 674 | .org 0x088bd100 675 | ;swc1 f4,0x458(a2) 676 | swc1 f20,0x458(a2) 677 | .org 0x088bd128 678 | ;swc1 f14,0x4B8(a2) 679 | swc1 f21,0x4b8(a2) 680 | .org 0x088bd138 681 | ;swc1 f4,0x4d8(a2) 682 | swc1 f20,0x4d8(a2) 683 | .org 0x088bd160 684 | ;swc1 f14,0x538(a2) 685 | swc1 f21,0x538(a2) 686 | .org 0x088bd170 687 | ;swc1 f4,0x558(a2) 688 | swc1 f20,0x558(a2) 689 | 690 | 691 | ;Don't use installed data, always return 0 from the function that checks for it 692 | .org 0x08807438 693 | j 0x08807470 694 | nop 695 | ;Do not prompt to install data on new game 696 | .org 0x088232c4 697 | ;li a1,0xa 698 | li a1,0xb 699 | 700 | ;Set the language to 1 (English) and buttonSwap to 1 (X) for syscalls 701 | ;sceImposeSetLanguageMode 702 | .org 0x0880706c 703 | li a1,0x1 704 | .skip 8 705 | li a0,0x1 706 | ;sceUtilitySavedataInitStart 707 | .org 0x08807174 708 | j SCE_SAVE 709 | .skip 4 710 | SCE_SAVE_RET: 711 | 712 | ;Swap Circle with Cross 713 | ;Call the code after the sceCtrlReadBufferPositive call 714 | .org 0x088ebd28 715 | j SWAP_CIRCLE_CROSS 716 | nop 717 | SWAP_CIRCLE_CROSS_RET: 718 | 719 | ;Redirect some error codes to free up some space 720 | ERROR_PTR equ 0x08968250 - 0x08804000 721 | .org 0x08925d24 722 | lui a1,hi(ERROR_PTR) 723 | addiu a1,a1,lo(ERROR_PTR) 724 | .org 0x08926184 725 | li a1,ERROR_PTR 726 | .org 0x0892619c 727 | addiu a1,a1,lo(ERROR_PTR) 728 | .org 0x089261c8 729 | addiu a1,a1,lo(ERROR_PTR) 730 | .org 0x089261ec 731 | addiu a1,a1,lo(ERROR_PTR) 732 | .org 0x08926450 733 | lui a1,hi(ERROR_PTR) 734 | .skip 4 735 | addiu a1,a1,lo(ERROR_PTR) 736 | .org 0x089264d8 737 | lui a1,hi(ERROR_PTR) 738 | .skip 4 739 | addiu a1,a1,lo(ERROR_PTR) 740 | .org 0x089264e4 741 | lui a1,hi(ERROR_PTR) 742 | .skip 8 743 | addiu a1,a1,lo(ERROR_PTR) 744 | .org 0x089264f8 745 | lui a1,hi(ERROR_PTR) 746 | .skip 4 747 | addiu a1,a1,lo(ERROR_PTR) 748 | .org 0x08926504 749 | lui a1,hi(ERROR_PTR) 750 | .skip 4 751 | addiu a1,a1,lo(ERROR_PTR) 752 | .org 0x08926698 753 | lui a1,hi(ERROR_PTR) 754 | .skip 4 755 | addiu a1,a1,lo(ERROR_PTR) 756 | .close 757 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "3773e49725ffab9b9fecb886bbf395a10a9c43a4e406c6b3dde7785fd7e04405" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": { 19 | "click": { 20 | "hashes": [ 21 | "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", 22 | "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de" 23 | ], 24 | "version": "==8.1.7" 25 | }, 26 | "colorama": { 27 | "hashes": [ 28 | "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", 29 | "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6" 30 | ], 31 | "markers": "platform_system == 'Windows'", 32 | "version": "==0.4.6" 33 | }, 34 | "customtkinter": { 35 | "hashes": [ 36 | "sha256:14ad3e7cd3cb3b9eb642b9d4e8711ae80d3f79fb82545ad11258eeffb2e6b37c", 37 | "sha256:fd8db3bafa961c982ee6030dba80b4c2e25858630756b513986db19113d8d207" 38 | ], 39 | "version": "==5.2.2" 40 | }, 41 | "darkdetect": { 42 | "hashes": [ 43 | "sha256:a7509ccf517eaad92b31c214f593dbcf138ea8a43b2935406bbd565e15527a85", 44 | "sha256:b5428e1170263eb5dea44c25dc3895edd75e6f52300986353cd63533fe7df8b1" 45 | ], 46 | "markers": "python_version >= '3.6'", 47 | "version": "==0.8.0" 48 | }, 49 | "hacktools": { 50 | "extras": [ 51 | "armips", 52 | "cli", 53 | "graphics", 54 | "psp", 55 | "xdelta" 56 | ], 57 | "hashes": [ 58 | "sha256:0196f89ccbd8ae90f3acb844d686d19bef9f650bf65782dde28ffa0668f36d35", 59 | "sha256:0b5a927cb8a169edce5967ebcdbb3910947acd1c63ac4a8599a90f972b37df6b", 60 | "sha256:130451084e67667f6c1628c12055a14a9d0af9c93654e1f90d1fa40252350186", 61 | "sha256:16c058be6f812240040227de58670d486649553dc15091de337b86128353411d", 62 | "sha256:22c34aac74ca91d2b85b3c30975523332fa9795e422bd37700828464f9cc07c6", 63 | "sha256:2377252d9b810ea345de228fddac852fd5c9b6fd7ace2c6bd25e46f397bdc1a9", 64 | "sha256:2960e3cf40efe5ac50f35f2c21ee89e1958d745e89980601e0c0cbd124586462", 65 | "sha256:2a94afabdee081479bf6e7a843bf0e2e534f9b7808877d41160cec09c342f4bd", 66 | "sha256:2aec5ec91280348492e766988ba0ed7febe1ea0148dbd297d32daaaa230de83b", 67 | "sha256:2bcddb9459432a0b116c2bd1517ea0cade3c2d5fce3b7f5b1457d2dfe238ebff", 68 | "sha256:2d496f2330c7ab5b0b24f8380a621dafbc96a4daa1534a4d3cb94693d8d2e6cf", 69 | "sha256:3d1101aa5d2b142334256abbdc7f97e59f8b7dd658b0815c43a0ac3af7708c75", 70 | "sha256:3d1841eff0b9f1d570180dee90feef2f99775ee68d2621b27b625101ffd797d5", 71 | "sha256:3e838f0d1c29e712d11daa4930c2aef7838eca18eeed872e954c0e355516be06", 72 | "sha256:3fb26af454077336abf8de61b00aa32e7ecbb5b0a8f8427937757512d175fbeb", 73 | "sha256:489b33914525d6ba19f752b4bab945395d03e477a2aac70ed3cb3aba18c1d41c", 74 | "sha256:49540f0537bc6d8e73dfe5edc968dbb4503b298b271188d0bd2ff15a10976d33", 75 | "sha256:4a761cdd0b3354576c563bb04255801a7d90f8d4e923c5a4f3183fbf60f01316", 76 | "sha256:4cb737d69c190bf86637d35f081a26686a8e1ad824b4a3d72a848c2424a5d148", 77 | "sha256:4f179dc26d15b70240953c6f1754a6307928a6d5e17122945c1369bc44ca4203", 78 | "sha256:5368dbeddea18a65cfaa4be66b9f9c36b226b225f3eb3e84d1578fb6113fd173", 79 | "sha256:578cde03edd241e7faad0d7ac501909221d58d25009ef27cbb9853211d1f6500", 80 | "sha256:579c1f0ae055358d150f089999116ac20c4c1df63ed1e8c44c7ca72607fe23c6", 81 | "sha256:5bd91261221a8d85440eb23537eb65803a22e333f5450b965fe5f972a5e6f9f9", 82 | "sha256:5bf260efc1402f6c74596f191d7f17b505bb2fd315bb6b3ce838324c4d41135c", 83 | "sha256:5f2d9d9f5a0b9eb9ab48f3bff064bd6b87aa415f962a38c109d32d0f4753ba9a", 84 | "sha256:61cbb8a94de3ef55b41a84051f8680585db7d6592f1e41c563a89b07d337c1fd", 85 | "sha256:68160b325f0df92da640e776f1dd51457a8fc97f8b546ad792da96eae97144c2", 86 | "sha256:6e7f6cc8fb32cc25cdaf9f75795315bfd41a5a15834b71a1773ff1dc0d1b5312", 87 | "sha256:6fd1d93f3be2d927f0a1df291d1e50fa092aaa45d851c808fb15fd5f4157bed8", 88 | "sha256:750e10ca583cf610b8f5a79b75ed96bdc40a8e87f0fe2e543fca1ac1aeba5f2c", 89 | "sha256:75b639bedd7f2e35ba1d29cf673140a4930ca9d0e4f57e601a423c118aa06f95", 90 | "sha256:763666e2fd3482d5ceb2071b2a0040fbe8f40708f6b3b6885d505f34c49dd807", 91 | "sha256:79338ce1e8cf0c296508b6d3d6f8ffd95c228cbc6ac53f8a99eb17055e7dcba7", 92 | "sha256:80fe783a298f3b8e4210b17a08203abf12c699161912d990b3523f19ac805a28", 93 | "sha256:81a9986116f8282ebae67c8cd72e92d37b0597cfec6b2debb840a8fb7f6c3028", 94 | "sha256:8dfcd4bc748595479c79498af75efe56d709e46b12f25f82b6d4a6e569dc0128", 95 | "sha256:910e23c6ab2d102a4f40ebfb50c11c845af34c0bd0a41f29c74a45f5b8cff301", 96 | "sha256:918bd8cadc63e4a95c2acfa82138b628f809daccb7f9e6a66c3df12e947abeda", 97 | "sha256:92aa212853dcbbc0dbd327fe6baff12585aa6f5bab1dd6f1791410de7e43e468", 98 | "sha256:a7e1b03d3741e83f3e90cf1eeb93c69d21254259ef659e89f6f7fa2d04b3fe8d", 99 | "sha256:a9dab63735fb9a0487d12c04834ff8d24c5639a25ad3276476a9f28991855a66", 100 | "sha256:b051ab5adfd7290e797515feeeddcd13fdc8fc85e9e6a9b9d7bf08d5aeebc9b1", 101 | "sha256:b09f5d3f7966f70746cfb4cf66531665577322defa7abb5f06567ee1dc8ac95b", 102 | "sha256:b1e21c6e59d1ef41caed4a1646a78824d769d7b697f0af20b760314bc68dd3a4", 103 | "sha256:b3df67cf80a6b30a113146a0862957a3483c41d899c0d46ceca0a10512e01ed0", 104 | "sha256:b48aa22c758727c371df0044fbab5c70b52fa6b976de6b684435f6b971d58e1b", 105 | "sha256:b87194e534633da923777fab9a9636c6258da0276c8a5f45a93fd2883cd8064c", 106 | "sha256:b884c6a6456f6fe5eba7aea401bc1ca782e61015a7c0bc33e2fd754a45fd7b1f", 107 | "sha256:b92354193901e289ac98b4c7002b8754a69c845a7f6e162379955adbe105f838", 108 | "sha256:ba9d6e3e017cd3c8532949ed6f4da2616d55829e0af1ba7f93c0db38c4f5ef30", 109 | "sha256:be6ac68f1c9159bd8898cbd5094708e59b16544233692be17337e1eb1e16b8d9", 110 | "sha256:c2b30fac490a3f5085e6afdd8b6b13b90ee76c66debaf66faf7ca1a73fce2300", 111 | "sha256:c7ac58cc853bce9772d0e57e9fc2a020558a735a1c9aa67a6e4492913111eac8", 112 | "sha256:cf260234980fa8201f2158e9d5f95030e47dc76c4659af3f576955278828e3d1", 113 | "sha256:d02a74090de39080c8406d06d33c837cb852181e1b20faec0ae19b6251c7310e", 114 | "sha256:dc2151622c42db6cdb20a42100d5e5d96f0348a5adb80821c9278aa0bee6c533", 115 | "sha256:e0dcb29f5390c7c4e578781d3a42bd2f5f68e7e339130bb84c68c593533508f0", 116 | "sha256:e5a368a490826a7387f47e1c426c4eede4d138a3eb8b4510c6cfd5a3e113214f", 117 | "sha256:e67194336db47b5e0e9a1d58fd176157f538edc58da70890ac2442fa395ab6c2", 118 | "sha256:e6b2a2698210bd95789f4c04801eae88114961b32470fe585844b8f4642faeda", 119 | "sha256:eb009a39a3cfd152910448c81563991726fa00a89c427cc27cdb4075cfad0638", 120 | "sha256:ec4682f48953fddb633946e8473ad2cda420276138221880faf3d0b1c25e596e", 121 | "sha256:efdfd9d3c741504b4d10222ba4b09ff695a6ecd891db6e814f37146789c15553" 122 | ], 123 | "markers": "python_version >= '3.7'", 124 | "version": "==0.33.1" 125 | }, 126 | "packaging": { 127 | "hashes": [ 128 | "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", 129 | "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" 130 | ], 131 | "markers": "python_version >= '3.7'", 132 | "version": "==24.0" 133 | }, 134 | "pillow": { 135 | "hashes": [ 136 | "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c", 137 | "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2", 138 | "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb", 139 | "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d", 140 | "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa", 141 | "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3", 142 | "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1", 143 | "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a", 144 | "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd", 145 | "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8", 146 | "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999", 147 | "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599", 148 | "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936", 149 | "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375", 150 | "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d", 151 | "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b", 152 | "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60", 153 | "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572", 154 | "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3", 155 | "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced", 156 | "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f", 157 | "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b", 158 | "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19", 159 | "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f", 160 | "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d", 161 | "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383", 162 | "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795", 163 | "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355", 164 | "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57", 165 | "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09", 166 | "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b", 167 | "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462", 168 | "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf", 169 | "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f", 170 | "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a", 171 | "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad", 172 | "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9", 173 | "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d", 174 | "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45", 175 | "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994", 176 | "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d", 177 | "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338", 178 | "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463", 179 | "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451", 180 | "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591", 181 | "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c", 182 | "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd", 183 | "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32", 184 | "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9", 185 | "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf", 186 | "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5", 187 | "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828", 188 | "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3", 189 | "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5", 190 | "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2", 191 | "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b", 192 | "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2", 193 | "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475", 194 | "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3", 195 | "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb", 196 | "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef", 197 | "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015", 198 | "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002", 199 | "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170", 200 | "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84", 201 | "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57", 202 | "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f", 203 | "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27", 204 | "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a" 205 | ], 206 | "version": "==10.3.0" 207 | }, 208 | "pyarmips": { 209 | "hashes": [ 210 | "sha256:09ea6b53e3b6596203344ad169a9e2c9732a8b190864d71d26812190bb0637a5", 211 | "sha256:0c44dda8893bf6944addfd32c466b5a947314ab968d0538525f4e1d8c61e9c60", 212 | "sha256:0dacecf8822cd099bc106beefcc6dadb93ad55a78429e560166920b87aa46e1d", 213 | "sha256:110783baceb906169e99489f3d07203b83e717be4cb59d1f7756a5b0c2e68d66", 214 | "sha256:153e91edcd949e600e605ffeca05c720afe0bb586b648f51b3234bb96ab8cc70", 215 | "sha256:1549402b204a914b617ed8fa48720553306d10f7c7e587f3421aabd59d196444", 216 | "sha256:156116cd66e96b089c8430d62d5a358f9c75fadd9e6df0a4efc93d9342cfbbf5", 217 | "sha256:1aed1f3fc4b4f185eee924a6901b4f33dc5dc5b6869a3c4ade362c4d73a64923", 218 | "sha256:2144cde8fec5b7c43fec2d56f2eeec51ecd6983a27e70075c72d0245320eb2f3", 219 | "sha256:21ca8cc2e0a870340506f1404c672078df64c80e59e6fed091aa2dce0d693393", 220 | "sha256:245cd74991e0efb12e6901001362b1a1039523f43c8e4858cfffd1e77d2866a0", 221 | "sha256:28470ccfcf54fab7417c2218f381feb46189219ad3cad3769d73ef28a06f68ac", 222 | "sha256:2d4660801ccb1dbb3382f8d80a3c42766d5bb6f6344a3f77b34d26e17dff6444", 223 | "sha256:3424aaeb23a857c1a09c081990fc4c9a0f51f4954e1f272998bfce36da72f687", 224 | "sha256:37218134aa2562e7b5925583b2383d14543af7dcca99b8f88a13f5d312c30015", 225 | "sha256:3777f246d117728cf2050f2888bbd86593eb3598ac4e5277f9f2c61852c3f5ee", 226 | "sha256:3c332e346889b3b37152bd1d9ba1ab59f30b572cd93db6f20469cca0ab6ba652", 227 | "sha256:3ef6057c02db0b3f07437a5ef20d51c37b92e2a9a6decb1879c2b4845af8d9a2", 228 | "sha256:479781e8aa1b67adb72a7412a8c56f67bc82003e4e852c46c9afc0512caedc19", 229 | "sha256:4c7b9f7968b01adbc8563c31474dc9c0aadcde3e52a045a7a4f4727360e7d1a4", 230 | "sha256:4c97fa21349513f2a253d4b233561286dd8179def449ac9f3e44d3de8b670c04", 231 | "sha256:4e0bd7769264cd28947cb5d45356d080ea592f0ed6ce394ad90ce816ad63d2f3", 232 | "sha256:550094f77cbb980a950b486184d602736409f2f41679f058dd6486abc759426d", 233 | "sha256:566d126695cb6839dde74d731ffd7f49ff82ab8c3d7641d0b8b52c3e952d8798", 234 | "sha256:5743937b2b0eabe285a8a33c3f00d228071eb437dcee6c5f4943e62d58d17b15", 235 | "sha256:59715661a70a1fe67dd2644c7a6d79cb45898b2e52e30622a1a71bb97459e8e4", 236 | "sha256:59a29e3e902957507e13cadcc78cde8c24e0082215dae338349e1c41c0f669bf", 237 | "sha256:5e2853a01389ba4fccc80fdf1c7a385b29408006859cdd0484465f6cc25b6c3e", 238 | "sha256:65021f163a2175565508405ef1ca38d63dd2ed2fffbdcf60816bb5cbc9557c6d", 239 | "sha256:6691a007480a25befc75ede1c39ff1b3753b79aa2b691cd156752b9943066f40", 240 | "sha256:673070aa7a4b1c88823be526f5b72275c1b7c42b40a10680b1e9dd1d50905bb3", 241 | "sha256:6f8913b9d7ee1a038ec14ecbcc1c35827d016f82da25d28b60104030623de8c7", 242 | "sha256:77e86532e43c9f1138d5cfa0894e770cb5c602b392932c2e3cc78e3a86cea44c", 243 | "sha256:7a1797883cd43aee452abf8ae07a8f1bb40be83005dc1144138b53737e3c430d", 244 | "sha256:7ec2566d8f3d51217d12fa7688e8aa903fa3993c2d2f8dd292836d9b8ce12f79", 245 | "sha256:8139c741b14d411c1de2989f4ca0ffdae9eb26848627799dd02cb3b523e47817", 246 | "sha256:81d87024ee7ea349dfc37faf5286917738a7e1df114f4d1254f1789a52a0403a", 247 | "sha256:8a385a22d1e43780afa237e8a02a1f336ccf1469c99a2a421b78882cd4e02215", 248 | "sha256:8a9dc16f4adcee466d26e839e98f64c1141bfdee2b0bc6172a252fa9f3f9b147", 249 | "sha256:8c0e2e42e8166da42ec706893b304ea537800c8f370733f4f836474f77a79fbf", 250 | "sha256:8c56f59cd63703b922aa5c8e21a5b69ed296ac289e623f6c4471257462712909", 251 | "sha256:969db6fc6d9cd0dd032465ba3ec52d5302714cf11e983706b626b71fc341330b", 252 | "sha256:9cadc29541aaf06a73a918c6696a97c9af01d7edafe88e7638348c2aca902bbc", 253 | "sha256:a0f1c6a00832b1578daed36e475b749c5080b855950ab5220996e24cb2933244", 254 | "sha256:a4611b84b43b983ee1fd3657b339545f2c5c7831ed28c8d8d1058f17946306d3", 255 | "sha256:a4b1d84b6861792472f16e1ef0bbdfc412c6f59724dec18f58e73e4eeb3ddc17", 256 | "sha256:a88421005f1461d4e9174e7d9e8294f1f79173f3bc3808f2b8985a065e724ae3", 257 | "sha256:a8a21cb2fa97d84a70f2638ba45de3cacb1184a76d4861f9772dc6b3f7b8f334", 258 | "sha256:aa3697f9e207a0117f0639bbb17a4858d38e9e55e369754f9b6e24e32a532ab5", 259 | "sha256:acbdb495cb1f63c25ea51442f150a1b344082dc044619e6a3cfdcaf3747d0df1", 260 | "sha256:b04975b467624b09e28cdb2464374fb39c40a67808236635de3df6b9db19f3be", 261 | "sha256:b0e5b54e8d936517a9eea617bf314dcdcf7a85fd21aa6792bb6708c6a08d5106", 262 | "sha256:b26bcbd21b5b45e2c01f11bb6b0dba2aaf42f6e98c4dd0ba65ba65fb732b1d35", 263 | "sha256:b26fa333a26b24fa7b109d0aaa490a184bbd6b0051d98c323f725072fada941f", 264 | "sha256:b92315b9579066028f96a2a4302d11f6e891119bb2d0f24f60290c9e701e714a", 265 | "sha256:be9c989fab7913d05af997d30de937c11a6f824d9fcf7818cdc9da2c2c6fa153", 266 | "sha256:c5f79417669698c7a0fe4411824172ebcbf228f7180afe2b1691fcfae1987599", 267 | "sha256:cb1d5d7a34659e22f8d037a10da7367d346fea6d7e9ae21a510056f55c610283", 268 | "sha256:ce7780e165c48934d326a0578f3ee85dd3622f0fcb94c4794c2e51e290ead98e", 269 | "sha256:d57dd33d880af6fd4fdd839f478db242eba56124ce0532c90d736136c88fa87e", 270 | "sha256:d6910204064afc63c0df31d7c32a0a3c5af1e1bcd6cd4a40b23c9aaf0a70a0e9", 271 | "sha256:d7a70bdb7b6ba7997e22f815b0e460646500692bd358d5b0c2641ddbf5d702f1", 272 | "sha256:e086da7c7dd9cbd1c47ef44616a98f73a61226e8965a8252b8fae0f282088af8", 273 | "sha256:e0dff93b0c12070b0ed490d65a9040b4f9a7db87eff0953ac8a631bcdf1d1f91", 274 | "sha256:e51cd3971ae1100607b6e94e581c409e8f9c9069d748b34ca5eaf32741ebbc67", 275 | "sha256:e9200514ddb0690064d3fdaf25dbf8491b7b8edba93b697cab1af8dbce74031b", 276 | "sha256:ebeb369d125a64359d61f46f1454836bd09d7b02434d3045647a4b3f5856acf0", 277 | "sha256:f258a5dae84b0e7bded99f8a198d9498c4cdfea51684cdcb316a9296abedb1b4", 278 | "sha256:f2ff53b49eaf6f59047a624f08d62f8990f39272e3604188c30927dbd7956b25", 279 | "sha256:fafe60554aa9d5fa8cdca24d97b284ff852a80c7a385c41d685aa4f795d440d7", 280 | "sha256:fe538c0267b1be869ecea3059883385d9dae0a43cf07dadb7217e2c063bc52f4" 281 | ], 282 | "version": "==0.11.2" 283 | }, 284 | "pycdlib": { 285 | "hashes": [ 286 | "sha256:8ec306b31d9c850f28c5fda52438d904edd1e8fcf862c5ffd756272efac9f422", 287 | "sha256:a905827335f0066af3fd416c5cf9b1f29dffaf4d0914b714555213d1809f38d4" 288 | ], 289 | "version": "==1.14.0" 290 | }, 291 | "pyeboot": { 292 | "hashes": [ 293 | "sha256:0374afca9f6972f87efc5b331636fe37a797782017988656a144061f8420dbb2", 294 | "sha256:094f7115fa7adab893e01bb580e289c6dfd4015e3afea751620d789762d7197a", 295 | "sha256:1b6f8ab2c97d94bb4b8b0ebae802eb88d530d78e6c2d70bdb05629b1841a705c", 296 | "sha256:202b2cd4675d44efc0ecee0beb6ed981100c53c39974c408121cc8c884570289", 297 | "sha256:2174ce1b00abfa1f8cd72aa018a1f3aed9289376c489c28ac63fbcb36ccc3140", 298 | "sha256:2260ae7386f8a6bdc7c93f22c7fe4000c698c119a02c9b144c362f03cbbe2fd8", 299 | "sha256:25a013d3709e20e3e74c6c60e9b6e7f9907062dc7c01fb37f83c9f721c4cd61d", 300 | "sha256:2836f628b2ae61b8e31f16ec6544abc6e5a12e82c2fc481ae28b2e7271ce7c2e", 301 | "sha256:2ab23847b4891c7cc8415e80630bd06c4511bbe87d878d814e9f25902455a2e6", 302 | "sha256:3a4121ac28fe95e38df36e9d922f28e1cc1ce754cbfe92ed415b8876e3b4af12", 303 | "sha256:3bf6a2025a0d4d3d6e41a00ee27e5c8d81bcd430ffb5e998f8aeb39b4e7ee17a", 304 | "sha256:3e3e3d3aef12a9159cc3d2150f9f100281be1b4482948124992c2247a76ba63b", 305 | "sha256:407fbcc1324aedd10a397453b7766a0da85d294c5dfc21d7e9a1aebe90af0cbe", 306 | "sha256:482ea6ae8f110e12a910f6cb92c9f41fbf5123271e0dda1ace67aea0f55ac46c", 307 | "sha256:4b188a1b02f80ac48799c50d08e32205c2df6f5b5e364cbd8fe27719c466b396", 308 | "sha256:4ddc1120802f657efff4cff5127f47bc2ef92304543f39c2c95122774bb3ecf4", 309 | "sha256:4ddf4eda794f9b91925b70517b8fab5dca4d87348dc2ac27ffd24400edfddebf", 310 | "sha256:4f91c7a388d01fdc84b4a018858abc6cbe7b57afaa324f4f9df76c5c8a499394", 311 | "sha256:5146c0bf8a66f13b562859d6b83bb539abb146e7b918e36e841d503301851af7", 312 | "sha256:51cac0bce476ef6e06153a91e3f6c9b01eb596fe04c62b12bab30b36eeee64dc", 313 | "sha256:590a0538189d2273c23c0384fe8c2b383875fdde60dc18bf55cc0326b97600c6", 314 | "sha256:5bd8a775d12e8154cba66d8414c3527053e90b07129a68055b0dc90d03326ce4", 315 | "sha256:62452e83426678b4bb7ab0bfc62f4f89247be8b7b939b2d6ea3377c58fada612", 316 | "sha256:663e4dce22e2b996e41324d6df9595b49a81217c3f2850eab250604d807de426", 317 | "sha256:7587515a6c7dafafe6602e65c5451cc4f197be7e3430c156988cc111a3cf63a3", 318 | "sha256:7e113afb73c89f2f1cf2538cf23a1cf28110c36e9af14006fd32c9c7ae4ab5fd", 319 | "sha256:7f4166eab00299866a590b50b2b1c780df4a668d3ea7c01b49a5ed7078730973", 320 | "sha256:8061778b28c0788601a72217a4340201bde15b641da68392f8196b7b1c5f6b72", 321 | "sha256:80a082b11b9a1e18b789b36d97d2f6de6a741ab8a0f889a4108538999b906d06", 322 | "sha256:83badd3dd80f15467f2b6aa3b06f6379ae70ec44da506aa05d7f70f553dcf0a1", 323 | "sha256:83d13148006161930b8f721ec9b4e89f802a2b346a9686f31bf6587fdfaee78b", 324 | "sha256:8408f17c5b5d438a51902f8608bbf8244b21f25dd2bcfa8cb51e2d9b34d60920", 325 | "sha256:8704afc324956038f610c9175baf3665d9d83258c85011ef106ec52084068191", 326 | "sha256:881431628c597ea9297018a31783c63d3f8c679003190d3036a16103badee5b8", 327 | "sha256:8c61018a7a63ff11b23f8f5bac13391a6a2cb111a8af4b2bfd4b4ddfc7288e62", 328 | "sha256:9439f2e088b4fe98f457c8ca921b578a4776e45a77ab085b7516ee5810f1c7b5", 329 | "sha256:94a1444f39d402a046800b6e96bbf72df198a7ae65558227a2008ed170787118", 330 | "sha256:94c32d355db2d445082d84da16ba68ee473e8f8b035fc6a5d3b605efd5882e68", 331 | "sha256:968e788cc5f05ea3d6d01ed0f963ff357acabb7414a85ba4aa38f14e844c700a", 332 | "sha256:97266c4f8f6b5c713626ca8ece3314d163e99b7982ab55f59e95d8b377e3555b", 333 | "sha256:981dc0097f5940bb3d2a12c4ec1ae2683464766bd47f9929a7c52e894165483d", 334 | "sha256:9f6c87cbdf9b53d7d4f0597276c8ced0f6875d471c9784c6bff764d7163e5eb7", 335 | "sha256:a3f1531bb9d99d2dc40c4414ee7c8c9b647564fefabedd342e2a268f4d1c1e99", 336 | "sha256:a4ebcfca282182b18c44e9233ad5083bb670d2aeac49a8cdeee07745868bb668", 337 | "sha256:a83914919788c5b04d60bf703f4027751ff2ea58ab192723d726133ab13114f4", 338 | "sha256:aa500d5a618af7c88de738235eed4018a65f3c5e73dba488c90825a44054033c", 339 | "sha256:aa6b06587f672b4b3f4170fb1ad3bcbf73fd5427da87cebdb82958475c5c8d22", 340 | "sha256:b644cc67876539d01185ccdf5cd2c55569dd1401b102c67def7932d43ac20c7e", 341 | "sha256:b8f0963f0087e0ec402b7123be92464c1302cd0a737497234f1683e623952af6", 342 | "sha256:bd01670d8122abd55c5a0f2221564f61a58931b498de07d9eb465068797fe4a6", 343 | "sha256:bde06ab9176f485d10ceb66ed1d92d9dbe6418641881b313c00809dbd0bb0489", 344 | "sha256:c2751a77a56883f7fd7be37850238c4ec8e2e8e947e5bc00002218422986822e", 345 | "sha256:c3532cbb969ac3d336b38c290869e946da39efa394a0df8de89870602b6dd4d5", 346 | "sha256:c5ef8632930aae1cee986b53a7e4092da015534a498c412dca8d76a60b5e0881", 347 | "sha256:c95811b1b481f9c862b81d20ca7c38e3b2e32813060e8aeb7ae3d66373419820", 348 | "sha256:cc489d8e1b6eb40e1f1285fd05905b0f10a51921672b5ead7c03f038c82f3d93", 349 | "sha256:cdd3352e52001c40092294b0d11595b42956c52f9b3c1eaac2f3100ddba5816b", 350 | "sha256:d126f9a6cd118c703f24cd677c4f4e265e2fc989cb06754782650504a767bc61", 351 | "sha256:d3b9a4b6344a579d589f495777018824537209ff06e033ab6ea836b66a334c41", 352 | "sha256:d3c2de2422de870e7e50eae2b18654dfc49b3016274852aeb90eed371d575e6e", 353 | "sha256:d6d3f539f39af0773c1b083ebd912f7b81902d70e8851562489ab0b483190093", 354 | "sha256:d8b1c1a237da84f4f1418addc29f715a5566cef0167f0f5e883d32fd2e47210f", 355 | "sha256:e8e3779cf930566d45c805dcfddf198c636f4c302b3a561f23f47f33896ebb46", 356 | "sha256:eb1a3cf99e7fbb159acace613ca9a8b6fbaefba91e243f9b5250836b5e78160f", 357 | "sha256:ec1d9d10977f5f4f7283d6e7af7bfcb69811b8ff93fbd457e76b942269294670", 358 | "sha256:f23fcea46a0081197b74522e6bd79aa00836b5782643afb7af0846944f897dbe", 359 | "sha256:f34f15d96673b3f32584ccd2085dd7cb741516837fb713333e49d4487c716e40", 360 | "sha256:f5e31708a916c73672050daae2cf13ffee5ab75363f01cb4bbcdeb5717eb72ed", 361 | "sha256:f612d678634979a1b8e5930fedad3ebd047dea2b30f3a12cb7495cba2f55d479", 362 | "sha256:f67c1b4fdae214389b4f9ff2f648ea475ebf7cd35213dc93703e0f253de26bf0", 363 | "sha256:f8b37b219fbc3d1a9a52eb914ff42d0cd78c7b1487ef2cca8066e203ba81faee" 364 | ], 365 | "version": "==0.2.1" 366 | }, 367 | "pyxdelta": { 368 | "hashes": [ 369 | "sha256:01d309e808d3a10bdda9ae37ff7111a53eb2bd0ad6ac09712adf988c410178c3", 370 | "sha256:07fd8088a0c282f8d3315028fc3417f79691d128d5662776a69a5b9d804e7267", 371 | "sha256:082564d2e49ae0f7ac1c7d7574cc3051af90289bb333238f03afe07a9f71fbfe", 372 | "sha256:092844eaff72316df0913114f056394f0340516ad9d566cbfff213d5c99922ca", 373 | "sha256:0a3d89d49bb47f4b089d94a875f5619433ea4bd3a730b8cbb267f4cf823d1a51", 374 | "sha256:0a61bf4227d2d7c360ccb8f1ef75d115763d68c1a500210eefe664418e9afcb3", 375 | "sha256:100cff7ceee649be8cafe174f24286522a2c818480b2d35b613a3bc1cf33e385", 376 | "sha256:10b4e5cffa0b737fe2f1bbd85a326bf6f75492691f31e4cbc950f41eb8747579", 377 | "sha256:11025138e83896ff3446a683516f8f7b7a558481ac15f6473fa25feff46d2398", 378 | "sha256:15ad493363e6004a5f05175b07e278a4ec449adfc5cf68f17b11305baca6e91f", 379 | "sha256:1a64af9df79a571ca51817f635151987448d917fe88c35a49be853b3872e159f", 380 | "sha256:1bf9fbe779ff890201a81622a8e0c46158c8550038e3b4c50d1fbd892d5f9657", 381 | "sha256:1f0fc89bbcfe0381b2f3f830e0a7364b608a656e017f563b10dd94017eca3e6b", 382 | "sha256:21c786ea0dc8722f73dd676be9a5fb2b1a225d44964052b33065f99cecd52886", 383 | "sha256:24ce333b228b2c73bac6d4c756bc3cbd7f54bcf73ef0169a06501d4eac927638", 384 | "sha256:264fb8c9754c561c68991b8928dc00705661d26538ea84a650149efba0aed473", 385 | "sha256:2d88cc7c5c7b91b78630e14622f118da2c008ee714b6f6a0de24844ba703f180", 386 | "sha256:30047cc1e1d01cedd15f4cc89557f73dfaaa6c07ca4150df2db90f920ea3dad6", 387 | "sha256:3234eb1fb8401e72986d0ef9a56168640ebfabb27d41f01355be4e55a34919a6", 388 | "sha256:34e45dea96880e419d821a232422f51397ba1bfd61b6ad29b234414e2e4747b3", 389 | "sha256:3955b046d115ec47f9f9f181d1bbfcde14781aba3274603554d0dc54d87d517e", 390 | "sha256:39b4bde9c2bf24a60ae48675dcdb20e34705257478905861cb82107875831cde", 391 | "sha256:3e40a5119348fe06d3d7f8f6d44ee7a2f861da359185e7c19558ce0b90a45b58", 392 | "sha256:400f66f782a576fcd8d97830a55c3116448d0830cd2f239d95ec115c01e83ba8", 393 | "sha256:40aea5941c372eac7adca84c5e438ea5abf692da7e962c2835fa34b624b0b895", 394 | "sha256:425a9e466341c575fdf808bda7743b783da2975f2c1eaad052e209bba96d7a54", 395 | "sha256:4b158577e1838e5495d0ec65da9b559938c86bdd6ee36ced2bbf4b8abc85327c", 396 | "sha256:5467876e756fceafa7e15c26eccbb17c1a13ee527c33bc1ba3b932f872210d16", 397 | "sha256:55c430ca378f150c218913058d75d8daf09d2fba3f34b428de552c9d0526eaf5", 398 | "sha256:593badc0fb074ded12ddab59561a639cb552346c788bb4022bf8b79f0423d284", 399 | "sha256:66f61116927d052dd05f1d5b98df6a47cd503c847c1e5583e18cbc517f0857d6", 400 | "sha256:686271b2fac04e8a3a3602680e26d56ca799bc51cbc26b152409feeb705c4849", 401 | "sha256:6a072353d6f0056c6a7d814603a0683188d6364399182b5e969aa63045304da2", 402 | "sha256:6cd4a9befa6079b6f401a565951b587507afac3dda0b6df4898b3a88687e602e", 403 | "sha256:7532466631128114e68fd13b5a069f58f88a976b1ffc7d2d7f1dbf3cf278a2cb", 404 | "sha256:758cd3eeef153d5299df17170ed22e7f9190113c6f959c57f81b1026ffa93b3b", 405 | "sha256:79980a4a8a06191019dd82d0e7df42f130d0b0c62a5c74b860e646b4b5f45417", 406 | "sha256:7fcd2e6a3939a254e077f6365fb706c9772084483d8e8103fbbea85202451c0c", 407 | "sha256:856121a384af4a5e8ad74e9538661d0eb0ad687f2b0f50fe52d0133426b43721", 408 | "sha256:85ed9f8a4dd067527c5ba0bdf4a8f6223f0670e87fd064a4e3b19e63aa86a938", 409 | "sha256:871b71783ca46ec7295fe548554b7dc34cf8c68adc061cdbff6170589cde7c98", 410 | "sha256:885dc8d39d9d742c72cfcf08b09c4abc96e85ab54f8c505dcb4c4f0bf1fa6195", 411 | "sha256:8d63308f5226474fced28c7036efc00d19739c543d25944a21e2143b2d522a81", 412 | "sha256:8ea1b340cfa060d8bbbe3a14e218b2146eb593dee13f26e0b0bebc4de7bea7dc", 413 | "sha256:919af567a7b6e1377273c8bd430c96ea8fdff6ee8965e30c46e2d811b1396a0f", 414 | "sha256:9cd94bfd572cf1287b094add88a412cd0d1285e42406665e4ec879f6769b5ddc", 415 | "sha256:9d72b5313db524335b54138845068d331e02a9662dd487ee6f336f7b52255562", 416 | "sha256:a136a18fa1f618431591657ea15beddd5eb7c9f4237405c3008248c5c4d413d8", 417 | "sha256:a212599bd4c430e57375d429b4ba418eba1f4fa8e9364ff4770055bc9fbae3ce", 418 | "sha256:ae98a5822434d833ac8d1e1105e3d926b15be500514bbece1c9e41d17a80defb", 419 | "sha256:af38e4a4e9573a85a91d25c9787c32231d2f3936bd9469405ca5295acc561757", 420 | "sha256:b00dc3b6920547befe50d42397e555f5753d49e29f88569ed49caa6b0fc39eed", 421 | "sha256:b1b3de6b6b4a5d0a4fe5ee95d024e1bcd610855ced8ddc1eeac729b95efffe35", 422 | "sha256:b2def86b2a6b6ed3866c95521030b72613c71388cb12e9a2910e7850f282b359", 423 | "sha256:b3e30b0d9d7b75bafb9a117be949743ef1e4f64e4ce039a2d0365979749e4901", 424 | "sha256:b73fb2d28e711760fd0540e06d2e4c660a4ab4ef4b7896e591f7e72ef743a88a", 425 | "sha256:bab1e2caa9cc4305a09f4313d046b68d0f9b334c57e7dbc445c11838dafbc84a", 426 | "sha256:bb91ea3879261b03979023a066a20bb201d5eff89d96169e3fc42a58b56b4b8a", 427 | "sha256:bd963e3da28b9f7bf46c23382f5b810460b6adc3ae8281272fca2a8b9a20f7bc", 428 | "sha256:bdd00007f09f1881baa240324226266b6d808b4c841ff2c3ceaaf1d5d211d591", 429 | "sha256:c993c9aa8de25aba9eab380c99b3581644b7cf63fbf3c8a7d3522750734cb388", 430 | "sha256:cb364e395822fd292ef2b6ae10d23013818ff027fc23211334dfafdcf83c4788", 431 | "sha256:d177f0c5098df7096bd10bfdc1a48f277b882b8b705cdabba2c437a40eb5d338", 432 | "sha256:d8f1c12facfc1f30459becf9f1c0c6706b4b0c5e909153cec69e59acb6f3615b", 433 | "sha256:dcce37369baac055cbd6c57e217ce731435c0601c55a7ac79694c5ee316e30b8", 434 | "sha256:e29b675554268a7883f16dfd6525df294c40609d15b0615d40ae64a5bcbf887b", 435 | "sha256:ebf09d5d76fc0a5e686df634e50f795c5150fd736d3acc071c657609ba74be5e", 436 | "sha256:f18ec27ee873c9435aa51df6116d29583852cec42ad425357442d264dd61b630", 437 | "sha256:f8428f293f9f541044fc52192faa64761a1968959db93fdd18152647f9ab739c", 438 | "sha256:f86c7a4413ab4ccca728fd822af4c87d134ee2c3e01375544b7f0aabd4b4c5b9", 439 | "sha256:fae4919a236a59c1e2b6de43d13522f1b04f02939d98c1c3382b5b3f9c3e867c" 440 | ], 441 | "version": "==0.1.3" 442 | }, 443 | "tqdm": { 444 | "hashes": [ 445 | "sha256:1ee4f8a893eb9bef51c6e35730cebf234d5d0b6bd112b0271e10ed7c24a02bd9", 446 | "sha256:6cd52cdf0fef0e0f543299cfc96fec90d7b8a7e88745f411ec33eb44d5ed3531" 447 | ], 448 | "version": "==4.66.2" 449 | } 450 | }, 451 | "develop": {} 452 | } 453 | --------------------------------------------------------------------------------