From 84e86bbbd7a60f998a1a26f28b8dda99e42026d2 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Fri, 1 Sep 2023 10:09:47 -0300 Subject: [PATCH 001/114] add batch airgapped firmware signer script more yahboom compatibility --- krux | 4 +- odudex.PEM | 3 + sign_release.py | 142 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 odudex.PEM create mode 100644 sign_release.py diff --git a/krux b/krux index 950aee6ba..8a562122a 100755 --- a/krux +++ b/krux @@ -74,7 +74,7 @@ elif [ "$1" == "flash" ]; then elif [ "$device" == "maixpy_amigo_ips" ]||[ "$device" == "maixpy_amigo_tft" ]||[ "$device" == "maixpy_bit" ]; then # https://devicehunt.com/view/type/usb/vendor/0403/device/6010 device_vendor_product_id="0403:6010" - elif [ "$device" == "maixpy_dock" ]; then + elif [ "$device" == "maixpy_dock" ]||[ "$device" == "maixpy_yahboom" ]; then # https://devicehunt.com/view/type/usb/vendor/1a86/device/7523 device_vendor_product_id="1a86:7523" fi @@ -191,7 +191,7 @@ elif [ "$1" == "build-release" ]; then cp -f ktool-win.exe ../$release_dir/ktool-win.exe cd .. - devices=("maixpy_m5stickv" "maixpy_amigo_ips" "maixpy_amigo_tft" "maixpy_bit" "maixpy_dock") + devices=("maixpy_m5stickv" "maixpy_amigo_ips" "maixpy_amigo_tft" "maixpy_bit" "maixpy_dock" "maixpy_yahboom") for device in ${devices[@]}; do ./krux build $device mkdir -p $release_dir/$device diff --git a/odudex.PEM b/odudex.PEM new file mode 100644 index 000000000..2ce42000d --- /dev/null +++ b/odudex.PEM @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MDYwEAYHKoZIzj0CAQYFK4EEAAoDIgACgw+uOhd7ie6I08S4q3vIZtYBP8TmBuQJkVDbAP4sty0= +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/sign_release.py b/sign_release.py new file mode 100644 index 000000000..db40b3124 --- /dev/null +++ b/sign_release.py @@ -0,0 +1,142 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2023 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +# This script batch signs firmware releases through air-gapped interaction with +# a Krux signing device. +# Load a 24 words mnemonic in testnet to sign the firmware hashes as messages. + +import os +import cv2 +import hashlib +from io import StringIO +import base64 +from qrcode import QRCode +import subprocess + +DEVICES = [ + "maixpy_m5stickv", + "maixpy_amigo_ips", + "maixpy_amigo_tft", + "maixpy_bit", + "maixpy_dock", + "maixpy_yahboom", +] + + +def release_folder(): + """Returns release folder specified on pyproject.toml""" + with open("pyproject.toml", "r") as project_file: + lines = project_file.readlines() + for line in lines: + if line.startswith("version"): + version = line.split('"')[-2] + release_folder_name = "krux-v" + version + print("Signing firmwares in:", release_folder_name) + return release_folder_name + + +def print_qr_code(data): + """Prints ascii QR code""" + qr_code = QRCode() + qr_code.add_data(data) + qr_string = StringIO() + qr_code.print_ascii(out=qr_string, invert=True) + print(qr_string.getvalue()) + + +def scan(): + """Opens a scan window and uses cv2 to detect and decode a QR code, returning its data""" + vid = cv2.VideoCapture(0) + detector = cv2.QRCodeDetector() + qr_data = None + while True: + # Capture the video frame by frame + _, frame = vid.read() + qr_data, _, _ = detector.detectAndDecode(frame) + if len(qr_data) > 0: + break + # Display the resulting frame + cv2.imshow("frame", frame) + # the 'q' button is set as the + # quitting button you may use any + # desired button of your choice + if cv2.waitKey(1) & 0xFF == ord("q"): + break + # After the loop release the cap object + vid.release() + # Destroy all the windows + cv2.destroyAllWindows() + return qr_data + + +def verify(file_to_verify, key_to_verify, signature_to_verify): + """Uses openssl to verify the signature and public key""" + print("Verifying signature of",file_to_verify.split("/")[1] ) + verification = subprocess.run( + "openssl sha256 <%s -binary | openssl pkeyutl -verify -pubin -inkey %s -sigfile %s" + % (file_to_verify, key_to_verify, signature_to_verify), + shell=True, + capture_output=True, + text=True, + check=True + ) + print(verification.stdout) + + +# Main routine +folder = release_folder() +for device in DEVICES: + print("Signing", device) + file_name = os.path.join(folder, device, "firmware.bin") + hash_string = "" + try: + with open(file_name, "rb") as f: + sig_bytes = f.read() # read file as bytes + hash_string = hashlib.sha256(sig_bytes).hexdigest() + except: + print("Unable to read target file") + # Prints the hash of the file + print("Hash of", file_name, ":") + print(hash_string + "\n") + + # Prints the QR code + print_qr_code(hash_string) + + # Scans the signature QR code + _ = input("Press enter to scan signature") + signature = scan() + binary_signature = base64.b64decode(signature.encode()) + # Prints signature + print("Signature:", signature) + # Saves a signature file + signature_file = os.path.join(folder, device, "firmware.bin.sig") + + print("Saving a signature file:", signature_file, "\n\n") + with open(signature_file, "wb") as f: + f.write(binary_signature) + +# Verify signatures +PUBLIC_KEY_FILE = "odudex.PEM" # "selfcustody.PEM" +for device in DEVICES: + file_name = os.path.join(folder, device, "firmware.bin") + signature_file = os.path.join(folder, device, "firmware.bin.sig") + verify(file_name, PUBLIC_KEY_FILE, signature_file) From 2bc85789f58f64fce20e96134d278241fd7d4ad9 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Wed, 30 Aug 2023 15:23:04 -0300 Subject: [PATCH 002/114] event/irq based touch and buttons --- src/krux/buttons.py | 158 ++++++++++++++++++++++++++++++++ src/krux/camera.py | 32 +++++-- src/krux/display.py | 16 ---- src/krux/firmware.py | 21 +++-- src/krux/input.py | 100 ++++++++++---------- src/krux/pages/__init__.py | 107 ++++++++++----------- src/krux/pages/addresses.py | 8 +- src/krux/pages/encryption_ui.py | 12 +-- src/krux/pages/home.py | 10 +- src/krux/pages/login.py | 16 ++-- src/krux/pages/print_page.py | 2 +- src/krux/pages/settings_page.py | 4 +- src/krux/pages/tiny_seed.py | 36 +++----- src/krux/pages/tools.py | 2 +- src/krux/rotary.py | 30 +++--- src/krux/touch.py | 108 ++++++++++++++-------- src/krux/touchscreens/ft6x36.py | 2 +- 17 files changed, 426 insertions(+), 238 deletions(-) create mode 100644 src/krux/buttons.py diff --git a/src/krux/buttons.py b/src/krux/buttons.py new file mode 100644 index 000000000..4f9ac1c38 --- /dev/null +++ b/src/krux/buttons.py @@ -0,0 +1,158 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2023 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from Maix import GPIO +from fpioa_manager import fm +import time + +DEBOUNCE = 250 # milliseconds + +PRESSED = 0 +RELEASED = 1 + + +def __handler__(pin_num=None): + """GPIO interrupt handler""" + buttons_control.event_handler(pin_num) + + +class TactileButtons: + """Interface with Buttons""" + + def __init__(self): + self.enter = None + self.page = None + self.page_prev = None + self.enter_event_flag = False + self.page_event_flag = False + self.page_prev_event_flag = False + self.time_frame = 0 + + def event_handler(self, pin_num): + """Set up a button event flag according to interruption source""" + if time.ticks_ms() > self.time_frame + DEBOUNCE: + if pin_num == buttons_control.enter: + self.enter_event_flag = True + elif pin_num == buttons_control.page: + self.page_event_flag = True + elif pin_num == buttons_control.page_prev: + self.page_prev_event_flag = True + self.time_frame = time.ticks_ms() + + def init_enter(self, pin): + """Register ENTER button IO""" + fm.register(pin, fm.fpioa.GPIOHS21) + self.enter = GPIO(GPIO.GPIOHS21, GPIO.IN, GPIO.PULL_UP) + self.enter.irq(__handler__, GPIO.IRQ_FALLING) + + def init_page(self, pin): + """Register PAGE button IO""" + fm.register(pin, fm.fpioa.GPIOHS22) + self.page = GPIO(GPIO.GPIOHS22, GPIO.IN, GPIO.PULL_UP) + self.page.irq(__handler__, GPIO.IRQ_FALLING) + + def init_page_prev(self, pin): + """Register PAGE_PREV button IO""" + fm.register(pin, fm.fpioa.GPIOHS0) + self.page_prev = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP) + self.page_prev.irq(__handler__, GPIO.IRQ_FALLING) + + +buttons_control = TactileButtons() # Singleton + + +class Button: + """Generic button handler format""" + + def __init__(self) -> None: + pass + + def value(self): + """Returns IO state""" + return RELEASED + + def event(self): + """Returns event state""" + return False + + +class ButtonEnter: + """Class to manage button ENTER state and events""" + + def __init__(self, pin) -> None: + buttons_control.init_enter(pin) + + def value(self): + """Returns the ENTER IO state""" + if buttons_control.enter is not None: + return buttons_control.enter.value() + return RELEASED + + def event(self): + """Returns the ENTER event state""" + if buttons_control.enter is not None: + if buttons_control.enter_event_flag: + buttons_control.enter_event_flag = False + return True + return False + + +class ButtonPage: + """Class to manage button PAGE state and events""" + + def __init__(self, pin) -> None: + buttons_control.init_page(pin) + + def value(self): + """Returns the PAGE IO state""" + if buttons_control.page is not None: + return buttons_control.page.value() + return RELEASED + + def event(self): + """Returns the PAGE event state""" + if buttons_control.page is not None: + if buttons_control.page_event_flag: + buttons_control.page_event_flag = False + return True + return False + + +class ButtonPagePrev: + """Class to manage button PAGE_PREV state and events""" + + def __init__(self, pin) -> None: + buttons_control.init_page_prev(pin) + + def value(self): + """Returns the PAGE_PREV IO state""" + if buttons_control.page_prev is not None: + return buttons_control.page_prev.value() + return RELEASED + + def event(self): + """Returns the PAGE_PREV event state""" + if buttons_control.page_prev is not None: + if buttons_control.page_prev_event_flag: + buttons_control.page_prev_event_flag = False + return True + return False diff --git a/src/krux/camera.py b/src/krux/camera.py index 722efdd9e..5fa6dcb72 100644 --- a/src/krux/camera.py +++ b/src/krux/camera.py @@ -36,13 +36,15 @@ class Camera: """Camera is a singleton interface for interacting with the device's camera""" def __init__(self): + self.initialized = False self.cam_id = None self.antiglare_enabled = False self.initialize_sensor() def initialize_sensor(self, grayscale=False): """Initializes the camera""" - sensor.reset(freq=16000000) + self.initialized = False + self.antiglare_enabled = False self.cam_id = sensor.get_id() if grayscale: sensor.set_pixformat(sensor.GRAYSCALE) @@ -115,13 +117,20 @@ def snapshot(self): img.rotation_corr(z_rotation=180) return img + def initialize_run(self): + self.initialize_sensor() + sensor.run(1) + + def stop_sensor(self): + gc.collect() + sensor.run(0) + def capture_qr_code_loop(self, callback): """Captures either singular or animated QRs and parses their contents until all parts of the message have been captured. The part data are then ordered and assembled into one message and returned. """ - self.initialize_sensor() - sensor.run(1) + self.initialize_run() parser = QRPartParser() @@ -130,6 +139,10 @@ def capture_qr_code_loop(self, callback): while True: wdt.feed() command = callback(parser.total_count(), parser.parsed_count(), new_part) + if not self.initialized: + # Ignores first callback as it may contain unintentional events + self.initialized = True + command = 0 if command == 1: break new_part = False @@ -157,8 +170,7 @@ def capture_qr_code_loop(self, callback): if parser.is_complete(): break - gc.collect() - sensor.run(0) + self.stop_sensor() if parser.is_complete(): return (parser.result(), parser.format) @@ -168,8 +180,7 @@ def capture_entropy(self, callback): """Captures camera's entropy as the hash of image buffer""" import hashlib - self.initialize_sensor() - sensor.run(1) + self.initialize_run() command = 0 while True: @@ -178,6 +189,10 @@ def capture_entropy(self, callback): img = self.snapshot() command = callback() + if not self.initialized: + # Ignores first callback as it may contain unintentional events + self.initialized = True + command = 0 if command > 0: break @@ -185,8 +200,7 @@ def capture_entropy(self, callback): img.lens_corr(strength=1.0, zoom=0.56) lcd.display(img) - gc.collect() - sensor.run(0) + self.stop_sensor() # User cancelled if command == 2: diff --git a/src/krux/display.py b/src/krux/display.py index 83d81f616..27a59bbd9 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -19,7 +19,6 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -import time import lcd import board from machine import I2C @@ -35,8 +34,6 @@ MAX_BACKLIGHT = 8 MIN_BACKLIGHT = 1 -FLASH_MSG_TIME = 2000 - class Display: """Display is a singleton interface for interacting with the device's display""" @@ -315,19 +312,6 @@ def draw_centered_text(self, text, color=theme.fg_color, bg_color=theme.bg_color offset_y = max(0, (self.height() - lines_height) // 2) self.draw_hcentered_text(text, offset_y, color, bg_color) - def flash_text( - self, - text, - color=theme.fg_color, - bg_color=theme.bg_color, - duration=FLASH_MSG_TIME, - ): - """Flashes text centered on the display for duration ms""" - self.clear() - self.draw_centered_text(text, color, bg_color) - time.sleep_ms(duration) - self.clear() - def draw_qr_code( self, offset_y, qr_code, dark_color=QR_DARK_COLOR, light_color=QR_LIGHT_COLOR ): diff --git a/src/krux/firmware.py b/src/krux/firmware.py index 383a4e676..4dd7b74c2 100644 --- a/src/krux/firmware.py +++ b/src/krux/firmware.py @@ -32,6 +32,8 @@ from .krux_settings import t from .wdt import wdt +FLASH_MSG_TIME = 2000 + MAX_FIRMWARE_SIZE = 0x300000 FIRMWARE_SLOT_1 = 0x00080000 @@ -171,6 +173,13 @@ def sha256(firmware_filename, firmware_size=None): def upgrade(): """Installs new firmware from SD card""" + def flash_text(text): + """Flashes text centered on the display for duration ms""" + display.clear() + display.draw_centered_text(text) + time.sleep_ms(FLASH_MSG_TIME) + display.clear() + firmware_path = "" try: firmware_filenames = list( @@ -204,21 +213,21 @@ def upgrade(): return False if new_size > MAX_FIRMWARE_SIZE: - display.flash_text(t("Firmware exceeds max size: %d") % MAX_FIRMWARE_SIZE) + flash_text(t("Firmware exceeds max size: %d") % MAX_FIRMWARE_SIZE) return False pubkey = None try: pubkey = ec.PublicKey.from_string(SIGNER_PUBKEY) except: - display.flash_text(t("Invalid public key")) + flash_text(t("Invalid public key")) return False - + sig = None try: sig = open(firmware_path + ".sig", "rb").read() except: - display.flash_text(t("Missing signature file")) + flash_text(t("Missing signature file")) return False try: @@ -237,7 +246,7 @@ def upgrade(): boot_config_sector = flash.read(BACKUP_BOOT_CONFIG_SECTOR_ADDRESS, 4096) address, _, entry_index = find_active_firmware(boot_config_sector) if address is None: - display.flash_text(t("Invalid bootloader")) + flash_text(t("Invalid bootloader")) return False # Write new firmware to the opposite slot @@ -276,5 +285,5 @@ def status_text(text): 4096, ) - display.flash_text(t("Upgrade complete.\n\nShutting down..")) + flash_text(t("Upgrade complete.\n\nShutting down..")) return True diff --git a/src/krux/input.py b/src/krux/input.py index d9846bb6f..dfe601dc8 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -21,10 +21,8 @@ # THE SOFTWARE. import time import board -from Maix import GPIO -from fpioa_manager import fm from .wdt import wdt -from .touch import Touch +from .buttons import PRESSED, RELEASED BUTTON_ENTER = 0 BUTTON_PAGE = 1 @@ -38,9 +36,6 @@ QR_ANIM_PERIOD = 300 # milliseconds LONG_PRESS_PERIOD = 1000 # milliseconds -PRESSED = 0 -RELEASED = 1 - BUTTON_WAIT_PRESS_DELAY = 10 @@ -52,8 +47,9 @@ def __init__(self): self.enter = None if "BUTTON_A" in board.config["krux"]["pins"]: - fm.register(board.config["krux"]["pins"]["BUTTON_A"], fm.fpioa.GPIOHS21) - self.enter = GPIO(GPIO.GPIOHS21, GPIO.IN, GPIO.PULL_UP) + from .buttons import ButtonEnter + + self.enter = ButtonEnter(board.config["krux"]["pins"]["BUTTON_A"]) self.page = None self.page_prev = None @@ -64,12 +60,16 @@ def __init__(self): self.page_prev = EncoderPagePrev() else: if "BUTTON_B" in board.config["krux"]["pins"]: - fm.register(board.config["krux"]["pins"]["BUTTON_B"], fm.fpioa.GPIOHS22) - self.page = GPIO(GPIO.GPIOHS22, GPIO.IN, GPIO.PULL_UP) + from .buttons import ButtonPage + + self.page = ButtonPage(board.config["krux"]["pins"]["BUTTON_B"]) if "BUTTON_C" in board.config["krux"]["pins"]: - fm.register(board.config["krux"]["pins"]["BUTTON_C"], fm.fpioa.GPIOHS0) - self.page_prev = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP) + from .buttons import ButtonPagePrev + + self.page_prev = ButtonPagePrev( + board.config["krux"]["pins"]["BUTTON_C"] + ) else: try: from pmu import PMU_Button @@ -85,28 +85,26 @@ def __init__(self): "touch" in board.config["krux"]["display"] and board.config["krux"]["display"]["touch"] ): + from .touch import Touch + self.touch = Touch( - board.config["lcd"]["width"], board.config["lcd"]["height"] + board.config["lcd"]["width"], + board.config["lcd"]["height"], + board.config["krux"]["pins"]["TOUCH_IRQ"], ) self.buttons_active = False def enter_value(self): - """Intermediary method to pull button A state, if available""" - if self.enter is not None: - return self.enter.value() - return RELEASED + """Intermediary method to pull button ENTER state""" + return self.enter.value() def page_value(self): - """Intermediary method to pull button B state, if available""" - if self.page is not None: - return self.page.value() - return RELEASED + """Intermediary method to pull button PAGE state""" + return self.page.value() def page_prev_value(self): - """Intermediary method to pull button C state, if available""" - if self.page_prev is not None: - return self.page_prev.value() - return RELEASED + """Intermediary method to pull button PAGE_PREV state""" + return self.page_prev.value() def touch_value(self): """Intermediary method to pull touch state, if touch available""" @@ -114,6 +112,23 @@ def touch_value(self): return self.touch.value() return RELEASED + def enter_event(self): + """Intermediary method to pull button ENTER event""" + return self.enter.event() + + def page_event(self): + """Intermediary method to pull button PAGE state""" + return self.page.event() + + def page_prev_event(self): + """Intermediary method to pull button PAGE_PREV state""" + return self.page_prev.event() + + def touch_event(self): + if self.touch is not None: + return self.touch.event() + return False + def swipe_right_value(self): """Intermediary method to pull touch gesture, if touch available""" if self.touch is not None: @@ -138,32 +153,18 @@ def swipe_down_value(self): return self.touch.swipe_down_value() return RELEASED - def wait_for_release(self): - """Loop until all buttons are released (if currently pressed)""" - while True: - if self.enter_value() == RELEASED and self.touch_value() == RELEASED: - if "ENCODER" in board.config["krux"]["pins"]: - # Encoder is event based, this check may disable event flag unintentionally - break - # TODO: Change standard buttons to be event(interrupt) based too - # So presses during high processing time(camera and animated QR) won't be lost - if self.page_value() == RELEASED and self.page_prev_value() == RELEASED: - break - self.entropy += 1 - wdt.feed() - def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD): """Wait for first button press or for wait_duration ms. Use block to wait indefinitely""" start_time = time.ticks_ms() while True: - if self.enter_value() == PRESSED: + if self.enter_event(): return BUTTON_ENTER - if self.page_value() == PRESSED: + if self.page_event(): return BUTTON_PAGE - if self.page_prev_value() == PRESSED: + if self.page_prev_event(): return BUTTON_PAGE_PREV - if self.touch_value() == PRESSED: + if self.touch_event(): return BUTTON_TOUCH self.entropy += 1 wdt.feed() # here is where krux spends most of its time @@ -173,9 +174,8 @@ def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD): def wait_for_button(self, block=True): """Waits for any button to release, optionally blocking if block=True. - Returns the button that was released, or None if nonblocking. + Returns the button that was released, or None if non blocking. """ - self.wait_for_release() btn = self.wait_for_press(block) if btn == BUTTON_ENTER: @@ -213,6 +213,8 @@ def wait_for_button(self, block=True): while self.touch_value() == PRESSED: self.entropy += 1 wdt.feed() + # Flush intermediary touch interrupt events + _ = self.touch_event() self.buttons_active = False if self.swipe_right_value() == PRESSED: return SWIPE_RIGHT @@ -223,5 +225,11 @@ def wait_for_button(self, block=True): if self.swipe_down_value() == PRESSED: return SWIPE_DOWN return BUTTON_TOUCH - return None + + def flush_events(self): + """Clean eventual event flags unintentionally collected""" + _ = self.enter_event() + _ = self.page_event() + _ = self.page_prev_event() + _ = self.touch_event() diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 0726dec27..d47042c67 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -43,12 +43,13 @@ MENU_EXIT = 1 MENU_SHUTDOWN = 2 +FLASH_MSG_TIME = 2000 + ESC_KEY = 1 FIXED_KEYS = 3 # 'More' key only appears when there are multiple keysets ANTI_GLARE_WAIT_TIME = 500 QR_CODE_STEP_TIME = 100 -CAMERA_INIT_TIME = 1000 SHUTDOWN_WAIT_TIME = 300 TOGGLE_BRIGHTNESS = (BUTTON_PAGE, BUTTON_PAGE_PREV) @@ -85,6 +86,20 @@ def esc_prompt(self): return ESC_KEY return None + def flash_text( + self, + text, + color=theme.fg_color, + bg_color=theme.bg_color, + duration=FLASH_MSG_TIME, + ): + """Flashes text centered on the display for duration ms""" + self.ctx.display.clear() + self.ctx.display.draw_centered_text(text, color, bg_color) + time.sleep_ms(duration) + self.ctx.display.clear() + self.ctx.input.flush_events() + def capture_from_keypad( self, title, @@ -170,40 +185,35 @@ def capture_qr_code(self): def callback(part_total, num_parts_captured, new_part): # Turn on the light as long as the enter button is held down (M5stickV and Amigo) - if self._time_to_check_input(): - if self.ctx.light: - if self.ctx.input.enter_value() == PRESSED: - self.ctx.light.turn_on() + if self.ctx.light: + if self.ctx.input.enter_value() == PRESSED: + self.ctx.light.turn_on() + else: + self.ctx.light.turn_off() + # If board don't have light, ENTER stops the capture + elif self.ctx.input.enter_event(): + return 1 + + # Anti-glare mode (M5stickV and Amigo) + if self.ctx.input.page_event(): + if self.ctx.camera.has_antiglare(): + self._time_frame = time.ticks_ms() + self.ctx.display.to_portrait() + if not self.ctx.camera.antiglare_enabled: + self.ctx.camera.enable_antiglare() + self.ctx.display.draw_centered_text(t("Anti-glare enabled")) else: - self.ctx.light.turn_off() - # If board don't have light, ENTER stops the capture - elif self.ctx.input.enter_value() == PRESSED: - return 1 - - # Anti-glare mode (M5stickV and Amigo) - if self.ctx.input.page_value() == PRESSED: - if self.ctx.camera.has_antiglare(): - self._time_frame = time.ticks_ms() - self.ctx.display.to_portrait() - if not self.ctx.camera.antiglare_enabled: - self.ctx.camera.enable_antiglare() - self.ctx.display.draw_centered_text(t("Anti-glare enabled")) - else: - self.ctx.camera.disable_antiglare() - self.ctx.display.draw_centered_text( - t("Anti-glare disabled") - ) - time.sleep_ms(ANTI_GLARE_WAIT_TIME) - self.ctx.display.to_landscape() - return 0 - return 1 - - # Exit the capture loop with PAGE_PREV or TOUCH - if ( - self.ctx.input.page_prev_value() == PRESSED - or self.ctx.input.touch_value() == PRESSED - ): - return 1 + self.ctx.camera.disable_antiglare() + self.ctx.display.draw_centered_text(t("Anti-glare disabled")) + time.sleep_ms(ANTI_GLARE_WAIT_TIME) + self.ctx.display.to_landscape() + self.ctx.input.flush_events() + return 0 + return 1 + + # Exit the capture loop with PAGE_PREV or TOUCH + if self.ctx.input.page_prev_event() or self.ctx.input.touch_event(): + return 1 # Indicate progress to the user that a new part was captured if new_part: @@ -248,28 +258,18 @@ def callback(part_total, num_parts_captured, new_part): ) return (code, qr_format) - def _time_to_check_input(self): - return time.ticks_ms() > self._time_frame + CAMERA_INIT_TIME - def capture_camera_entropy(self): "Helper to capture camera's entropy as the hash of image buffer" self._time_frame = time.ticks_ms() def callback(): - if self._time_to_check_input(): - # Accepted - if ( - self.ctx.input.enter_value() == PRESSED - or self.ctx.input.touch_value() == PRESSED - ): - return 1 - - # Exited - if ( - self.ctx.input.page_value() == PRESSED - or self.ctx.input.page_prev_value() == PRESSED - ): - return 2 + # Accepted + if self.ctx.input.enter_event() or self.ctx.input.touch_event(): + return 1 + + # Exited + if self.ctx.input.page_event() or self.ctx.input.page_prev_event(): + return 2 return 0 self.ctx.display.clear() @@ -320,11 +320,13 @@ def display_qr_codes(self, data, qr_format, title=""): ) self.ctx.display.draw_hcentered_text(subtitle, offset_y) i = (i + 1) % num_parts - # There are cases we can allow any btn to change the screen + self.ctx.input.buttons_active = True btn = self.ctx.input.wait_for_button(num_parts == 1) if btn in TOGGLE_BRIGHTNESS: bright = not bright elif btn in PROCEED: + if self.ctx.input.touch is not None: + self.ctx.input.buttons_active = False done = True # interval done in input.py using timers @@ -556,6 +558,7 @@ def run_loop(self, start_from_index=None): self._draw_menu(selected_item_index) self.draw_status_bar() + self.ctx.input.flush_events() if start_from_submenu: status = self._clicked_item(selected_item_index) diff --git a/src/krux/pages/addresses.py b/src/krux/pages/addresses.py index b4143381d..af3f0ba95 100644 --- a/src/krux/pages/addresses.py +++ b/src/krux/pages/addresses.py @@ -50,7 +50,7 @@ def addresses_menu(self): """Handler for the 'address' menu item""" # only show address for single-sig or multisig with wallet output descriptor loaded if not self.ctx.wallet.is_loaded() and self.ctx.wallet.is_multisig(): - self.ctx.display.flash_text( + self.flash_text( t("Please load a wallet output descriptor"), theme.error_color ) return MENU_CONTINUE @@ -166,7 +166,7 @@ def pre_scan_address(self): """Handler for the 'scan address' menu item""" # only show address for single-sig or multisig with wallet output descriptor loaded if not self.ctx.wallet.is_loaded() and self.ctx.wallet.is_multisig(): - self.ctx.display.flash_text( + self.flash_text( t("Please load a wallet output descriptor"), theme.error_color ) return MENU_CONTINUE @@ -186,7 +186,7 @@ def scan_address(self, addr_type=0): """Handler for the 'receive' or 'change' menu item""" data, qr_format = self.capture_qr_code() if data is None or qr_format != FORMAT_NONE: - self.ctx.display.flash_text(t("Failed to load address"), theme.error_color) + self.flash_text(t("Failed to load address"), theme.error_color) return MENU_CONTINUE addr = None @@ -195,7 +195,7 @@ def scan_address(self, addr_type=0): addr = parse_address(data) except: - self.ctx.display.flash_text(t("Invalid address"), theme.error_color) + self.flash_text(t("Invalid address"), theme.error_color) return MENU_CONTINUE self.show_address(data, title=addr, qr_format=qr_format) diff --git a/src/krux/pages/encryption_ui.py b/src/krux/pages/encryption_ui.py index eb93ae298..e352f9bf9 100644 --- a/src/krux/pages/encryption_ui.py +++ b/src/krux/pages/encryption_ui.py @@ -78,10 +78,10 @@ def load_qr_encryption_key(self): """Loads and returns a key from a QR code""" data, _ = self.capture_qr_code() if data is None: - self.ctx.display.flash_text(t("Failed to load key"), theme.error_color) + self.flash_text(t("Failed to load key"), theme.error_color) return None if len(data) > ENCRYPTION_KEY_MAX_LEN: - self.ctx.display.flash_text( + self.flash_text( t("Maximum length exceeded (%s)") % ENCRYPTION_KEY_MAX_LEN, theme.error_color, ) @@ -127,7 +127,7 @@ def store_mnemonic_on_memory(self, sd_card=False): key_capture = EncryptionKey(self.ctx) key = key_capture.encryption_key() if key is None: - self.ctx.display.flash_text(t("Mnemonic was not encrypted")) + self.flash_text(t("Mnemonic was not encrypted")) return version = Settings().encryption.version @@ -156,7 +156,7 @@ def store_mnemonic_on_memory(self, sd_card=False): if mnemonic_id in (None, ESC_KEY): mnemonic_id = self.ctx.wallet.key.fingerprint_hex_str() if mnemonic_id in mnemonic_storage.list_mnemonics(sd_card): - self.ctx.display.flash_text( + self.flash_text( t("ID already exists\n") + t("Encrypted mnemonic was not stored") ) del mnemonic_storage @@ -181,7 +181,7 @@ def encrypted_qr_code(self): key_capture = EncryptionKey(self.ctx) key = key_capture.encryption_key() if key is None: - self.ctx.display.flash_text(t("Mnemonic was not encrypted")) + self.flash_text(t("Mnemonic was not encrypted")) return version = Settings().encryption.version i_vector = None @@ -191,7 +191,7 @@ def encrypted_qr_code(self): t("Aditional entropy from camera required for AES-CBC mode") ) if not self.prompt(t("Proceed?"), self.ctx.display.bottom_prompt_line): - self.ctx.display.flash_text(t("Mnemonic was not encrypted")) + self.flash_text(t("Mnemonic was not encrypted")) return i_vector = self.capture_camera_entropy()[:AES_BLOCK_SIZE] mnemonic_id = None diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 05ed46fb2..db3e4809a 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -227,7 +227,7 @@ def wallet(self): def _load_wallet(self): wallet_data, qr_format = self.capture_qr_code() if wallet_data is None: - self.ctx.display.flash_text( + self.flash_text( t("Failed to load output descriptor"), theme.error_color ) return MENU_CONTINUE @@ -245,7 +245,7 @@ def _load_wallet(self): "Wallet output descriptor: %s" % self.ctx.wallet.descriptor.to_string() ) - self.ctx.display.flash_text(t("Wallet output descriptor loaded!")) + self.flash_text(t("Wallet output descriptor loaded!")) # BlueWallet single sig descriptor without fingerprint if ( @@ -318,7 +318,7 @@ def sign_psbt(self): if data is None: # Both the camera and the file on SD card failed! - self.ctx.display.flash_text(t("Failed to load PSBT"), theme.error_color) + self.flash_text(t("Failed to load PSBT"), theme.error_color) return MENU_CONTINUE # PSBT read OK! Will try to sign @@ -428,7 +428,7 @@ def sign_message(self): pass if data is None: - self.ctx.display.flash_text(t("Failed to load message"), theme.error_color) + self.flash_text(t("Failed to load message"), theme.error_color) return MENU_CONTINUE # message read OK! @@ -551,7 +551,7 @@ def _save_file( else: sd.write(filename, data) self.ctx.display.clear() - self.ctx.display.flash_text( + self.flash_text( t("Saved to SD card:\n%s") % filename ) else: diff --git a/src/krux/pages/login.py b/src/krux/pages/login.py index 0d5a86ff6..c8ad9ab9c 100644 --- a/src/krux/pages/login.py +++ b/src/krux/pages/login.py @@ -260,7 +260,7 @@ def delete_roll(buffer): if len(rolls) > 0: rolls.pop() elif len(rolls) < min_rolls: # Not enough to Go - self.ctx.display.flash_text(t("Not enough rolls!")) + self.flash_text(t("Not enough rolls!")) else: # Go break @@ -293,12 +293,10 @@ def delete_roll(buffer): def _load_qr_passphrase(self): data, _ = self.capture_qr_code() if data is None: - self.ctx.display.flash_text( - t("Failed to load passphrase"), theme.error_color - ) + self.flash_text(t("Failed to load passphrase"), theme.error_color) return MENU_CONTINUE if len(data) > PASSPHRASE_MAX_LEN: - self.ctx.display.flash_text( + self.flash_text( t("Maximum length exceeded (%s)") % PASSPHRASE_MAX_LEN, theme.error_color, ) @@ -414,7 +412,7 @@ def _encrypted_qr_code(self, data): key_capture = EncryptionKey(self.ctx) key = key_capture.encryption_key() if key is None: - self.ctx.display.flash_text(t("Mnemonic was not decrypted")) + self.flash_text(t("Mnemonic was not decrypted")) return None self.ctx.display.clear() self.ctx.display.draw_centered_text(t("Processing ...")) @@ -430,7 +428,7 @@ def load_key_from_qr_code(self): """Handler for the 'via qr code' menu item""" data, qr_format = self.capture_qr_code() if data is None: - self.ctx.display.flash_text(t("Failed to load mnemonic"), theme.error_color) + self.flash_text(t("Failed to load mnemonic"), theme.error_color) return MENU_CONTINUE words = [] @@ -465,7 +463,7 @@ def load_key_from_qr_code(self): if not words: words = self._encrypted_qr_code(data) if not words or (len(words) != 12 and len(words) != 24): - self.ctx.display.flash_text(t("Invalid mnemonic length"), theme.error_color) + self.flash_text(t("Invalid mnemonic length"), theme.error_color) return MENU_CONTINUE return self._load_key_from_words(words) @@ -773,7 +771,7 @@ def load_key_from_tiny_seed_image(self): words = tiny_scanner.scanner(w24) del tiny_scanner if words is None: - self.ctx.display.flash_text(t("Failed to load mnemonic"), theme.error_color) + self.flash_text(t("Failed to load mnemonic"), theme.error_color) return MENU_CONTINUE return self._load_key_from_words(words) diff --git a/src/krux/pages/print_page.py b/src/krux/pages/print_page.py index 7e3bbace2..53a76dd4a 100644 --- a/src/krux/pages/print_page.py +++ b/src/krux/pages/print_page.py @@ -52,7 +52,7 @@ def print_qr(self, data, qr_format=FORMAT_NONE, title="", width=33, is_qr=False) if a printer is connected """ if self.printer is None: - self.ctx.display.flash_text(t("Printer Driver not set!"), theme.error_color) + self.flash_text(t("Printer Driver not set!"), theme.error_color) return self.ctx.display.clear() if title: diff --git a/src/krux/pages/settings_page.py b/src/krux/pages/settings_page.py index 9639fd2e3..c66c77bf5 100644 --- a/src/krux/pages/settings_page.py +++ b/src/krux/pages/settings_page.py @@ -39,10 +39,10 @@ from ..input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV, BUTTON_TOUCH from ..krux_settings import t from ..sd_card import SDHandler -from ..display import FLASH_MSG_TIME from . import ( Page, Menu, + FLASH_MSG_TIME, MENU_CONTINUE, MENU_EXIT, ESC_KEY, @@ -336,7 +336,7 @@ def number_setting(self, settings_namespace, setting): if setting.value_range[0] <= new_value <= setting.value_range[1]: setting.__set__(settings_namespace, new_value) else: - self.ctx.display.flash_text( + self.flash_text( t("Value %s out of range: [%s, %s]") % (new_value, setting.value_range[0], setting.value_range[1]), theme.error_color, diff --git a/src/krux/pages/tiny_seed.py b/src/krux/pages/tiny_seed.py index 778dc4adb..965881b31 100644 --- a/src/krux/pages/tiny_seed.py +++ b/src/krux/pages/tiny_seed.py @@ -5,13 +5,13 @@ import sensor import time from embit.wordlists.bip39 import WORDLIST -from . import Page +from . import Page, FLASH_MSG_TIME from ..themes import theme from ..wdt import wdt from ..krux_settings import t -from ..display import DEFAULT_PADDING, FLASH_MSG_TIME +from ..display import DEFAULT_PADDING from ..camera import OV7740_ID, OV2640_ID, OV5642_ID -from ..input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV, BUTTON_TOUCH, PRESSED +from ..input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV, BUTTON_TOUCH # Tiny Seed last bit index positions according to checksums TS_LAST_BIT_NO_CS = 143 @@ -880,21 +880,14 @@ def _exit_camera(self): self.ctx.display.clear() def _check_buttons(self, w24, page): - if time.ticks_ms() > self.time_frame + 1000: - enter_or_touch = ( - self.ctx.input.enter_value() == PRESSED - or self.ctx.input.touch_value() == PRESSED - ) - if w24: - if page == 0 and enter_or_touch: - self.capturing = True - elif enter_or_touch: - return True - if ( - self.ctx.input.page_value() == PRESSED - or self.ctx.input.page_prev_value() == PRESSED - ): - return True + enter_or_touch = self.ctx.input.enter_event() or self.ctx.input.touch_event() + if w24: + if page == 0 and enter_or_touch: + self.capturing = True + elif enter_or_touch: + return True + if self.ctx.input.page_event() or self.ctx.input.page_prev_event(): + return True return False def _process_12w_scan(self, page_seed_numbers): @@ -914,7 +907,7 @@ def _process_12w_scan(self, page_seed_numbers): return words # Else esc command was given, turn camera on again and reset words self.ctx.display.clear() - self.ctx.display.flash_text( + self.flash_text( t("Scanning words 1-12 again") + "\n\n" + t("Wait for the capture") ) self._run_camera() @@ -935,14 +928,14 @@ def _process_24w_pg0_scan(self, page_seed_numbers): self.capturing = False if words is not None: # Fisrt 12 words confirmed, moving to 13-24 self.ctx.display.clear() - self.ctx.display.flash_text( + self.flash_text( t("Scanning words 13-24") + "\n\n" + t("Wait for the capture") ) self._run_camera() return words # Esc command was given self.ctx.display.clear() - self.ctx.display.flash_text( + self.flash_text( t("Scanning words 1-12 again") + "\n\n" + t("TOUCH or ENTER to capture") ) self._run_camera() # Run camera and rotate screen after message was given @@ -971,6 +964,7 @@ def scanner(self, w24=False): if precamera_ticks + FLASH_MSG_TIME > postcamera_ticks: time.sleep_ms(precamera_ticks + FLASH_MSG_TIME - postcamera_ticks) del message, precamera_ticks, postcamera_ticks + self.ctx.input.flush_events() # # Debug FPS 1/4 # clock = time.clock() # fps = 0 diff --git a/src/krux/pages/tools.py b/src/krux/pages/tools.py index 3a12cd820..8450d1935 100644 --- a/src/krux/pages/tools.py +++ b/src/krux/pages/tools.py @@ -97,7 +97,7 @@ def sd_check(self): select_file_handler=file_manager.show_file_details ) except OSError: - self.ctx.display.flash_text(t("SD card not detected"), theme.error_color) + self.flash_text(t("SD card not detected"), theme.error_color) return MENU_CONTINUE diff --git a/src/krux/rotary.py b/src/krux/rotary.py index e75fb6a01..a83d75276 100644 --- a/src/krux/rotary.py +++ b/src/krux/rotary.py @@ -25,7 +25,7 @@ from fpioa_manager import fm import time from .krux_settings import Settings -from .logging import logger as log +from .buttons import Button RIGHT = 1 LEFT = 0 @@ -57,8 +57,6 @@ def __init__(self): self.debounce = Settings().encoder.debounce - log.info("Encoder Initiated Pins: %d and %d" % (pins[0], pins[1])) - def process(self, new_state): """Sets new encoder state after position is changed""" @@ -103,29 +101,23 @@ def _left(): encoder = RotaryEncoder() # Singleton -class EncoderPage: +class EncoderPage(Button): """Encoder class that mimics Krux Page GPIO Button behavior""" - def __init__(self): - pass - - def value(self): - """Returns encoder status while mimics Krux GPIO Buttons behavior""" + def event(self): + """Returns encoder events while mimics Krux GPIO Buttons behavior""" if encoder.value > 0: encoder.value -= 1 - return 0 - return 1 + return True + return False -class EncoderPagePrev: +class EncoderPagePrev(Button): """Encoder class that mimics Krux Page_prev GPIO Button behavior""" - def __init__(self): - pass - - def value(self): - """Returns encoder status while mimics Krux GPIO Buttons behavior""" + def event(self): + """Returns encoder events while mimics Krux GPIO Buttons behavior""" if encoder.value < 0: encoder.value += 1 - return 0 - return 1 + return True + return False diff --git a/src/krux/touch.py b/src/krux/touch.py index 1ddffe761..8678a9fa4 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -22,10 +22,17 @@ # pylint: disable=R0902 import time +from Maix import GPIO +from fpioa_manager import fm + from .touchscreens.ft6x36 import FT6X36 from .logging import logger as log from .krux_settings import Settings +IDLE = 0 +PRESSED = 1 +RELEASED = 2 + SWIPE_THRESHOLD = 50 SWIPE_RIGHT = 1 SWIPE_LEFT = 2 @@ -35,13 +42,19 @@ TOUCH_S_PERIOD = 20 # Touch sample period - Min = 10 TOUCH_DEBOUNCE = 200 # Time to wait before sampling touch again after a release +event_flag = False + + +def __handler__(pin_num=None): + """GPIO interrupt handler""" + global event_flag + event_flag = True + class Touch: """Touch is a singleton API to interact with touchscreen driver""" - idle, press, release = 0, 1, 2 - - def __init__(self, width, height): + def __init__(self, width, height, irq_pin=None): """Touch API init - width and height are in Landscape mode For Krux width = max_y, height = max_x """ @@ -53,10 +66,14 @@ def __init__(self, width, height): self.press_point = [] self.release_point = (0, 0) self.gesture = None - self.state = Touch.idle + self.state = IDLE self.width, self.height = width, height self.touch_driver = FT6X36() self.touch_driver.threshold(Settings().touch.threshold) + if irq_pin: + fm.register(irq_pin, fm.fpioa.GPIOHS1) + self.enter = GPIO(GPIO.GPIOHS1, GPIO.IN, GPIO.PULL_UP) + self.enter.irq(__handler__, GPIO.IRQ_FALLING) def clear_regions(self): """Remove previously stored buttons map""" @@ -83,7 +100,7 @@ def _extract_index(self, data): if data[1] > region: index += 1 if index == 0 or index >= len(self.y_regions): # outside y areas - self.state = self.release + self.state = RELEASED else: index -= 1 if self.x_regions: # if 2D array @@ -95,7 +112,7 @@ def _extract_index(self, data): if x_index == 0 or x_index >= len( self.x_regions ): # outside x areas - self.state = self.release + self.state = RELEASED else: x_index -= 1 index += x_index @@ -105,12 +122,12 @@ def _extract_index(self, data): def _store_points(self, data): """Store pressed points and calculare an average pressed point""" - if self.state == self.idle: - self.state = self.press + if self.state == IDLE: + self.state = PRESSED self.press_point = [data] self.index = self._extract_index(self.press_point[0]) # Calculare an average (max. 10 samples) pressed point to increase precision - elif self.state == self.press and len(self.press_point) < 10: + elif self.state == PRESSED and len(self.press_point) < 10: self.press_point.append(data) len_press = len(self.press_point) x = 0 @@ -125,45 +142,56 @@ def _store_points(self, data): def current_state(self): """Returns the touchscreen state""" + global event_flag + self.sample_time = time.ticks_ms() + data = self.touch_driver.current_point() + if isinstance(data, tuple): + self._store_points(data) + elif data is None: # gets release then return to idle. + if self.state == RELEASED: # On touch release + self.state = IDLE + event_flag = False # Clears event flag + self.debounce = time.ticks_ms() # Sets debounce + elif self.state == PRESSED: + lateral_lenght = self.release_point[0] - self.press_point[0][0] + if lateral_lenght > SWIPE_THRESHOLD: + self.gesture = SWIPE_RIGHT + elif -lateral_lenght > SWIPE_THRESHOLD: + self.gesture = SWIPE_LEFT + lateral_lenght *= -1 # make it positive value + vertical_lenght = self.release_point[1] - self.press_point[0][1] + if ( + vertical_lenght > SWIPE_THRESHOLD + and vertical_lenght > lateral_lenght + ): + self.gesture = SWIPE_DOWN + elif ( + -vertical_lenght > SWIPE_THRESHOLD + and -vertical_lenght > lateral_lenght + ): + self.gesture = SWIPE_UP + self.state = RELEASED + else: + log.warn("Touch error: " + str(data)) + return self.state + + def event(self): + global event_flag + check_event = event_flag + event_flag = False # Always clean event flag current_time = time.ticks_ms() if ( current_time > self.sample_time + TOUCH_S_PERIOD and current_time > self.debounce + TOUCH_DEBOUNCE ): - self.sample_time = time.ticks_ms() - data = self.touch_driver.current_point() - if isinstance(data, tuple): - self._store_points(data) - elif data is None: # gets release then return to idle. - if self.state == self.release: - self.state = self.idle - self.debounce = time.ticks_ms() - elif self.state == self.press: - lateral_lenght = self.release_point[0] - self.press_point[0][0] - if lateral_lenght > SWIPE_THRESHOLD: - self.gesture = SWIPE_RIGHT - elif -lateral_lenght > SWIPE_THRESHOLD: - self.gesture = SWIPE_LEFT - lateral_lenght *= -1 # make it positive value - vertical_lenght = self.release_point[1] - self.press_point[0][1] - if ( - vertical_lenght > SWIPE_THRESHOLD - and vertical_lenght > lateral_lenght - ): - self.gesture = SWIPE_DOWN - elif ( - -vertical_lenght > SWIPE_THRESHOLD - and -vertical_lenght > lateral_lenght - ): - self.gesture = SWIPE_UP - self.state = self.release - else: - log.warn("Touch error: " + str(data)) - return self.state + # Checks and updates index + if self.current_state() == PRESSED or check_event: + return True + return False def value(self): """Wraps touch states to behave like a regular button""" - return 0 if self.current_state() == self.press else 1 + return 0 if self.current_state() == PRESSED else 1 def swipe_right_value(self): """Returns detected gestures and clean respective variable""" diff --git a/src/krux/touchscreens/ft6x36.py b/src/krux/touchscreens/ft6x36.py index 323387403..782fefa0e 100644 --- a/src/krux/touchscreens/ft6x36.py +++ b/src/krux/touchscreens/ft6x36.py @@ -57,7 +57,7 @@ def __init__(self): self.write_reg(FT_DEVICE_MODE, 0) # Threshold for touch detection self.write_reg(FT_ID_G_THGROUP, TOUCH_THRESHOLD) - # Mode = 0 = polling mode + # Mode = 0 = polling mode | Mode = 1 = trigger mode self.write_reg(FT_ID_G_MODE, 0) def write_reg(self, reg_addr, buf): From fbe714b863890debce7c1271cbe89d71ea406ff4 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Wed, 30 Aug 2023 15:23:56 -0300 Subject: [PATCH 003/114] add anti-glare to OV2640 sensor --- src/krux/camera.py | 70 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/src/krux/camera.py b/src/krux/camera.py index 5fa6dcb72..2bc0c8ccb 100644 --- a/src/krux/camera.py +++ b/src/krux/camera.py @@ -46,6 +46,10 @@ def initialize_sensor(self, grayscale=False): self.initialized = False self.antiglare_enabled = False self.cam_id = sensor.get_id() + if self.cam_id == OV7740_ID: + sensor.reset(freq=16000000) + else: + sensor.reset() if grayscale: sensor.set_pixformat(sensor.GRAYSCALE) else: @@ -54,13 +58,15 @@ def initialize_sensor(self, grayscale=False): # CIF mode will use central pixels and discard darker periphery sensor.set_framesize(sensor.CIF) sensor.set_hmirror(1) - if self.cam_id == OV2640_ID: + elif self.cam_id == OV2640_ID: sensor.set_framesize(sensor.CIF) sensor.set_vflip(1) else: sensor.set_framesize(sensor.QVGA) if self.cam_id == OV7740_ID: self.config_ov_7740() + if self.cam_id == OV2640_ID: + self.config_ov_2640() sensor.skip_frames() def config_ov_7740(self): @@ -82,37 +88,71 @@ def config_ov_7740(self): # Regions 13,14,15,16 sensor.__write_reg(0x59, 0x0) # pylint: disable=W0212 + def config_ov_2640(self): + """Specialized config for OV2640 sensor""" + # Set register bank 0 + sensor.__write_reg(0xFF, 0x00) # pylint: disable=W0212 + # Enable AEC + sensor.__write_reg(0xC2, 0x8C) # pylint: disable=W0212 + # Set register bank 1 + sensor.__write_reg(0xFF, 0x01) # pylint: disable=W0212 + sensor.__write_reg(0x03, 0xCF) + # Allowed luminance thresholds: + # luminance high threshold, default=0x78 + sensor.__write_reg(0x24, 0x70) # pylint: disable=W0212 + # luminance low threshold, default=0x68 + sensor.__write_reg(0x25, 0x60) # pylint: disable=W0212 + + # Average-based sensing window definition + # Ingnore periphery and measure luminance only on central area + # Regions 1,2,3,4 + sensor.__write_reg(0x5D, 0xFF) # pylint: disable=W0212 + # Regions 5,6,7,8 + sensor.__write_reg(0x5E, 0b11000011) # pylint: disable=W0212 + # Regions 9,10,11,12 + sensor.__write_reg(0x5F, 0b11000011) # pylint: disable=W0212 + # Regions 13,14,15,16 + sensor.__write_reg(0x60, 0xFF) # pylint: disable=W0212 + def has_antiglare(self): """Returns whether the camera has anti-glare functionality""" - return self.cam_id == OV7740_ID + return self.cam_id in (OV7740_ID, OV2640_ID) def enable_antiglare(self): """Enables anti-glare mode""" - if self.cam_id == OV7740_ID: + if self.cam_id == OV2640_ID: + # Set register bank 1 + sensor.__write_reg(0xFF, 0x01) # pylint: disable=W0212 + # luminance high level, default=0x78 + sensor.__write_reg(0x24, 0x28) # pylint: disable=W0212 + else: # luminance high level, default=0x78 sensor.__write_reg(0x24, 0x38) # pylint: disable=W0212 - # luminance low level, default=0x68 - sensor.__write_reg(0x25, 0x20) # pylint: disable=W0212 + # luminance low level, default=0x68 + sensor.__write_reg(0x25, 0x20) # pylint: disable=W0212 + if self.cam_id == OV7740_ID: # Disable frame integrtation (night mode) sensor.__write_reg(0x15, 0x00) # pylint: disable=W0212 - sensor.skip_frames() - self.antiglare_enabled = True + sensor.skip_frames() + self.antiglare_enabled = True def disable_antiglare(self): """Disables anti-glare mode""" - if self.cam_id == OV7740_ID: - # luminance high level, default=0x78 - sensor.__write_reg(0x24, 0x70) # pylint: disable=W0212 - # luminance low level, default=0x68 - sensor.__write_reg(0x25, 0x60) # pylint: disable=W0212 - sensor.skip_frames() - self.antiglare_enabled = False + if self.cam_id == OV2640_ID: + # Set register bank 1 + sensor.__write_reg(0xFF, 0x01) # pylint: disable=W0212 + # luminance high level, default=0x78 + sensor.__write_reg(0x24, 0x70) # pylint: disable=W0212 + # luminance low level, default=0x68 + sensor.__write_reg(0x25, 0x60) # pylint: disable=W0212 + sensor.skip_frames() + self.antiglare_enabled = False def snapshot(self): """Helper to take a customized snapshot from sensor""" img = sensor.snapshot() if self.cam_id in (OV2640_ID, OV5642_ID): - img.lens_corr(strength=1.1, zoom=0.96) + img.lens_corr(strength=1.1) if self.cam_id == OV2640_ID: img.rotation_corr(z_rotation=180) return img From 7b1aaf006a913954c64c3938209848324e8d835e Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Fri, 1 Sep 2023 09:44:03 -0300 Subject: [PATCH 004/114] add Yahboom AI motion compatibility --- src/krux/camera.py | 11 +++++------ src/krux/input.py | 26 ++++++++++++++++---------- src/krux/krux_settings.py | 4 ++-- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/krux/camera.py b/src/krux/camera.py index 2bc0c8ccb..388a48aaa 100644 --- a/src/krux/camera.py +++ b/src/krux/camera.py @@ -55,12 +55,12 @@ def initialize_sensor(self, grayscale=False): else: sensor.set_pixformat(sensor.RGB565) if self.cam_id == OV5642_ID: - # CIF mode will use central pixels and discard darker periphery - sensor.set_framesize(sensor.CIF) sensor.set_hmirror(1) - elif self.cam_id == OV2640_ID: - sensor.set_framesize(sensor.CIF) + if self.cam_id == OV2640_ID: sensor.set_vflip(1) + if board.config["type"] == "bit": + # CIF mode will use central pixels and discard darker periphery + sensor.set_framesize(sensor.CIF) else: sensor.set_framesize(sensor.QVGA) if self.cam_id == OV7740_ID: @@ -151,9 +151,8 @@ def disable_antiglare(self): def snapshot(self): """Helper to take a customized snapshot from sensor""" img = sensor.snapshot() - if self.cam_id in (OV2640_ID, OV5642_ID): + if board.config["type"] == "bit": img.lens_corr(strength=1.1) - if self.cam_id == OV2640_ID: img.rotation_corr(z_rotation=180) return img diff --git a/src/krux/input.py b/src/krux/input.py index dfe601dc8..101c94aa1 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -96,15 +96,18 @@ def __init__(self): def enter_value(self): """Intermediary method to pull button ENTER state""" - return self.enter.value() + if self.enter is not None: + return self.enter.value() def page_value(self): """Intermediary method to pull button PAGE state""" - return self.page.value() + if self.page is not None: + return self.page.value() def page_prev_value(self): """Intermediary method to pull button PAGE_PREV state""" - return self.page_prev.value() + if self.page_prev is not None: + return self.page_prev.value() def touch_value(self): """Intermediary method to pull touch state, if touch available""" @@ -114,15 +117,18 @@ def touch_value(self): def enter_event(self): """Intermediary method to pull button ENTER event""" - return self.enter.event() + if self.enter is not None: + return self.enter.event() def page_event(self): """Intermediary method to pull button PAGE state""" - return self.page.event() + if self.page is not None: + return self.page.event() def page_prev_event(self): """Intermediary method to pull button PAGE_PREV state""" - return self.page_prev.event() + if self.page_prev is not None: + return self.page_prev.event() def touch_event(self): if self.touch is not None: @@ -229,7 +235,7 @@ def wait_for_button(self, block=True): def flush_events(self): """Clean eventual event flags unintentionally collected""" - _ = self.enter_event() - _ = self.page_event() - _ = self.page_prev_event() - _ = self.touch_event() + self.enter_event() + self.page_event() + self.page_prev_event() + self.touch_event() diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index 10ea25fa3..dfa847712 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -347,7 +347,7 @@ def __init__(self): self.printer = PrinterSettings() self.persist = PersistSettings() self.appearance = ThemeSettings() - if board.config["type"].startswith("amigo"): + if board.config["type"].startswith("amigo") or board.config["type"] == "yahboom": self.touch = TouchSettings() if board.config["type"] == "dock": self.encoder = EncoderSettings() @@ -363,7 +363,7 @@ def label(self, attr): "printer": t("Printer"), "appearance": t("Theme"), } - if board.config["type"].startswith("amigo"): + if board.config["type"].startswith("amigo") or board.config["type"] == "yahboom": main_menu["touchscreen"] = t("Touchscreen") if board.config["type"] == "dock": main_menu["encoder"] = t("Encoder") From ccfb51f98711d146908c486423f2a34d6e50984b Mon Sep 17 00:00:00 2001 From: Odudex Date: Fri, 15 Sep 2023 17:00:58 -0300 Subject: [PATCH 005/114] remove part of thermal printer settings --- src/krux/krux_settings.py | 4 --- src/krux/printers/thermal.py | 58 ------------------------------------ 2 files changed, 62 deletions(-) diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index dfa847712..a54aea8d8 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -155,8 +155,6 @@ class AdafruitPrinterSettings(SettingsNamespace): paper_width = NumberSetting(int, "paper_width", 384, [100, 1000]) tx_pin = NumberSetting(int, "tx_pin", DEFAULT_TX_PIN, [0, 10000]) rx_pin = NumberSetting(int, "rx_pin", DEFAULT_RX_PIN, [0, 10000]) - heat_time = NumberSetting(int, "heat_time", 120, [3, 255]) - heat_interval = NumberSetting(int, "heat_interval", 40, [0, 255]) line_delay = NumberSetting(int, "line_delay", 20, [0, 255]) scale = NumberSetting(int, "scale", 75, [25, 100]) @@ -167,8 +165,6 @@ def label(self, attr): "paper_width": t("Paper Width"), "tx_pin": t("TX Pin"), "rx_pin": t("RX Pin"), - "heat_time": t("Heat Time"), - "heat_interval": t("Heat Interval"), "line_delay": t("Line Delay"), "scale": t("Scale"), }[attr] diff --git a/src/krux/printers/thermal.py b/src/krux/printers/thermal.py index 74a012633..3b6ee3bda 100644 --- a/src/krux/printers/thermal.py +++ b/src/krux/printers/thermal.py @@ -69,67 +69,9 @@ def __init__(self): self.dot_print_time = Settings().printer.thermal.adafruit.line_delay self.dot_feed_time = 2 # miliseconds - self.setup() - if not self.has_paper(): raise ValueError("missing paper") - def setup(self): - """Sets up the connection to the printer and sets default settings""" - # The printer can't start receiving data immediately - # upon power up -- it needs a moment to cold boot - # and initialize. Allow at least 1/2 sec of uptime - # before printer can receive data. - time.sleep_ms(INITIALIZE_WAIT_TIME) - - # Wake up the printer to get ready for printing - self.write_bytes(255) - self.write_bytes(27, 118, 0) # Sleep off (important!) - - # Reset the printer - self.write_bytes(27, 64) # Esc @ = init command - # Configure tab stops on recent printers - self.write_bytes(27, 68) # Set tab stops - self.write_bytes(4, 8, 12, 16) # every 4 columns, - self.write_bytes(20, 24, 28, 0) # 0 is end-of-list. - - # Description of print settings from p. 23 of manual: - # ESC 7 n1 n2 n3 Setting Control Parameter Command - # Decimal: 27 55 n1 n2 n3 - # max heating dots, heating time, heating interval - # n1 = 0-255 Max heat dots, Unit (8dots), Default: 7 (64 dots) - # n2 = 3-255 Heating time, Unit (10us), Default: 80 (800us) - # n3 = 0-255 Heating interval, Unit (10us), Default: 2 (20us) - # The more max heating dots, the more peak current - # will cost when printing, the faster printing speed. - # The max heating dots is 8*(n1+1). The more heating - # time, the more density, but the slower printing - # speed. If heating time is too short, blank page - # may occur. The more heating interval, the more - # clear, but the slower printing speed. - self.write_bytes( - 27, # Esc - 55, # 7 (print settings) - 11, # Heat dots - Settings().printer.thermal.adafruit.heat_time, - Settings().printer.thermal.adafruit.heat_interval, - ) - - # Description of print density from p. 23 of manual: - # DC2 # n Set printing density - # Decimal: 18 35 n - # D4..D0 of n is used to set the printing density. - # Density is 50% + 5% * n(D4-D0) printing density. - # D7..D5 of n is used to set the printing break time. - # Break time is n(D7-D5)*250us. - # (Unsure of default values -- not documented) - print_density = 10 # 100% - print_break_time = 2 # 500 uS - - self.write_bytes( - 18, 35, (print_break_time << 5) | print_density # DC2 # Print density - ) - def write_bytes(self, *args): """Writes bytes to the printer at a stable speed""" for arg in args: From db8859480579ecef6c60e759c9cbb6dd7773eb8e Mon Sep 17 00:00:00 2001 From: Odudex Date: Fri, 15 Sep 2023 17:01:21 -0300 Subject: [PATCH 006/114] integrated debounce control --- src/krux/buttons.py | 18 +++++-------- src/krux/firmware.py | 6 ++--- src/krux/input.py | 55 +++++++++++++++++++++++---------------- src/krux/krux_settings.py | 12 ++++++--- src/krux/pages/home.py | 8 ++---- src/krux/touch.py | 10 ++----- 6 files changed, 55 insertions(+), 54 deletions(-) diff --git a/src/krux/buttons.py b/src/krux/buttons.py index 4f9ac1c38..24baf84c0 100644 --- a/src/krux/buttons.py +++ b/src/krux/buttons.py @@ -22,9 +22,6 @@ from Maix import GPIO from fpioa_manager import fm -import time - -DEBOUNCE = 250 # milliseconds PRESSED = 0 RELEASED = 1 @@ -45,18 +42,15 @@ def __init__(self): self.enter_event_flag = False self.page_event_flag = False self.page_prev_event_flag = False - self.time_frame = 0 def event_handler(self, pin_num): """Set up a button event flag according to interruption source""" - if time.ticks_ms() > self.time_frame + DEBOUNCE: - if pin_num == buttons_control.enter: - self.enter_event_flag = True - elif pin_num == buttons_control.page: - self.page_event_flag = True - elif pin_num == buttons_control.page_prev: - self.page_prev_event_flag = True - self.time_frame = time.ticks_ms() + if pin_num == buttons_control.enter: + self.enter_event_flag = True + elif pin_num == buttons_control.page: + self.page_event_flag = True + elif pin_num == buttons_control.page_prev: + self.page_prev_event_flag = True def init_enter(self, pin): """Register ENTER button IO""" diff --git a/src/krux/firmware.py b/src/krux/firmware.py index 4dd7b74c2..7e65f915a 100644 --- a/src/krux/firmware.py +++ b/src/krux/firmware.py @@ -222,7 +222,7 @@ def flash_text(text): except: flash_text(t("Invalid public key")) return False - + sig = None try: sig = open(firmware_path + ".sig", "rb").read() @@ -234,10 +234,10 @@ def flash_text(text): # Parse, serialize, and reparse to ensure signature is compact prior to verification sig = ec.Signature.parse(ec.Signature.parse(sig).serialize()) if not pubkey.verify(sig, firmware_hash): - display.flash_text(t("Bad signature")) + flash_text(t("Bad signature")) return False except: - display.flash_text(t("Bad signature")) + flash_text(t("Bad signature")) return False boot_config_sector = flash.read(MAIN_BOOT_CONFIG_SECTOR_ADDRESS, 4096) diff --git a/src/krux/input.py b/src/krux/input.py index 101c94aa1..259671fad 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -37,6 +37,7 @@ LONG_PRESS_PERIOD = 1000 # milliseconds BUTTON_WAIT_PRESS_DELAY = 10 +DEBOUNCE = 100 class Input: @@ -44,6 +45,7 @@ class Input: def __init__(self): self.entropy = 0 + self.debounce_time = 0 self.enter = None if "BUTTON_A" in board.config["krux"]["pins"]: @@ -98,16 +100,19 @@ def enter_value(self): """Intermediary method to pull button ENTER state""" if self.enter is not None: return self.enter.value() + return RELEASED def page_value(self): """Intermediary method to pull button PAGE state""" if self.page is not None: return self.page.value() + return RELEASED def page_prev_value(self): """Intermediary method to pull button PAGE_PREV state""" if self.page_prev is not None: return self.page_prev.value() + return RELEASED def touch_value(self): """Intermediary method to pull touch state, if touch available""" @@ -119,18 +124,22 @@ def enter_event(self): """Intermediary method to pull button ENTER event""" if self.enter is not None: return self.enter.event() + return False def page_event(self): - """Intermediary method to pull button PAGE state""" + """Intermediary method to pull button PAGE event""" if self.page is not None: return self.page.event() + return False def page_prev_event(self): - """Intermediary method to pull button PAGE_PREV state""" + """Intermediary method to pull button PAGE_PREV event""" if self.page_prev is not None: return self.page_prev.event() + return False def touch_event(self): + """Intermediary method to pull button TOUCH event""" if self.touch is not None: return self.touch.event() return False @@ -163,6 +172,8 @@ def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD): """Wait for first button press or for wait_duration ms. Use block to wait indefinitely""" start_time = time.ticks_ms() + while time.ticks_ms() < self.debounce_time + DEBOUNCE: + self.flush_events() while True: if self.enter_event(): return BUTTON_ENTER @@ -183,15 +194,15 @@ def wait_for_button(self, block=True): Returns the button that was released, or None if non blocking. """ btn = self.wait_for_press(block) - if btn == BUTTON_ENTER: # Wait for release while self.enter_value() == PRESSED: self.entropy += 1 wdt.feed() - if self.buttons_active: - return BUTTON_ENTER - self.buttons_active = True + if not self.buttons_active: + self.buttons_active = True + btn = None + elif btn == BUTTON_PAGE: start_time = time.ticks_ms() # Wait for release @@ -199,10 +210,11 @@ def wait_for_button(self, block=True): self.entropy += 1 wdt.feed() if time.ticks_ms() > start_time + LONG_PRESS_PERIOD: - return SWIPE_LEFT - if self.buttons_active: - return BUTTON_PAGE - self.buttons_active = True + btn = SWIPE_LEFT + break + if not self.buttons_active: + self.buttons_active = True + btn = None elif btn == BUTTON_PAGE_PREV: start_time = time.ticks_ms() # Wait for release @@ -210,28 +222,27 @@ def wait_for_button(self, block=True): self.entropy += 1 wdt.feed() if time.ticks_ms() > start_time + LONG_PRESS_PERIOD: - return SWIPE_RIGHT - if self.buttons_active: - return BUTTON_PAGE_PREV - self.buttons_active = True + btn = SWIPE_RIGHT + break + if not self.buttons_active: + self.buttons_active = True + btn = None elif btn == BUTTON_TOUCH: # Wait for release while self.touch_value() == PRESSED: self.entropy += 1 wdt.feed() - # Flush intermediary touch interrupt events - _ = self.touch_event() self.buttons_active = False if self.swipe_right_value() == PRESSED: - return SWIPE_RIGHT + btn = SWIPE_RIGHT if self.swipe_left_value() == PRESSED: - return SWIPE_LEFT + btn = SWIPE_LEFT if self.swipe_up_value() == PRESSED: - return SWIPE_UP + btn = SWIPE_UP if self.swipe_down_value() == PRESSED: - return SWIPE_DOWN - return BUTTON_TOUCH - return None + btn = SWIPE_DOWN + self.debounce_time = time.ticks_ms() + return btn def flush_events(self): """Clean eventual event flags unintentionally collected""" diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index a54aea8d8..a71d42534 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -250,7 +250,7 @@ class EncoderSettings(SettingsNamespace): """Encoder debounce settings""" namespace = "settings.encoder" - debounce = NumberSetting(int, "debounce", 50, [25, 250]) + debounce = NumberSetting(int, "debounce", 100, [100, 250]) def label(self, attr): """Returns a label for UI when given a setting name or namespace""" @@ -343,7 +343,10 @@ def __init__(self): self.printer = PrinterSettings() self.persist = PersistSettings() self.appearance = ThemeSettings() - if board.config["type"].startswith("amigo") or board.config["type"] == "yahboom": + if ( + board.config["type"].startswith("amigo") + or board.config["type"] == "yahboom" + ): self.touch = TouchSettings() if board.config["type"] == "dock": self.encoder = EncoderSettings() @@ -359,7 +362,10 @@ def label(self, attr): "printer": t("Printer"), "appearance": t("Theme"), } - if board.config["type"].startswith("amigo") or board.config["type"] == "yahboom": + if ( + board.config["type"].startswith("amigo") + or board.config["type"] == "yahboom" + ): main_menu["touchscreen"] = t("Touchscreen") if board.config["type"] == "dock": main_menu["encoder"] = t("Encoder") diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index db3e4809a..7aefaf9c8 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -227,9 +227,7 @@ def wallet(self): def _load_wallet(self): wallet_data, qr_format = self.capture_qr_code() if wallet_data is None: - self.flash_text( - t("Failed to load output descriptor"), theme.error_color - ) + self.flash_text(t("Failed to load output descriptor"), theme.error_color) return MENU_CONTINUE try: @@ -551,9 +549,7 @@ def _save_file( else: sd.write(filename, data) self.ctx.display.clear() - self.flash_text( - t("Saved to SD card:\n%s") % filename - ) + self.flash_text(t("Saved to SD card:\n%s") % filename) else: filename_undefined = False diff --git a/src/krux/touch.py b/src/krux/touch.py index 8678a9fa4..447c37ea1 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -40,7 +40,6 @@ SWIPE_DOWN = 4 TOUCH_S_PERIOD = 20 # Touch sample period - Min = 10 -TOUCH_DEBOUNCE = 200 # Time to wait before sampling touch again after a release event_flag = False @@ -59,7 +58,6 @@ def __init__(self, width, height, irq_pin=None): For Krux width = max_y, height = max_x """ self.sample_time = 0 - self.debounce = 0 self.y_regions = [] self.x_regions = [] self.index = 0 @@ -151,7 +149,6 @@ def current_state(self): if self.state == RELEASED: # On touch release self.state = IDLE event_flag = False # Clears event flag - self.debounce = time.ticks_ms() # Sets debounce elif self.state == PRESSED: lateral_lenght = self.release_point[0] - self.press_point[0][0] if lateral_lenght > SWIPE_THRESHOLD: @@ -180,14 +177,11 @@ def event(self): check_event = event_flag event_flag = False # Always clean event flag current_time = time.ticks_ms() - if ( - current_time > self.sample_time + TOUCH_S_PERIOD - and current_time > self.debounce + TOUCH_DEBOUNCE - ): + if current_time > self.sample_time + TOUCH_S_PERIOD: # Checks and updates index if self.current_state() == PRESSED or check_event: return True - return False + return False def value(self): """Wraps touch states to behave like a regular button""" From f098b3f6635d7e99bb79235bba0e12e77b3c622f Mon Sep 17 00:00:00 2001 From: Jean Do Date: Sat, 9 Sep 2023 21:29:54 -0400 Subject: [PATCH 007/114] docs for maintaining fonts --- firmware/font/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/font/README.md b/firmware/font/README.md index 45a7c44d0..99a848a2d 100644 --- a/firmware/font/README.md +++ b/firmware/font/README.md @@ -4,11 +4,11 @@ Krux uses a [custom fork](https://github.com/bachan/terminus-font-vietnamese) of To rebuild the font for all devices, run: ``` ./bdftokff.sh ter-u14n 8 14 > m5stickv.kff -./bdftokff.sh ter-u16n 8 16 > bit_dock.kff +./bdftokff.sh ter-u16n 8 16 > bit_dock_yahboom.kff ./bdftokff.sh ter-u24b 12 24 > amigo.kff ``` -Once you have a `.kff` file, locate the project that you want to use the updated font under `firmware/MaixPy/projects/` (`maixpy_amigo_tft/` for ex.), open its `compile/overrides/components/micropython/port/src/omv/img/font.c` file and replace the array contents in the `unicode` variable with the byte array found within the `.kff` file, then rebuild the firmware. +Once you have `.kff` files, for each project that you want to use the updated fonts, edit `../MaixPy/projects/*/compile/overrides/components/micropython/port/src/omv/img/font.c` (substituting `maixpy_amigo_tft` for `*` if only for an amigo) and replace the array contents in the `unicode` variable with the byte array found within the appropriate `.kff` file, then rebuild the firmware. # How it works Krux uses bitmap fonts that are custom-built for each device it runs on. The format that the firmware expects fonts to be in is a custom format referred to as "krux font format," or `.kff`. From 467ab0d0ce6d9a996ff9956edc5bb11e3d51f410 Mon Sep 17 00:00:00 2001 From: Jean Do Date: Sat, 9 Sep 2023 21:30:39 -0400 Subject: [PATCH 008/114] google-translate food for PL/RU fonts --- i18n/translations/pl-PL.json | 243 +++++++++++++++++++++++++++++++++++ i18n/translations/ru-RU.json | 243 +++++++++++++++++++++++++++++++++++ 2 files changed, 486 insertions(+) create mode 100644 i18n/translations/pl-PL.json create mode 100644 i18n/translations/ru-RU.json diff --git a/i18n/translations/pl-PL.json b/i18n/translations/pl-PL.json new file mode 100644 index 000000000..20eb4915e --- /dev/null +++ b/i18n/translations/pl-PL.json @@ -0,0 +1,243 @@ +{ + "%d of %d multisig": "%d z %d multisig", + "%d. Change: \n\n%s\n\n": "%D.Zmiana:\n\n%s\n\n", + "%d. Self-transfer: \n\n%s\n\n": "%D.Samo-transfer:\n\n%s\n\n", + "%d. Spend: \n\n%s\n\n": "%D.Wydać:\n\n%s\n\n", + "%s\n\nis a valid change address!": "%s\n\nis prawidłowy adres zmiany!", + "%s\n\nis a valid receive address!": "%s\n\nis ważny adres odbierania!", + "%s\n\nwas NOT FOUND in the first %d change addresses": "%s\n\nwas nie znaleziono w pierwszych adresach zmiany", + "%s\n\nwas NOT FOUND in the first %d receive addresses": "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", + "12 words": "12 słów", + "24 words": "24 słowa", + "ABC": "ABC ĄĆĘŃÓŚŹŻ", + "About": "O", + "Adafruit": "Adafruit", + "Address": "Adres", + "Aditional entropy from camera required for AES-CBC mode": "Dodatkowa entropia z kamery wymaganej dla trybu AES-CBC", + "Align camera and Tiny Seed properly.": "Właściwie wyrównaj kamerę i maleńkie nasiona.", + "Anti-glare disabled": "Niepełnosprawne przeciwblokowane", + "Anti-glare enabled": "Włączona anty-zabawa", + "Are you sure?": "Jesteś pewny?", + "BIP39 Mnemonic": "BIP39 Mnemonic", + "Back": "Z powrotem", + "Backing up bootloader..\n\n%d%%": "Kopie zapasowe bootloader ..\n\n%d %%", + "Bad signature": "zły podpis", + "Baudrate": "Baudrate", + "Bitcoin": "Bitcoin", + "Border Padding": "Wyściółka graniczna", + "CNC": "CNC", + "Change": "Zmiana", + "Change Addresses": "Zmień adresy", + "Change theme and reboot?": "Zmienić motyw i ponownie uruchomić?", + "Changes persisted to SD card!": "Zmiany utrzymywały się na karcie SD!", + "Changes will last until shutdown.": "Zmiany będą trwać do zamknięcia.", + "Check SD Card": "Sprawdź kartę SD", + "Check that address belongs to this wallet?": "Sprawdź, czy adres należy do tego portfela?", + "Checked %d change addresses with no matches.": "Sprawdzone %d adresy zmiany bez dopasowań.", + "Checked %d receive addresses with no matches.": "Sprawdzone %D Otrzymuj adresy bez zapałek.", + "Checking change address %d for match..": "Sprawdzanie Zmieniania Adres %D dla dopasowania.", + "Checking for SD card..": "Sprawdzanie karty SD ..", + "Checking receive address %d for match..": "Sprawdzanie adresu Otrzymaj %D dla meczu.", + "Compact SeedQR": "Kompaktowy seedqr", + "Continue?": "Kontynuować?", + "Create QR Code": "Utwórz kod QR", + "Create QR code from text?": "Utwórz kod QR z tekstu?", + "Created: ": "Utworzony:", + "Custom QR Code": "Niestandardowy kod QR", + "Cut Depth": "Wytnij głębokość", + "Cut Method": "Metoda cięcia", + "Decimal": "Dziesiętny", + "Decrypt?": "Odszyfrować?", + "Delete File?": "Usunąć plik?", + "Delete Mnemonic": "Usuń mnemonic", + "Depth Per Pass": "Głębokość na przepustkę", + "Derivation: %s": "Pochodzenie: %s", + "Device flash storage not detected.": "Nie wykryto pamięci flash urządzenia.", + "Done?": "Zrobione?", + "Driver": "Kierowca", + "Encoder": "Enkoder", + "Encoder Debounce": "Encoder Debunet", + "Encrypt Mnemonic": "Szyfrowanie mnemoniki", + "Encrypted QR Code": "Zaszyfrowany kod QR", + "Encrypted mnemonic was not stored": "Szyfrowana mnemonika nie była przechowywana", + "Encrypted mnemonic was stored with ID: ": "Szyfrowana mnemonika była przechowywana z ID:", + "Encryption": "Szyfrowanie", + "Encryption Mode": "Tryb szyfrowania", + "Enter each word of your BIP-39 mnemonic as a number from 1 to 2048.": "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę od 1 do 2048 r.", + "Enter each word of your BIP-39 mnemonic as a number in hexadecimal from 1 to 800.": "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w heksadecimal od 1 do 800.", + "Enter each word of your BIP-39 mnemonic as a number in octal from 1 to 4000.": "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w wysokości od 1 do 4000.", + "Enter each word of your BIP-39 mnemonic.": "Wprowadź każde słowo swojego mnemonika BIP-39.", + "Error:\n%s": "Błąd:\n%s", + "Esc": "wyjście", + "Explore files?": "Eksplorować pliki?", + "Exporting to SD card..": "Eksportowanie do karty SD ..", + "Extended Public Key": "Rozszerzony klucz publiczny", + "Failed to decrypt": "Nie udało się odszyfrować", + "Failed to load PSBT": "Nie udało się załadować PSBT", + "Failed to load address": "Nie udało się załadować adresu", + "Failed to load key": "Nie udało się załadować klucza", + "Failed to load message": "Nie udało się załadować wiadomości", + "Failed to load mnemonic": "Nie udało się załadować mnemonika", + "Failed to load output descriptor": "Nie udało się załadować deskryptora wyjściowego", + "Failed to load passphrase": "Nie udało się załadować pseudonim", + "Failed to store mnemonic": "Nie udało się przechowywać mnemonika", + "Fee: ": "Opłata:", + "Feed Rate": "Szybkość pasz", + "Filename": "Nazwa pliku", + "Filename %s exists on SD card, overwrite?": "Nazwa pliku %s istnieje na karcie SD, zastąp?", + "Fingerprint: %s": "Odcisk palca: %s", + "Firmware exceeds max size: %d": "Oprogramowanie układowe przekracza maksymalny rozmiar: %D", + "Flute Diameter": "Średnica fletu", + "Free: ": "Bezpłatny:", + "From Storage": "Z przechowywania", + "GRBL": "Grbl", + "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Podaj temu mnemonicznemu identyfikatorowi?W przeciwnym razie zostanie użyty obecny odcisk palca", + "Go": "Iść", + "Heat Interval": "Odstęp cieplny", + "Heat Time": "Czas ciepła", + "Hex Public Key": "Hex Key Public", + "Hexadecimal": "Szesnastkowy", + "ID already exists\n": "ID już istnieje\n", + "Inputs (%d): ": "Wejścia (%d):", + "Invalid address": "Błędny adres", + "Invalid bootloader": "Nieprawidłowy bootloader", + "Invalid mnemonic length": "Nieprawidłowa długość mnemoniczna", + "Invalid public key": "Nieprawidłowy klucz publiczny", + "Invalid wallet:\n%s": "Nieprawidłowy portfel:\n%s", + "Invert": "Odwracać", + "Key": "Klucz", + "Key: ": "Klucz:", + "Krux\n\n\nVersion\n%s": "Krux\n\n\neversion\n%s", + "Krux Printer Test QR": "Test drukarki Krux QR", + "Language": "Język", + "Line Delay": "Opóźnienie linii", + "Line: ": "Linia:", + "Load Mnemonic": "Ładuj mnemoniczne", + "Load from SD card?": "Załaduj z karty SD?", + "Load one?": "Załaduj jeden?", + "Load?": "Obciążenie?", + "Loading Camera..": "Ładowanie aparatu ..", + "Loading change address %d..": "Ładowanie ZMIANY Adres %D ..", + "Loading printer..": "Ładowanie drukarki ..", + "Loading receive address %d..": "Ładowanie adresu odbierania %d ..", + "Loading..": "Ładowanie..", + "Locale": "Widownia", + "Location": "Lokalizacja", + "Log Level": "Poziom dziennika", + "Logging": "Logowanie", + "Maximum length exceeded (%s)": "Maksymalna długość przekroczona (%s)", + "Message": "Wiadomość", + "Missing signature file": "Brakujący plik podpisu", + "Mnemonic": "Mnemoniczny", + "Mnemonic ID": "Mnemoniczne id", + "Mnemonic Storage ID": "Mnemoniczny identyfikator przechowywania", + "Mnemonic was not decrypted": "Mnemonik nie został odszyfrowany", + "Mnemonic was not encrypted": "Mnemoniczny nie był szyfrowany", + "Modified: ": "Zmodyfikowany:", + "Multisig": "Multisig", + "Network": "Sieć", + "New Mnemonic": "Nowy Mnemonic", + "New firmware detected.\n\nSHA256:\n%s\n\n\n\nInstall?": "Wykryto nowe oprogramowanie.\n\nsha256:\n%s\n\n\n\ninstall?", + "No": "NIE", + "No BIP39 passphrase": "Brak frazy BIP39", + "Not enough rolls!": "Za mało rolki!", + "Octal": "Octal", + "PBKDF2 Iter.": "PBKDF2 ITER.", + "PSBT": "PSBT", + "Paint punched dots black so they can be detected.": "Parzyj kropki czarne, aby można je było wykryć.", + "Paper Width": "Szerokość papieru", + "Part\n%d / %d": "Część\n %d / %d", + "Part Size": "Rozmiar części", + "Passphrase": "Fraza", + "Passphrase: ": "FRASSE:", + "Persist": "Trwać", + "Plaintext QR": "PlainText QR", + "Please load a wallet output descriptor": "Załaduj deskryptor wyjściowy portfela", + "Plunge Rate": "Szybkość spadku", + "Print Test QR": "Test wydrukuj QR", + "Print to QR?\n\n%s\n\n": "Drukuj do qr?\n\n%s\n\n", + "Print?\n\n%s\n\n": "Wydrukować?\n\n%s\n\n", + "Printer": "Drukarka", + "Printer Driver not set!": "Sterownik drukarki nie jest ustawiony!", + "Printing\n%d / %d": "Drukowanie\n %d / %d", + "Printing ...": "Drukowanie ...", + "Proceed?": "Przystępować?", + "Processing ...": "Przetwarzanie ...", + "QR Code": "Kod QR", + "RX Pin": "Pin Rx", + "Receive": "Odbierać", + "Receive Addresses": "Odbierać adresy", + "Region: ": "Region:", + "Review scanned data, edit if necessary": "Przejrzyj zeskanowane dane, w razie potrzeby edytuj", + "Roll dice at least %d times to generate a mnemonic.": "Rzuć kostkę co najmniej %d, aby wygenerować mnemoniczny.", + "Rolls:\n\n%s": "Rolls:\n\n%s", + "Rolls: %d\n": "Rolls: %d\n", + "SD card": "karta SD", + "SD card not detected": "Karta SD nie została wykryta", + "SD card not detected.": "Karta SD nie została wykryta.", + "SHA256 of rolls:\n\n%s": "SHA256 Rolls:\n\n%s", + "SHA256 of snapshot:\n\n%s": "SHA256 migawki:\n\n%s", + "SHA256:\n%s": "SHA256:\n%s", + "Save to SD card?": "Zapisz na karcie SD?", + "Saved to SD card:\n%s": "Zapisano na karcie SD:\n%s", + "Scale": "Skala", + "Scan Address": "Adres skanowania", + "Scan BIP39 passphrase": "Scan BIP39 Passhraz", + "Scan Key QR code": "Skanuj kod QR", + "Scanning words 1-12 again": "Znowu skanowanie słów 1-12", + "Scanning words 13-24": "Skanowanie słów 13-24", + "SeedQR": "Seedqr", + "Self-transfer or Change (%d): ": "Samo-transfer lub zmiana (%d):", + "Settings": "Ustawienia", + "Shutdown": "Zamknięcie", + "Shutting down..": "Wyłączanie..", + "Sign": "Podpisać", + "Sign?": "Podpisać?", + "Signature": "Podpis", + "Signed Message": "Podpisana wiadomość", + "Signed PSBT": "Podpisano PSBT", + "Single-sig": "Pojedyncze Sig", + "Size: ": "Rozmiar:", + "Spend (%d): ": "Wydać (%d):", + "Stackbit 1248": "Stackbit 1248", + "Store on Flash": "Przechowuj na Flash", + "Store on SD Card": "Przechowuj na karcie SD", + "Swipe to change mode": "Przesuń tryb zmiany", + "TOUCH or ENTER to capture": "Dotknij lub wejdź do przechwytywania", + "TX Pin": "Pin TX", + "Text": "Tekst", + "Theme": "Temat", + "Thermal": "Termiczny", + "Tiny Seed": "Małe ziarno", + "Tiny Seed (Bits)": "Małe nasiona (bity)", + "Tools": "Narzędzia", + "Touch Threshold": "Próg dotykowy", + "Touchscreen": "Ekran dotykowy", + "Try more?": "Próbuj bardziej?", + "Type BIP39 passphrase": "Passówka typu BIP39", + "Type Key": "Klucz typu", + "Unit": "Jednostka", + "Updating bootloader..\n\n%d%%": "Aktualizacja bootloader ..\n\n%d %%", + "Upgrade complete.\n\nShutting down..": "Uaktualnienie zakończone.\n\nshutting w dół ..", + "Upgrading firmware..\n\n%d%%": "Aktualizacja oprogramowania układowego ..\n\n%d %%", + "Use a black background surface.": "Użyj czarnej powierzchni tła.", + "Use camera's entropy to create a new mnemonic": "Użyj entropii aparatu, aby stworzyć nowy mnemonik", + "Used: ": "Używany:", + "Value %s out of range: [%s, %s]": "Wartość %s z zakresu: [ %s, %s]", + "Via Camera": "Za pośrednictwem aparatu", + "Via D20": "Via D20", + "Via D6": "Przez D6", + "Via Manual Input": "Poprzez ręczne wejście", + "Wait for the capture": "Poczekaj na schwytanie", + "Wallet Descriptor": "Deskryptor portfela", + "Wallet output descriptor": "Deskryptor wyjściowy portfela", + "Wallet output descriptor loaded!": "Załadowany deskryptor wyjściowy portfela!", + "Wallet output descriptor not found.": "Nie znaleziono deskryptora wyjściowego portfela.", + "Warning:\nIncomplete output descriptor": "Ostrzeżenie:\ninComplete Descriptor", + "Word %d": "Słowo %d", + "Word Numbers": "Numery słów", + "Words": "Słowa", + "Yes": "Tak", + "Your changes will be kept on device flash storage.": "Twoje zmiany będą przechowywane w pamięci flash urządzenia.", + "Your changes will be kept on the SD card.": "Twoje zmiany będą przechowywane na karcie SD." +} \ No newline at end of file diff --git a/i18n/translations/ru-RU.json b/i18n/translations/ru-RU.json new file mode 100644 index 000000000..6d8d26bf5 --- /dev/null +++ b/i18n/translations/ru-RU.json @@ -0,0 +1,243 @@ +{ + "%d of %d multisig": "%d %d multisig", + "%d. Change: \n\n%s\n\n": "%d.Изменение:\n\n%s\n\n", + "%d. Self-transfer: \n\n%s\n\n": "%d.Самотрансфер:\n\n%s\n\n", + "%d. Spend: \n\n%s\n\n": "%d.Потратить:\n\n%s\n\n", + "%s\n\nis a valid change address!": "%s\n\nis действительный адрес изменения!", + "%s\n\nis a valid receive address!": "%s\n\nis действительный адрес приема!", + "%s\n\nwas NOT FOUND in the first %d change addresses": "%s\n\nwas не найден в адресах первого %d.", + "%s\n\nwas NOT FOUND in the first %d receive addresses": "%s\n\nwas не найден в первом %d", + "12 words": "12 слов", + "24 words": "24 слова", + "ABC": "Азбука ЁЙТФЦЩЪЫЬЮъё", + "About": "О", + "Adafruit": "Адафрут", + "Address": "Адрес", + "Aditional entropy from camera required for AES-CBC mode": "Дополнительная энтропия от камеры, необходимая для режима AES-CBC", + "Align camera and Tiny Seed properly.": "Выровняйте камеру и крошечное семя.", + "Anti-glare disabled": "Анти-блестящий инвалид", + "Anti-glare enabled": "Anti-Glare включена", + "Are you sure?": "Вы уверены?", + "BIP39 Mnemonic": "BIP39 Мнемоник", + "Back": "Назад", + "Backing up bootloader..\n\n%d%%": "Резервное копирование загрузчика ..\n\n%d %%", + "Bad signature": "Плохая подпись", + "Baudrate": "Baudrate", + "Bitcoin": "Биткойн", + "Border Padding": "Пограничная прокладка", + "CNC": "Сжигание", + "Change": "Изменять", + "Change Addresses": "Изменить адреса", + "Change theme and reboot?": "Изменить тему и перезагрузить?", + "Changes persisted to SD card!": "Изменения сохранялись в SD -карте!", + "Changes will last until shutdown.": "Изменения будут длиться до выключения.", + "Check SD Card": "Проверьте SD -карту", + "Check that address belongs to this wallet?": "Проверить этот адрес принадлежит этому кошельку?", + "Checked %d change addresses with no matches.": "Проверено %D Адреса изменения без совпадений.", + "Checked %d receive addresses with no matches.": "Проверено %d получение адресов без совпадений.", + "Checking change address %d for match..": "Проверка изменения изменения %d для матча ..", + "Checking for SD card..": "Проверка на SD -карту ..", + "Checking receive address %d for match..": "Проверка получения адреса %d для матча ..", + "Compact SeedQR": "Compact SeedQr", + "Continue?": "Продолжать?", + "Create QR Code": "Создать QR -код", + "Create QR code from text?": "Создать QR -код из текста?", + "Created: ": "Созданный:", + "Custom QR Code": "Пользовательский QR -код", + "Cut Depth": "Вырезать глубину", + "Cut Method": "Метод вырезания", + "Decimal": "Десятичная дробь", + "Decrypt?": "Дешифровать?", + "Delete File?": "Удалить файл?", + "Delete Mnemonic": "Удалить мнемоника", + "Depth Per Pass": "Глубина за проход", + "Derivation: %s": "Деривация: %s", + "Device flash storage not detected.": "Устройство флэш -памяти не обнаружено.", + "Done?": "Сделанный?", + "Driver": "Водитель", + "Encoder": "Энкодер", + "Encoder Debounce": "Encoder Debounce", + "Encrypt Mnemonic": "Шифровать мнемоники", + "Encrypted QR Code": "Зашифрованный QR -код", + "Encrypted mnemonic was not stored": "Зашифрованная мнемоника не была сохранена", + "Encrypted mnemonic was stored with ID: ": "Зашифрованная мнемоника была сохранена с удостоверением личности:", + "Encryption": "Шифрование", + "Encryption Mode": "Режим шифрования", + "Enter each word of your BIP-39 mnemonic as a number from 1 to 2048.": "Введите каждое слово вашего BIP-39 мнемоники в качестве числа от 1 до 2048 года.", + "Enter each word of your BIP-39 mnemonic as a number in hexadecimal from 1 to 800.": "Введите каждое слово вашего BIP-39 мнемоники в качестве числа в шестнадцатеричном состоянии от 1 до 800.", + "Enter each word of your BIP-39 mnemonic as a number in octal from 1 to 4000.": "Введите каждое слово вашего BIP-39 мнемоники в качестве числа в восьмиуровне от 1 до 4000.", + "Enter each word of your BIP-39 mnemonic.": "Введите каждое слово вашего BIP-39 мнемоника.", + "Error:\n%s": "Ошибка:\n%s", + "Esc": "Эск", + "Explore files?": "Изучить файлы?", + "Exporting to SD card..": "Экспорт в SD -карту ..", + "Extended Public Key": "Расширенный открытый ключ", + "Failed to decrypt": "Не удалось расшифровать", + "Failed to load PSBT": "Не удалось загрузить PSBT", + "Failed to load address": "Не удалось загрузить адрес", + "Failed to load key": "Не удалось загрузить ключ", + "Failed to load message": "Не удалось загрузить сообщение", + "Failed to load mnemonic": "Не удалось загрузить мнемонику", + "Failed to load output descriptor": "Не удалось загрузить выходной дескриптор", + "Failed to load passphrase": "Не удалось загрузить пасфразу", + "Failed to store mnemonic": "Не удалось хранить мнемонику", + "Fee: ": "Платеж:", + "Feed Rate": "Скорость подачи", + "Filename": "Имя файла", + "Filename %s exists on SD card, overwrite?": "FileName %S существует на SD -карте, перезаписывает?", + "Fingerprint: %s": "Отпечаток пальца: %s", + "Firmware exceeds max size: %d": "Прошивка превышает максимальный размер: %d", + "Flute Diameter": "Диаметр флейты", + "Free: ": "Бесплатно:", + "From Storage": "От хранения", + "GRBL": "Грбл", + "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Дайте этой мнемонике пользовательский идентификатор?В противном случае будет использоваться текущий отпечаток пальцев", + "Go": "Идти", + "Heat Interval": "Тепловой интервал", + "Heat Time": "Тепловое время", + "Hex Public Key": "HEX Public Key", + "Hexadecimal": "Шестнадцатеричный", + "ID already exists\n": "ID уже существует\n", + "Inputs (%d): ": "Входные данные (%d):", + "Invalid address": "Неверный адрес", + "Invalid bootloader": "Неверный загрузчик", + "Invalid mnemonic length": "Неверная мнемоническая длина", + "Invalid public key": "Неверный открытый ключ", + "Invalid wallet:\n%s": "Неверный кошелек:\n%s", + "Invert": "Инвертировать", + "Key": "Ключ", + "Key: ": "Ключ:", + "Krux\n\n\nVersion\n%s": "Krux\n\n\nversion\n%s", + "Krux Printer Test QR": "Krux printer test qr", + "Language": "Язык", + "Line Delay": "Линейная задержка", + "Line: ": "Линия:", + "Load Mnemonic": "Загрузить мнемоники", + "Load from SD card?": "Загрузка с SD -карты?", + "Load one?": "Загрузить один?", + "Load?": "Нагрузка?", + "Loading Camera..": "Загрузка камеры ..", + "Loading change address %d..": "Загрузка Изменения Адрес %D ..", + "Loading printer..": "Загрузочный принтер ..", + "Loading receive address %d..": "Загрузка получения адреса %d ..", + "Loading..": "Загрузка ..", + "Locale": "Локаль", + "Location": "Расположение", + "Log Level": "Log Уровень", + "Logging": "Ведение журнала", + "Maximum length exceeded (%s)": "Максимальная длина превышена (%s)", + "Message": "Сообщение", + "Missing signature file": "Отсутствует подпись файл", + "Mnemonic": "Мнемоник", + "Mnemonic ID": "Мнемонический идентификатор", + "Mnemonic Storage ID": "Мнемонический идентификатор хранения", + "Mnemonic was not decrypted": "Мнемоника не была расшифрована", + "Mnemonic was not encrypted": "Мнемоника не была зашифрована", + "Modified: ": "Модифицировано:", + "Multisig": "Multisig", + "Network": "Сеть", + "New Mnemonic": "Новая мнемоника", + "New firmware detected.\n\nSHA256:\n%s\n\n\n\nInstall?": "Обнаружено новая прошивка.\n\nsha256:\n%s\n\n\n\ninstall?", + "No": "Нет", + "No BIP39 passphrase": "Нет BIP39 PassFrase", + "Not enough rolls!": "Недостаточно бросков!", + "Octal": "Восьми", + "PBKDF2 Iter.": "Pbkdf2 iter.", + "PSBT": "PSBT", + "Paint punched dots black so they can be detected.": "Краска перфорированные точки черные, чтобы их можно было обнаружить.", + "Paper Width": "Ширина бумаги", + "Part\n%d / %d": "Часть\n %d / %d", + "Part Size": "Размер частично", + "Passphrase": "Пасфраза", + "Passphrase: ": "Passfrase:", + "Persist": "Сопротивляться", + "Plaintext QR": "Основной текст QR", + "Please load a wallet output descriptor": "Пожалуйста, загрузите дескриптор вывода кошелька", + "Plunge Rate": "Скорость погружения", + "Print Test QR": "Печать тест QR", + "Print to QR?\n\n%s\n\n": "Печать в QR?\n\n%s\n\n", + "Print?\n\n%s\n\n": "Печать?\n\n%s\n\n", + "Printer": "Принтер", + "Printer Driver not set!": "Драйвер принтера не установлен!", + "Printing\n%d / %d": "Печать\n %d / %d", + "Printing ...": "Печать ...", + "Proceed?": "Продолжить?", + "Processing ...": "Обработка ...", + "QR Code": "QR код", + "RX Pin": "RX PIN", + "Receive": "Получать", + "Receive Addresses": "Получить адреса", + "Region: ": "Область, край:", + "Review scanned data, edit if necessary": "Просмотрите отсканированные данные, отредактируйте при необходимости", + "Roll dice at least %d times to generate a mnemonic.": "Рулоть кости, по крайней мере, %D, чтобы генерировать мнемонику.", + "Rolls:\n\n%s": "Rolls:\n\n%s", + "Rolls: %d\n": "Рулоты: %d\n", + "SD card": "SD Card", + "SD card not detected": "SD -карта не обнаружена", + "SD card not detected.": "SD -карта не обнаружена.", + "SHA256 of rolls:\n\n%s": "SHA256 ROLLS:\n\n%s", + "SHA256 of snapshot:\n\n%s": "SHA256 с моментальным снимком:\n\n%s", + "SHA256:\n%s": "SHA256:\n%s", + "Save to SD card?": "Сохранить на SD -карту?", + "Saved to SD card:\n%s": "Сохраняется на SD -карту:\n%s", + "Scale": "Шкала", + "Scan Address": "Адрес сканирования", + "Scan BIP39 passphrase": "Сканирование BIP39 PassFrase", + "Scan Key QR code": "Сканировать ключ QR -код", + "Scanning words 1-12 again": "Сканирование слов 1-12 снова", + "Scanning words 13-24": "Сканирование слов 13-24", + "SeedQR": "SEEDQR", + "Self-transfer or Change (%d): ": "Самооценка или изменение (%d):", + "Settings": "Настройки", + "Shutdown": "Неисправность", + "Shutting down..": "Выключение..", + "Sign": "Знак", + "Sign?": "Знак?", + "Signature": "Подпись", + "Signed Message": "Подписанное сообщение", + "Signed PSBT": "Подписанный PSBT", + "Single-sig": "Одиночный", + "Size: ": "Размер:", + "Spend (%d): ": "Потратить (%d):", + "Stackbit 1248": "Stackbit 1248", + "Store on Flash": "Хранить на вспышке", + "Store on SD Card": "Магазин на SD -карте", + "Swipe to change mode": "Пылать, чтобы изменить режим", + "TOUCH or ENTER to capture": "Коснуться или войти, чтобы захватить", + "TX Pin": "TX PIN", + "Text": "Текст", + "Theme": "Тема", + "Thermal": "Тепло", + "Tiny Seed": "Крошечное семя", + "Tiny Seed (Bits)": "Крошечное семя (биты)", + "Tools": "Инструменты", + "Touch Threshold": "Прикосновение порога", + "Touchscreen": "Сенсорный экран", + "Try more?": "Попробовать больше?", + "Type BIP39 passphrase": "Тип BIP39 PassFrase", + "Type Key": "Тип ключа", + "Unit": "Единица", + "Updating bootloader..\n\n%d%%": "Обновление загрузчика ..\n\n%d %%", + "Upgrade complete.\n\nShutting down..": "Обновление завершено.\n\nshutting ..", + "Upgrading firmware..\n\n%d%%": "Модернизация прошивки ..\n\n%d %%", + "Use a black background surface.": "Используйте черную фоновую поверхность.", + "Use camera's entropy to create a new mnemonic": "Используйте энтропию камеры, чтобы создать новую мнемонику", + "Used: ": "Использовал:", + "Value %s out of range: [%s, %s]": "Значение %s из диапазона: [ %s, %s]", + "Via Camera": "Через камеру", + "Via D20": "Через D20", + "Via D6": "Через D6", + "Via Manual Input": "Через ручной ввод", + "Wait for the capture": "Ждать захвата", + "Wallet Descriptor": "Дескриптор кошелька", + "Wallet output descriptor": "Дескриптор вывода кошелька", + "Wallet output descriptor loaded!": "Выходной дескриптор кошелька загружен!", + "Wallet output descriptor not found.": "Дескриптор вывода кошелька не найден.", + "Warning:\nIncomplete output descriptor": "ПРЕДУПРЕЖДЕНИЕ:\nincoplete Вывод дескриптор", + "Word %d": "Слово %d", + "Word Numbers": "Номера слов", + "Words": "Слова", + "Yes": "Да", + "Your changes will be kept on device flash storage.": "Ваши изменения будут храниться на хранении вспышки устройства.", + "Your changes will be kept on the SD card.": "Ваши изменения будут храниться на SD -карте." +} \ No newline at end of file From 09ab9897867487cf3e0e706b933cbd8a92294dc4 Mon Sep 17 00:00:00 2001 From: Odudex Date: Tue, 12 Sep 2023 14:24:19 -0300 Subject: [PATCH 009/114] remove temporary glyphs --- i18n/translations/pl-PL.json | 2 +- i18n/translations/ru-RU.json | 2 +- src/krux/translations.py | 243 +++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+), 2 deletions(-) diff --git a/i18n/translations/pl-PL.json b/i18n/translations/pl-PL.json index 20eb4915e..e9274ddbb 100644 --- a/i18n/translations/pl-PL.json +++ b/i18n/translations/pl-PL.json @@ -9,7 +9,7 @@ "%s\n\nwas NOT FOUND in the first %d receive addresses": "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", "12 words": "12 słów", "24 words": "24 słowa", - "ABC": "ABC ĄĆĘŃÓŚŹŻ", + "ABC": "ABC", "About": "O", "Adafruit": "Adafruit", "Address": "Adres", diff --git a/i18n/translations/ru-RU.json b/i18n/translations/ru-RU.json index 6d8d26bf5..62f13cf9f 100644 --- a/i18n/translations/ru-RU.json +++ b/i18n/translations/ru-RU.json @@ -9,7 +9,7 @@ "%s\n\nwas NOT FOUND in the first %d receive addresses": "%s\n\nwas не найден в первом %d", "12 words": "12 слов", "24 words": "24 слова", - "ABC": "Азбука ЁЙТФЦЩЪЫЬЮъё", + "ABC": "АБВ", "About": "О", "Adafruit": "Адафрут", "Address": "Адрес", diff --git a/src/krux/translations.py b/src/krux/translations.py index df72c8451..6859f97fd 100644 --- a/src/krux/translations.py +++ b/src/krux/translations.py @@ -265,6 +265,249 @@ 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", 2569054451: "Suas alterações serão mantidas no cartão SD.", }, + "pl-PL": { + 1185266064: "%d z %d multisig", + 2004520398: "%D.Zmiana:\n\n%s\n\n", + 3862364126: "%D.Samo-transfer:\n\n%s\n\n", + 3264377309: "%D.Wydać:\n\n%s\n\n", + 2399232215: "%s\n\nis prawidłowy adres zmiany!", + 3921290840: "%s\n\nis ważny adres odbierania!", + 1808355833: "%s\n\nwas nie znaleziono w pierwszych adresach zmiany", + 1306127065: "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", + 2739590230: "12 słów", + 1310058127: "24 słowa", + 2743272264: "ABC", + 1949634023: "O", + 1517128857: "Adafruit", + 3270727197: "Adres", + 2574498267: "Dodatkowa entropia z kamery wymaganej dla trybu AES-CBC", + 283202181: "Właściwie wyrównaj kamerę i maleńkie nasiona.", + 88746165: "Niepełnosprawne przeciwblokowane", + 1521033296: "Włączona anty-zabawa", + 1056821534: "Jesteś pewny?", + 3247612282: "BIP39 Mnemonic", + 3455872521: "Z powrotem", + 2541860807: "Kopie zapasowe bootloader ..\n\n%d %%", + 2256777600: "zły podpis", + 3937333362: "Baudrate", + 427617266: "Bitcoin", + 928727036: "Wyściółka graniczna", + 213030954: "CNC", + 1207696150: "Zmiana", + 3126552510: "Zmień adresy", + 1583186953: "Zmienić motyw i ponownie uruchomić?", + 2697733395: "Zmiany utrzymywały się na karcie SD!", + 388908871: "Zmiany będą trwać do zamknięcia.", + 3442025874: "Sprawdź kartę SD", + 3119547911: "Sprawdź, czy adres należy do tego portfela?", + 2856261511: "Sprawdzone %d adresy zmiany bez dopasowań.", + 2788541416: "Sprawdzone %D Otrzymuj adresy bez zapałek.", + 2446472910: "Sprawdzanie Zmieniania Adres %D dla dopasowania.", + 2470115694: "Sprawdzanie karty SD ..", + 3655273987: "Sprawdzanie adresu Otrzymaj %D dla meczu.", + 2407028014: "Kompaktowy seedqr", + 4041895036: "Kontynuować?", + 4094072796: "Utwórz kod QR", + 167798282: "Utwórz kod QR z tekstu?", + 2767642191: "Utworzony:", + 3513215254: "Niestandardowy kod QR", + 124617190: "Wytnij głębokość", + 597912140: "Metoda cięcia", + 2504034831: "Dziesiętny", + 2751113454: "Odszyfrować?", + 1016609898: "Usunąć plik?", + 1364509700: "Usuń mnemonic", + 4102535566: "Głębokość na przepustkę", + 2791699253: "Pochodzenie: %s", + 1230133196: "Nie wykryto pamięci flash urządzenia.", + 3836852788: "Zrobione?", + 382368239: "Kierowca", + 3978947916: "Enkoder", + 4090746898: "Encoder Debunet", + 374684711: "Szyfrowanie mnemoniki", + 1244124409: "Zaszyfrowany kod QR", + 2968548114: "Szyfrowana mnemonika nie była przechowywana", + 3315319371: "Szyfrowana mnemonika była przechowywana z ID:", + 350279787: "Szyfrowanie", + 2601598799: "Tryb szyfrowania", + 3504179008: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę od 1 do 2048 r.", + 1100685007: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w heksadecimal od 1 do 800.", + 4090266642: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w wysokości od 1 do 4000.", + 2780625730: "Wprowadź każde słowo swojego mnemonika BIP-39.", + 784361051: "Błąd:\n%s", + 1505332462: "wyjście", + 3838465623: "Eksplorować pliki?", + 4170881190: "Eksportowanie do karty SD ..", + 1711312434: "Rozszerzony klucz publiczny", + 383371114: "Nie udało się odszyfrować", + 3048830188: "Nie udało się załadować PSBT", + 4192663412: "Nie udało się załadować adresu", + 1996021743: "Nie udało się załadować klucza", + 1108715658: "Nie udało się załadować wiadomości", + 1081425878: "Nie udało się załadować mnemonika", + 928667220: "Nie udało się załadować deskryptora wyjściowego", + 1620572516: "Nie udało się załadować pseudonim", + 2946146830: "Nie udało się przechowywać mnemonika", + 1303554751: "Opłata:", + 104500973: "Szybkość pasz", + 3313339187: "Nazwa pliku", + 1982637349: "Nazwa pliku %s istnieje na karcie SD, zastąp?", + 3737729752: "Odcisk palca: %s", + 2542772894: "Oprogramowanie układowe przekracza maksymalny rozmiar: %D", + 1406590538: "Średnica fletu", + 3086093110: "Bezpłatny:", + 1893243331: "Z przechowywania", + 4120536442: "Grbl", + 299338213: "Podaj temu mnemonicznemu identyfikatorowi?W przeciwnym razie zostanie użyty obecny odcisk palca", + 602716148: "Iść", + 831562513: "Odstęp cieplny", + 2300171403: "Czas ciepła", + 3580020863: "Hex Key Public", + 2691246967: "Szesnastkowy", + 2736309107: "ID już istnieje\n", + 631342955: "Wejścia (%d):", + 2585599782: "Błędny adres", + 2874529150: "Nieprawidłowy bootloader", + 4093416954: "Nieprawidłowa długość mnemoniczna", + 1422874211: "Nieprawidłowy klucz publiczny", + 2443867979: "Nieprawidłowy portfel:\n%s", + 4122897393: "Odwracać", + 3000888649: "Klucz", + 2686333978: "Klucz:", + 4123798664: "Krux\n\n\neversion\n%s", + 3835918229: "Test drukarki Krux QR", + 766317539: "Język", + 972436696: "Opóźnienie linii", + 3596093890: "Linia:", + 2820726296: "Ładuj mnemoniczne", + 879727077: "Załaduj z karty SD?", + 669106195: "Załaduj jeden?", + 3330705289: "Obciążenie?", + 2596531078: "Ładowanie aparatu ..", + 596389387: "Ładowanie ZMIANY Adres %D ..", + 336702608: "Ładowanie drukarki ..", + 2538883522: "Ładowanie adresu odbierania %d ..", + 3159494909: "Ładowanie..", + 1177338798: "Widownia", + 2817059741: "Lokalizacja", + 63976957: "Poziom dziennika", + 86530918: "Logowanie", + 2917810189: "Maksymalna długość przekroczona (%s)", + 2030045667: "Wiadomość", + 3928301843: "Brakujący plik podpisu", + 1948316555: "Mnemoniczny", + 2123991188: "Mnemoniczne id", + 3911073154: "Mnemoniczny identyfikator przechowywania", + 570639842: "Mnemonik nie został odszyfrowany", + 1746030071: "Mnemoniczny nie był szyfrowany", + 1458925155: "Zmodyfikowany:", + 1845376098: "Multisig", + 2939797024: "Sieć", + 73574491: "Nowy Mnemonic", + 2792272353: "Wykryto nowe oprogramowanie.\n\nsha256:\n%s\n\n\n\ninstall?", + 4063104189: "NIE", + 3927838899: "Brak frazy BIP39", + 4092516657: "Za mało rolki!", + 1577637745: "Octal", + 3312581301: "PBKDF2 ITER.", + 721090621: "PSBT", + 995862913: "Parzyj kropki czarne, aby można je było wykryć.", + 2987800462: "Szerokość papieru", + 3050763890: "Część\n %d / %d", + 3559456868: "Rozmiar części", + 4249903283: "Fraza", + 3712257341: "FRASSE:", + 140802882: "Trwać", + 1703779997: "PlainText QR", + 3561756278: "Załaduj deskryptor wyjściowy portfela", + 784609464: "Szybkość spadku", + 3037062877: "Test wydrukuj QR", + 4278257699: "Drukuj do qr?\n\n%s\n\n", + 516488026: "Wydrukować?\n\n%s\n\n", + 1123106929: "Drukarka", + 3903571079: "Sterownik drukarki nie jest ustawiony!", + 2609799302: "Drukowanie\n %d / %d", + 844861889: "Drukowanie ...", + 2580599003: "Przystępować?", + 556126964: "Przetwarzanie ...", + 1848310591: "Kod QR", + 710709610: "Pin Rx", + 2697857197: "Odbierać", + 1746677167: "Odbierać adresy", + 364354944: "Region:", + 1662254634: "Przejrzyj zeskanowane dane, w razie potrzeby edytuj", + 770350922: "Rzuć kostkę co najmniej %d, aby wygenerować mnemoniczny.", + 856795528: "Rolls:\n\n%s", + 255086803: "Rolls: %d\n", + 3976793317: "karta SD", + 2827687530: "Karta SD nie została wykryta", + 2736513298: "Karta SD nie została wykryta.", + 3593785196: "SHA256 Rolls:\n\n%s", + 1143278725: "SHA256 migawki:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Zapisz na karcie SD?", + 810036588: "Zapisano na karcie SD:\n%s", + 763824768: "Skala", + 4117455079: "Adres skanowania", + 3219991109: "Scan BIP39 Passhraz", + 2537207336: "Skanuj kod QR", + 4006316572: "Znowu skanowanie słów 1-12", + 2736506158: "Skanowanie słów 13-24", + 266935239: "Seedqr", + 1698829144: "Samo-transfer lub zmiana (%d):", + 473154195: "Ustawienia", + 1825881236: "Zamknięcie", + 2120776272: "Wyłączanie..", + 1061961408: "Podpisać", + 4282338366: "Podpisać?", + 746161122: "Podpis", + 1988416729: "Podpisana wiadomość", + 3672006076: "Podpisano PSBT", + 2281377987: "Pojedyncze Sig", + 4221794628: "Rozmiar:", + 2309020186: "Wydać (%d):", + 3355862324: "Stackbit 1248", + 3303592908: "Przechowuj na Flash", + 720041451: "Przechowuj na karcie SD", + 3514476519: "Przesuń tryb zmiany", + 1898550184: "Dotknij lub wejdź do przechwytywania", + 4228215415: "Pin TX", + 2612594937: "Tekst", + 1454688268: "Temat", + 1180180513: "Termiczny", + 4119292117: "Małe ziarno", + 1732872974: "Małe nasiona (bity)", + 725348723: "Narzędzia", + 3684696112: "Próg dotykowy", + 2978718564: "Ekran dotykowy", + 2732611775: "Próbuj bardziej?", + 1487826746: "Passówka typu BIP39", + 2061556020: "Klucz typu", + 2089395053: "Jednostka", + 2845607430: "Aktualizacja bootloader ..\n\n%d %%", + 4164597446: "Uaktualnienie zakończone.\n\nshutting w dół ..", + 2736001501: "Aktualizacja oprogramowania układowego ..\n\n%d %%", + 2674953168: "Użyj czarnej powierzchni tła.", + 2402455261: "Użyj entropii aparatu, aby stworzyć nowy mnemonik", + 236075140: "Używany:", + 4003084591: "Wartość %s z zakresu: [ %s, %s]", + 4191058607: "Za pośrednictwem aparatu", + 1254681955: "Via D20", + 525309547: "Przez D6", + 590330112: "Poprzez ręczne wejście", + 2504354847: "Poczekaj na schwytanie", + 2297028319: "Deskryptor portfela", + 4232654916: "Deskryptor wyjściowy portfela", + 2587172867: "Załadowany deskryptor wyjściowy portfela!", + 2499782468: "Nie znaleziono deskryptora wyjściowego portfela.", + 1831109430: "Ostrzeżenie:\ninComplete Descriptor", + 797660533: "Słowo %d", + 3742424146: "Numery słów", + 2965123464: "Słowa", + 1303016265: "Tak", + 771968845: "Twoje zmiany będą przechowywane w pamięci flash urządzenia.", + 2569054451: "Twoje zmiany będą przechowywane na karcie SD.", + }, "es-MX": { 1185266064: "%d de %d multisig", 2004520398: "%d. Cambio: \n\n%s\n\n", From b3a27230534a1de9e8894cb14fb88ceee812bfb8 Mon Sep 17 00:00:00 2001 From: aglkm Date: Thu, 14 Sep 2023 12:37:09 +0300 Subject: [PATCH 010/114] Adding RU translation --- i18n/translations/ru-RU.json | 377 ++++---- src/krux/translations.py | 1702 +++++++++++++++++++--------------- 2 files changed, 1162 insertions(+), 917 deletions(-) diff --git a/i18n/translations/ru-RU.json b/i18n/translations/ru-RU.json index 62f13cf9f..825098ee0 100644 --- a/i18n/translations/ru-RU.json +++ b/i18n/translations/ru-RU.json @@ -1,77 +1,78 @@ { - "%d of %d multisig": "%d %d multisig", - "%d. Change: \n\n%s\n\n": "%d.Изменение:\n\n%s\n\n", - "%d. Self-transfer: \n\n%s\n\n": "%d.Самотрансфер:\n\n%s\n\n", - "%d. Spend: \n\n%s\n\n": "%d.Потратить:\n\n%s\n\n", - "%s\n\nis a valid change address!": "%s\n\nis действительный адрес изменения!", - "%s\n\nis a valid receive address!": "%s\n\nis действительный адрес приема!", - "%s\n\nwas NOT FOUND in the first %d change addresses": "%s\n\nwas не найден в адресах первого %d.", - "%s\n\nwas NOT FOUND in the first %d receive addresses": "%s\n\nwas не найден в первом %d", + "%d of %d multisig": "%d из %d мультиподпись", + "%d. Change: \n\n%s\n\n": "%d. Сдача: \n\n%s\n\n", + "%d. Self-transfer: \n\n%s\n\n": "%d. Перевод самому себе: \n\n%s\n\n", + "%d. Spend: \n\n%s\n\n": "%d. Расход: \n\n%s\n\n", + "%s\n\nis a valid change address!": "%s\n\nвалидный адрес сдачи!", + "%s\n\nis a valid receive address!": "%s\n\nвалидный адрес получения!", + "%s\n\nwas NOT FOUND in the first %d change addresses": "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", + "%s\n\nwas NOT FOUND in the first %d receive addresses": "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", + "(Experimental)": "(Эксперементальный)", "12 words": "12 слов", "24 words": "24 слова", - "ABC": "АБВ", - "About": "О", - "Adafruit": "Адафрут", + "ABC": "ABC", + "About": "О Программе", + "Adafruit": "Adafruit", "Address": "Адрес", - "Aditional entropy from camera required for AES-CBC mode": "Дополнительная энтропия от камеры, необходимая для режима AES-CBC", - "Align camera and Tiny Seed properly.": "Выровняйте камеру и крошечное семя.", - "Anti-glare disabled": "Анти-блестящий инвалид", - "Anti-glare enabled": "Anti-Glare включена", + "Aditional entropy from camera required for AES-CBC mode": "Для режима AES-CBC требуется дополнительная энтропия от камеры", + "Align camera and Tiny Seed properly.": "Правильно совместите камеру и Мини Сид-фразу.", + "Anti-glare disabled": "Антиблик отключен", + "Anti-glare enabled": "Антиблик включен", "Are you sure?": "Вы уверены?", - "BIP39 Mnemonic": "BIP39 Мнемоник", + "BIP39 Mnemonic": "BIP39 Мнемоника", "Back": "Назад", - "Backing up bootloader..\n\n%d%%": "Резервное копирование загрузчика ..\n\n%d %%", + "Backing up bootloader..\n\n%d%%": "Резервное копирование загрузчика..\n\n%d%%", "Bad signature": "Плохая подпись", - "Baudrate": "Baudrate", - "Bitcoin": "Биткойн", - "Border Padding": "Пограничная прокладка", - "CNC": "Сжигание", - "Change": "Изменять", - "Change Addresses": "Изменить адреса", - "Change theme and reboot?": "Изменить тему и перезагрузить?", - "Changes persisted to SD card!": "Изменения сохранялись в SD -карте!", - "Changes will last until shutdown.": "Изменения будут длиться до выключения.", - "Check SD Card": "Проверьте SD -карту", - "Check that address belongs to this wallet?": "Проверить этот адрес принадлежит этому кошельку?", - "Checked %d change addresses with no matches.": "Проверено %D Адреса изменения без совпадений.", - "Checked %d receive addresses with no matches.": "Проверено %d получение адресов без совпадений.", - "Checking change address %d for match..": "Проверка изменения изменения %d для матча ..", - "Checking for SD card..": "Проверка на SD -карту ..", - "Checking receive address %d for match..": "Проверка получения адреса %d для матча ..", - "Compact SeedQR": "Compact SeedQr", - "Continue?": "Продолжать?", - "Create QR Code": "Создать QR -код", - "Create QR code from text?": "Создать QR -код из текста?", - "Created: ": "Созданный:", - "Custom QR Code": "Пользовательский QR -код", - "Cut Depth": "Вырезать глубину", - "Cut Method": "Метод вырезания", - "Decimal": "Десятичная дробь", - "Decrypt?": "Дешифровать?", - "Delete File?": "Удалить файл?", - "Delete Mnemonic": "Удалить мнемоника", - "Depth Per Pass": "Глубина за проход", - "Derivation: %s": "Деривация: %s", - "Device flash storage not detected.": "Устройство флэш -памяти не обнаружено.", - "Done?": "Сделанный?", - "Driver": "Водитель", - "Encoder": "Энкодер", - "Encoder Debounce": "Encoder Debounce", - "Encrypt Mnemonic": "Шифровать мнемоники", - "Encrypted QR Code": "Зашифрованный QR -код", + "Baudrate": "Скорость Передачи Данных", + "Bitcoin": "Биткоин", + "Border Padding": "Заполнение границ", + "CNC": "CNC", + "Change": "Сдача", + "Change Addresses": "Адрес Сдачи", + "Change theme and reboot?": "Сменить тему и перезагрузить?", + "Changes persisted to SD card!": "Изменения сохранены на SD карте!", + "Changes will last until shutdown.": "Изменения будут храниться до выключения.", + "Check SD Card": "Проверить SD Карту", + "Check that address belongs to this wallet?": "Проверить, что адрес принадлежит этому кошельку?", + "Checked %d change addresses with no matches.": "Проверено %d адресов сдачи без совпадений.", + "Checked %d receive addresses with no matches.": "Проверено %d адресов получения без совпадений.", + "Checking change address %d for match..": "Проверяем адрес сдачи %d на совпадение..", + "Checking for SD card..": "Проверка SD карты..", + "Checking receive address %d for match..": "Проверяем адрес получения %d на совпадение..", + "Compact SeedQR": "Компактный SeedQR", + "Continue?": "Продолжить?", + "Create QR Code": "Создать QR Код", + "Create QR code from text?": "Создать QR код из текста?", + "Created: ": "Создано", + "Custom QR Code": "Пользовательский QR Код", + "Cut Depth": "Глубина Резки", + "Cut Method": "Метод Резки", + "Decimal": "Десятичный", + "Decrypt?": "Расшифровать?", + "Delete File?": "Удалить Файл?", + "Delete Mnemonic": "Удалить Мнемонику", + "Depth Per Pass": "Глубина За Проход", + "Derivation: %s": "Производный путь: %s", + "Device flash storage not detected.": "Флэш память устройства не обнаружена.", + "Done?": "Готово?", + "Driver": "Драйвер", + "Encoder": "Кодер", + "Encoder Debounce": "Дебаунс Кодера", + "Encrypt Mnemonic": "Зашифровать Мнемонику", + "Encrypted QR Code": "Зашифрованный QR Код", "Encrypted mnemonic was not stored": "Зашифрованная мнемоника не была сохранена", - "Encrypted mnemonic was stored with ID: ": "Зашифрованная мнемоника была сохранена с удостоверением личности:", + "Encrypted mnemonic was stored with ID: ": "Зашифрованная мнемоника была сохранена с ID", "Encryption": "Шифрование", - "Encryption Mode": "Режим шифрования", - "Enter each word of your BIP-39 mnemonic as a number from 1 to 2048.": "Введите каждое слово вашего BIP-39 мнемоники в качестве числа от 1 до 2048 года.", - "Enter each word of your BIP-39 mnemonic as a number in hexadecimal from 1 to 800.": "Введите каждое слово вашего BIP-39 мнемоники в качестве числа в шестнадцатеричном состоянии от 1 до 800.", - "Enter each word of your BIP-39 mnemonic as a number in octal from 1 to 4000.": "Введите каждое слово вашего BIP-39 мнемоники в качестве числа в восьмиуровне от 1 до 4000.", - "Enter each word of your BIP-39 mnemonic.": "Введите каждое слово вашего BIP-39 мнемоника.", + "Encryption Mode": "Метод шифрования", + "Enter each word of your BIP-39 mnemonic as a number from 1 to 2048.": "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", + "Enter each word of your BIP-39 mnemonic as a number in hexadecimal from 1 to 800.": "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", + "Enter each word of your BIP-39 mnemonic as a number in octal from 1 to 4000.": "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", + "Enter each word of your BIP-39 mnemonic.": "Введите каждое слово вашей BIP-39 мнемоники.", "Error:\n%s": "Ошибка:\n%s", - "Esc": "Эск", - "Explore files?": "Изучить файлы?", - "Exporting to SD card..": "Экспорт в SD -карту ..", - "Extended Public Key": "Расширенный открытый ключ", + "Esc": "Выйти", + "Explore files?": "Исследовать файлы?", + "Exporting to SD card..": "Экспортирование на SD карту..", + "Extended Public Key": "Расширенный Публичный Ключ", "Failed to decrypt": "Не удалось расшифровать", "Failed to load PSBT": "Не удалось загрузить PSBT", "Failed to load address": "Не удалось загрузить адрес", @@ -79,165 +80,165 @@ "Failed to load message": "Не удалось загрузить сообщение", "Failed to load mnemonic": "Не удалось загрузить мнемонику", "Failed to load output descriptor": "Не удалось загрузить выходной дескриптор", - "Failed to load passphrase": "Не удалось загрузить пасфразу", - "Failed to store mnemonic": "Не удалось хранить мнемонику", - "Fee: ": "Платеж:", + "Failed to load passphrase": "Не удалось загрузить фразу-пароль", + "Failed to store mnemonic": "Не удалось сохранить мнемонику", + "Fee: ": "Комиссия: ", "Feed Rate": "Скорость подачи", "Filename": "Имя файла", - "Filename %s exists on SD card, overwrite?": "FileName %S существует на SD -карте, перезаписывает?", - "Fingerprint: %s": "Отпечаток пальца: %s", + "Filename %s exists on SD card, overwrite?": "Файл %s существует на SD карте, перезаписать?", + "Fingerprint: %s": "Фингерпринт: %s", "Firmware exceeds max size: %d": "Прошивка превышает максимальный размер: %d", - "Flute Diameter": "Диаметр флейты", - "Free: ": "Бесплатно:", - "From Storage": "От хранения", - "GRBL": "Грбл", - "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Дайте этой мнемонике пользовательский идентификатор?В противном случае будет использоваться текущий отпечаток пальцев", - "Go": "Идти", - "Heat Interval": "Тепловой интервал", - "Heat Time": "Тепловое время", - "Hex Public Key": "HEX Public Key", + "Flute Diameter": "Flute Диаметр", + "Free: ": "Бесплатно: ", + "From Storage": "Из Памяти", + "GRBL": "GRBL", + "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", + "Go": "OK", + "Heat Interval": "Интервал Нагрева", + "Heat Time": "Время Нагрева", + "Hex Public Key": "Шестнадцатеричный Публичный Ключ", "Hexadecimal": "Шестнадцатеричный", "ID already exists\n": "ID уже существует\n", - "Inputs (%d): ": "Входные данные (%d):", + "Inputs (%d): ": "Входы (%d): ", "Invalid address": "Неверный адрес", "Invalid bootloader": "Неверный загрузчик", - "Invalid mnemonic length": "Неверная мнемоническая длина", - "Invalid public key": "Неверный открытый ключ", + "Invalid mnemonic length": "Неверная длина мнемоники", + "Invalid public key": "Неверный публичный ключ", "Invalid wallet:\n%s": "Неверный кошелек:\n%s", "Invert": "Инвертировать", "Key": "Ключ", - "Key: ": "Ключ:", - "Krux\n\n\nVersion\n%s": "Krux\n\n\nversion\n%s", - "Krux Printer Test QR": "Krux printer test qr", + "Key: ": "Ключ: ", + "Krux\n\n\nVersion\n%s": "Krux\n\n\nВерсия\n%s", + "Krux Printer Test QR": "Тестовый QR Принтера Krux", "Language": "Язык", - "Line Delay": "Линейная задержка", - "Line: ": "Линия:", - "Load Mnemonic": "Загрузить мнемоники", - "Load from SD card?": "Загрузка с SD -карты?", - "Load one?": "Загрузить один?", - "Load?": "Нагрузка?", - "Loading Camera..": "Загрузка камеры ..", - "Loading change address %d..": "Загрузка Изменения Адрес %D ..", - "Loading printer..": "Загрузочный принтер ..", - "Loading receive address %d..": "Загрузка получения адреса %d ..", - "Loading..": "Загрузка ..", + "Line Delay": "Задержка Линии", + "Line: ": "Линия: ", + "Load Mnemonic": "Загрузить Мнемонику", + "Load from SD card?": "Загрузить с SD карты?", + "Load one?": "Загрузить одну?", + "Load?": "Загрузить?", + "Loading Camera..": "Загрузка Камеры..", + "Loading change address %d..": "Загрузка адреса сдачи %d..", + "Loading printer..": "Загрузка принтера..", + "Loading receive address %d..": "Загрузка адреса получения %d..", + "Loading..": "Загрузка..", "Locale": "Локаль", "Location": "Расположение", - "Log Level": "Log Уровень", - "Logging": "Ведение журнала", + "Log Level": "Уровень логирования", + "Logging": "Логирование", "Maximum length exceeded (%s)": "Максимальная длина превышена (%s)", "Message": "Сообщение", - "Missing signature file": "Отсутствует подпись файл", - "Mnemonic": "Мнемоник", - "Mnemonic ID": "Мнемонический идентификатор", - "Mnemonic Storage ID": "Мнемонический идентификатор хранения", + "Missing signature file": "Отсутствует файл подписи", + "Mnemonic": "Мнемоника", + "Mnemonic ID": "ID мнемоники", + "Mnemonic Storage ID": "ID памяти мнемоники", "Mnemonic was not decrypted": "Мнемоника не была расшифрована", "Mnemonic was not encrypted": "Мнемоника не была зашифрована", - "Modified: ": "Модифицировано:", - "Multisig": "Multisig", + "Modified: ": "Изменено: ", + "Multisig": "Мультиподпись", "Network": "Сеть", - "New Mnemonic": "Новая мнемоника", - "New firmware detected.\n\nSHA256:\n%s\n\n\n\nInstall?": "Обнаружено новая прошивка.\n\nsha256:\n%s\n\n\n\ninstall?", + "New Mnemonic": "Новая Мнемоника", + "New firmware detected.\n\nSHA256:\n%s\n\n\n\nInstall?": "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", "No": "Нет", - "No BIP39 passphrase": "Нет BIP39 PassFrase", + "No BIP39 passphrase": "Без BIP39 фразы-пароля", "Not enough rolls!": "Недостаточно бросков!", - "Octal": "Восьми", - "PBKDF2 Iter.": "Pbkdf2 iter.", + "Octal": "Восьмеричный", + "PBKDF2 Iter.": "PBKDF2 Итерации", "PSBT": "PSBT", - "Paint punched dots black so they can be detected.": "Краска перфорированные точки черные, чтобы их можно было обнаружить.", - "Paper Width": "Ширина бумаги", - "Part\n%d / %d": "Часть\n %d / %d", - "Part Size": "Размер частично", - "Passphrase": "Пасфраза", - "Passphrase: ": "Passfrase:", - "Persist": "Сопротивляться", - "Plaintext QR": "Основной текст QR", - "Please load a wallet output descriptor": "Пожалуйста, загрузите дескриптор вывода кошелька", - "Plunge Rate": "Скорость погружения", - "Print Test QR": "Печать тест QR", - "Print to QR?\n\n%s\n\n": "Печать в QR?\n\n%s\n\n", - "Print?\n\n%s\n\n": "Печать?\n\n%s\n\n", + "Paint punched dots black so they can be detected.": "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", + "Paper Width": "Ширина Бумаги", + "Part\n%d / %d": "Часть\n%d / %d", + "Part Size": "Размер Части", + "Passphrase": "Фраза-пароль", + "Passphrase: ": "Фраза-пароль: ", + "Persist": "Постоянная Память", + "Plaintext QR": "QR открытым текстом", + "Please load a wallet output descriptor": "Пожалуйста загрузите выходной дескриптор кошелька", + "Plunge Rate": "Скорость Погружения", + "Print Test QR": "Напечатать Тестовый QR", + "Print to QR?\n\n%s\n\n": "Напечатать в виде QR?\n\n%s\n\n", + "Print?\n\n%s\n\n": "Печатать?\n\n%s\n\n", "Printer": "Принтер", - "Printer Driver not set!": "Драйвер принтера не установлен!", - "Printing\n%d / %d": "Печать\n %d / %d", - "Printing ...": "Печать ...", + "Printer Driver not set!": "Драйвер Принтера не установлен!", + "Printing\n%d / %d": "Идет печать\n%d / %d", + "Printing ...": "Идет печать ...", "Proceed?": "Продолжить?", - "Processing ...": "Обработка ...", - "QR Code": "QR код", - "RX Pin": "RX PIN", - "Receive": "Получать", - "Receive Addresses": "Получить адреса", - "Region: ": "Область, край:", + "Processing ...": "Обрабатываю ...", + "QR Code": "QR Код", + "RX Pin": "RX Пин", + "Receive": "Получить", + "Receive Addresses": "Адрес Получения", + "Region: ": "Регион: ", "Review scanned data, edit if necessary": "Просмотрите отсканированные данные, отредактируйте при необходимости", - "Roll dice at least %d times to generate a mnemonic.": "Рулоть кости, по крайней мере, %D, чтобы генерировать мнемонику.", - "Rolls:\n\n%s": "Rolls:\n\n%s", - "Rolls: %d\n": "Рулоты: %d\n", - "SD card": "SD Card", - "SD card not detected": "SD -карта не обнаружена", - "SD card not detected.": "SD -карта не обнаружена.", - "SHA256 of rolls:\n\n%s": "SHA256 ROLLS:\n\n%s", - "SHA256 of snapshot:\n\n%s": "SHA256 с моментальным снимком:\n\n%s", + "Roll dice at least %d times to generate a mnemonic.": "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", + "Rolls:\n\n%s": "Броски:\n\n%s", + "Rolls: %d\n": "Броски: %d\n", + "SD card": "SD карта", + "SD card not detected": "SD карта не обнаружена", + "SD card not detected.": "SD карта не обнаружена.", + "SHA256 of rolls:\n\n%s": "SHA256 бросков:\n\n%s", + "SHA256 of snapshot:\n\n%s": "SHA256 снэпшота:\n\n%s", "SHA256:\n%s": "SHA256:\n%s", - "Save to SD card?": "Сохранить на SD -карту?", - "Saved to SD card:\n%s": "Сохраняется на SD -карту:\n%s", + "Save to SD card?": "Сохранить на SD карту?", + "Saved to SD card:\n%s": "Сохранено на SD карту:\n%s", "Scale": "Шкала", - "Scan Address": "Адрес сканирования", - "Scan BIP39 passphrase": "Сканирование BIP39 PassFrase", - "Scan Key QR code": "Сканировать ключ QR -код", + "Scan Address": "Отсканировать Адрес", + "Scan BIP39 passphrase": "Отсканировать BIP39 фразу-пароль", + "Scan Key QR code": "Отсканировать Ключ QR код", "Scanning words 1-12 again": "Сканирование слов 1-12 снова", "Scanning words 13-24": "Сканирование слов 13-24", - "SeedQR": "SEEDQR", - "Self-transfer or Change (%d): ": "Самооценка или изменение (%d):", + "SeedQR": "SeedQR", + "Self-transfer or Change (%d): ": "Трансфер самому себе или Сдача (%d): ", "Settings": "Настройки", - "Shutdown": "Неисправность", + "Shutdown": "Выключить", "Shutting down..": "Выключение..", - "Sign": "Знак", - "Sign?": "Знак?", + "Sign": "Подписать", + "Sign?": "Подписать?", "Signature": "Подпись", - "Signed Message": "Подписанное сообщение", - "Signed PSBT": "Подписанный PSBT", - "Single-sig": "Одиночный", - "Size: ": "Размер:", - "Spend (%d): ": "Потратить (%d):", - "Stackbit 1248": "Stackbit 1248", - "Store on Flash": "Хранить на вспышке", - "Store on SD Card": "Магазин на SD -карте", - "Swipe to change mode": "Пылать, чтобы изменить режим", - "TOUCH or ENTER to capture": "Коснуться или войти, чтобы захватить", - "TX Pin": "TX PIN", + "Signed Message": "Подписанное Сообщение", + "Signed PSBT": "Подписанное PSBT", + "Single-sig": "Одна подпись", + "Size: ": "Размер: ", + "Spend (%d): ": "Расход (%d): ", + "Stackbit 1248": "Стэкбит 1248", + "Store on Flash": "Сохранить на Флэш Память", + "Store on SD Card": "Сохранить на SD Карту", + "Swipe to change mode": "Свайпните, чтобы сменить режим", + "TOUCH or ENTER to capture": "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", + "TX Pin": "TX Пин", "Text": "Текст", "Theme": "Тема", - "Thermal": "Тепло", - "Tiny Seed": "Крошечное семя", - "Tiny Seed (Bits)": "Крошечное семя (биты)", + "Thermal": "Термальный", + "Tiny Seed": "Мини Сид-фраза", + "Tiny Seed (Bits)": "Мини Сид-фраза (Биты)", "Tools": "Инструменты", - "Touch Threshold": "Прикосновение порога", - "Touchscreen": "Сенсорный экран", - "Try more?": "Попробовать больше?", - "Type BIP39 passphrase": "Тип BIP39 PassFrase", - "Type Key": "Тип ключа", - "Unit": "Единица", - "Updating bootloader..\n\n%d%%": "Обновление загрузчика ..\n\n%d %%", - "Upgrade complete.\n\nShutting down..": "Обновление завершено.\n\nshutting ..", - "Upgrading firmware..\n\n%d%%": "Модернизация прошивки ..\n\n%d %%", - "Use a black background surface.": "Используйте черную фоновую поверхность.", - "Use camera's entropy to create a new mnemonic": "Используйте энтропию камеры, чтобы создать новую мнемонику", - "Used: ": "Использовал:", - "Value %s out of range: [%s, %s]": "Значение %s из диапазона: [ %s, %s]", - "Via Camera": "Через камеру", - "Via D20": "Через D20", - "Via D6": "Через D6", - "Via Manual Input": "Через ручной ввод", - "Wait for the capture": "Ждать захвата", - "Wallet Descriptor": "Дескриптор кошелька", - "Wallet output descriptor": "Дескриптор вывода кошелька", + "Touch Threshold": "Прикоснитесь Границы", + "Touchscreen": "Тачскрин", + "Try more?": "Попробовать ещё?", + "Type BIP39 passphrase": "Введите BIP39 фразу-пароль", + "Type Key": "Введите Ключ", + "Unit": "Юнит", + "Updating bootloader..\n\n%d%%": "Обновление загрузчика..\n\n%d%%", + "Upgrade complete.\n\nShutting down..": "Обновление завершено.\n\nВыключение..", + "Upgrading firmware..\n\n%d%%": "Обновление прошивки..\n\n%d%%", + "Use a black background surface.": "Использовать черную фоновую поверхность.", + "Use camera's entropy to create a new mnemonic": "Использовать энтропию камеры, чтобы создать новую мнемонику", + "Used: ": "Использовано: ", + "Value %s out of range: [%s, %s]": "Значение %s вне диапозона: [%s, %s]", + "Via Camera": "С Помощью Камеры", + "Via D20": "С Помощью D20", + "Via D6": "С Помощью D6", + "Via Manual Input": "С Помощью Ручного Ввода", + "Wait for the capture": "Дождитесь Захвата", + "Wallet Descriptor": "Дескриптор Кошелька", + "Wallet output descriptor": "Выходной дескриптор кошелька", "Wallet output descriptor loaded!": "Выходной дескриптор кошелька загружен!", - "Wallet output descriptor not found.": "Дескриптор вывода кошелька не найден.", - "Warning:\nIncomplete output descriptor": "ПРЕДУПРЕЖДЕНИЕ:\nincoplete Вывод дескриптор", + "Wallet output descriptor not found.": "Выходной дескриптор кошелька не найден.", + "Warning:\nIncomplete output descriptor": "Предупреждение:\nНеполный выходной дескриптор", "Word %d": "Слово %d", - "Word Numbers": "Номера слов", + "Word Numbers": "Числа Слов", "Words": "Слова", "Yes": "Да", - "Your changes will be kept on device flash storage.": "Ваши изменения будут храниться на хранении вспышки устройства.", - "Your changes will be kept on the SD card.": "Ваши изменения будут храниться на SD -карте." -} \ No newline at end of file + "Your changes will be kept on device flash storage.": "Ваши изменения буду храниться на флэш памяти устройства.", + "Your changes will be kept on the SD card.": "Ваши изменения будут храниться на SD карте." +} diff --git a/src/krux/translations.py b/src/krux/translations.py index 6859f97fd..d33138ccf 100644 --- a/src/krux/translations.py +++ b/src/krux/translations.py @@ -21,249 +21,249 @@ # THE SOFTWARE. # pylint: disable=C0301 translation_table = { - "pt-BR": { - 1185266064: "%d da %d multisig", - 2004520398: "%d. Troco: \n\n%s\n\n", - 3862364126: "%d. Autotransferência: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n é um endereço de troco válido!", - 3921290840: "%s\n\né um endereço de recepção válido!", - 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", - 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", - 3348584292: "(Experimental)", - 2739590230: "12 palavras", - 1310058127: "24 palavras", + "ru-RU": { + 1185266064: "%d из %d мультиподпись", + 2004520398: "%d. Сдача: \n\n%s\n\n", + 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", + 3264377309: "%d. Расход: \n\n%s\n\n", + 2399232215: "%s\n\nвалидный адрес сдачи!", + 3921290840: "%s\n\nвалидный адрес получения!", + 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", + 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", + 3348584292: "(Эксперементальный)", + 2739590230: "12 слов", + 1310058127: "24 слова", 2743272264: "ABC", - 1949634023: "Sobre", + 1949634023: "О Программе", 1517128857: "Adafruit", - 3270727197: "Endereço", - 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", - 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", - 88746165: "Antirreflexo desativado", - 1521033296: "Antirreflexo ativado", - 1056821534: "Tem certeza?", - 3247612282: "Mnemônico BIP39", - 3455872521: "Voltar", - 2541860807: "Backing up bootloader..\n\n%d%%", - 2256777600: "Assinatura Inválida", - 3937333362: "Baudrate", - 427617266: "Bitcoin", - 928727036: "Borda", + 3270727197: "Адрес", + 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", + 283202181: "Правильно совместите камеру и Мини Сид-фразу.", + 88746165: "Антиблик отключен", + 1521033296: "Антиблик включен", + 1056821534: "Вы уверены?", + 3247612282: "BIP39 Мнемоника", + 3455872521: "Назад", + 2541860807: "Резервное копирование загрузчика..\n\n%d%%", + 2256777600: "Плохая подпись", + 3937333362: "Скорость Передачи Данных", + 427617266: "Биткоин", + 928727036: "Заполнение границ", 213030954: "CNC", - 1207696150: "Troco", - 3126552510: "Endereços de Troco", - 1583186953: "Mudar o tema e reiniciar?", - 2697733395: "Mudanças salvas no cartão SD!", - 388908871: "Alterações só durarão até o desligamento.", - 3442025874: "Verifique o cartão SD", - 3119547911: "Verificar se este endereço pertence a carteira?", - 2856261511: "Endereço de troco %d não corresponde.", - 2788541416: "Endereço de recebimento %d não corresponde.", - 2446472910: "Verificando correspondência do endereço de troco %d ..", - 2470115694: "Verificando o cartão SD..", - 3655273987: "Verificando correspondência do endereço de recebimento %d ..", - 2407028014: "SeedQR Compacto", - 4041895036: "Continuar?", - 4094072796: "Gerar Código QR", - 167798282: "Gerar código QR do texto?", - 2767642191: "Criado: ", - 3513215254: "Código QR Customizado", - 124617190: "Profundidade de Corte", - 597912140: "Método de Corte", - 2504034831: "Decimal", - 2751113454: "Descriptografar?", - 1016609898: "Excluir Arquivo?", - 1364509700: "Excluir Mnemônico", - 4102535566: "Profundidade da Passagem", - 2791699253: "Derivação: %s", - 1230133196: "Armazenamento flash do dispositivo não detectado.", - 3836852788: "Feito?", - 382368239: "Driver", - 3978947916: "Codificador", - 4090746898: "Debounce do Encoder", - 374684711: "Criptografar Mnemônico", - 1244124409: "Código QR Criptografado", - 2968548114: "Mnemonic criptografado não foi armazenado", - 3315319371: "Mnemônico criptografado foi armazenado com ID:", - 350279787: "Criptografia", - 2601598799: "Modo de Criptografia", - 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", - 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", - 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", - 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", - 784361051: "Erro:\n%s", - 1505332462: "Esc", - 3838465623: "Explorar arquivos?", - 4170881190: "Exportando para o cartão SD..", - 1711312434: "Chave Pública Estendida", - 383371114: "Falhou em descriptografar", - 3048830188: "Falhou ao carregar PSBT", - 4192663412: "Falhou ao carregar endereço", - 1996021743: "Falha ao carregar a chave", - 1108715658: "Falhou ao carregar mensagem", - 1081425878: "Falhou ao carregar mnemônico", - 928667220: "Falha ao carregar o descritor de saída", - 1620572516: "Falha ao carregar a senha", - 2946146830: "Falhou ao armazenar mnemônico", - 1303554751: "Taxa: ", - 104500973: "Taxa de Alimentação", - 3313339187: "Nome do arquivo", - 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", - 3737729752: "Impressão digital: %s", - 2542772894: "Firmware excede o tamanho máximo: %d", - 1406590538: "Diâmetro da Fresa", - 3086093110: "Livre: ", - 1893243331: "Do Armazenamento", + 1207696150: "Сдача", + 3126552510: "Адрес Сдачи", + 1583186953: "Сменить тему и перезагрузить?", + 2697733395: "Изменения сохранены на SD карте!", + 388908871: "Изменения будут храниться до выключения.", + 3442025874: "Проверить SD Карту", + 3119547911: "Проверить, что адрес принадлежит этому кошельку?", + 2856261511: "Проверено %d адресов сдачи без совпадений.", + 2788541416: "Проверено %d адресов получения без совпадений.", + 2446472910: "Проверяем адрес сдачи %d на совпадение..", + 2470115694: "Проверка SD карты..", + 3655273987: "Проверяем адрес получения %d на совпадение..", + 2407028014: "Компактный SeedQR", + 4041895036: "Продолжить?", + 4094072796: "Создать QR Код", + 167798282: "Создать QR код из текста?", + 2767642191: "Создано", + 3513215254: "Пользовательский QR Код", + 124617190: "Глубина Резки", + 597912140: "Метод Резки", + 2504034831: "Десятичный", + 2751113454: "Расшифровать?", + 1016609898: "Удалить Файл?", + 1364509700: "Удалить Мнемонику", + 4102535566: "Глубина За Проход", + 2791699253: "Производный путь: %s", + 1230133196: "Флэш память устройства не обнаружена.", + 3836852788: "Готово?", + 382368239: "Драйвер", + 3978947916: "Кодер", + 4090746898: "Дебаунс Кодера", + 374684711: "Зашифровать Мнемонику", + 1244124409: "Зашифрованный QR Код", + 2968548114: "Зашифрованная мнемоника не была сохранена", + 3315319371: "Зашифрованная мнемоника была сохранена с ID", + 350279787: "Шифрование", + 2601598799: "Метод шифрования", + 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", + 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", + 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", + 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", + 784361051: "Ошибка:\n%s", + 1505332462: "Выйти", + 3838465623: "Исследовать файлы?", + 4170881190: "Экспортирование на SD карту..", + 1711312434: "Расширенный Публичный Ключ", + 383371114: "Не удалось расшифровать", + 3048830188: "Не удалось загрузить PSBT", + 4192663412: "Не удалось загрузить адрес", + 1996021743: "Не удалось загрузить ключ", + 1108715658: "Не удалось загрузить сообщение", + 1081425878: "Не удалось загрузить мнемонику", + 928667220: "Не удалось загрузить выходной дескриптор", + 1620572516: "Не удалось загрузить фразу-пароль", + 2946146830: "Не удалось сохранить мнемонику", + 1303554751: "Комиссия: ", + 104500973: "Скорость подачи", + 3313339187: "Имя файла", + 1982637349: "Файл %s существует на SD карте, перезаписать?", + 3737729752: "Фингерпринт: %s", + 2542772894: "Прошивка превышает максимальный размер: %d", + 1406590538: "Flute Диаметр", + 3086093110: "Бесплатно: ", + 1893243331: "Из Памяти", 4120536442: "GRBL", - 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", - 602716148: "Ir", - 831562513: "Intervalo de Aquecimento", - 2300171403: "Tempo de Aquecimento", - 3580020863: "Chave pública hexadecimal", - 2691246967: "Hexadecimal", - 2736309107: "Id já existe\n", - 631342955: "Entradas (%d): ", - 2585599782: "Endereço inválido", - 2874529150: "Bootloader inválido", - 4093416954: "Comprimento de mnemônico inválido", - 1422874211: "Chave pública inválida", - 2443867979: "Carteira inválida:\n%s", - 4122897393: "Invertido", - 3000888649: "Chave", - 2686333978: "Chave:", - 4123798664: "Krux\n\n\nVersão\n%s", - 3835918229: "Teste de impressão de QR krux", - 766317539: "Língua", - 972436696: "Atraso de Linha", - 3596093890: "Linha: ", - 2820726296: "Carregar Mnemônico", - 879727077: "Carregar do cartão SD?", - 669106195: "Carregar um?", - 3330705289: "Carregar?", - 2596531078: "Carregando Câmera..", - 596389387: "Carregando endereço de troco %d..", - 336702608: "Carregando impressora..", - 2538883522: "Carregando endereço de recebimento %d..", - 3159494909: "Carregando..", - 1177338798: "Idioma", - 2817059741: "Local", - 63976957: "Nível de log", - 86530918: "Logging", - 2917810189: "Comprimento máximo excedido (%s)", - 2030045667: "Mensagem", - 3928301843: "Arquivo de assinatura faltando", - 1948316555: "Mnemônico", - 2123991188: "ID do mnemônico", - 3911073154: "ID de armazenamento", - 570639842: "Mnemônico não foi descriptografado", - 1746030071: "Mnemônico não foi criptografado", - 1458925155: "Modificado:", - 1845376098: "Multisig", - 2939797024: "Rede", - 73574491: "Novo Mnemônico", - 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", - 4063104189: "Não", - 3927838899: "Sem senha BIP39", - 4092516657: "Jogadas insuficientes!", - 1577637745: "Octal", - 3312581301: "Iter. PBKDF2", + 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", + 602716148: "OK", + 831562513: "Интервал Нагрева", + 2300171403: "Время Нагрева", + 3580020863: "Шестнадцатеричный Публичный Ключ", + 2691246967: "Шестнадцатеричный", + 2736309107: "ID уже существует\n", + 631342955: "Входы (%d): ", + 2585599782: "Неверный адрес", + 2874529150: "Неверный загрузчик", + 4093416954: "Неверная длина мнемоники", + 1422874211: "Неверный публичный ключ", + 2443867979: "Неверный кошелек:\n%s", + 4122897393: "Инвертировать", + 3000888649: "Ключ", + 2686333978: "Ключ: ", + 4123798664: "Krux\n\n\nВерсия\n%s", + 3835918229: "Тестовый QR Принтера Krux", + 766317539: "Язык", + 972436696: "Задержка Линии", + 3596093890: "Линия: ", + 2820726296: "Загрузить Мнемонику", + 879727077: "Загрузить с SD карты?", + 669106195: "Загрузить одну?", + 3330705289: "Загрузить?", + 2596531078: "Загрузка Камеры..", + 596389387: "Загрузка адреса сдачи %d..", + 336702608: "Загрузка принтера..", + 2538883522: "Загрузка адреса получения %d..", + 3159494909: "Загрузка..", + 1177338798: "Локаль", + 2817059741: "Расположение", + 63976957: "Уровень логирования", + 86530918: "Логирование", + 2917810189: "Максимальная длина превышена (%s)", + 2030045667: "Сообщение", + 3928301843: "Отсутствует файл подписи", + 1948316555: "Мнемоника", + 2123991188: "ID мнемоники", + 3911073154: "ID памяти мнемоники", + 570639842: "Мнемоника не была расшифрована", + 1746030071: "Мнемоника не была зашифрована", + 1458925155: "Изменено: ", + 1845376098: "Мультиподпись", + 2939797024: "Сеть", + 73574491: "Новая Мнемоника", + 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", + 4063104189: "Нет", + 3927838899: "Без BIP39 фразы-пароля", + 4092516657: "Недостаточно бросков!", + 1577637745: "Восьмеричный", + 3312581301: "PBKDF2 Итерации", 721090621: "PSBT", - 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", - 2987800462: "Largura do papel", - 3050763890: "Parte\n%d / %d", - 3559456868: "Tamanho da peça", - 4249903283: "Senha", - 3712257341: "Senha:", - 140802882: "Salvar", - 1703779997: "QR em Texto", - 3561756278: "Carregue um descritor da carteira", - 784609464: "Taxa de Mergulho", - 3037062877: "Imprimir QR de teste", - 4278257699: "Imprimir QR?\n\n%s\n\n", - 516488026: "Imprimir?\n\n%s\n\n", - 1123106929: "Impressora", - 3903571079: "Driver de impressora não está definido!", - 2609799302: "Imprimindo\n%d / %d", - 844861889: "Imprimindo ...", - 2580599003: "Seguir?", - 556126964: "Processando ...", - 1848310591: "Código QR", - 710709610: "Pino RX", - 2697857197: "Recebimento", - 1746677167: "Endereços de Recebimento", - 364354944: "Região: ", - 1662254634: "Revise os dados, edite se necessário", - 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", - 856795528: "Jogadas:\n\n%s", - 255086803: "Jogadas: %d\n", - 3976793317: "Cartão SD", - 2827687530: "Cartão SD não detectado", - 2736513298: "Cartão SD não detectado.", - 3593785196: "SHA256 de jogadas:\n\n%s", - 1143278725: "Sha256 da imagem:\n\n%s", + 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", + 2987800462: "Ширина Бумаги", + 3050763890: "Часть\n%d / %d", + 3559456868: "Размер Части", + 4249903283: "Фраза-пароль", + 3712257341: "Фраза-пароль: ", + 140802882: "Постоянная Память", + 1703779997: "QR открытым текстом", + 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", + 784609464: "Скорость Погружения", + 3037062877: "Напечатать Тестовый QR", + 4278257699: "Напечатать в виде QR?\n\n%s\n\n", + 516488026: "Печатать?\n\n%s\n\n", + 1123106929: "Принтер", + 3903571079: "Драйвер Принтера не установлен!", + 2609799302: "Идет печать\n%d / %d", + 844861889: "Идет печать ...", + 2580599003: "Продолжить?", + 556126964: "Обрабатываю ...", + 1848310591: "QR Код", + 710709610: "RX Пин", + 2697857197: "Получить", + 1746677167: "Адрес Получения", + 364354944: "Регион: ", + 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", + 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", + 856795528: "Броски:\n\n%s", + 255086803: "Броски: %d\n", + 3976793317: "SD карта", + 2827687530: "SD карта не обнаружена", + 2736513298: "SD карта не обнаружена.", + 3593785196: "SHA256 бросков:\n\n%s", + 1143278725: "SHA256 снэпшота:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Salvar no cartão SD?", - 810036588: "Salvo no cartão SD:\n%s", - 763824768: "Escala", - 4117455079: "Escanear Endereço", - 3219991109: "Escanear a senha BIP39", - 2537207336: "Escanear código QR da chave", - 4006316572: "Escaneando as palavras 1-12 novamente", - 2736506158: "Escaneando as palavras 13-24", + 3531742595: "Сохранить на SD карту?", + 810036588: "Сохранено на SD карту:\n%s", + 763824768: "Шкала", + 4117455079: "Отсканировать Адрес", + 3219991109: "Отсканировать BIP39 фразу-пароль", + 2537207336: "Отсканировать Ключ QR код", + 4006316572: "Сканирование слов 1-12 снова", + 2736506158: "Сканирование слов 13-24", 266935239: "SeedQR", - 1698829144: "Autotransferência ou Troco (%d): ", - 473154195: "Configurações", - 1825881236: "Desligar", - 2120776272: "Desligando..", - 1061961408: "Assinar", - 4282338366: "Assinar?", - 746161122: "Assinatura", - 1988416729: "Mensagem Assinada", - 3672006076: "PSBT Assinada", - 2281377987: "Single-sig", - 4221794628: "Total: ", - 2309020186: "Gastos (%d): ", - 3355862324: "Stackbit 1248", - 3303592908: "Armazene na Flash", - 720041451: "Armazene no Cartão SD", - 3514476519: "Deslize para mudar de modo", - 1898550184: "TOQUE ou ENTER para capturar", - 4228215415: "Pino TX", - 2612594937: "Texto", - 1454688268: "Tema", - 1180180513: "Térmica", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Ferramentas", - 3684696112: "Limiar de Toque", - 2978718564: "Touchscreen", - 2732611775: "Tentar mais?", - 1487826746: "Digitar a senha BIP39", - 2061556020: "Digite a Chave", - 2089395053: "Unidade", - 2845607430: "Atualizando bootloader..\n\n%d%%", - 4164597446: "Atualização completa.\n\nDesligando..", - 2736001501: "Atualizando firmware..\n\n%d%%", - 2674953168: "Use uma superfície de fundo preta.", - 2402455261: "Use a entropia da câmera para criar um novo mnemônico", - 236075140: "Usado: ", - 4003084591: "Valor %s fora do alcance: [ %s, %s]", - 4191058607: "Pela Câmera", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Por entrada manual", - 2504354847: "Aguarde a captura", - 2297028319: "Descritor de Carteira", - 4232654916: "Descritor da carteira", - 2587172867: "Descritor de saída da carteira carregado!", - 2499782468: "O descritor de saída da carteira não foi encontrado.", - 1831109430: "Atenção:\nDescritor de saída incompleto", - 797660533: "Palavra %d", - 3742424146: "Números das Palavras", - 2965123464: "Palavras", - 1303016265: "Sim", - 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", - 2569054451: "Suas alterações serão mantidas no cartão SD.", + 1698829144: "Трансфер самому себе или Сдача (%d): ", + 473154195: "Настройки", + 1825881236: "Выключить", + 2120776272: "Выключение..", + 1061961408: "Подписать", + 4282338366: "Подписать?", + 746161122: "Подпись", + 1988416729: "Подписанное Сообщение", + 3672006076: "Подписанное PSBT", + 2281377987: "Одна подпись", + 4221794628: "Размер: ", + 2309020186: "Расход (%d): ", + 3355862324: "Стэкбит 1248", + 3303592908: "Сохранить на Флэш Память", + 720041451: "Сохранить на SD Карту", + 3514476519: "Свайпните, чтобы сменить режим", + 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", + 4228215415: "TX Пин", + 2612594937: "Текст", + 1454688268: "Тема", + 1180180513: "Термальный", + 4119292117: "Мини Сид-фраза", + 1732872974: "Мини Сид-фраза (Биты)", + 725348723: "Инструменты", + 3684696112: "Прикоснитесь Границы", + 2978718564: "Тачскрин", + 2732611775: "Попробовать ещё?", + 1487826746: "Введите BIP39 фразу-пароль", + 2061556020: "Введите Ключ", + 2089395053: "Юнит", + 2845607430: "Обновление загрузчика..\n\n%d%%", + 4164597446: "Обновление завершено.\n\nВыключение..", + 2736001501: "Обновление прошивки..\n\n%d%%", + 2674953168: "Использовать черную фоновую поверхность.", + 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", + 236075140: "Использовано: ", + 4003084591: "Значение %s вне диапозона: [%s, %s]", + 4191058607: "С Помощью Камеры", + 1254681955: "С Помощью D20", + 525309547: "С Помощью D6", + 590330112: "С Помощью Ручного Ввода", + 2504354847: "Дождитесь Захвата", + 2297028319: "Дескриптор Кошелька", + 4232654916: "Выходной дескриптор кошелька", + 2587172867: "Выходной дескриптор кошелька загружен!", + 2499782468: "Выходной дескриптор кошелька не найден.", + 1831109430: "Предупреждение:\nНеполный выходной дескриптор", + 797660533: "Слово %d", + 3742424146: "Числа Слов", + 2965123464: "Слова", + 1303016265: "Да", + 771968845: "Ваши изменения буду храниться на флэш памяти устройства.", + 2569054451: "Ваши изменения будут храниться на SD карте.", }, "pl-PL": { 1185266064: "%d z %d multisig", @@ -752,522 +752,278 @@ 771968845: "Sus cambios se guardarán en el almacenamiento flash del dispositivo.", 2569054451: "Sus cambios se guardarán en la tarjeta SD.", }, - "de-DE": { - 1185266064: "%d von %d Multisig", - 2004520398: "%d. Change: \n\n%s\n\n", - 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", - 3264377309: "%d. Ausgaben: \n\n%s\n\n", - 2399232215: "%s\n\nist eine gültige Change Adresse!", - 3921290840: "%s\n\nist eine gültige Empfangsadresse!", - 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", - 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", + "pt-BR": { + 1185266064: "%d da %d multisig", + 2004520398: "%d. Troco: \n\n%s\n\n", + 3862364126: "%d. Autotransferência: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n é um endereço de troco válido!", + 3921290840: "%s\n\né um endereço de recepção válido!", + 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", + 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", 3348584292: "(Experimental)", - 2739590230: "12 Wörter", - 1310058127: "24 Wörter", + 2739590230: "12 palavras", + 1310058127: "24 palavras", 2743272264: "ABC", - 1949634023: "Über", + 1949634023: "Sobre", 1517128857: "Adafruit", - 3270727197: "Adresse", - 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", - 283202181: "Richte Kamera und Tiny Seed korrekt aus.", - 88746165: "Blendschutz deaktiviert", - 1521033296: "Blendschutz aktiviert", - 1056821534: "Bist Du sicher?", - 3247612282: "BIP39 Mnemonic", - 3455872521: "Zurück", - 2541860807: "Bootloader wird gesichert..\n\n%d%%", - 2256777600: "Ungültige Signatur", + 3270727197: "Endereço", + 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", + 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", + 88746165: "Antirreflexo desativado", + 1521033296: "Antirreflexo ativado", + 1056821534: "Tem certeza?", + 3247612282: "Mnemônico BIP39", + 3455872521: "Voltar", + 2541860807: "Backing up bootloader..\n\n%d%%", + 2256777600: "Assinatura Inválida", 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Randpolsterung", + 928727036: "Borda", 213030954: "CNC", - 1207696150: "Change Adresse", - 3126552510: "Change Adressen", - 1583186953: "Thema ändern und neu starten?", - 2697733395: "Änderungen auf SD-Karte gespeichert!", - 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", - 3442025874: "Prüfe SD-Karte", - 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", - 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", - 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", - 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", - 2470115694: "Suche nach SD-Karte..", - 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", - 2407028014: "Kompakt SeedQR", - 4041895036: "Weiter?", - 4094072796: "Erstelle QR-Code", - 167798282: "QR-Code aus Text erzeugen?", - 2767642191: "Erstellt:", - 3513215254: "Benutzerdefinierte QR-Code", - 124617190: "Schnitttiefe", - 597912140: "Cut-Methode", - 2504034831: "Dezimal", - 2751113454: "Entschlüsseln?", - 1016609898: "Datei löschen?", - 1364509700: "Mnemonic löschen", - 4102535566: "Tiefe pro Durchgang", - 2791699253: "Ableitung: %s", - 1230133196: "Geräte-Flash-Speicher nicht erkannt.", - 3836852788: "Fertig?", + 1207696150: "Troco", + 3126552510: "Endereços de Troco", + 1583186953: "Mudar o tema e reiniciar?", + 2697733395: "Mudanças salvas no cartão SD!", + 388908871: "Alterações só durarão até o desligamento.", + 3442025874: "Verifique o cartão SD", + 3119547911: "Verificar se este endereço pertence a carteira?", + 2856261511: "Endereço de troco %d não corresponde.", + 2788541416: "Endereço de recebimento %d não corresponde.", + 2446472910: "Verificando correspondência do endereço de troco %d ..", + 2470115694: "Verificando o cartão SD..", + 3655273987: "Verificando correspondência do endereço de recebimento %d ..", + 2407028014: "SeedQR Compacto", + 4041895036: "Continuar?", + 4094072796: "Gerar Código QR", + 167798282: "Gerar código QR do texto?", + 2767642191: "Criado: ", + 3513215254: "Código QR Customizado", + 124617190: "Profundidade de Corte", + 597912140: "Método de Corte", + 2504034831: "Decimal", + 2751113454: "Descriptografar?", + 1016609898: "Excluir Arquivo?", + 1364509700: "Excluir Mnemônico", + 4102535566: "Profundidade da Passagem", + 2791699253: "Derivação: %s", + 1230133196: "Armazenamento flash do dispositivo não detectado.", + 3836852788: "Feito?", 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-Entprellung", - 374684711: "Verschlüssel Mnemonic", - 1244124409: "Verschlüsselter QR-Code", - 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", - 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", - 350279787: "Verschlüsselung", - 2601598799: "Verschlüsselungsmodus", - 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", - 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", - 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", - 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", - 784361051: "Fehler:\n%s", + 3978947916: "Codificador", + 4090746898: "Debounce do Encoder", + 374684711: "Criptografar Mnemônico", + 1244124409: "Código QR Criptografado", + 2968548114: "Mnemonic criptografado não foi armazenado", + 3315319371: "Mnemônico criptografado foi armazenado com ID:", + 350279787: "Criptografia", + 2601598799: "Modo de Criptografia", + 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", + 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", + 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", + 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", + 784361051: "Erro:\n%s", 1505332462: "Esc", - 3838465623: "Dateien durchsuchen?", - 4170881190: "Auf SD-Karte exportieren..", - 1711312434: "Öffentlicher Schlüssel", - 383371114: "Entschlüsselung fehlgeschlagen", - 3048830188: "PSBT konnte nicht geladen werden", - 4192663412: "Adresse konnte nicht geladen werden", - 1996021743: "Schlüssel konnte nicht geladen werden", - 1108715658: "Nachricht konnte nicht geladen werden", - 1081425878: "Mnemonic konnte nicht geladen werden", - 928667220: "Ausgabedeskriptor konnte nicht geladen werden", - 1620572516: "Passphrase konnte nicht geladen werden", - 2946146830: "Mnemonic konnte nicht gespeichert werden", - 1303554751: "Gebühr: ", - 104500973: "Vorschubgeschwindigkeit", - 3313339187: "Dateiname", - 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", - 3737729752: "Fingerabdruck: %s", - 2542772894: "Die Firmware übersteigt die maximale Größe: %d", - 1406590538: "Flötendurchmesser", - 3086093110: "Frei: ", - 1893243331: "Vom Speicher", + 3838465623: "Explorar arquivos?", + 4170881190: "Exportando para o cartão SD..", + 1711312434: "Chave Pública Estendida", + 383371114: "Falhou em descriptografar", + 3048830188: "Falhou ao carregar PSBT", + 4192663412: "Falhou ao carregar endereço", + 1996021743: "Falha ao carregar a chave", + 1108715658: "Falhou ao carregar mensagem", + 1081425878: "Falhou ao carregar mnemônico", + 928667220: "Falha ao carregar o descritor de saída", + 1620572516: "Falha ao carregar a senha", + 2946146830: "Falhou ao armazenar mnemônico", + 1303554751: "Taxa: ", + 104500973: "Taxa de Alimentação", + 3313339187: "Nome do arquivo", + 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", + 3737729752: "Impressão digital: %s", + 2542772894: "Firmware excede o tamanho máximo: %d", + 1406590538: "Diâmetro da Fresa", + 3086093110: "Livre: ", + 1893243331: "Do Armazenamento", 4120536442: "GRBL", - 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", - 602716148: "Go", - 831562513: "Wärmeintervall", - 2300171403: "Hitzezeit", - 3580020863: "Hex öffentlicher Schlüssel", - 2691246967: "Hexadezimal", - 2736309107: "ID existiert bereits\n", - 631342955: "Input (%d): ", - 2585599782: "Ungültige Adresse", - 2874529150: "Ungültiger Bootloader", - 4093416954: "Ungültige mnemonische Lange", - 1422874211: "Ungültiger öffentlicher Schlüssel", - 2443867979: "Ungültige Wallet:\n%s", - 4122897393: "Umkehren", - 3000888649: "Schlüssel", - 2686333978: "Schlüssel:", - 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Krux Drucker Test-QR", - 766317539: "Sprache", - 972436696: "Leitungsverzögerung", - 3596093890: "Linie: ", - 2820726296: "Mnemonic laden", - 879727077: "Von SD-Karte laden?", - 669106195: "Eine laden?", - 3330705289: "Laden?", - 2596531078: "Lade Kamera..", - 596389387: "Lade Change Adresse %d..", - 336702608: "Drucker wird geladen..", - 2538883522: "Lade Empfangsadresse %d..", - 3159494909: "Wird geladen..", - 1177338798: "Spracheinstellung", - 2817059741: "Speicherort", - 63976957: "Log Level", + 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", + 602716148: "Ir", + 831562513: "Intervalo de Aquecimento", + 2300171403: "Tempo de Aquecimento", + 3580020863: "Chave pública hexadecimal", + 2691246967: "Hexadecimal", + 2736309107: "Id já existe\n", + 631342955: "Entradas (%d): ", + 2585599782: "Endereço inválido", + 2874529150: "Bootloader inválido", + 4093416954: "Comprimento de mnemônico inválido", + 1422874211: "Chave pública inválida", + 2443867979: "Carteira inválida:\n%s", + 4122897393: "Invertido", + 3000888649: "Chave", + 2686333978: "Chave:", + 4123798664: "Krux\n\n\nVersão\n%s", + 3835918229: "Teste de impressão de QR krux", + 766317539: "Língua", + 972436696: "Atraso de Linha", + 3596093890: "Linha: ", + 2820726296: "Carregar Mnemônico", + 879727077: "Carregar do cartão SD?", + 669106195: "Carregar um?", + 3330705289: "Carregar?", + 2596531078: "Carregando Câmera..", + 596389387: "Carregando endereço de troco %d..", + 336702608: "Carregando impressora..", + 2538883522: "Carregando endereço de recebimento %d..", + 3159494909: "Carregando..", + 1177338798: "Idioma", + 2817059741: "Local", + 63976957: "Nível de log", 86530918: "Logging", - 2917810189: "Maximale Länge überschritten (%s)", - 2030045667: "Nachricht", - 3928301843: "Fehlende Signaturdatei", - 1948316555: "Mnemonic", - 2123991188: "Mnemonische ID", - 3911073154: "Mnemonische Speicher-ID", - 570639842: "Mnemonic wurde nicht entschlüsselt", - 1746030071: "Mnemonic wurde nicht verschlüsselt", - 1458925155: "Geändert:", + 2917810189: "Comprimento máximo excedido (%s)", + 2030045667: "Mensagem", + 3928301843: "Arquivo de assinatura faltando", + 1948316555: "Mnemônico", + 2123991188: "ID do mnemônico", + 3911073154: "ID de armazenamento", + 570639842: "Mnemônico não foi descriptografado", + 1746030071: "Mnemônico não foi criptografado", + 1458925155: "Modificado:", 1845376098: "Multisig", - 2939797024: "Netzwerk", - 73574491: "Neue Mnemonic", - 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", - 4063104189: "Nein", - 3927838899: "Keine BIP39 Passphrase", - 4092516657: "Nicht genug Würfe!", - 1577637745: "Oktal", - 3312581301: "PBKDF2-Iter.", + 2939797024: "Rede", + 73574491: "Novo Mnemônico", + 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", + 4063104189: "Não", + 3927838899: "Sem senha BIP39", + 4092516657: "Jogadas insuficientes!", + 1577637745: "Octal", + 3312581301: "Iter. PBKDF2", 721090621: "PSBT", - 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", - 2987800462: "Papierbreite", - 3050763890: "Teil\n%d / %d", - 3559456868: "Teilegröße", - 4249903283: "Passphrase", - 3712257341: "Passphrase:", - 140802882: "Speicher", - 1703779997: "Klartext-QR", - 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", - 784609464: "Tauchrate", - 3037062877: "Drucke Test-QR", - 4278257699: "Als QR-Code drucken?\n\n%s\n\n", - 516488026: "Drucken?\n\n%s\n\n", - 1123106929: "Drucker", - 3903571079: "Druckertreiber nicht gesetzt!", - 2609799302: "Drucken\n%d / %d", - 844861889: "Wird gedruckt ...", - 2580599003: "Weiter?", - 556126964: "Wird bearbeitet ...", - 1848310591: "QR-Code", - 710709610: "RX Pin", - 2697857197: "Empfangen", - 1746677167: "Empfangsadresse", - 364354944: "Region: ", - 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", - 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", - 856795528: "Würfe:\n\n%s", - 255086803: "Würfe: %d\n", - 3976793317: "SD-Karte", - 2827687530: "SD-Karte nicht erkannt", - 2736513298: "SD-Karte nicht erkannt.", - 3593785196: "SHA256 der Würfe:\n\n%s", - 1143278725: "SHA256 des Snapshots:\n\n%s", + 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", + 2987800462: "Largura do papel", + 3050763890: "Parte\n%d / %d", + 3559456868: "Tamanho da peça", + 4249903283: "Senha", + 3712257341: "Senha:", + 140802882: "Salvar", + 1703779997: "QR em Texto", + 3561756278: "Carregue um descritor da carteira", + 784609464: "Taxa de Mergulho", + 3037062877: "Imprimir QR de teste", + 4278257699: "Imprimir QR?\n\n%s\n\n", + 516488026: "Imprimir?\n\n%s\n\n", + 1123106929: "Impressora", + 3903571079: "Driver de impressora não está definido!", + 2609799302: "Imprimindo\n%d / %d", + 844861889: "Imprimindo ...", + 2580599003: "Seguir?", + 556126964: "Processando ...", + 1848310591: "Código QR", + 710709610: "Pino RX", + 2697857197: "Recebimento", + 1746677167: "Endereços de Recebimento", + 364354944: "Região: ", + 1662254634: "Revise os dados, edite se necessário", + 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", + 856795528: "Jogadas:\n\n%s", + 255086803: "Jogadas: %d\n", + 3976793317: "Cartão SD", + 2827687530: "Cartão SD não detectado", + 2736513298: "Cartão SD não detectado.", + 3593785196: "SHA256 de jogadas:\n\n%s", + 1143278725: "Sha256 da imagem:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Auf SD-Karte speichern?", - 810036588: "Auf SD-Karte gespeichert:\n%s", - 763824768: "Skala", - 4117455079: "Adresse\nscannen", - 3219991109: "Scan BIP39 Passphrase", - 2537207336: "Schlüssel QR-Code scannen", - 4006316572: "Wörter 1-12 erneut scannen", - 2736506158: "Wörter 13-24 scannen", + 3531742595: "Salvar no cartão SD?", + 810036588: "Salvo no cartão SD:\n%s", + 763824768: "Escala", + 4117455079: "Escanear Endereço", + 3219991109: "Escanear a senha BIP39", + 2537207336: "Escanear código QR da chave", + 4006316572: "Escaneando as palavras 1-12 novamente", + 2736506158: "Escaneando as palavras 13-24", 266935239: "SeedQR", - 1698829144: "Selbstübertragung oder Change (%d): ", - 473154195: "Einstellungen", - 1825881236: "Ausschalten", - 2120776272: "Herunterfahren..", - 1061961408: "Signieren", - 4282338366: "Signieren?", - 746161122: "Signatur", - 1988416729: "Signierte Nachricht", - 3672006076: "Signierte PSBT", - 2281377987: "Single-Sig", - 4221794628: "Größe: ", - 2309020186: "Ausgabe (%d): ", + 1698829144: "Autotransferência ou Troco (%d): ", + 473154195: "Configurações", + 1825881236: "Desligar", + 2120776272: "Desligando..", + 1061961408: "Assinar", + 4282338366: "Assinar?", + 746161122: "Assinatura", + 1988416729: "Mensagem Assinada", + 3672006076: "PSBT Assinada", + 2281377987: "Single-sig", + 4221794628: "Total: ", + 2309020186: "Gastos (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Auf Flash speichern", - 720041451: "Auf der SD-Karte speichern", - 3514476519: "Wischen um den Modus zu ändern", - 1898550184: "TOUCH oder ENTER zum Erfassen", - 4228215415: "TX Pin", - 2612594937: "Text", - 1454688268: "Thema", - 1180180513: "Thermisch", + 3303592908: "Armazene na Flash", + 720041451: "Armazene no Cartão SD", + 3514476519: "Deslize para mudar de modo", + 1898550184: "TOQUE ou ENTER para capturar", + 4228215415: "Pino TX", + 2612594937: "Texto", + 1454688268: "Tema", + 1180180513: "Térmica", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Werkzeuge", - 3684696112: "Berühre Schwellenwert", + 1732872974: "Tiny Seed (bits)", + 725348723: "Ferramentas", + 3684696112: "Limiar de Toque", 2978718564: "Touchscreen", - 2732611775: "Weiter versuchen?", - 1487826746: "BIP39 Passphrase eingeben", - 2061556020: "Schlüssel eingeben", - 2089395053: "Einheit", - 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", - 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", - 2736001501: "Firmware wird aktualisiert..\n\n%d%%", - 2674953168: "Verwende eine schwarze Hintergrundfläche.", - 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", - 236075140: "Belegt: ", - 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", - 4191058607: "Via Kamera", + 2732611775: "Tentar mais?", + 1487826746: "Digitar a senha BIP39", + 2061556020: "Digite a Chave", + 2089395053: "Unidade", + 2845607430: "Atualizando bootloader..\n\n%d%%", + 4164597446: "Atualização completa.\n\nDesligando..", + 2736001501: "Atualizando firmware..\n\n%d%%", + 2674953168: "Use uma superfície de fundo preta.", + 2402455261: "Use a entropia da câmera para criar um novo mnemônico", + 236075140: "Usado: ", + 4003084591: "Valor %s fora do alcance: [ %s, %s]", + 4191058607: "Pela Câmera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Via manueller Eingabe", - 2504354847: "Warte auf die Erfassung", - 2297028319: "Wallet-Deskriptor", - 4232654916: "Wallet Ausgabedeskriptor", - 2587172867: "Wallet Ausgabedeskriptor geladen!", - 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", - 1831109430: "Warnung:\nUnvollständiger Ausgabedeskriptor", - 797660533: "Wort %d", - 3742424146: "Wortnummern", - 2965123464: "Wörter", - 1303016265: "Ja", - 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", - 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", + 590330112: "Por entrada manual", + 2504354847: "Aguarde a captura", + 2297028319: "Descritor de Carteira", + 4232654916: "Descritor da carteira", + 2587172867: "Descritor de saída da carteira carregado!", + 2499782468: "O descritor de saída da carteira não foi encontrado.", + 1831109430: "Atenção:\nDescritor de saída incompleto", + 797660533: "Palavra %d", + 3742424146: "Números das Palavras", + 2965123464: "Palavras", + 1303016265: "Sim", + 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", + 2569054451: "Suas alterações serão mantidas no cartão SD.", }, - "vi-VN": { - 1185266064: "%d của %d đa chữ kí", - 2004520398: "%d. Thay đổi: \n\n%s\n\n", - 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", - 3264377309: "%d. Chi tiêu: \n\n%s\n\n", - 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", - 3921290840: "%s\n\nlà một địa chỉ khả dụng!", - 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 3348584292: "(Thực nghiệm)", - 2739590230: "12 từ", - 1310058127: "24 từ", + "fr-FR": { + 1185266064: "%d de %d multisignature", + 2004520398: "%d. Changement : \n\n%s\n\n", + 3862364126: "%d. Auto-transfert : \n\n%s\n\n", + 3264377309: "%d. Dépense : \n\n%s\n\n", + 2399232215: "%s\n\nest une adresse changement valide!", + 3921290840: "%s\n\nest une adresse reçue valide!", + 1808355833: "INTROUVABLE dans les premières %d adresses de changement", + 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", + 3348584292: "(Expérimental)", + 2739590230: "12 mots", + 1310058127: "24 mots", 2743272264: "ABC", - 1949634023: "Về chúng tôi", + 1949634023: "À propos", 1517128857: "Adafruit", - 3270727197: "Địa chỉ", - 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", - 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", - 88746165: "Chống lóa bị vô hiệu hóa", - 1521033296: "Đã bật chống lóa", - 1056821534: "Bạn có chắc không?", - 3247612282: "Mã mnemonic dạng chuẩn BIP39", - 3455872521: "Trở lại", - 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", - 2256777600: "Chữ ký xấu", - 3937333362: "Tốc độ baud", + 3270727197: "Adresse", + 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", + 283202181: "Alignez correctement la caméra et Tiny Seed.", + 88746165: "Anti-éblouissement désactivé", + 1521033296: "Anti-éblouissement activé", + 1056821534: "Es-tu sûr?", + 3247612282: "BIP39 Mnémonique", + 3455872521: "Retour", + 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", + 2256777600: "Mauvaise signature", + 3937333362: "Débit en bauds", 427617266: "Bitcoin", - 928727036: "Đệm viền", - 213030954: "CNC", - 1207696150: "Thay đổi", - 3126552510: "Thay địa chỉ", - 1583186953: "Thay đổi chủ đề và khởi động lại?", - 2697733395: "Thay đổi được lưu trên thẻ SD!", - 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", - 3442025874: "Kiểm tra thẻ SD", - 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", - 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", - 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", - 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", - 2470115694: "Kiểm tra thẻ SD..", - 3655273987: "Đang kiểm tra %d địa chỉ..", - 2407028014: "SeedQR nhỏ gọn", - 4041895036: "Tiếp tục?", - 4094072796: "Tạo mã QR", - 167798282: "Tạo mã QR từ văn bản?", - 2767642191: "Tạo:", - 3513215254: "Mã QR tùy chỉnh", - 124617190: "Chiều sâu cắt", - 597912140: "Phương pháp cắt", - 2504034831: "Số thập phân", - 2751113454: "Phản đối?", - 1016609898: "Xóa tài liệu?", - 1364509700: "Xóa ghi nhớ", - 4102535566: "Độ sâu mỗi lần vượt qua", - 2791699253: "Nguồn gốc: %s", - 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", - 3836852788: "Hoàn tất?", - 382368239: "Người cầm lái", - 3978947916: "Mã hoá", - 4090746898: "Gỡ lỗi bộ mã hóa", - 374684711: "Mã hóa Mnemonic", - 1244124409: "Mã QR được mã hóa", - 2968548114: "MNemon được mã hóa không được lưu trữ", - 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", - 350279787: "Mã hóa", - 2601598799: "Chế độ mã hóa", - 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", - 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", - 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", - 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", - 784361051: "Lỗi:\n%s", - 1505332462: "Esc", - 3838465623: "Khám phá các tập tin?", - 4170881190: "Xuất vào thẻ SD ..", - 1711312434: "Khóa công cộng", - 383371114: "Không giải mã được", - 3048830188: "Tải PSBT thất bại", - 4192663412: "Tải địa chỉ thất bại", - 1996021743: "Không tải khóa", - 1108715658: "Không tải được tin nhắn", - 1081425878: "Tải mã mnemonic thất bại", - 928667220: "Không thể tải bộ mô tả đầu ra", - 1620572516: "Không tải được cụm mật khẩu", - 2946146830: "Không lưu trữ MNemonic", - 1303554751: "Phí: ", - 104500973: "Tỷ lệ thức ăn", - 3313339187: "Tên tệp", - 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", - 3737729752: "Dấu vân tay: %s", - 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", - 1406590538: "Đường kính ống sáo", - 3086093110: "Khả dụng: ", - 1893243331: "Từ lưu trữ", - 4120536442: "GRBL", - 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", - 602716148: "Đến", - 831562513: "Khoảng thời gian nhiệt", - 2300171403: "Thời gian nhiệt", - 3580020863: "Khóa công khai Hex", - 2691246967: "Thập lục phân", - 2736309107: "Id đã tồn tại\n", - 631342955: "Đầu vào (%d): ", - 2585599782: "Địa chỉ không hợp lệ", - 2874529150: "Bộ tải khởi động không hợp lệ", - 4093416954: "Độ dài mã mnemonic không hợp lệ", - 1422874211: "Khóa công khai không hợp lệ", - 2443867979: "Ví không hợp lệ:\n%s", - 4122897393: "Đảo ngược", - 3000888649: "Chìa khóa", - 2686333978: "Chìa khóa:", - 4123798664: "Krux\n\n\nPhiên Bản\n%s", - 3835918229: "QR kiểm tra máy in Krux", - 766317539: "Ngôn ngữ", - 972436696: "Độ trễ Dòng", - 3596093890: "Đường kẻ: ", - 2820726296: "Tải mã mnemonic", - 879727077: "Tải từ thẻ SD?", - 669106195: "Tải một?", - 3330705289: "Tải?", - 2596531078: "Đang tải máy ảnh..", - 596389387: "Đang tải thay đổi địa chỉ %d..", - 336702608: "Tải máy in ..", - 2538883522: "Đang tải địa chỉ nhận %d..", - 3159494909: "Đang tải..", - 1177338798: "Ngôn ngữ", - 2817059741: "Vị trí cửa hàng", - 63976957: "Log Level", - 86530918: "Khai thác gỗ", - 2917810189: "Chiều dài tối đa vượt quá (%s)", - 2030045667: "Tin nhắn", - 3928301843: "Thiếu tập tin chữ ký", - 1948316555: "Mã mnemonic", - 2123991188: "ID ghi nhớ", - 3911073154: "ID lưu trữ ghi nhớ", - 570639842: "Ghi nhớ không được giải mã", - 1746030071: "Ghi nhớ không được mã hóa", - 1458925155: "Đã sửa đổi:", - 1845376098: "Đa chữ kí", - 2939797024: "Mạng lưới", - 73574491: "Mnemonic mới", - 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", - 4063104189: "Không", - 3927838899: "Không có cụm mật khẩu BIP39", - 4092516657: "Không đủ cuộn!", - 1577637745: "Bát phân", - 3312581301: "Lặp lại PBKDF2", - 721090621: "PSBT", - 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", - 2987800462: "Chiều rộng giấy", - 3050763890: "Phần\n%d / %d", - 3559456868: "Kích thước một phần", - 4249903283: "Cụm mật khẩu", - 3712257341: "Cụm cụm:", - 140802882: "Vị trí lưu", - 1703779997: "Văn bản rõ QR", - 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", - 784609464: "Tỷ lệ sụt giảm", - 3037062877: "In kiểm tra QR", - 4278257699: "In ra mã QR?\n\n%s\n\n", - 516488026: "In?\n\n%s\n\n", - 1123106929: "Máy in", - 3903571079: "Trình điều khiển máy in không đặt!", - 2609799302: "Đang in\n%d / %d", - 844861889: "In ấn ...", - 2580599003: "Thực hiện?", - 556126964: "Xử lý ...", - 1848310591: "Mã QR", - 710709610: "RX Ghim", - 2697857197: "Nhận được", - 1746677167: "Nhận địa chỉ", - 364354944: "Vùng: ", - 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", - 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", - 856795528: "Súc sắc cuộn:\n\n%s", - 255086803: "Súc sắc cuộn: %d\n", - 3976793317: "Thẻ SD", - 2827687530: "Thẻ SD không được phát hiện", - 2736513298: "Thẻ SD không được phát hiện.", - 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", - 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Lưu vào thẻ SD?", - 810036588: "Đã lưu vào thẻ SD:\n%s", - 763824768: "Cái cân", - 4117455079: "Quét địa chỉ", - 3219991109: "Quét BIP39 Cụm cụm", - 2537207336: "Quét mã QR khóa", - 4006316572: "Quét lại từ 1-12", - 2736506158: "Quét từ 13-24", - 266935239: "SEEDQR", - 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", - 473154195: "Cài đặt", - 1825881236: "Tắt", - 2120776272: "Đang tắt..", - 1061961408: "Chữ kí", - 4282338366: "Kí?", - 746161122: "Chữ ký", - 1988416729: "Tin nhắn đã ký", - 3672006076: "Đã ký PSBT", - 2281377987: "Khóa đơn", - 4221794628: "Dung lượng: ", - 2309020186: "Chi tiêu (%d): ", - 3355862324: "Stackbit 1248", - 3303592908: "Lưu trữ trên flash", - 720041451: "Lưu trữ trên thẻ SD", - 3514476519: "Vuốt để thay đổi chế độ", - 1898550184: "TOUCH hoặc ENTER để chụp", - 4228215415: "TX Ghim", - 2612594937: "Chữ", - 1454688268: "Chủ đề", - 1180180513: "Nhiệt", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bit)", - 725348723: "Công cụ", - 3684696112: "Ngưỡng cảm ứng", - 2978718564: "Màn hình cảm ứng", - 2732611775: "Thử thêm nữa?", - 1487826746: "Nhập cụm BIP39", - 2061556020: "Nhập khóa", - 2089395053: "Đơn vị", - 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", - 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", - 2736001501: "Nâng cấp firmware..\n\n%d%%", - 2674953168: "Sử dụng bề mặt nền đen.", - 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", - 236075140: "Đã sử dụng: ", - 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", - 4191058607: "Qua máy ảnh", - 1254681955: "Qua D20", - 525309547: "Qua D6", - 590330112: "Thông qua đầu vào thủ công", - 2504354847: "Chờ bắt", - 2297028319: "Trình mô tả ví", - 4232654916: "Ví đầu ra mô tả", - 2587172867: "Đã tải bộ mô tả đầu ra của ví!", - 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", - 1831109430: "Cảnh báo:\nBộ mô tả đầu ra chưa hoàn chỉnh", - 797660533: "Kí tự %d", - 3742424146: "Từ số", - 2965123464: "Từ ngữ", - 1303016265: "Đúng", - 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", - 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", - }, - "fr-FR": { - 1185266064: "%d de %d multisignature", - 2004520398: "%d. Changement : \n\n%s\n\n", - 3862364126: "%d. Auto-transfert : \n\n%s\n\n", - 3264377309: "%d. Dépense : \n\n%s\n\n", - 2399232215: "%s\n\nest une adresse changement valide!", - 3921290840: "%s\n\nest une adresse reçue valide!", - 1808355833: "INTROUVABLE dans les premières %d adresses de changement", - 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", - 3348584292: "(Expérimental)", - 2739590230: "12 mots", - 1310058127: "24 mots", - 2743272264: "ABC", - 1949634023: "À propos", - 1517128857: "Adafruit", - 3270727197: "Adresse", - 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", - 283202181: "Alignez correctement la caméra et Tiny Seed.", - 88746165: "Anti-éblouissement désactivé", - 1521033296: "Anti-éblouissement activé", - 1056821534: "Es-tu sûr?", - 3247612282: "BIP39 Mnémonique", - 3455872521: "Retour", - 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", - 2256777600: "Mauvaise signature", - 3937333362: "Débit en bauds", - 427617266: "Bitcoin", - 928727036: "Rembourrage de bordure", + 928727036: "Rembourrage de bordure", 213030954: "CNC", 1207696150: "Changement", 3126552510: "Adresses de Changement", @@ -1728,4 +1484,492 @@ 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", 2569054451: "Veranderingen worden opgeslagen op SD kaart.", }, + "de-DE": { + 1185266064: "%d von %d Multisig", + 2004520398: "%d. Change: \n\n%s\n\n", + 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", + 3264377309: "%d. Ausgaben: \n\n%s\n\n", + 2399232215: "%s\n\nist eine gültige Change Adresse!", + 3921290840: "%s\n\nist eine gültige Empfangsadresse!", + 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", + 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", + 3348584292: "(Experimental)", + 2739590230: "12 Wörter", + 1310058127: "24 Wörter", + 2743272264: "ABC", + 1949634023: "Über", + 1517128857: "Adafruit", + 3270727197: "Adresse", + 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", + 283202181: "Richte Kamera und Tiny Seed korrekt aus.", + 88746165: "Blendschutz deaktiviert", + 1521033296: "Blendschutz aktiviert", + 1056821534: "Bist Du sicher?", + 3247612282: "BIP39 Mnemonic", + 3455872521: "Zurück", + 2541860807: "Bootloader wird gesichert..\n\n%d%%", + 2256777600: "Ungültige Signatur", + 3937333362: "Baudrate", + 427617266: "Bitcoin", + 928727036: "Randpolsterung", + 213030954: "CNC", + 1207696150: "Change Adresse", + 3126552510: "Change Adressen", + 1583186953: "Thema ändern und neu starten?", + 2697733395: "Änderungen auf SD-Karte gespeichert!", + 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", + 3442025874: "Prüfe SD-Karte", + 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", + 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", + 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", + 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", + 2470115694: "Suche nach SD-Karte..", + 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", + 2407028014: "Kompakt SeedQR", + 4041895036: "Weiter?", + 4094072796: "Erstelle QR-Code", + 167798282: "QR-Code aus Text erzeugen?", + 2767642191: "Erstellt:", + 3513215254: "Benutzerdefinierte QR-Code", + 124617190: "Schnitttiefe", + 597912140: "Cut-Methode", + 2504034831: "Dezimal", + 2751113454: "Entschlüsseln?", + 1016609898: "Datei löschen?", + 1364509700: "Mnemonic löschen", + 4102535566: "Tiefe pro Durchgang", + 2791699253: "Ableitung: %s", + 1230133196: "Geräte-Flash-Speicher nicht erkannt.", + 3836852788: "Fertig?", + 382368239: "Driver", + 3978947916: "Encoder", + 4090746898: "Encoder-Entprellung", + 374684711: "Verschlüssel Mnemonic", + 1244124409: "Verschlüsselter QR-Code", + 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", + 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", + 350279787: "Verschlüsselung", + 2601598799: "Verschlüsselungsmodus", + 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", + 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", + 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", + 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", + 784361051: "Fehler:\n%s", + 1505332462: "Esc", + 3838465623: "Dateien durchsuchen?", + 4170881190: "Auf SD-Karte exportieren..", + 1711312434: "Öffentlicher Schlüssel", + 383371114: "Entschlüsselung fehlgeschlagen", + 3048830188: "PSBT konnte nicht geladen werden", + 4192663412: "Adresse konnte nicht geladen werden", + 1996021743: "Schlüssel konnte nicht geladen werden", + 1108715658: "Nachricht konnte nicht geladen werden", + 1081425878: "Mnemonic konnte nicht geladen werden", + 928667220: "Ausgabedeskriptor konnte nicht geladen werden", + 1620572516: "Passphrase konnte nicht geladen werden", + 2946146830: "Mnemonic konnte nicht gespeichert werden", + 1303554751: "Gebühr: ", + 104500973: "Vorschubgeschwindigkeit", + 3313339187: "Dateiname", + 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", + 3737729752: "Fingerabdruck: %s", + 2542772894: "Die Firmware übersteigt die maximale Größe: %d", + 1406590538: "Flötendurchmesser", + 3086093110: "Frei: ", + 1893243331: "Vom Speicher", + 4120536442: "GRBL", + 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 602716148: "Go", + 831562513: "Wärmeintervall", + 2300171403: "Hitzezeit", + 3580020863: "Hex öffentlicher Schlüssel", + 2691246967: "Hexadezimal", + 2736309107: "ID existiert bereits\n", + 631342955: "Input (%d): ", + 2585599782: "Ungültige Adresse", + 2874529150: "Ungültiger Bootloader", + 4093416954: "Ungültige mnemonische Lange", + 1422874211: "Ungültiger öffentlicher Schlüssel", + 2443867979: "Ungültige Wallet:\n%s", + 4122897393: "Umkehren", + 3000888649: "Schlüssel", + 2686333978: "Schlüssel:", + 4123798664: "Krux\n\n\nVersion\n%s", + 3835918229: "Krux Drucker Test-QR", + 766317539: "Sprache", + 972436696: "Leitungsverzögerung", + 3596093890: "Linie: ", + 2820726296: "Mnemonic laden", + 879727077: "Von SD-Karte laden?", + 669106195: "Eine laden?", + 3330705289: "Laden?", + 2596531078: "Lade Kamera..", + 596389387: "Lade Change Adresse %d..", + 336702608: "Drucker wird geladen..", + 2538883522: "Lade Empfangsadresse %d..", + 3159494909: "Wird geladen..", + 1177338798: "Spracheinstellung", + 2817059741: "Speicherort", + 63976957: "Log Level", + 86530918: "Logging", + 2917810189: "Maximale Länge überschritten (%s)", + 2030045667: "Nachricht", + 3928301843: "Fehlende Signaturdatei", + 1948316555: "Mnemonic", + 2123991188: "Mnemonische ID", + 3911073154: "Mnemonische Speicher-ID", + 570639842: "Mnemonic wurde nicht entschlüsselt", + 1746030071: "Mnemonic wurde nicht verschlüsselt", + 1458925155: "Geändert:", + 1845376098: "Multisig", + 2939797024: "Netzwerk", + 73574491: "Neue Mnemonic", + 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", + 4063104189: "Nein", + 3927838899: "Keine BIP39 Passphrase", + 4092516657: "Nicht genug Würfe!", + 1577637745: "Oktal", + 3312581301: "PBKDF2-Iter.", + 721090621: "PSBT", + 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", + 2987800462: "Papierbreite", + 3050763890: "Teil\n%d / %d", + 3559456868: "Teilegröße", + 4249903283: "Passphrase", + 3712257341: "Passphrase:", + 140802882: "Speicher", + 1703779997: "Klartext-QR", + 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", + 784609464: "Tauchrate", + 3037062877: "Drucke Test-QR", + 4278257699: "Als QR-Code drucken?\n\n%s\n\n", + 516488026: "Drucken?\n\n%s\n\n", + 1123106929: "Drucker", + 3903571079: "Druckertreiber nicht gesetzt!", + 2609799302: "Drucken\n%d / %d", + 844861889: "Wird gedruckt ...", + 2580599003: "Weiter?", + 556126964: "Wird bearbeitet ...", + 1848310591: "QR-Code", + 710709610: "RX Pin", + 2697857197: "Empfangen", + 1746677167: "Empfangsadresse", + 364354944: "Region: ", + 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", + 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", + 856795528: "Würfe:\n\n%s", + 255086803: "Würfe: %d\n", + 3976793317: "SD-Karte", + 2827687530: "SD-Karte nicht erkannt", + 2736513298: "SD-Karte nicht erkannt.", + 3593785196: "SHA256 der Würfe:\n\n%s", + 1143278725: "SHA256 des Snapshots:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Auf SD-Karte speichern?", + 810036588: "Auf SD-Karte gespeichert:\n%s", + 763824768: "Skala", + 4117455079: "Adresse\nscannen", + 3219991109: "Scan BIP39 Passphrase", + 2537207336: "Schlüssel QR-Code scannen", + 4006316572: "Wörter 1-12 erneut scannen", + 2736506158: "Wörter 13-24 scannen", + 266935239: "SeedQR", + 1698829144: "Selbstübertragung oder Change (%d): ", + 473154195: "Einstellungen", + 1825881236: "Ausschalten", + 2120776272: "Herunterfahren..", + 1061961408: "Signieren", + 4282338366: "Signieren?", + 746161122: "Signatur", + 1988416729: "Signierte Nachricht", + 3672006076: "Signierte PSBT", + 2281377987: "Single-Sig", + 4221794628: "Größe: ", + 2309020186: "Ausgabe (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Auf Flash speichern", + 720041451: "Auf der SD-Karte speichern", + 3514476519: "Wischen um den Modus zu ändern", + 1898550184: "TOUCH oder ENTER zum Erfassen", + 4228215415: "TX Pin", + 2612594937: "Text", + 1454688268: "Thema", + 1180180513: "Thermisch", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Werkzeuge", + 3684696112: "Berühre Schwellenwert", + 2978718564: "Touchscreen", + 2732611775: "Weiter versuchen?", + 1487826746: "BIP39 Passphrase eingeben", + 2061556020: "Schlüssel eingeben", + 2089395053: "Einheit", + 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", + 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", + 2736001501: "Firmware wird aktualisiert..\n\n%d%%", + 2674953168: "Verwende eine schwarze Hintergrundfläche.", + 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", + 236075140: "Belegt: ", + 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", + 4191058607: "Via Kamera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Via manueller Eingabe", + 2504354847: "Warte auf die Erfassung", + 2297028319: "Wallet-Deskriptor", + 4232654916: "Wallet Ausgabedeskriptor", + 2587172867: "Wallet Ausgabedeskriptor geladen!", + 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", + 1831109430: "Warnung:\nUnvollständiger Ausgabedeskriptor", + 797660533: "Wort %d", + 3742424146: "Wortnummern", + 2965123464: "Wörter", + 1303016265: "Ja", + 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", + 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", + }, + "vi-VN": { + 1185266064: "%d của %d đa chữ kí", + 2004520398: "%d. Thay đổi: \n\n%s\n\n", + 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", + 3264377309: "%d. Chi tiêu: \n\n%s\n\n", + 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", + 3921290840: "%s\n\nlà một địa chỉ khả dụng!", + 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 3348584292: "(Thực nghiệm)", + 2739590230: "12 từ", + 1310058127: "24 từ", + 2743272264: "ABC", + 1949634023: "Về chúng tôi", + 1517128857: "Adafruit", + 3270727197: "Địa chỉ", + 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", + 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", + 88746165: "Chống lóa bị vô hiệu hóa", + 1521033296: "Đã bật chống lóa", + 1056821534: "Bạn có chắc không?", + 3247612282: "Mã mnemonic dạng chuẩn BIP39", + 3455872521: "Trở lại", + 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", + 2256777600: "Chữ ký xấu", + 3937333362: "Tốc độ baud", + 427617266: "Bitcoin", + 928727036: "Đệm viền", + 213030954: "CNC", + 1207696150: "Thay đổi", + 3126552510: "Thay địa chỉ", + 1583186953: "Thay đổi chủ đề và khởi động lại?", + 2697733395: "Thay đổi được lưu trên thẻ SD!", + 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", + 3442025874: "Kiểm tra thẻ SD", + 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", + 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", + 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", + 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", + 2470115694: "Kiểm tra thẻ SD..", + 3655273987: "Đang kiểm tra %d địa chỉ..", + 2407028014: "SeedQR nhỏ gọn", + 4041895036: "Tiếp tục?", + 4094072796: "Tạo mã QR", + 167798282: "Tạo mã QR từ văn bản?", + 2767642191: "Tạo:", + 3513215254: "Mã QR tùy chỉnh", + 124617190: "Chiều sâu cắt", + 597912140: "Phương pháp cắt", + 2504034831: "Số thập phân", + 2751113454: "Phản đối?", + 1016609898: "Xóa tài liệu?", + 1364509700: "Xóa ghi nhớ", + 4102535566: "Độ sâu mỗi lần vượt qua", + 2791699253: "Nguồn gốc: %s", + 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", + 3836852788: "Hoàn tất?", + 382368239: "Người cầm lái", + 3978947916: "Mã hoá", + 4090746898: "Gỡ lỗi bộ mã hóa", + 374684711: "Mã hóa Mnemonic", + 1244124409: "Mã QR được mã hóa", + 2968548114: "MNemon được mã hóa không được lưu trữ", + 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", + 350279787: "Mã hóa", + 2601598799: "Chế độ mã hóa", + 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", + 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", + 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", + 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", + 784361051: "Lỗi:\n%s", + 1505332462: "Esc", + 3838465623: "Khám phá các tập tin?", + 4170881190: "Xuất vào thẻ SD ..", + 1711312434: "Khóa công cộng", + 383371114: "Không giải mã được", + 3048830188: "Tải PSBT thất bại", + 4192663412: "Tải địa chỉ thất bại", + 1996021743: "Không tải khóa", + 1108715658: "Không tải được tin nhắn", + 1081425878: "Tải mã mnemonic thất bại", + 928667220: "Không thể tải bộ mô tả đầu ra", + 1620572516: "Không tải được cụm mật khẩu", + 2946146830: "Không lưu trữ MNemonic", + 1303554751: "Phí: ", + 104500973: "Tỷ lệ thức ăn", + 3313339187: "Tên tệp", + 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", + 3737729752: "Dấu vân tay: %s", + 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", + 1406590538: "Đường kính ống sáo", + 3086093110: "Khả dụng: ", + 1893243331: "Từ lưu trữ", + 4120536442: "GRBL", + 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", + 602716148: "Đến", + 831562513: "Khoảng thời gian nhiệt", + 2300171403: "Thời gian nhiệt", + 3580020863: "Khóa công khai Hex", + 2691246967: "Thập lục phân", + 2736309107: "Id đã tồn tại\n", + 631342955: "Đầu vào (%d): ", + 2585599782: "Địa chỉ không hợp lệ", + 2874529150: "Bộ tải khởi động không hợp lệ", + 4093416954: "Độ dài mã mnemonic không hợp lệ", + 1422874211: "Khóa công khai không hợp lệ", + 2443867979: "Ví không hợp lệ:\n%s", + 4122897393: "Đảo ngược", + 3000888649: "Chìa khóa", + 2686333978: "Chìa khóa:", + 4123798664: "Krux\n\n\nPhiên Bản\n%s", + 3835918229: "QR kiểm tra máy in Krux", + 766317539: "Ngôn ngữ", + 972436696: "Độ trễ Dòng", + 3596093890: "Đường kẻ: ", + 2820726296: "Tải mã mnemonic", + 879727077: "Tải từ thẻ SD?", + 669106195: "Tải một?", + 3330705289: "Tải?", + 2596531078: "Đang tải máy ảnh..", + 596389387: "Đang tải thay đổi địa chỉ %d..", + 336702608: "Tải máy in ..", + 2538883522: "Đang tải địa chỉ nhận %d..", + 3159494909: "Đang tải..", + 1177338798: "Ngôn ngữ", + 2817059741: "Vị trí cửa hàng", + 63976957: "Log Level", + 86530918: "Khai thác gỗ", + 2917810189: "Chiều dài tối đa vượt quá (%s)", + 2030045667: "Tin nhắn", + 3928301843: "Thiếu tập tin chữ ký", + 1948316555: "Mã mnemonic", + 2123991188: "ID ghi nhớ", + 3911073154: "ID lưu trữ ghi nhớ", + 570639842: "Ghi nhớ không được giải mã", + 1746030071: "Ghi nhớ không được mã hóa", + 1458925155: "Đã sửa đổi:", + 1845376098: "Đa chữ kí", + 2939797024: "Mạng lưới", + 73574491: "Mnemonic mới", + 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", + 4063104189: "Không", + 3927838899: "Không có cụm mật khẩu BIP39", + 4092516657: "Không đủ cuộn!", + 1577637745: "Bát phân", + 3312581301: "Lặp lại PBKDF2", + 721090621: "PSBT", + 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", + 2987800462: "Chiều rộng giấy", + 3050763890: "Phần\n%d / %d", + 3559456868: "Kích thước một phần", + 4249903283: "Cụm mật khẩu", + 3712257341: "Cụm cụm:", + 140802882: "Vị trí lưu", + 1703779997: "Văn bản rõ QR", + 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", + 784609464: "Tỷ lệ sụt giảm", + 3037062877: "In kiểm tra QR", + 4278257699: "In ra mã QR?\n\n%s\n\n", + 516488026: "In?\n\n%s\n\n", + 1123106929: "Máy in", + 3903571079: "Trình điều khiển máy in không đặt!", + 2609799302: "Đang in\n%d / %d", + 844861889: "In ấn ...", + 2580599003: "Thực hiện?", + 556126964: "Xử lý ...", + 1848310591: "Mã QR", + 710709610: "RX Ghim", + 2697857197: "Nhận được", + 1746677167: "Nhận địa chỉ", + 364354944: "Vùng: ", + 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", + 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", + 856795528: "Súc sắc cuộn:\n\n%s", + 255086803: "Súc sắc cuộn: %d\n", + 3976793317: "Thẻ SD", + 2827687530: "Thẻ SD không được phát hiện", + 2736513298: "Thẻ SD không được phát hiện.", + 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", + 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Lưu vào thẻ SD?", + 810036588: "Đã lưu vào thẻ SD:\n%s", + 763824768: "Cái cân", + 4117455079: "Quét địa chỉ", + 3219991109: "Quét BIP39 Cụm cụm", + 2537207336: "Quét mã QR khóa", + 4006316572: "Quét lại từ 1-12", + 2736506158: "Quét từ 13-24", + 266935239: "SEEDQR", + 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", + 473154195: "Cài đặt", + 1825881236: "Tắt", + 2120776272: "Đang tắt..", + 1061961408: "Chữ kí", + 4282338366: "Kí?", + 746161122: "Chữ ký", + 1988416729: "Tin nhắn đã ký", + 3672006076: "Đã ký PSBT", + 2281377987: "Khóa đơn", + 4221794628: "Dung lượng: ", + 2309020186: "Chi tiêu (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Lưu trữ trên flash", + 720041451: "Lưu trữ trên thẻ SD", + 3514476519: "Vuốt để thay đổi chế độ", + 1898550184: "TOUCH hoặc ENTER để chụp", + 4228215415: "TX Ghim", + 2612594937: "Chữ", + 1454688268: "Chủ đề", + 1180180513: "Nhiệt", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (bit)", + 725348723: "Công cụ", + 3684696112: "Ngưỡng cảm ứng", + 2978718564: "Màn hình cảm ứng", + 2732611775: "Thử thêm nữa?", + 1487826746: "Nhập cụm BIP39", + 2061556020: "Nhập khóa", + 2089395053: "Đơn vị", + 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", + 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", + 2736001501: "Nâng cấp firmware..\n\n%d%%", + 2674953168: "Sử dụng bề mặt nền đen.", + 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", + 236075140: "Đã sử dụng: ", + 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", + 4191058607: "Qua máy ảnh", + 1254681955: "Qua D20", + 525309547: "Qua D6", + 590330112: "Thông qua đầu vào thủ công", + 2504354847: "Chờ bắt", + 2297028319: "Trình mô tả ví", + 4232654916: "Ví đầu ra mô tả", + 2587172867: "Đã tải bộ mô tả đầu ra của ví!", + 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", + 1831109430: "Cảnh báo:\nBộ mô tả đầu ra chưa hoàn chỉnh", + 797660533: "Kí tự %d", + 3742424146: "Từ số", + 2965123464: "Từ ngữ", + 1303016265: "Đúng", + 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", + 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", + }, } From c009b8a3a08fcb4ac6de994380e89c880dbe547a Mon Sep 17 00:00:00 2001 From: Odudex Date: Mon, 18 Sep 2023 11:06:51 -0300 Subject: [PATCH 011/114] translations update reviewed RU fixed undetected texts --- i18n/translations/de-DE.json | 6 +- i18n/translations/es-MX.json | 6 +- i18n/translations/fr-FR.json | 6 +- i18n/translations/nl-NL.json | 6 +- i18n/translations/pl-PL.json | 7 +- i18n/translations/pt-BR.json | 6 +- i18n/translations/ru-RU.json | 8 +- i18n/translations/vi-VN.json | 6 +- src/krux/pages/home.py | 12 +- src/krux/translations.py | 2809 +++++++++++++++++----------------- 10 files changed, 1438 insertions(+), 1434 deletions(-) diff --git a/i18n/translations/de-DE.json b/i18n/translations/de-DE.json index e9eb5cb5b..6feabc798 100644 --- a/i18n/translations/de-DE.json +++ b/i18n/translations/de-DE.json @@ -94,11 +94,10 @@ "GRBL": "GRBL", "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", "Go": "Go", - "Heat Interval": "Wärmeintervall", - "Heat Time": "Hitzezeit", "Hex Public Key": "Hex öffentlicher Schlüssel", "Hexadecimal": "Hexadezimal", "ID already exists\n": "ID existiert bereits\n", + "Incomplete output descriptor": "Unvollständiger Ausgabedeskriptor", "Inputs (%d): ": "Input (%d): ", "Invalid address": "Ungültige Adresse", "Invalid bootloader": "Ungültiger Bootloader", @@ -199,6 +198,7 @@ "Signed PSBT": "Signierte PSBT", "Single-sig": "Single-Sig", "Size: ": "Größe: ", + "Some checks cannot be performed.": "Einige Schecks können nicht durchgeführt werden.", "Spend (%d): ": "Ausgabe (%d): ", "Stackbit 1248": "Stackbit 1248", "Store on Flash": "Auf Flash speichern", @@ -234,7 +234,7 @@ "Wallet output descriptor": "Wallet Ausgabedeskriptor", "Wallet output descriptor loaded!": "Wallet Ausgabedeskriptor geladen!", "Wallet output descriptor not found.": "Wallet Ausgabedeskriptor nicht gefunden.", - "Warning:\nIncomplete output descriptor": "Warnung:\nUnvollständiger Ausgabedeskriptor", + "Warning:": "Warnung:", "Word %d": "Wort %d", "Word Numbers": "Wortnummern", "Words": "Wörter", diff --git a/i18n/translations/es-MX.json b/i18n/translations/es-MX.json index 281ae6634..43d5def8a 100644 --- a/i18n/translations/es-MX.json +++ b/i18n/translations/es-MX.json @@ -94,11 +94,10 @@ "GRBL": "GRBL", "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "¿Darle a este mnemónico una identificación personalizada?De lo contrario se utilizará la huella digital actual", "Go": "Ir", - "Heat Interval": "Intervalo de calor", - "Heat Time": "Tiempo de calor", "Hex Public Key": "Clave pública hexadecimal", "Hexadecimal": "Hexadecimal", "ID already exists\n": "ID ya existe\n", + "Incomplete output descriptor": "Descriptor incompleto", "Inputs (%d): ": "Entradas (%d): ", "Invalid address": "Dirección inválida", "Invalid bootloader": "Cargador de arranque inválido", @@ -199,6 +198,7 @@ "Signed PSBT": "PSBT firmado", "Single-sig": "Single-sig", "Size: ": "Espacio: ", + "Some checks cannot be performed.": "No se pueden realizar algunos cheques.", "Spend (%d): ": "Gastos (%d): ", "Stackbit 1248": "Stackbit 1248", "Store on Flash": "Almacenar en flash", @@ -234,7 +234,7 @@ "Wallet output descriptor": "Descriptor de salida de billetera", "Wallet output descriptor loaded!": "¡Se ha cargado el descriptor de salida de la cartera!", "Wallet output descriptor not found.": "No se encontró el descriptor de salida de la cartera.", - "Warning:\nIncomplete output descriptor": "Advertencia:\nDescriptor de salida incompleto", + "Warning:": "Advertencia:", "Word %d": "Palabra %d", "Word Numbers": "Números de palabra", "Words": "Palabras", diff --git a/i18n/translations/fr-FR.json b/i18n/translations/fr-FR.json index 7edb57d51..00ea8847e 100644 --- a/i18n/translations/fr-FR.json +++ b/i18n/translations/fr-FR.json @@ -94,11 +94,10 @@ "GRBL": "GRBL", "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", "Go": "Go", - "Heat Interval": "Intervalle de chauffe", - "Heat Time": "Temps de chauffe", "Hex Public Key": "Clé public hexadécimal", "Hexadecimal": "Hexadécimal", "ID already exists\n": "Id existe déjà\n", + "Incomplete output descriptor": "Descripteur de sortie incomplet", "Inputs (%d): ": "Entrées (%d) : ", "Invalid address": "Adresse invalide", "Invalid bootloader": "Chargeur de démarrage invalide", @@ -199,6 +198,7 @@ "Signed PSBT": "PSBT signé", "Single-sig": "Clé unique", "Size: ": "Capacité: ", + "Some checks cannot be performed.": "Certains chèques ne peuvent pas être effectués.", "Spend (%d): ": "Dépense (%d) : ", "Stackbit 1248": "Stackbit 1248", "Store on Flash": "Stocker sur flash", @@ -234,7 +234,7 @@ "Wallet output descriptor": "Descripteur de sortie du portefeuille", "Wallet output descriptor loaded!": "Descripteur de sortie du portefeuille chargé!", "Wallet output descriptor not found.": "Descripteur de sortie du portefeuille introuvable.", - "Warning:\nIncomplete output descriptor": "Attention:\nDescripteur de sortie incomplet", + "Warning:": "Avertissement:", "Word %d": "Mot %d", "Word Numbers": "Numéros de mots", "Words": "Mots", diff --git a/i18n/translations/nl-NL.json b/i18n/translations/nl-NL.json index b3211947a..28aa1372b 100644 --- a/i18n/translations/nl-NL.json +++ b/i18n/translations/nl-NL.json @@ -94,11 +94,10 @@ "GRBL": "GRBL", "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", "Go": "Ga", - "Heat Interval": "Warmte interval", - "Heat Time": "Warmte tijd", "Hex Public Key": "Hex publieke sleutel", "Hexadecimal": "Hexadecimaal", "ID already exists\n": "ID bestaat al\n", + "Incomplete output descriptor": "Incomplete portemonnee descriptor", "Inputs (%d): ": "Invoer (%d): ", "Invalid address": "Ongeldig adres", "Invalid bootloader": "Ongeldige bootloader", @@ -199,6 +198,7 @@ "Signed PSBT": "PSBT ondertekend", "Single-sig": "Enkele sleutel", "Size: ": "Grootte: ", + "Some checks cannot be performed.": "Sommige controles kunnen niet worden uitgevoerd.", "Spend (%d): ": "Uitgaven (%d): ", "Stackbit 1248": "Stackbit 1248", "Store on Flash": "Opslaan op apparaat", @@ -234,7 +234,7 @@ "Wallet output descriptor": "Portemonnee descriptor", "Wallet output descriptor loaded!": "Portemonnee descriptor geladen!", "Wallet output descriptor not found.": "Portemonnee descriptor niet gevonden.", - "Warning:\nIncomplete output descriptor": "Waarschuwing:\nIncomplete portemonnee descriptor", + "Warning:": "Waarschuwing:", "Word %d": "Woord %d", "Word Numbers": "Woord nummers", "Words": "Woorden", diff --git a/i18n/translations/pl-PL.json b/i18n/translations/pl-PL.json index e9274ddbb..6a075b2db 100644 --- a/i18n/translations/pl-PL.json +++ b/i18n/translations/pl-PL.json @@ -7,6 +7,7 @@ "%s\n\nis a valid receive address!": "%s\n\nis ważny adres odbierania!", "%s\n\nwas NOT FOUND in the first %d change addresses": "%s\n\nwas nie znaleziono w pierwszych adresach zmiany", "%s\n\nwas NOT FOUND in the first %d receive addresses": "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", + "(Experimental)": "(Eksperymentalny)", "12 words": "12 słów", "24 words": "24 słowa", "ABC": "ABC", @@ -93,11 +94,10 @@ "GRBL": "Grbl", "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Podaj temu mnemonicznemu identyfikatorowi?W przeciwnym razie zostanie użyty obecny odcisk palca", "Go": "Iść", - "Heat Interval": "Odstęp cieplny", - "Heat Time": "Czas ciepła", "Hex Public Key": "Hex Key Public", "Hexadecimal": "Szesnastkowy", "ID already exists\n": "ID już istnieje\n", + "Incomplete output descriptor": "inComplete Descriptor", "Inputs (%d): ": "Wejścia (%d):", "Invalid address": "Błędny adres", "Invalid bootloader": "Nieprawidłowy bootloader", @@ -198,6 +198,7 @@ "Signed PSBT": "Podpisano PSBT", "Single-sig": "Pojedyncze Sig", "Size: ": "Rozmiar:", + "Some checks cannot be performed.": "Nie można wykonać niektórych kontroli.", "Spend (%d): ": "Wydać (%d):", "Stackbit 1248": "Stackbit 1248", "Store on Flash": "Przechowuj na Flash", @@ -233,7 +234,7 @@ "Wallet output descriptor": "Deskryptor wyjściowy portfela", "Wallet output descriptor loaded!": "Załadowany deskryptor wyjściowy portfela!", "Wallet output descriptor not found.": "Nie znaleziono deskryptora wyjściowego portfela.", - "Warning:\nIncomplete output descriptor": "Ostrzeżenie:\ninComplete Descriptor", + "Warning:": "Ostrzeżenie:", "Word %d": "Słowo %d", "Word Numbers": "Numery słów", "Words": "Słowa", diff --git a/i18n/translations/pt-BR.json b/i18n/translations/pt-BR.json index 6154a6d7a..b26bbf57c 100644 --- a/i18n/translations/pt-BR.json +++ b/i18n/translations/pt-BR.json @@ -94,11 +94,10 @@ "GRBL": "GRBL", "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", "Go": "Ir", - "Heat Interval": "Intervalo de Aquecimento", - "Heat Time": "Tempo de Aquecimento", "Hex Public Key": "Chave pública hexadecimal", "Hexadecimal": "Hexadecimal", "ID already exists\n": "Id já existe\n", + "Incomplete output descriptor": "Descritor incompleto", "Inputs (%d): ": "Entradas (%d): ", "Invalid address": "Endereço inválido", "Invalid bootloader": "Bootloader inválido", @@ -199,6 +198,7 @@ "Signed PSBT": "PSBT Assinada", "Single-sig": "Single-sig", "Size: ": "Total: ", + "Some checks cannot be performed.": "Algumas verificações não podem ser realizadas.", "Spend (%d): ": "Gastos (%d): ", "Stackbit 1248": "Stackbit 1248", "Store on Flash": "Armazene na Flash", @@ -234,7 +234,7 @@ "Wallet output descriptor": "Descritor da carteira", "Wallet output descriptor loaded!": "Descritor de saída da carteira carregado!", "Wallet output descriptor not found.": "O descritor de saída da carteira não foi encontrado.", - "Warning:\nIncomplete output descriptor": "Atenção:\nDescritor de saída incompleto", + "Warning:": "Aviso:", "Word %d": "Palavra %d", "Word Numbers": "Números das Palavras", "Words": "Palavras", diff --git a/i18n/translations/ru-RU.json b/i18n/translations/ru-RU.json index 825098ee0..9a76c183c 100644 --- a/i18n/translations/ru-RU.json +++ b/i18n/translations/ru-RU.json @@ -94,11 +94,10 @@ "GRBL": "GRBL", "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", "Go": "OK", - "Heat Interval": "Интервал Нагрева", - "Heat Time": "Время Нагрева", "Hex Public Key": "Шестнадцатеричный Публичный Ключ", "Hexadecimal": "Шестнадцатеричный", "ID already exists\n": "ID уже существует\n", + "Incomplete output descriptor": "Неполный выходной дескриптор", "Inputs (%d): ": "Входы (%d): ", "Invalid address": "Неверный адрес", "Invalid bootloader": "Неверный загрузчик", @@ -199,6 +198,7 @@ "Signed PSBT": "Подписанное PSBT", "Single-sig": "Одна подпись", "Size: ": "Размер: ", + "Some checks cannot be performed.": "Некоторые проверки не могут быть выполнены.", "Spend (%d): ": "Расход (%d): ", "Stackbit 1248": "Стэкбит 1248", "Store on Flash": "Сохранить на Флэш Память", @@ -234,11 +234,11 @@ "Wallet output descriptor": "Выходной дескриптор кошелька", "Wallet output descriptor loaded!": "Выходной дескриптор кошелька загружен!", "Wallet output descriptor not found.": "Выходной дескриптор кошелька не найден.", - "Warning:\nIncomplete output descriptor": "Предупреждение:\nНеполный выходной дескриптор", + "Warning:": "Предупреждение:", "Word %d": "Слово %d", "Word Numbers": "Числа Слов", "Words": "Слова", "Yes": "Да", "Your changes will be kept on device flash storage.": "Ваши изменения буду храниться на флэш памяти устройства.", "Your changes will be kept on the SD card.": "Ваши изменения будут храниться на SD карте." -} +} \ No newline at end of file diff --git a/i18n/translations/vi-VN.json b/i18n/translations/vi-VN.json index d88820240..5fa912567 100644 --- a/i18n/translations/vi-VN.json +++ b/i18n/translations/vi-VN.json @@ -94,11 +94,10 @@ "GRBL": "GRBL", "Give this mnemonic a custom ID? Otherwise current fingerprint will be used": "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", "Go": "Đến", - "Heat Interval": "Khoảng thời gian nhiệt", - "Heat Time": "Thời gian nhiệt", "Hex Public Key": "Khóa công khai Hex", "Hexadecimal": "Thập lục phân", "ID already exists\n": "Id đã tồn tại\n", + "Incomplete output descriptor": "Bộ mô tả đầu ra chưa hoàn chỉnh", "Inputs (%d): ": "Đầu vào (%d): ", "Invalid address": "Địa chỉ không hợp lệ", "Invalid bootloader": "Bộ tải khởi động không hợp lệ", @@ -199,6 +198,7 @@ "Signed PSBT": "Đã ký PSBT", "Single-sig": "Khóa đơn", "Size: ": "Dung lượng: ", + "Some checks cannot be performed.": "Một số kiểm tra không thể được thực hiện.", "Spend (%d): ": "Chi tiêu (%d): ", "Stackbit 1248": "Stackbit 1248", "Store on Flash": "Lưu trữ trên flash", @@ -234,7 +234,7 @@ "Wallet output descriptor": "Ví đầu ra mô tả", "Wallet output descriptor loaded!": "Đã tải bộ mô tả đầu ra của ví!", "Wallet output descriptor not found.": "Không tìm thấy bộ mô tả đầu ra ví.", - "Warning:\nIncomplete output descriptor": "Cảnh báo:\nBộ mô tả đầu ra chưa hoàn chỉnh", + "Warning:": "Cảnh báo:", "Word %d": "Kí tự %d", "Word Numbers": "Từ số", "Words": "Từ ngữ", diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 7aefaf9c8..0c949fa23 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -252,7 +252,8 @@ def _load_wallet(self): ): self.ctx.display.clear() self.ctx.display.draw_centered_text( - t("Warning:\nIncomplete output descriptor"), theme.error_color + t("Warning:") + "\n" + t("Incomplete output descriptor"), + theme.error_color, ) self.ctx.input.wait_for_button() @@ -294,10 +295,11 @@ def sign_psbt(self): # Warns in case multisig wallet descriptor is not loaded if not self.ctx.wallet.is_loaded() and self.ctx.wallet.is_multisig(): self.ctx.display.draw_centered_text( - t( - """Warning:\nWallet output descriptor not found.\n\n - Some checks cannot be performed.""" - ) + t("Warning:") + + "\n" + + t("Wallet output descriptor not found.") + + "\n\n" + + t("Some checks cannot be performed.") ) if not self.prompt(t("Proceed?"), self.ctx.display.bottom_prompt_line): return MENU_CONTINUE diff --git a/src/krux/translations.py b/src/krux/translations.py index d33138ccf..6d26801c6 100644 --- a/src/krux/translations.py +++ b/src/krux/translations.py @@ -21,249 +21,249 @@ # THE SOFTWARE. # pylint: disable=C0301 translation_table = { - "ru-RU": { - 1185266064: "%d из %d мультиподпись", - 2004520398: "%d. Сдача: \n\n%s\n\n", - 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", - 3264377309: "%d. Расход: \n\n%s\n\n", - 2399232215: "%s\n\nвалидный адрес сдачи!", - 3921290840: "%s\n\nвалидный адрес получения!", - 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", - 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", - 3348584292: "(Эксперементальный)", - 2739590230: "12 слов", - 1310058127: "24 слова", + "pt-BR": { + 1185266064: "%d da %d multisig", + 2004520398: "%d. Troco: \n\n%s\n\n", + 3862364126: "%d. Autotransferência: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n é um endereço de troco válido!", + 3921290840: "%s\n\né um endereço de recepção válido!", + 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", + 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", + 3348584292: "(Experimental)", + 2739590230: "12 palavras", + 1310058127: "24 palavras", 2743272264: "ABC", - 1949634023: "О Программе", + 1949634023: "Sobre", 1517128857: "Adafruit", - 3270727197: "Адрес", - 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", - 283202181: "Правильно совместите камеру и Мини Сид-фразу.", - 88746165: "Антиблик отключен", - 1521033296: "Антиблик включен", - 1056821534: "Вы уверены?", - 3247612282: "BIP39 Мнемоника", - 3455872521: "Назад", - 2541860807: "Резервное копирование загрузчика..\n\n%d%%", - 2256777600: "Плохая подпись", - 3937333362: "Скорость Передачи Данных", - 427617266: "Биткоин", - 928727036: "Заполнение границ", + 3270727197: "Endereço", + 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", + 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", + 88746165: "Antirreflexo desativado", + 1521033296: "Antirreflexo ativado", + 1056821534: "Tem certeza?", + 3247612282: "Mnemônico BIP39", + 3455872521: "Voltar", + 2541860807: "Backing up bootloader..\n\n%d%%", + 2256777600: "Assinatura Inválida", + 3937333362: "Baudrate", + 427617266: "Bitcoin", + 928727036: "Borda", 213030954: "CNC", - 1207696150: "Сдача", - 3126552510: "Адрес Сдачи", - 1583186953: "Сменить тему и перезагрузить?", - 2697733395: "Изменения сохранены на SD карте!", - 388908871: "Изменения будут храниться до выключения.", - 3442025874: "Проверить SD Карту", - 3119547911: "Проверить, что адрес принадлежит этому кошельку?", - 2856261511: "Проверено %d адресов сдачи без совпадений.", - 2788541416: "Проверено %d адресов получения без совпадений.", - 2446472910: "Проверяем адрес сдачи %d на совпадение..", - 2470115694: "Проверка SD карты..", - 3655273987: "Проверяем адрес получения %d на совпадение..", - 2407028014: "Компактный SeedQR", - 4041895036: "Продолжить?", - 4094072796: "Создать QR Код", - 167798282: "Создать QR код из текста?", - 2767642191: "Создано", - 3513215254: "Пользовательский QR Код", - 124617190: "Глубина Резки", - 597912140: "Метод Резки", - 2504034831: "Десятичный", - 2751113454: "Расшифровать?", - 1016609898: "Удалить Файл?", - 1364509700: "Удалить Мнемонику", - 4102535566: "Глубина За Проход", - 2791699253: "Производный путь: %s", - 1230133196: "Флэш память устройства не обнаружена.", - 3836852788: "Готово?", - 382368239: "Драйвер", - 3978947916: "Кодер", - 4090746898: "Дебаунс Кодера", - 374684711: "Зашифровать Мнемонику", - 1244124409: "Зашифрованный QR Код", - 2968548114: "Зашифрованная мнемоника не была сохранена", - 3315319371: "Зашифрованная мнемоника была сохранена с ID", - 350279787: "Шифрование", - 2601598799: "Метод шифрования", - 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", - 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", - 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", - 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", - 784361051: "Ошибка:\n%s", - 1505332462: "Выйти", - 3838465623: "Исследовать файлы?", - 4170881190: "Экспортирование на SD карту..", - 1711312434: "Расширенный Публичный Ключ", - 383371114: "Не удалось расшифровать", - 3048830188: "Не удалось загрузить PSBT", - 4192663412: "Не удалось загрузить адрес", - 1996021743: "Не удалось загрузить ключ", - 1108715658: "Не удалось загрузить сообщение", - 1081425878: "Не удалось загрузить мнемонику", - 928667220: "Не удалось загрузить выходной дескриптор", - 1620572516: "Не удалось загрузить фразу-пароль", - 2946146830: "Не удалось сохранить мнемонику", - 1303554751: "Комиссия: ", - 104500973: "Скорость подачи", - 3313339187: "Имя файла", - 1982637349: "Файл %s существует на SD карте, перезаписать?", - 3737729752: "Фингерпринт: %s", - 2542772894: "Прошивка превышает максимальный размер: %d", - 1406590538: "Flute Диаметр", - 3086093110: "Бесплатно: ", - 1893243331: "Из Памяти", + 1207696150: "Troco", + 3126552510: "Endereços de Troco", + 1583186953: "Mudar o tema e reiniciar?", + 2697733395: "Mudanças salvas no cartão SD!", + 388908871: "Alterações só durarão até o desligamento.", + 3442025874: "Verifique o cartão SD", + 3119547911: "Verificar se este endereço pertence a carteira?", + 2856261511: "Endereço de troco %d não corresponde.", + 2788541416: "Endereço de recebimento %d não corresponde.", + 2446472910: "Verificando correspondência do endereço de troco %d ..", + 2470115694: "Verificando o cartão SD..", + 3655273987: "Verificando correspondência do endereço de recebimento %d ..", + 2407028014: "SeedQR Compacto", + 4041895036: "Continuar?", + 4094072796: "Gerar Código QR", + 167798282: "Gerar código QR do texto?", + 2767642191: "Criado: ", + 3513215254: "Código QR Customizado", + 124617190: "Profundidade de Corte", + 597912140: "Método de Corte", + 2504034831: "Decimal", + 2751113454: "Descriptografar?", + 1016609898: "Excluir Arquivo?", + 1364509700: "Excluir Mnemônico", + 4102535566: "Profundidade da Passagem", + 2791699253: "Derivação: %s", + 1230133196: "Armazenamento flash do dispositivo não detectado.", + 3836852788: "Feito?", + 382368239: "Driver", + 3978947916: "Codificador", + 4090746898: "Debounce do Encoder", + 374684711: "Criptografar Mnemônico", + 1244124409: "Código QR Criptografado", + 2968548114: "Mnemonic criptografado não foi armazenado", + 3315319371: "Mnemônico criptografado foi armazenado com ID:", + 350279787: "Criptografia", + 2601598799: "Modo de Criptografia", + 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", + 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", + 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", + 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", + 784361051: "Erro:\n%s", + 1505332462: "Esc", + 3838465623: "Explorar arquivos?", + 4170881190: "Exportando para o cartão SD..", + 1711312434: "Chave Pública Estendida", + 383371114: "Falhou em descriptografar", + 3048830188: "Falhou ao carregar PSBT", + 4192663412: "Falhou ao carregar endereço", + 1996021743: "Falha ao carregar a chave", + 1108715658: "Falhou ao carregar mensagem", + 1081425878: "Falhou ao carregar mnemônico", + 928667220: "Falha ao carregar o descritor de saída", + 1620572516: "Falha ao carregar a senha", + 2946146830: "Falhou ao armazenar mnemônico", + 1303554751: "Taxa: ", + 104500973: "Taxa de Alimentação", + 3313339187: "Nome do arquivo", + 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", + 3737729752: "Impressão digital: %s", + 2542772894: "Firmware excede o tamanho máximo: %d", + 1406590538: "Diâmetro da Fresa", + 3086093110: "Livre: ", + 1893243331: "Do Armazenamento", 4120536442: "GRBL", - 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", - 602716148: "OK", - 831562513: "Интервал Нагрева", - 2300171403: "Время Нагрева", - 3580020863: "Шестнадцатеричный Публичный Ключ", - 2691246967: "Шестнадцатеричный", - 2736309107: "ID уже существует\n", - 631342955: "Входы (%d): ", - 2585599782: "Неверный адрес", - 2874529150: "Неверный загрузчик", - 4093416954: "Неверная длина мнемоники", - 1422874211: "Неверный публичный ключ", - 2443867979: "Неверный кошелек:\n%s", - 4122897393: "Инвертировать", - 3000888649: "Ключ", - 2686333978: "Ключ: ", - 4123798664: "Krux\n\n\nВерсия\n%s", - 3835918229: "Тестовый QR Принтера Krux", - 766317539: "Язык", - 972436696: "Задержка Линии", - 3596093890: "Линия: ", - 2820726296: "Загрузить Мнемонику", - 879727077: "Загрузить с SD карты?", - 669106195: "Загрузить одну?", - 3330705289: "Загрузить?", - 2596531078: "Загрузка Камеры..", - 596389387: "Загрузка адреса сдачи %d..", - 336702608: "Загрузка принтера..", - 2538883522: "Загрузка адреса получения %d..", - 3159494909: "Загрузка..", - 1177338798: "Локаль", - 2817059741: "Расположение", - 63976957: "Уровень логирования", - 86530918: "Логирование", - 2917810189: "Максимальная длина превышена (%s)", - 2030045667: "Сообщение", - 3928301843: "Отсутствует файл подписи", - 1948316555: "Мнемоника", - 2123991188: "ID мнемоники", - 3911073154: "ID памяти мнемоники", - 570639842: "Мнемоника не была расшифрована", - 1746030071: "Мнемоника не была зашифрована", - 1458925155: "Изменено: ", - 1845376098: "Мультиподпись", - 2939797024: "Сеть", - 73574491: "Новая Мнемоника", - 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", - 4063104189: "Нет", - 3927838899: "Без BIP39 фразы-пароля", - 4092516657: "Недостаточно бросков!", - 1577637745: "Восьмеричный", - 3312581301: "PBKDF2 Итерации", - 721090621: "PSBT", - 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", - 2987800462: "Ширина Бумаги", - 3050763890: "Часть\n%d / %d", - 3559456868: "Размер Части", - 4249903283: "Фраза-пароль", - 3712257341: "Фраза-пароль: ", - 140802882: "Постоянная Память", - 1703779997: "QR открытым текстом", - 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", - 784609464: "Скорость Погружения", - 3037062877: "Напечатать Тестовый QR", - 4278257699: "Напечатать в виде QR?\n\n%s\n\n", - 516488026: "Печатать?\n\n%s\n\n", - 1123106929: "Принтер", - 3903571079: "Драйвер Принтера не установлен!", - 2609799302: "Идет печать\n%d / %d", - 844861889: "Идет печать ...", - 2580599003: "Продолжить?", - 556126964: "Обрабатываю ...", - 1848310591: "QR Код", - 710709610: "RX Пин", - 2697857197: "Получить", - 1746677167: "Адрес Получения", - 364354944: "Регион: ", - 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", - 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", - 856795528: "Броски:\n\n%s", - 255086803: "Броски: %d\n", - 3976793317: "SD карта", - 2827687530: "SD карта не обнаружена", - 2736513298: "SD карта не обнаружена.", - 3593785196: "SHA256 бросков:\n\n%s", - 1143278725: "SHA256 снэпшота:\n\n%s", + 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", + 602716148: "Ir", + 3580020863: "Chave pública hexadecimal", + 2691246967: "Hexadecimal", + 2736309107: "Id já existe\n", + 1706005805: "Descritor incompleto", + 631342955: "Entradas (%d): ", + 2585599782: "Endereço inválido", + 2874529150: "Bootloader inválido", + 4093416954: "Comprimento de mnemônico inválido", + 1422874211: "Chave pública inválida", + 2443867979: "Carteira inválida:\n%s", + 4122897393: "Invertido", + 3000888649: "Chave", + 2686333978: "Chave:", + 4123798664: "Krux\n\n\nVersão\n%s", + 3835918229: "Teste de impressão de QR krux", + 766317539: "Língua", + 972436696: "Atraso de Linha", + 3596093890: "Linha: ", + 2820726296: "Carregar Mnemônico", + 879727077: "Carregar do cartão SD?", + 669106195: "Carregar um?", + 3330705289: "Carregar?", + 2596531078: "Carregando Câmera..", + 596389387: "Carregando endereço de troco %d..", + 336702608: "Carregando impressora..", + 2538883522: "Carregando endereço de recebimento %d..", + 3159494909: "Carregando..", + 1177338798: "Idioma", + 2817059741: "Local", + 63976957: "Nível de log", + 86530918: "Logging", + 2917810189: "Comprimento máximo excedido (%s)", + 2030045667: "Mensagem", + 3928301843: "Arquivo de assinatura faltando", + 1948316555: "Mnemônico", + 2123991188: "ID do mnemônico", + 3911073154: "ID de armazenamento", + 570639842: "Mnemônico não foi descriptografado", + 1746030071: "Mnemônico não foi criptografado", + 1458925155: "Modificado:", + 1845376098: "Multisig", + 2939797024: "Rede", + 73574491: "Novo Mnemônico", + 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", + 4063104189: "Não", + 3927838899: "Sem senha BIP39", + 4092516657: "Jogadas insuficientes!", + 1577637745: "Octal", + 3312581301: "Iter. PBKDF2", + 721090621: "PSBT", + 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", + 2987800462: "Largura do papel", + 3050763890: "Parte\n%d / %d", + 3559456868: "Tamanho da peça", + 4249903283: "Senha", + 3712257341: "Senha:", + 140802882: "Salvar", + 1703779997: "QR em Texto", + 3561756278: "Carregue um descritor da carteira", + 784609464: "Taxa de Mergulho", + 3037062877: "Imprimir QR de teste", + 4278257699: "Imprimir QR?\n\n%s\n\n", + 516488026: "Imprimir?\n\n%s\n\n", + 1123106929: "Impressora", + 3903571079: "Driver de impressora não está definido!", + 2609799302: "Imprimindo\n%d / %d", + 844861889: "Imprimindo ...", + 2580599003: "Seguir?", + 556126964: "Processando ...", + 1848310591: "Código QR", + 710709610: "Pino RX", + 2697857197: "Recebimento", + 1746677167: "Endereços de Recebimento", + 364354944: "Região: ", + 1662254634: "Revise os dados, edite se necessário", + 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", + 856795528: "Jogadas:\n\n%s", + 255086803: "Jogadas: %d\n", + 3976793317: "Cartão SD", + 2827687530: "Cartão SD não detectado", + 2736513298: "Cartão SD não detectado.", + 3593785196: "SHA256 de jogadas:\n\n%s", + 1143278725: "Sha256 da imagem:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Сохранить на SD карту?", - 810036588: "Сохранено на SD карту:\n%s", - 763824768: "Шкала", - 4117455079: "Отсканировать Адрес", - 3219991109: "Отсканировать BIP39 фразу-пароль", - 2537207336: "Отсканировать Ключ QR код", - 4006316572: "Сканирование слов 1-12 снова", - 2736506158: "Сканирование слов 13-24", + 3531742595: "Salvar no cartão SD?", + 810036588: "Salvo no cartão SD:\n%s", + 763824768: "Escala", + 4117455079: "Escanear Endereço", + 3219991109: "Escanear a senha BIP39", + 2537207336: "Escanear código QR da chave", + 4006316572: "Escaneando as palavras 1-12 novamente", + 2736506158: "Escaneando as palavras 13-24", 266935239: "SeedQR", - 1698829144: "Трансфер самому себе или Сдача (%d): ", - 473154195: "Настройки", - 1825881236: "Выключить", - 2120776272: "Выключение..", - 1061961408: "Подписать", - 4282338366: "Подписать?", - 746161122: "Подпись", - 1988416729: "Подписанное Сообщение", - 3672006076: "Подписанное PSBT", - 2281377987: "Одна подпись", - 4221794628: "Размер: ", - 2309020186: "Расход (%d): ", - 3355862324: "Стэкбит 1248", - 3303592908: "Сохранить на Флэш Память", - 720041451: "Сохранить на SD Карту", - 3514476519: "Свайпните, чтобы сменить режим", - 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", - 4228215415: "TX Пин", - 2612594937: "Текст", - 1454688268: "Тема", - 1180180513: "Термальный", - 4119292117: "Мини Сид-фраза", - 1732872974: "Мини Сид-фраза (Биты)", - 725348723: "Инструменты", - 3684696112: "Прикоснитесь Границы", - 2978718564: "Тачскрин", - 2732611775: "Попробовать ещё?", - 1487826746: "Введите BIP39 фразу-пароль", - 2061556020: "Введите Ключ", - 2089395053: "Юнит", - 2845607430: "Обновление загрузчика..\n\n%d%%", - 4164597446: "Обновление завершено.\n\nВыключение..", - 2736001501: "Обновление прошивки..\n\n%d%%", - 2674953168: "Использовать черную фоновую поверхность.", - 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", - 236075140: "Использовано: ", - 4003084591: "Значение %s вне диапозона: [%s, %s]", - 4191058607: "С Помощью Камеры", - 1254681955: "С Помощью D20", - 525309547: "С Помощью D6", - 590330112: "С Помощью Ручного Ввода", - 2504354847: "Дождитесь Захвата", - 2297028319: "Дескриптор Кошелька", - 4232654916: "Выходной дескриптор кошелька", - 2587172867: "Выходной дескриптор кошелька загружен!", - 2499782468: "Выходной дескриптор кошелька не найден.", - 1831109430: "Предупреждение:\nНеполный выходной дескриптор", - 797660533: "Слово %d", - 3742424146: "Числа Слов", - 2965123464: "Слова", - 1303016265: "Да", - 771968845: "Ваши изменения буду храниться на флэш памяти устройства.", - 2569054451: "Ваши изменения будут храниться на SD карте.", + 1698829144: "Autotransferência ou Troco (%d): ", + 473154195: "Configurações", + 1825881236: "Desligar", + 2120776272: "Desligando..", + 1061961408: "Assinar", + 4282338366: "Assinar?", + 746161122: "Assinatura", + 1988416729: "Mensagem Assinada", + 3672006076: "PSBT Assinada", + 2281377987: "Single-sig", + 4221794628: "Total: ", + 2344747135: "Algumas verificações não podem ser realizadas.", + 2309020186: "Gastos (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Armazene na Flash", + 720041451: "Armazene no Cartão SD", + 3514476519: "Deslize para mudar de modo", + 1898550184: "TOQUE ou ENTER para capturar", + 4228215415: "Pino TX", + 2612594937: "Texto", + 1454688268: "Tema", + 1180180513: "Térmica", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (bits)", + 725348723: "Ferramentas", + 3684696112: "Limiar de Toque", + 2978718564: "Touchscreen", + 2732611775: "Tentar mais?", + 1487826746: "Digitar a senha BIP39", + 2061556020: "Digite a Chave", + 2089395053: "Unidade", + 2845607430: "Atualizando bootloader..\n\n%d%%", + 4164597446: "Atualização completa.\n\nDesligando..", + 2736001501: "Atualizando firmware..\n\n%d%%", + 2674953168: "Use uma superfície de fundo preta.", + 2402455261: "Use a entropia da câmera para criar um novo mnemônico", + 236075140: "Usado: ", + 4003084591: "Valor %s fora do alcance: [ %s, %s]", + 4191058607: "Pela Câmera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Por entrada manual", + 2504354847: "Aguarde a captura", + 2297028319: "Descritor de Carteira", + 4232654916: "Descritor da carteira", + 2587172867: "Descritor de saída da carteira carregado!", + 2499782468: "O descritor de saída da carteira não foi encontrado.", + 2671738224: "Aviso:", + 797660533: "Palavra %d", + 3742424146: "Números das Palavras", + 2965123464: "Palavras", + 1303016265: "Sim", + 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", + 2569054451: "Suas alterações serão mantidas no cartão SD.", }, "pl-PL": { 1185266064: "%d z %d multisig", @@ -274,6 +274,7 @@ 3921290840: "%s\n\nis ważny adres odbierania!", 1808355833: "%s\n\nwas nie znaleziono w pierwszych adresach zmiany", 1306127065: "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", + 3348584292: "(Eksperymentalny)", 2739590230: "12 słów", 1310058127: "24 słowa", 2743272264: "ABC", @@ -360,11 +361,10 @@ 4120536442: "Grbl", 299338213: "Podaj temu mnemonicznemu identyfikatorowi?W przeciwnym razie zostanie użyty obecny odcisk palca", 602716148: "Iść", - 831562513: "Odstęp cieplny", - 2300171403: "Czas ciepła", 3580020863: "Hex Key Public", 2691246967: "Szesnastkowy", 2736309107: "ID już istnieje\n", + 1706005805: "inComplete Descriptor", 631342955: "Wejścia (%d):", 2585599782: "Błędny adres", 2874529150: "Nieprawidłowy bootloader", @@ -465,6 +465,7 @@ 3672006076: "Podpisano PSBT", 2281377987: "Pojedyncze Sig", 4221794628: "Rozmiar:", + 2344747135: "Nie można wykonać niektórych kontroli.", 2309020186: "Wydać (%d):", 3355862324: "Stackbit 1248", 3303592908: "Przechowuj na Flash", @@ -500,7 +501,7 @@ 4232654916: "Deskryptor wyjściowy portfela", 2587172867: "Załadowany deskryptor wyjściowy portfela!", 2499782468: "Nie znaleziono deskryptora wyjściowego portfela.", - 1831109430: "Ostrzeżenie:\ninComplete Descriptor", + 2671738224: "Ostrzeżenie:", 797660533: "Słowo %d", 3742424146: "Numery słów", 2965123464: "Słowa", @@ -604,11 +605,10 @@ 4120536442: "GRBL", 299338213: "¿Darle a este mnemónico una identificación personalizada?De lo contrario se utilizará la huella digital actual", 602716148: "Ir", - 831562513: "Intervalo de calor", - 2300171403: "Tiempo de calor", 3580020863: "Clave pública hexadecimal", 2691246967: "Hexadecimal", 2736309107: "ID ya existe\n", + 1706005805: "Descriptor incompleto", 631342955: "Entradas (%d): ", 2585599782: "Dirección inválida", 2874529150: "Cargador de arranque inválido", @@ -709,6 +709,7 @@ 3672006076: "PSBT firmado", 2281377987: "Single-sig", 4221794628: "Espacio: ", + 2344747135: "No se pueden realizar algunos cheques.", 2309020186: "Gastos (%d): ", 3355862324: "Stackbit 1248", 3303592908: "Almacenar en flash", @@ -744,7 +745,7 @@ 4232654916: "Descriptor de salida de billetera", 2587172867: "¡Se ha cargado el descriptor de salida de la cartera!", 2499782468: "No se encontró el descriptor de salida de la cartera.", - 1831109430: "Advertencia:\nDescriptor de salida incompleto", + 2671738224: "Advertencia:", 797660533: "Palabra %d", 3742424146: "Números de palabra", 2965123464: "Palabras", @@ -752,1224 +753,1224 @@ 771968845: "Sus cambios se guardarán en el almacenamiento flash del dispositivo.", 2569054451: "Sus cambios se guardarán en la tarjeta SD.", }, - "pt-BR": { - 1185266064: "%d da %d multisig", - 2004520398: "%d. Troco: \n\n%s\n\n", - 3862364126: "%d. Autotransferência: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n é um endereço de troco válido!", - 3921290840: "%s\n\né um endereço de recepção válido!", - 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", - 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", + "de-DE": { + 1185266064: "%d von %d Multisig", + 2004520398: "%d. Change: \n\n%s\n\n", + 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", + 3264377309: "%d. Ausgaben: \n\n%s\n\n", + 2399232215: "%s\n\nist eine gültige Change Adresse!", + 3921290840: "%s\n\nist eine gültige Empfangsadresse!", + 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", + 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", 3348584292: "(Experimental)", - 2739590230: "12 palavras", - 1310058127: "24 palavras", + 2739590230: "12 Wörter", + 1310058127: "24 Wörter", 2743272264: "ABC", - 1949634023: "Sobre", + 1949634023: "Über", 1517128857: "Adafruit", - 3270727197: "Endereço", - 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", - 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", - 88746165: "Antirreflexo desativado", - 1521033296: "Antirreflexo ativado", - 1056821534: "Tem certeza?", - 3247612282: "Mnemônico BIP39", - 3455872521: "Voltar", - 2541860807: "Backing up bootloader..\n\n%d%%", - 2256777600: "Assinatura Inválida", + 3270727197: "Adresse", + 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", + 283202181: "Richte Kamera und Tiny Seed korrekt aus.", + 88746165: "Blendschutz deaktiviert", + 1521033296: "Blendschutz aktiviert", + 1056821534: "Bist Du sicher?", + 3247612282: "BIP39 Mnemonic", + 3455872521: "Zurück", + 2541860807: "Bootloader wird gesichert..\n\n%d%%", + 2256777600: "Ungültige Signatur", 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Borda", + 928727036: "Randpolsterung", 213030954: "CNC", - 1207696150: "Troco", - 3126552510: "Endereços de Troco", - 1583186953: "Mudar o tema e reiniciar?", - 2697733395: "Mudanças salvas no cartão SD!", - 388908871: "Alterações só durarão até o desligamento.", - 3442025874: "Verifique o cartão SD", - 3119547911: "Verificar se este endereço pertence a carteira?", - 2856261511: "Endereço de troco %d não corresponde.", - 2788541416: "Endereço de recebimento %d não corresponde.", - 2446472910: "Verificando correspondência do endereço de troco %d ..", - 2470115694: "Verificando o cartão SD..", - 3655273987: "Verificando correspondência do endereço de recebimento %d ..", - 2407028014: "SeedQR Compacto", - 4041895036: "Continuar?", - 4094072796: "Gerar Código QR", - 167798282: "Gerar código QR do texto?", - 2767642191: "Criado: ", - 3513215254: "Código QR Customizado", - 124617190: "Profundidade de Corte", - 597912140: "Método de Corte", - 2504034831: "Decimal", - 2751113454: "Descriptografar?", - 1016609898: "Excluir Arquivo?", - 1364509700: "Excluir Mnemônico", - 4102535566: "Profundidade da Passagem", - 2791699253: "Derivação: %s", - 1230133196: "Armazenamento flash do dispositivo não detectado.", - 3836852788: "Feito?", + 1207696150: "Change Adresse", + 3126552510: "Change Adressen", + 1583186953: "Thema ändern und neu starten?", + 2697733395: "Änderungen auf SD-Karte gespeichert!", + 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", + 3442025874: "Prüfe SD-Karte", + 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", + 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", + 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", + 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", + 2470115694: "Suche nach SD-Karte..", + 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", + 2407028014: "Kompakt SeedQR", + 4041895036: "Weiter?", + 4094072796: "Erstelle QR-Code", + 167798282: "QR-Code aus Text erzeugen?", + 2767642191: "Erstellt:", + 3513215254: "Benutzerdefinierte QR-Code", + 124617190: "Schnitttiefe", + 597912140: "Cut-Methode", + 2504034831: "Dezimal", + 2751113454: "Entschlüsseln?", + 1016609898: "Datei löschen?", + 1364509700: "Mnemonic löschen", + 4102535566: "Tiefe pro Durchgang", + 2791699253: "Ableitung: %s", + 1230133196: "Geräte-Flash-Speicher nicht erkannt.", + 3836852788: "Fertig?", 382368239: "Driver", - 3978947916: "Codificador", - 4090746898: "Debounce do Encoder", - 374684711: "Criptografar Mnemônico", - 1244124409: "Código QR Criptografado", - 2968548114: "Mnemonic criptografado não foi armazenado", - 3315319371: "Mnemônico criptografado foi armazenado com ID:", - 350279787: "Criptografia", - 2601598799: "Modo de Criptografia", - 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", - 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", - 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", - 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", - 784361051: "Erro:\n%s", + 3978947916: "Encoder", + 4090746898: "Encoder-Entprellung", + 374684711: "Verschlüssel Mnemonic", + 1244124409: "Verschlüsselter QR-Code", + 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", + 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", + 350279787: "Verschlüsselung", + 2601598799: "Verschlüsselungsmodus", + 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", + 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", + 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", + 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", + 784361051: "Fehler:\n%s", 1505332462: "Esc", - 3838465623: "Explorar arquivos?", - 4170881190: "Exportando para o cartão SD..", - 1711312434: "Chave Pública Estendida", - 383371114: "Falhou em descriptografar", - 3048830188: "Falhou ao carregar PSBT", - 4192663412: "Falhou ao carregar endereço", - 1996021743: "Falha ao carregar a chave", - 1108715658: "Falhou ao carregar mensagem", - 1081425878: "Falhou ao carregar mnemônico", - 928667220: "Falha ao carregar o descritor de saída", - 1620572516: "Falha ao carregar a senha", - 2946146830: "Falhou ao armazenar mnemônico", - 1303554751: "Taxa: ", - 104500973: "Taxa de Alimentação", - 3313339187: "Nome do arquivo", - 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", - 3737729752: "Impressão digital: %s", - 2542772894: "Firmware excede o tamanho máximo: %d", - 1406590538: "Diâmetro da Fresa", - 3086093110: "Livre: ", - 1893243331: "Do Armazenamento", + 3838465623: "Dateien durchsuchen?", + 4170881190: "Auf SD-Karte exportieren..", + 1711312434: "Öffentlicher Schlüssel", + 383371114: "Entschlüsselung fehlgeschlagen", + 3048830188: "PSBT konnte nicht geladen werden", + 4192663412: "Adresse konnte nicht geladen werden", + 1996021743: "Schlüssel konnte nicht geladen werden", + 1108715658: "Nachricht konnte nicht geladen werden", + 1081425878: "Mnemonic konnte nicht geladen werden", + 928667220: "Ausgabedeskriptor konnte nicht geladen werden", + 1620572516: "Passphrase konnte nicht geladen werden", + 2946146830: "Mnemonic konnte nicht gespeichert werden", + 1303554751: "Gebühr: ", + 104500973: "Vorschubgeschwindigkeit", + 3313339187: "Dateiname", + 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", + 3737729752: "Fingerabdruck: %s", + 2542772894: "Die Firmware übersteigt die maximale Größe: %d", + 1406590538: "Flötendurchmesser", + 3086093110: "Frei: ", + 1893243331: "Vom Speicher", 4120536442: "GRBL", - 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", - 602716148: "Ir", - 831562513: "Intervalo de Aquecimento", - 2300171403: "Tempo de Aquecimento", - 3580020863: "Chave pública hexadecimal", - 2691246967: "Hexadecimal", - 2736309107: "Id já existe\n", - 631342955: "Entradas (%d): ", - 2585599782: "Endereço inválido", - 2874529150: "Bootloader inválido", - 4093416954: "Comprimento de mnemônico inválido", - 1422874211: "Chave pública inválida", - 2443867979: "Carteira inválida:\n%s", - 4122897393: "Invertido", - 3000888649: "Chave", - 2686333978: "Chave:", - 4123798664: "Krux\n\n\nVersão\n%s", - 3835918229: "Teste de impressão de QR krux", - 766317539: "Língua", - 972436696: "Atraso de Linha", - 3596093890: "Linha: ", - 2820726296: "Carregar Mnemônico", - 879727077: "Carregar do cartão SD?", - 669106195: "Carregar um?", - 3330705289: "Carregar?", - 2596531078: "Carregando Câmera..", - 596389387: "Carregando endereço de troco %d..", - 336702608: "Carregando impressora..", - 2538883522: "Carregando endereço de recebimento %d..", - 3159494909: "Carregando..", - 1177338798: "Idioma", - 2817059741: "Local", - 63976957: "Nível de log", + 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 602716148: "Go", + 3580020863: "Hex öffentlicher Schlüssel", + 2691246967: "Hexadezimal", + 2736309107: "ID existiert bereits\n", + 1706005805: "Unvollständiger Ausgabedeskriptor", + 631342955: "Input (%d): ", + 2585599782: "Ungültige Adresse", + 2874529150: "Ungültiger Bootloader", + 4093416954: "Ungültige mnemonische Lange", + 1422874211: "Ungültiger öffentlicher Schlüssel", + 2443867979: "Ungültige Wallet:\n%s", + 4122897393: "Umkehren", + 3000888649: "Schlüssel", + 2686333978: "Schlüssel:", + 4123798664: "Krux\n\n\nVersion\n%s", + 3835918229: "Krux Drucker Test-QR", + 766317539: "Sprache", + 972436696: "Leitungsverzögerung", + 3596093890: "Linie: ", + 2820726296: "Mnemonic laden", + 879727077: "Von SD-Karte laden?", + 669106195: "Eine laden?", + 3330705289: "Laden?", + 2596531078: "Lade Kamera..", + 596389387: "Lade Change Adresse %d..", + 336702608: "Drucker wird geladen..", + 2538883522: "Lade Empfangsadresse %d..", + 3159494909: "Wird geladen..", + 1177338798: "Spracheinstellung", + 2817059741: "Speicherort", + 63976957: "Log Level", 86530918: "Logging", - 2917810189: "Comprimento máximo excedido (%s)", - 2030045667: "Mensagem", - 3928301843: "Arquivo de assinatura faltando", - 1948316555: "Mnemônico", - 2123991188: "ID do mnemônico", - 3911073154: "ID de armazenamento", - 570639842: "Mnemônico não foi descriptografado", - 1746030071: "Mnemônico não foi criptografado", - 1458925155: "Modificado:", + 2917810189: "Maximale Länge überschritten (%s)", + 2030045667: "Nachricht", + 3928301843: "Fehlende Signaturdatei", + 1948316555: "Mnemonic", + 2123991188: "Mnemonische ID", + 3911073154: "Mnemonische Speicher-ID", + 570639842: "Mnemonic wurde nicht entschlüsselt", + 1746030071: "Mnemonic wurde nicht verschlüsselt", + 1458925155: "Geändert:", 1845376098: "Multisig", - 2939797024: "Rede", - 73574491: "Novo Mnemônico", - 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", - 4063104189: "Não", - 3927838899: "Sem senha BIP39", - 4092516657: "Jogadas insuficientes!", - 1577637745: "Octal", - 3312581301: "Iter. PBKDF2", + 2939797024: "Netzwerk", + 73574491: "Neue Mnemonic", + 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", + 4063104189: "Nein", + 3927838899: "Keine BIP39 Passphrase", + 4092516657: "Nicht genug Würfe!", + 1577637745: "Oktal", + 3312581301: "PBKDF2-Iter.", 721090621: "PSBT", - 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", - 2987800462: "Largura do papel", - 3050763890: "Parte\n%d / %d", - 3559456868: "Tamanho da peça", - 4249903283: "Senha", - 3712257341: "Senha:", - 140802882: "Salvar", - 1703779997: "QR em Texto", - 3561756278: "Carregue um descritor da carteira", - 784609464: "Taxa de Mergulho", - 3037062877: "Imprimir QR de teste", - 4278257699: "Imprimir QR?\n\n%s\n\n", - 516488026: "Imprimir?\n\n%s\n\n", - 1123106929: "Impressora", - 3903571079: "Driver de impressora não está definido!", - 2609799302: "Imprimindo\n%d / %d", - 844861889: "Imprimindo ...", - 2580599003: "Seguir?", - 556126964: "Processando ...", - 1848310591: "Código QR", - 710709610: "Pino RX", - 2697857197: "Recebimento", - 1746677167: "Endereços de Recebimento", - 364354944: "Região: ", - 1662254634: "Revise os dados, edite se necessário", - 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", - 856795528: "Jogadas:\n\n%s", - 255086803: "Jogadas: %d\n", - 3976793317: "Cartão SD", - 2827687530: "Cartão SD não detectado", - 2736513298: "Cartão SD não detectado.", - 3593785196: "SHA256 de jogadas:\n\n%s", - 1143278725: "Sha256 da imagem:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Salvar no cartão SD?", - 810036588: "Salvo no cartão SD:\n%s", - 763824768: "Escala", - 4117455079: "Escanear Endereço", - 3219991109: "Escanear a senha BIP39", - 2537207336: "Escanear código QR da chave", - 4006316572: "Escaneando as palavras 1-12 novamente", - 2736506158: "Escaneando as palavras 13-24", + 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", + 2987800462: "Papierbreite", + 3050763890: "Teil\n%d / %d", + 3559456868: "Teilegröße", + 4249903283: "Passphrase", + 3712257341: "Passphrase:", + 140802882: "Speicher", + 1703779997: "Klartext-QR", + 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", + 784609464: "Tauchrate", + 3037062877: "Drucke Test-QR", + 4278257699: "Als QR-Code drucken?\n\n%s\n\n", + 516488026: "Drucken?\n\n%s\n\n", + 1123106929: "Drucker", + 3903571079: "Druckertreiber nicht gesetzt!", + 2609799302: "Drucken\n%d / %d", + 844861889: "Wird gedruckt ...", + 2580599003: "Weiter?", + 556126964: "Wird bearbeitet ...", + 1848310591: "QR-Code", + 710709610: "RX Pin", + 2697857197: "Empfangen", + 1746677167: "Empfangsadresse", + 364354944: "Region: ", + 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", + 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", + 856795528: "Würfe:\n\n%s", + 255086803: "Würfe: %d\n", + 3976793317: "SD-Karte", + 2827687530: "SD-Karte nicht erkannt", + 2736513298: "SD-Karte nicht erkannt.", + 3593785196: "SHA256 der Würfe:\n\n%s", + 1143278725: "SHA256 des Snapshots:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Auf SD-Karte speichern?", + 810036588: "Auf SD-Karte gespeichert:\n%s", + 763824768: "Skala", + 4117455079: "Adresse\nscannen", + 3219991109: "Scan BIP39 Passphrase", + 2537207336: "Schlüssel QR-Code scannen", + 4006316572: "Wörter 1-12 erneut scannen", + 2736506158: "Wörter 13-24 scannen", 266935239: "SeedQR", - 1698829144: "Autotransferência ou Troco (%d): ", - 473154195: "Configurações", - 1825881236: "Desligar", - 2120776272: "Desligando..", - 1061961408: "Assinar", - 4282338366: "Assinar?", - 746161122: "Assinatura", - 1988416729: "Mensagem Assinada", - 3672006076: "PSBT Assinada", - 2281377987: "Single-sig", - 4221794628: "Total: ", - 2309020186: "Gastos (%d): ", + 1698829144: "Selbstübertragung oder Change (%d): ", + 473154195: "Einstellungen", + 1825881236: "Ausschalten", + 2120776272: "Herunterfahren..", + 1061961408: "Signieren", + 4282338366: "Signieren?", + 746161122: "Signatur", + 1988416729: "Signierte Nachricht", + 3672006076: "Signierte PSBT", + 2281377987: "Single-Sig", + 4221794628: "Größe: ", + 2344747135: "Einige Schecks können nicht durchgeführt werden.", + 2309020186: "Ausgabe (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Armazene na Flash", - 720041451: "Armazene no Cartão SD", - 3514476519: "Deslize para mudar de modo", - 1898550184: "TOQUE ou ENTER para capturar", - 4228215415: "Pino TX", - 2612594937: "Texto", - 1454688268: "Tema", - 1180180513: "Térmica", + 3303592908: "Auf Flash speichern", + 720041451: "Auf der SD-Karte speichern", + 3514476519: "Wischen um den Modus zu ändern", + 1898550184: "TOUCH oder ENTER zum Erfassen", + 4228215415: "TX Pin", + 2612594937: "Text", + 1454688268: "Thema", + 1180180513: "Thermisch", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Ferramentas", - 3684696112: "Limiar de Toque", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Werkzeuge", + 3684696112: "Berühre Schwellenwert", 2978718564: "Touchscreen", - 2732611775: "Tentar mais?", - 1487826746: "Digitar a senha BIP39", - 2061556020: "Digite a Chave", - 2089395053: "Unidade", - 2845607430: "Atualizando bootloader..\n\n%d%%", - 4164597446: "Atualização completa.\n\nDesligando..", - 2736001501: "Atualizando firmware..\n\n%d%%", - 2674953168: "Use uma superfície de fundo preta.", - 2402455261: "Use a entropia da câmera para criar um novo mnemônico", - 236075140: "Usado: ", - 4003084591: "Valor %s fora do alcance: [ %s, %s]", - 4191058607: "Pela Câmera", + 2732611775: "Weiter versuchen?", + 1487826746: "BIP39 Passphrase eingeben", + 2061556020: "Schlüssel eingeben", + 2089395053: "Einheit", + 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", + 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", + 2736001501: "Firmware wird aktualisiert..\n\n%d%%", + 2674953168: "Verwende eine schwarze Hintergrundfläche.", + 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", + 236075140: "Belegt: ", + 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", + 4191058607: "Via Kamera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Por entrada manual", - 2504354847: "Aguarde a captura", - 2297028319: "Descritor de Carteira", - 4232654916: "Descritor da carteira", - 2587172867: "Descritor de saída da carteira carregado!", - 2499782468: "O descritor de saída da carteira não foi encontrado.", - 1831109430: "Atenção:\nDescritor de saída incompleto", - 797660533: "Palavra %d", - 3742424146: "Números das Palavras", - 2965123464: "Palavras", - 1303016265: "Sim", - 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", - 2569054451: "Suas alterações serão mantidas no cartão SD.", + 590330112: "Via manueller Eingabe", + 2504354847: "Warte auf die Erfassung", + 2297028319: "Wallet-Deskriptor", + 4232654916: "Wallet Ausgabedeskriptor", + 2587172867: "Wallet Ausgabedeskriptor geladen!", + 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", + 2671738224: "Warnung:", + 797660533: "Wort %d", + 3742424146: "Wortnummern", + 2965123464: "Wörter", + 1303016265: "Ja", + 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", + 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", }, - "fr-FR": { - 1185266064: "%d de %d multisignature", - 2004520398: "%d. Changement : \n\n%s\n\n", - 3862364126: "%d. Auto-transfert : \n\n%s\n\n", - 3264377309: "%d. Dépense : \n\n%s\n\n", - 2399232215: "%s\n\nest une adresse changement valide!", - 3921290840: "%s\n\nest une adresse reçue valide!", - 1808355833: "INTROUVABLE dans les premières %d adresses de changement", - 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", - 3348584292: "(Expérimental)", - 2739590230: "12 mots", - 1310058127: "24 mots", + "vi-VN": { + 1185266064: "%d của %d đa chữ kí", + 2004520398: "%d. Thay đổi: \n\n%s\n\n", + 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", + 3264377309: "%d. Chi tiêu: \n\n%s\n\n", + 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", + 3921290840: "%s\n\nlà một địa chỉ khả dụng!", + 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 3348584292: "(Thực nghiệm)", + 2739590230: "12 từ", + 1310058127: "24 từ", 2743272264: "ABC", - 1949634023: "À propos", + 1949634023: "Về chúng tôi", 1517128857: "Adafruit", - 3270727197: "Adresse", - 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", - 283202181: "Alignez correctement la caméra et Tiny Seed.", - 88746165: "Anti-éblouissement désactivé", - 1521033296: "Anti-éblouissement activé", - 1056821534: "Es-tu sûr?", - 3247612282: "BIP39 Mnémonique", - 3455872521: "Retour", - 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", - 2256777600: "Mauvaise signature", - 3937333362: "Débit en bauds", + 3270727197: "Địa chỉ", + 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", + 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", + 88746165: "Chống lóa bị vô hiệu hóa", + 1521033296: "Đã bật chống lóa", + 1056821534: "Bạn có chắc không?", + 3247612282: "Mã mnemonic dạng chuẩn BIP39", + 3455872521: "Trở lại", + 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", + 2256777600: "Chữ ký xấu", + 3937333362: "Tốc độ baud", 427617266: "Bitcoin", - 928727036: "Rembourrage de bordure", + 928727036: "Đệm viền", 213030954: "CNC", - 1207696150: "Changement", - 3126552510: "Adresses de Changement", - 1583186953: "Changer de thème et redémarrer?", - 2697733395: "Modifications enregistrées sur la carte SD!", - 388908871: "Les modifications dureront jusqu'à l'arrêt.", - 3442025874: "Vérifiez la carte SD", - 3119547911: "Vérifiez que l'adresse appartient à cette portefeuille?", - 2856261511: "Adresses %d changement vérifiées sans correspondance.", - 2788541416: "Adresses %d reçues vérifiées sans correspondance.", - 2446472910: "Vérification de l'adresse changement %d pour correspondance..", - 2470115694: "Vérification de la carte SD..", - 3655273987: "Vérification de l'adresse reçue %d pour correspondance..", - 2407028014: "SeedQR Compact", - 4041895036: "Continuer?", - 4094072796: "Créer du code QR", - 167798282: "Créer du code QR à partir du texte?", - 2767642191: "Créé:", - 3513215254: "Code QR personnalisé", - 124617190: "Profondeur de coupe", - 597912140: "Méthode de coupe", - 2504034831: "Décimal", - 2751113454: "Décrypter?", - 1016609898: "Supprimer le fichier?", - 1364509700: "Supprimer mnémonique", - 4102535566: "Profondeur par passage", - 2791699253: "Dérivation: %s", - 1230133196: "Stockage flash de l'appareil non détecté.", - 3836852788: "Terminé?", - 382368239: "Conducteur", - 3978947916: "Encodeur", - 4090746898: "Anti-rebond de l'encodeur", - 374684711: "Crypter mnémonique", - 1244124409: "Code QR crypté", - 2968548114: "Le mnémonique crypté n'a pas été stocké", - 3315319371: "Mnémonique cryptée a été stockée avec ID:", - 350279787: "Chiffrement", - 2601598799: "Mode de chiffrement", - 3504179008: "Entrez chaque mot de votre BIP-39 mnémonique sous la forme d'un nombre 1 jusqu'à 2048.", - 1100685007: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en hexadécimal de 1 à 800.", - 4090266642: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en octal de 1 à 4000.", - 2780625730: "Entrez chaque mot de votre BIP-39 mnémonique.", - 784361051: "Erreur:\n%s", - 1505332462: "Esc", - 3838465623: "Explorer des fichiers?", - 4170881190: "Exportation vers la carte SD..", - 1711312434: "Clé publique", - 383371114: "Échec de décrypter", - 3048830188: "Erreur de chargement PSBT", - 4192663412: "Erreur de chargement d'adresse", - 1996021743: "Échec du chargement de la clé", - 1108715658: "Échec du chargement du message", - 1081425878: "Erreur de chargement mnémonique", - 928667220: "Échec du chargement du descripteur de sortie", - 1620572516: "Échec du chargement de la phrase secrète", - 2946146830: "Échec de stocker mnémonique", - 1303554751: "Frais: ", - 104500973: "Taux d'alimentation", - 3313339187: "Nom de fichier", - 1982637349: "Le nom de fichier %s existe sur la carte SD, écraser ?", - 3737729752: "Empreinte Digitale: %s", - 2542772894: "Le micrologiciel dépasse la taille maximale: %d", - 1406590538: "Diamètre de flûte", - 3086093110: "Libre: ", - 1893243331: "Du stockage", + 1207696150: "Thay đổi", + 3126552510: "Thay địa chỉ", + 1583186953: "Thay đổi chủ đề và khởi động lại?", + 2697733395: "Thay đổi được lưu trên thẻ SD!", + 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", + 3442025874: "Kiểm tra thẻ SD", + 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", + 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", + 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", + 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", + 2470115694: "Kiểm tra thẻ SD..", + 3655273987: "Đang kiểm tra %d địa chỉ..", + 2407028014: "SeedQR nhỏ gọn", + 4041895036: "Tiếp tục?", + 4094072796: "Tạo mã QR", + 167798282: "Tạo mã QR từ văn bản?", + 2767642191: "Tạo:", + 3513215254: "Mã QR tùy chỉnh", + 124617190: "Chiều sâu cắt", + 597912140: "Phương pháp cắt", + 2504034831: "Số thập phân", + 2751113454: "Phản đối?", + 1016609898: "Xóa tài liệu?", + 1364509700: "Xóa ghi nhớ", + 4102535566: "Độ sâu mỗi lần vượt qua", + 2791699253: "Nguồn gốc: %s", + 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", + 3836852788: "Hoàn tất?", + 382368239: "Người cầm lái", + 3978947916: "Mã hoá", + 4090746898: "Gỡ lỗi bộ mã hóa", + 374684711: "Mã hóa Mnemonic", + 1244124409: "Mã QR được mã hóa", + 2968548114: "MNemon được mã hóa không được lưu trữ", + 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", + 350279787: "Mã hóa", + 2601598799: "Chế độ mã hóa", + 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", + 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", + 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", + 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", + 784361051: "Lỗi:\n%s", + 1505332462: "Esc", + 3838465623: "Khám phá các tập tin?", + 4170881190: "Xuất vào thẻ SD ..", + 1711312434: "Khóa công cộng", + 383371114: "Không giải mã được", + 3048830188: "Tải PSBT thất bại", + 4192663412: "Tải địa chỉ thất bại", + 1996021743: "Không tải khóa", + 1108715658: "Không tải được tin nhắn", + 1081425878: "Tải mã mnemonic thất bại", + 928667220: "Không thể tải bộ mô tả đầu ra", + 1620572516: "Không tải được cụm mật khẩu", + 2946146830: "Không lưu trữ MNemonic", + 1303554751: "Phí: ", + 104500973: "Tỷ lệ thức ăn", + 3313339187: "Tên tệp", + 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", + 3737729752: "Dấu vân tay: %s", + 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", + 1406590538: "Đường kính ống sáo", + 3086093110: "Khả dụng: ", + 1893243331: "Từ lưu trữ", 4120536442: "GRBL", - 299338213: "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", - 602716148: "Go", - 831562513: "Intervalle de chauffe", - 2300171403: "Temps de chauffe", - 3580020863: "Clé public hexadécimal", - 2691246967: "Hexadécimal", - 2736309107: "Id existe déjà\n", - 631342955: "Entrées (%d) : ", - 2585599782: "Adresse invalide", - 2874529150: "Chargeur de démarrage invalide", - 4093416954: "Longueur mnémonique invalide", - 1422874211: "Clé publique non valide", - 2443867979: "Portefeuille invalide:\n%s", - 4122897393: "Inverser", - 3000888649: "Clé", - 2686333978: "Clé:", - 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Test de l'imprimante Krux QR", - 766317539: "Langue", - 972436696: "Délai de Ligne", - 3596093890: "Ligne: ", - 2820726296: "Charger mnémonique", - 879727077: "Charger depuis la carte SD ?", - 669106195: "En charger qu'un?", - 3330705289: "Charger?", - 2596531078: "Caméra de Chargement..", - 596389387: "Chargement de l'adresse de changement %d..", - 336702608: "Chargement de l'imprimante..", - 2538883522: "Chargement de l'adresse de réception %d..", - 3159494909: "Chargement..", - 1177338798: "Paramètres régionaux", - 2817059741: "Emplacement", - 63976957: "Niveau de journalisation", - 86530918: "Enregistrement", - 2917810189: "Longueur maximale dépassée (% s)", - 2030045667: "Message", - 3928301843: "Fichier de signature manquant", - 1948316555: "Mnémonique", - 2123991188: "ID mnémonique", - 3911073154: "ID de stockage mnémonique", - 570639842: "Mnémonique n'a pas été décryptée", - 1746030071: "Mnémonique n'était pas cryptée", - 1458925155: "Modifié:", - 1845376098: "Multi\nsignature", - 2939797024: "Réseau", - 73574491: "Nouveau mnémonique", - 2792272353: "Nouveau micrologiciel détecté.\n\nSHA256:\n%s\n\n\n\nInstaller?", - 4063104189: "Non", - 3927838899: "Pas de phrase passante bip39", - 4092516657: "Pas assez de rouleaux !", - 1577637745: "Octale", - 3312581301: "Itér. PBKDF2", + 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", + 602716148: "Đến", + 3580020863: "Khóa công khai Hex", + 2691246967: "Thập lục phân", + 2736309107: "Id đã tồn tại\n", + 1706005805: "Bộ mô tả đầu ra chưa hoàn chỉnh", + 631342955: "Đầu vào (%d): ", + 2585599782: "Địa chỉ không hợp lệ", + 2874529150: "Bộ tải khởi động không hợp lệ", + 4093416954: "Độ dài mã mnemonic không hợp lệ", + 1422874211: "Khóa công khai không hợp lệ", + 2443867979: "Ví không hợp lệ:\n%s", + 4122897393: "Đảo ngược", + 3000888649: "Chìa khóa", + 2686333978: "Chìa khóa:", + 4123798664: "Krux\n\n\nPhiên Bản\n%s", + 3835918229: "QR kiểm tra máy in Krux", + 766317539: "Ngôn ngữ", + 972436696: "Độ trễ Dòng", + 3596093890: "Đường kẻ: ", + 2820726296: "Tải mã mnemonic", + 879727077: "Tải từ thẻ SD?", + 669106195: "Tải một?", + 3330705289: "Tải?", + 2596531078: "Đang tải máy ảnh..", + 596389387: "Đang tải thay đổi địa chỉ %d..", + 336702608: "Tải máy in ..", + 2538883522: "Đang tải địa chỉ nhận %d..", + 3159494909: "Đang tải..", + 1177338798: "Ngôn ngữ", + 2817059741: "Vị trí cửa hàng", + 63976957: "Log Level", + 86530918: "Khai thác gỗ", + 2917810189: "Chiều dài tối đa vượt quá (%s)", + 2030045667: "Tin nhắn", + 3928301843: "Thiếu tập tin chữ ký", + 1948316555: "Mã mnemonic", + 2123991188: "ID ghi nhớ", + 3911073154: "ID lưu trữ ghi nhớ", + 570639842: "Ghi nhớ không được giải mã", + 1746030071: "Ghi nhớ không được mã hóa", + 1458925155: "Đã sửa đổi:", + 1845376098: "Đa chữ kí", + 2939797024: "Mạng lưới", + 73574491: "Mnemonic mới", + 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", + 4063104189: "Không", + 3927838899: "Không có cụm mật khẩu BIP39", + 4092516657: "Không đủ cuộn!", + 1577637745: "Bát phân", + 3312581301: "Lặp lại PBKDF2", 721090621: "PSBT", - 995862913: "Peignez les points perforés en noir afin qu'ils puissent être détectés.", - 2987800462: "Largeur du papier", - 3050763890: "Partie\n%d / %d", - 3559456868: "Taille de la pièce", - 4249903283: "Phrase de passe", - 3712257341: "Phrass de passe:", - 140802882: "Persister", - 1703779997: "QR en Texte Brut", - 3561756278: "Veuillez charger un descripteur de sortie de portefeuille", - 784609464: "Taux de plongée", - 3037062877: "Test d'impression QR", - 4278257699: "Imprimer en QR?\n\n%s\n\n", - 516488026: "Imprimer?\n\n%s\n\n", - 1123106929: "Imprimante", - 3903571079: "Le conducteur d'imprimante n'est pas défini!", - 2609799302: "Impression\n%d / %d", - 844861889: "Impression ...", - 2580599003: "Procéder?", - 556126964: "Traitement ...", - 1848310591: "QR Code", - 710709610: "RX Fiche", - 2697857197: "Recevoir", - 1746677167: "Adresses de Réception", - 364354944: "Région: ", - 1662254634: "Examinez les données numérisées, modifiez-les si nécessaire", - 770350922: "Lancez le dé au moins %d fois pour générer un mnémonique.", - 856795528: "Rouleaux:\n\n%s", - 255086803: "Rouleaux: %d\n", - 3976793317: "Carte SD", - 2827687530: "Carte SD non détectée", - 2736513298: "Carte SD non détectée.", - 3593785196: "SHA256 de rouleaux:\n\n%s", - 1143278725: "Sha256 de Snapshot:\n\n% s", + 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", + 2987800462: "Chiều rộng giấy", + 3050763890: "Phần\n%d / %d", + 3559456868: "Kích thước một phần", + 4249903283: "Cụm mật khẩu", + 3712257341: "Cụm cụm:", + 140802882: "Vị trí lưu", + 1703779997: "Văn bản rõ QR", + 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", + 784609464: "Tỷ lệ sụt giảm", + 3037062877: "In kiểm tra QR", + 4278257699: "In ra mã QR?\n\n%s\n\n", + 516488026: "In?\n\n%s\n\n", + 1123106929: "Máy in", + 3903571079: "Trình điều khiển máy in không đặt!", + 2609799302: "Đang in\n%d / %d", + 844861889: "In ấn ...", + 2580599003: "Thực hiện?", + 556126964: "Xử lý ...", + 1848310591: "Mã QR", + 710709610: "RX Ghim", + 2697857197: "Nhận được", + 1746677167: "Nhận địa chỉ", + 364354944: "Vùng: ", + 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", + 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", + 856795528: "Súc sắc cuộn:\n\n%s", + 255086803: "Súc sắc cuộn: %d\n", + 3976793317: "Thẻ SD", + 2827687530: "Thẻ SD không được phát hiện", + 2736513298: "Thẻ SD không được phát hiện.", + 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", + 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Enregistrer sur la carte SD ?", - 810036588: "Enregistré sur la carte SD :\n%s", - 763824768: "L'échelle", - 4117455079: "Scannez l'adresse", - 3219991109: "Scan bip39 en phrase secrète", - 2537207336: "Scanner le code QR de la clé", - 4006316572: "Analyser à nouveau les mots 1 à 12", - 2736506158: "Analyser les mots 13 à 24", - 266935239: "Seedqr", - 1698829144: "Auto-transfert ou changement (%d): ", - 473154195: "Paramètres", - 1825881236: "Fermer", - 2120776272: "Éteindre..", - 1061961408: "Signature", - 4282338366: "Signature?", - 746161122: "Signature", - 1988416729: "Message signé", - 3672006076: "PSBT signé", - 2281377987: "Clé unique", - 4221794628: "Capacité: ", - 2309020186: "Dépense (%d) : ", + 3531742595: "Lưu vào thẻ SD?", + 810036588: "Đã lưu vào thẻ SD:\n%s", + 763824768: "Cái cân", + 4117455079: "Quét địa chỉ", + 3219991109: "Quét BIP39 Cụm cụm", + 2537207336: "Quét mã QR khóa", + 4006316572: "Quét lại từ 1-12", + 2736506158: "Quét từ 13-24", + 266935239: "SEEDQR", + 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", + 473154195: "Cài đặt", + 1825881236: "Tắt", + 2120776272: "Đang tắt..", + 1061961408: "Chữ kí", + 4282338366: "Kí?", + 746161122: "Chữ ký", + 1988416729: "Tin nhắn đã ký", + 3672006076: "Đã ký PSBT", + 2281377987: "Khóa đơn", + 4221794628: "Dung lượng: ", + 2344747135: "Một số kiểm tra không thể được thực hiện.", + 2309020186: "Chi tiêu (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Stocker sur flash", - 720041451: "Stocker sur la carte SD", - 3514476519: "Faites glisser pour changer de mode", - 1898550184: "TOUCHEZ ou ENTER pour capturer", - 4228215415: "TX Fiche", - 2612594937: "Texte", - 1454688268: "Thème", - 1180180513: "Thermique", + 3303592908: "Lưu trữ trên flash", + 720041451: "Lưu trữ trên thẻ SD", + 3514476519: "Vuốt để thay đổi chế độ", + 1898550184: "TOUCH hoặc ENTER để chụp", + 4228215415: "TX Ghim", + 2612594937: "Chữ", + 1454688268: "Chủ đề", + 1180180513: "Nhiệt", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Outils", - 3684696112: "Seuil Tactile", - 2978718564: "Écran Tactile", - 2732611775: "Réessayer?", - 1487826746: "Type Bip39 Plasque", - 2061556020: "Clé de type", - 2089395053: "Unité", - 2845607430: "Mise à jour du chargeur de démarrage..\n\n%d%%", - 4164597446: "Mise à niveau complète.\n\nÉteindre..", - 2736001501: "Mise à niveau du micrologiciel..\n\n%d%%", - 2674953168: "Utilisez une surface de fond noire.", - 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", - 236075140: "Utilisé: ", - 4003084591: "Valeur% s hors de portée: [% s,% s]", - 4191058607: "Par caméra", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Par saisie manuelle", - 2504354847: "Attendez la capture", - 2297028319: "Descripteur de Portefeuille", - 4232654916: "Descripteur de sortie du portefeuille", - 2587172867: "Descripteur de sortie du portefeuille chargé!", - 2499782468: "Descripteur de sortie du portefeuille introuvable.", - 1831109430: "Attention:\nDescripteur de sortie incomplet", - 797660533: "Mot %d", - 3742424146: "Numéros de mots", - 2965123464: "Mots", - 1303016265: "Oui", - 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", - 2569054451: "Vos modifications seront conservées sur la carte SD.", + 1732872974: "Tiny Seed (bit)", + 725348723: "Công cụ", + 3684696112: "Ngưỡng cảm ứng", + 2978718564: "Màn hình cảm ứng", + 2732611775: "Thử thêm nữa?", + 1487826746: "Nhập cụm BIP39", + 2061556020: "Nhập khóa", + 2089395053: "Đơn vị", + 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", + 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", + 2736001501: "Nâng cấp firmware..\n\n%d%%", + 2674953168: "Sử dụng bề mặt nền đen.", + 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", + 236075140: "Đã sử dụng: ", + 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", + 4191058607: "Qua máy ảnh", + 1254681955: "Qua D20", + 525309547: "Qua D6", + 590330112: "Thông qua đầu vào thủ công", + 2504354847: "Chờ bắt", + 2297028319: "Trình mô tả ví", + 4232654916: "Ví đầu ra mô tả", + 2587172867: "Đã tải bộ mô tả đầu ra của ví!", + 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", + 2671738224: "Cảnh báo:", + 797660533: "Kí tự %d", + 3742424146: "Từ số", + 2965123464: "Từ ngữ", + 1303016265: "Đúng", + 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", + 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", }, - "nl-NL": { - 1185266064: "%d van %d multisig", - 2004520398: "%d. Wisselgeld: \n\n%s\n\n", - 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", - 3264377309: "%d. Uitgaven: \n\n%s\n\n", - 2399232215: "%s\n\nis een valide wisselgeld adres!", - 3921290840: "%s\n\nis een valide ontvangst adres!", - 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", - 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", - 3348584292: "(Experimenteel)", - 2739590230: "12 woorden", - 1310058127: "24 woorden", + "ru-RU": { + 1185266064: "%d из %d мультиподпись", + 2004520398: "%d. Сдача: \n\n%s\n\n", + 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", + 3264377309: "%d. Расход: \n\n%s\n\n", + 2399232215: "%s\n\nвалидный адрес сдачи!", + 3921290840: "%s\n\nвалидный адрес получения!", + 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", + 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", + 3348584292: "(Эксперементальный)", + 2739590230: "12 слов", + 1310058127: "24 слова", 2743272264: "ABC", - 1949634023: "Over", + 1949634023: "О Программе", 1517128857: "Adafruit", - 3270727197: "Adres", - 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", - 283202181: "Richt de camera en Tiny Seed op de juiste manier.", - 88746165: "Anti reflecterend uitgeschakeld", - 1521033296: "Anti reflecterend ingeschakeld", - 1056821534: "Weet je het zeker?", - 3247612282: "BIP-39 geheugensteun", - 3455872521: "Terug", - 2541860807: "Backup van de bootloader...\n\n%d%%", - 2256777600: "Ongeldige handtekening", - 3937333362: "Baudratio", - 427617266: "Bitcoin", - 928727036: "Rand opvulling", - 213030954: "CNC", - 1207696150: "Change", - 3126552510: "Wisselgeldadres", - 1583186953: "Thema veranderen en opnieuw opstarten?", - 2697733395: "Wijzigingen aanhouden op SD kaart!", - 388908871: "Wijzigingen blijven van kracht tot afsluiten.", - 3442025874: "Controleer SD kaart", - 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", - 2856261511: "Na %d geen wisselgeld adressen gevonden.", - 2788541416: "Na %d geen ontvangst adressen gevonden.", - 2446472910: "Wisselgeldadres %d controleren...", - 2470115694: "SD kaart controleren...", - 3655273987: "Ontvangstadres %d controleren...", - 2407028014: "Compact SeedQR", - 4041895036: "Doorgaan?", - 4094072796: "QR code maken", - 167798282: "QR code maken van tekst?", - 2767642191: "Aangemaakt: ", - 3513215254: "Aangepaste QR code", - 124617190: "Snijdiepte", - 597912140: "Snijmethode", - 2504034831: "Decimaal", - 2751113454: "Ontsleutelen?", - 1016609898: "Bestand verwijderen?", - 1364509700: "Geheugensteun verwijderen", - 4102535566: "Diepte per pas", - 2791699253: "Afgeleide: %s", - 1230133196: "Opslag op apparaat is niet gedetecteerd.", - 3836852788: "Klaar?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-debounce", - 374684711: "Geheugensteun versleutelen", - 1244124409: "Versleutelde QR code", - 2968548114: "Versleutelde geheugensteun was niet opgeslagen", - 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", - 350279787: "Versleutelen", - 2601598799: "Versleutel modus", - 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", - 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", - 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", - 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", - 784361051: "Fout:\n%s", - 1505332462: "Esc", - 3838465623: "Bestanden verkennen?", - 4170881190: "Exporteren naar SD-kaart..", - 1711312434: "Uitgebreide publieke sleutel", - 383371114: "Ontsleutelen is niet gelukt", - 3048830188: "PSBT laden is niet gelukt", - 4192663412: "Adres laden is niet gelukt", - 1996021743: "Sleutel laden is niet gelukt", - 1108715658: "Bericht laden is niet gelukt", - 1081425878: "Geheugensteun laden is niet gelukt", - 928667220: "Descriptor laden is niet gelukt", - 1620572516: "Wachtwoord laden is niet gelukt", - 2946146830: "Geheugensteun opslaan is niet gelukt", - 1303554751: "Tarief: ", - 104500973: "Voedingssnelheid", - 3313339187: "Bestandsnaam", - 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", - 3737729752: "Vingerafdruk: %s", - 2542772894: "Firmware overschrijdt de maximale grootte: %d", - 1406590538: "Fluit diameter", - 3086093110: "Vrij: ", - 1893243331: "Uit data-opslag", + 3270727197: "Адрес", + 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", + 283202181: "Правильно совместите камеру и Мини Сид-фразу.", + 88746165: "Антиблик отключен", + 1521033296: "Антиблик включен", + 1056821534: "Вы уверены?", + 3247612282: "BIP39 Мнемоника", + 3455872521: "Назад", + 2541860807: "Резервное копирование загрузчика..\n\n%d%%", + 2256777600: "Плохая подпись", + 3937333362: "Скорость Передачи Данных", + 427617266: "Биткоин", + 928727036: "Заполнение границ", + 213030954: "CNC", + 1207696150: "Сдача", + 3126552510: "Адрес Сдачи", + 1583186953: "Сменить тему и перезагрузить?", + 2697733395: "Изменения сохранены на SD карте!", + 388908871: "Изменения будут храниться до выключения.", + 3442025874: "Проверить SD Карту", + 3119547911: "Проверить, что адрес принадлежит этому кошельку?", + 2856261511: "Проверено %d адресов сдачи без совпадений.", + 2788541416: "Проверено %d адресов получения без совпадений.", + 2446472910: "Проверяем адрес сдачи %d на совпадение..", + 2470115694: "Проверка SD карты..", + 3655273987: "Проверяем адрес получения %d на совпадение..", + 2407028014: "Компактный SeedQR", + 4041895036: "Продолжить?", + 4094072796: "Создать QR Код", + 167798282: "Создать QR код из текста?", + 2767642191: "Создано", + 3513215254: "Пользовательский QR Код", + 124617190: "Глубина Резки", + 597912140: "Метод Резки", + 2504034831: "Десятичный", + 2751113454: "Расшифровать?", + 1016609898: "Удалить Файл?", + 1364509700: "Удалить Мнемонику", + 4102535566: "Глубина За Проход", + 2791699253: "Производный путь: %s", + 1230133196: "Флэш память устройства не обнаружена.", + 3836852788: "Готово?", + 382368239: "Драйвер", + 3978947916: "Кодер", + 4090746898: "Дебаунс Кодера", + 374684711: "Зашифровать Мнемонику", + 1244124409: "Зашифрованный QR Код", + 2968548114: "Зашифрованная мнемоника не была сохранена", + 3315319371: "Зашифрованная мнемоника была сохранена с ID", + 350279787: "Шифрование", + 2601598799: "Метод шифрования", + 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", + 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", + 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", + 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", + 784361051: "Ошибка:\n%s", + 1505332462: "Выйти", + 3838465623: "Исследовать файлы?", + 4170881190: "Экспортирование на SD карту..", + 1711312434: "Расширенный Публичный Ключ", + 383371114: "Не удалось расшифровать", + 3048830188: "Не удалось загрузить PSBT", + 4192663412: "Не удалось загрузить адрес", + 1996021743: "Не удалось загрузить ключ", + 1108715658: "Не удалось загрузить сообщение", + 1081425878: "Не удалось загрузить мнемонику", + 928667220: "Не удалось загрузить выходной дескриптор", + 1620572516: "Не удалось загрузить фразу-пароль", + 2946146830: "Не удалось сохранить мнемонику", + 1303554751: "Комиссия: ", + 104500973: "Скорость подачи", + 3313339187: "Имя файла", + 1982637349: "Файл %s существует на SD карте, перезаписать?", + 3737729752: "Фингерпринт: %s", + 2542772894: "Прошивка превышает максимальный размер: %d", + 1406590538: "Flute Диаметр", + 3086093110: "Бесплатно: ", + 1893243331: "Из Памяти", 4120536442: "GRBL", - 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", - 602716148: "Ga", - 831562513: "Warmte interval", - 2300171403: "Warmte tijd", - 3580020863: "Hex publieke sleutel", - 2691246967: "Hexadecimaal", - 2736309107: "ID bestaat al\n", - 631342955: "Invoer (%d): ", - 2585599782: "Ongeldig adres", - 2874529150: "Ongeldige bootloader", - 4093416954: "Ongeldige geheugensteun lengte", - 1422874211: "Ongeldige publieke sleutel", - 2443867979: "Ongeldige portemonnee:\n%s", - 4122897393: "Omkeren", - 3000888649: "Sleutel", - 2686333978: "Sleutel: ", - 4123798664: "Krux\n\n\nVersie\n%s", - 3835918229: "Krux printer test QR", - 766317539: "Taal", - 972436696: "Lijn vertraging", - 3596093890: "Lijn: ", - 2820726296: "Geheugensteun laden", - 879727077: "Laden vanaf SD-kaart?", - 669106195: "Laden?", - 3330705289: "Laden?", - 2596531078: "Camera laden...", - 596389387: "Wisselgeldadres %d laden...", - 336702608: "Laadprinter..", - 2538883522: "Ontvangstadres %d laden...", - 3159494909: "Laden...", - 1177338798: "Taal", - 2817059741: "Opslaglocatie", - 63976957: "Log niveau", - 86530918: "Debug logs", - 2917810189: "Maximale lengte overschreden (%s)", - 2030045667: "Bericht", - 3928301843: "Handtekening bestand mist", - 1948316555: "Geheugensteun", - 2123991188: "Geheugensteun ID", - 3911073154: "Geheugensteun opslag ID", - 570639842: "Geheugensteun is niet ontsleuteld", - 1746030071: "Geheugensteun is niet versleuteld", - 1458925155: "Aangepast: ", - 1845376098: "Multisig", - 2939797024: "Netwerk", - 73574491: "Geheugensteun aanmaken", - 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", - 4063104189: "Nee", - 3927838899: "Geen BIP-39 wachtwoord", - 4092516657: "Niet genoeg gedobbeld!", - 1577637745: "Octaal", - 3312581301: "PBKDF2 iter.", + 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", + 602716148: "OK", + 3580020863: "Шестнадцатеричный Публичный Ключ", + 2691246967: "Шестнадцатеричный", + 2736309107: "ID уже существует\n", + 1706005805: "Неполный выходной дескриптор", + 631342955: "Входы (%d): ", + 2585599782: "Неверный адрес", + 2874529150: "Неверный загрузчик", + 4093416954: "Неверная длина мнемоники", + 1422874211: "Неверный публичный ключ", + 2443867979: "Неверный кошелек:\n%s", + 4122897393: "Инвертировать", + 3000888649: "Ключ", + 2686333978: "Ключ: ", + 4123798664: "Krux\n\n\nВерсия\n%s", + 3835918229: "Тестовый QR Принтера Krux", + 766317539: "Язык", + 972436696: "Задержка Линии", + 3596093890: "Линия: ", + 2820726296: "Загрузить Мнемонику", + 879727077: "Загрузить с SD карты?", + 669106195: "Загрузить одну?", + 3330705289: "Загрузить?", + 2596531078: "Загрузка Камеры..", + 596389387: "Загрузка адреса сдачи %d..", + 336702608: "Загрузка принтера..", + 2538883522: "Загрузка адреса получения %d..", + 3159494909: "Загрузка..", + 1177338798: "Локаль", + 2817059741: "Расположение", + 63976957: "Уровень логирования", + 86530918: "Логирование", + 2917810189: "Максимальная длина превышена (%s)", + 2030045667: "Сообщение", + 3928301843: "Отсутствует файл подписи", + 1948316555: "Мнемоника", + 2123991188: "ID мнемоники", + 3911073154: "ID памяти мнемоники", + 570639842: "Мнемоника не была расшифрована", + 1746030071: "Мнемоника не была зашифрована", + 1458925155: "Изменено: ", + 1845376098: "Мультиподпись", + 2939797024: "Сеть", + 73574491: "Новая Мнемоника", + 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", + 4063104189: "Нет", + 3927838899: "Без BIP39 фразы-пароля", + 4092516657: "Недостаточно бросков!", + 1577637745: "Восьмеричный", + 3312581301: "PBKDF2 Итерации", 721090621: "PSBT", - 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", - 2987800462: "Papier breedte", - 3050763890: "Deel\n%d / %d", - 3559456868: "Deel grootte", - 4249903283: "Wachtwoord", - 3712257341: "Wachtwoord: ", - 140802882: "Opslag", - 1703779997: "Platte tekst QR", - 3561756278: "Laadt een portemonnee descriptor in", - 784609464: "Duik tarief", - 3037062877: "Test QR afdrukken", - 4278257699: "Afdrukken naar QR?\n\n%s\n\n", - 516488026: "Afdrukken?\n\n%s\n\n", - 1123106929: "Printer", - 3903571079: "Printer driver niet ingesteld!", - 2609799302: "Afdruk\n%d / %d", - 844861889: "Afdrukken...", - 2580599003: "Doorgaan?", - 556126964: "Verwerken...", - 1848310591: "QR code", - 710709610: "RX pin", - 2697857197: "Ontvangen", - 1746677167: "Ontvangstadres", - 364354944: "Regio: ", - 1662254634: "Controleer gescande gegevens en bewerk indien nodig", - 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", - 856795528: "Gedobbeld:\n\n%s", - 255086803: "Gedobbeld: %d\n", - 3976793317: "SD kaart", - 2827687530: "SD kaart niet gedetecteerd", - 2736513298: "SD kaart niet gedetecteerd.", - 3593785196: "Gedobbelde SHA256:\n\n%s", - 1143278725: "Momentopname van SHA256:\n\n%s", + 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", + 2987800462: "Ширина Бумаги", + 3050763890: "Часть\n%d / %d", + 3559456868: "Размер Части", + 4249903283: "Фраза-пароль", + 3712257341: "Фраза-пароль: ", + 140802882: "Постоянная Память", + 1703779997: "QR открытым текстом", + 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", + 784609464: "Скорость Погружения", + 3037062877: "Напечатать Тестовый QR", + 4278257699: "Напечатать в виде QR?\n\n%s\n\n", + 516488026: "Печатать?\n\n%s\n\n", + 1123106929: "Принтер", + 3903571079: "Драйвер Принтера не установлен!", + 2609799302: "Идет печать\n%d / %d", + 844861889: "Идет печать ...", + 2580599003: "Продолжить?", + 556126964: "Обрабатываю ...", + 1848310591: "QR Код", + 710709610: "RX Пин", + 2697857197: "Получить", + 1746677167: "Адрес Получения", + 364354944: "Регион: ", + 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", + 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", + 856795528: "Броски:\n\n%s", + 255086803: "Броски: %d\n", + 3976793317: "SD карта", + 2827687530: "SD карта не обнаружена", + 2736513298: "SD карта не обнаружена.", + 3593785196: "SHA256 бросков:\n\n%s", + 1143278725: "SHA256 снэпшота:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Opslaan op SD-kaart?", - 810036588: "Opgeslagen op SD-kaart:\n%s", - 763824768: "Schaal", - 4117455079: "Adres scannen", - 3219991109: "BIP-39 wachtwoord scannen", - 2537207336: "QR code sleutel scannen", - 4006316572: "Woorden 1 t/m 12 opnieuw scannen", - 2736506158: "Woorden 13 t/m 24 scannen", + 3531742595: "Сохранить на SD карту?", + 810036588: "Сохранено на SD карту:\n%s", + 763824768: "Шкала", + 4117455079: "Отсканировать Адрес", + 3219991109: "Отсканировать BIP39 фразу-пароль", + 2537207336: "Отсканировать Ключ QR код", + 4006316572: "Сканирование слов 1-12 снова", + 2736506158: "Сканирование слов 13-24", 266935239: "SeedQR", - 1698829144: "Zelf overschrijving of wisselgeld (%d): ", - 473154195: "Instellingen", - 1825881236: "Afsluiten", - 2120776272: "Bezig met afsluiten...", - 1061961408: "Ondertekenen", - 4282338366: "Ondertekenen?", - 746161122: "Handtekening", - 1988416729: "Bericht ondertekend", - 3672006076: "PSBT ondertekend", - 2281377987: "Enkele sleutel", - 4221794628: "Grootte: ", - 2309020186: "Uitgaven (%d): ", - 3355862324: "Stackbit 1248", - 3303592908: "Opslaan op apparaat", - 720041451: "Opslaan op SD kaart", - 3514476519: "Verander modus", - 1898550184: "TIK of ENTER voor opname", - 4228215415: "TX pin", - 2612594937: "Tekst", - 1454688268: "Thema", - 1180180513: "Thermisch", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Hulpmiddelen", - 3684696112: "Aanraak gevoeligheid", - 2978718564: "Aanraakscherm", - 2732611775: "Meer proberen?", - 1487826746: "Voer BIP-39 wachtwoord in", - 2061556020: "Voer sleutel in", - 2089395053: "Eenheid", - 2845607430: "Bootloader updaten...\n\n%d%%", - 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", - 2736001501: "Firmware upgraden...\n\n%d%%", - 2674953168: "Gebruik een donker achergrond.", - 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", - 236075140: "Gebruikt: ", - 4003084591: "Waarde %s is buiten bereik: [%s, %s]", - 4191058607: "Via camera", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Via handmatige invoer", - 2504354847: "Wacht op opname", - 2297028319: "Descriptor", - 4232654916: "Portemonnee descriptor", - 2587172867: "Portemonnee descriptor geladen!", - 2499782468: "Portemonnee descriptor niet gevonden.", - 1831109430: "Waarschuwing:\nIncomplete portemonnee descriptor", - 797660533: "Woord %d", - 3742424146: "Woord nummers", - 2965123464: "Woorden", - 1303016265: "Yes", - 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", - 2569054451: "Veranderingen worden opgeslagen op SD kaart.", + 1698829144: "Трансфер самому себе или Сдача (%d): ", + 473154195: "Настройки", + 1825881236: "Выключить", + 2120776272: "Выключение..", + 1061961408: "Подписать", + 4282338366: "Подписать?", + 746161122: "Подпись", + 1988416729: "Подписанное Сообщение", + 3672006076: "Подписанное PSBT", + 2281377987: "Одна подпись", + 4221794628: "Размер: ", + 2344747135: "Некоторые проверки не могут быть выполнены.", + 2309020186: "Расход (%d): ", + 3355862324: "Стэкбит 1248", + 3303592908: "Сохранить на Флэш Память", + 720041451: "Сохранить на SD Карту", + 3514476519: "Свайпните, чтобы сменить режим", + 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", + 4228215415: "TX Пин", + 2612594937: "Текст", + 1454688268: "Тема", + 1180180513: "Термальный", + 4119292117: "Мини Сид-фраза", + 1732872974: "Мини Сид-фраза (Биты)", + 725348723: "Инструменты", + 3684696112: "Прикоснитесь Границы", + 2978718564: "Тачскрин", + 2732611775: "Попробовать ещё?", + 1487826746: "Введите BIP39 фразу-пароль", + 2061556020: "Введите Ключ", + 2089395053: "Юнит", + 2845607430: "Обновление загрузчика..\n\n%d%%", + 4164597446: "Обновление завершено.\n\nВыключение..", + 2736001501: "Обновление прошивки..\n\n%d%%", + 2674953168: "Использовать черную фоновую поверхность.", + 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", + 236075140: "Использовано: ", + 4003084591: "Значение %s вне диапозона: [%s, %s]", + 4191058607: "С Помощью Камеры", + 1254681955: "С Помощью D20", + 525309547: "С Помощью D6", + 590330112: "С Помощью Ручного Ввода", + 2504354847: "Дождитесь Захвата", + 2297028319: "Дескриптор Кошелька", + 4232654916: "Выходной дескриптор кошелька", + 2587172867: "Выходной дескриптор кошелька загружен!", + 2499782468: "Выходной дескриптор кошелька не найден.", + 2671738224: "Предупреждение:", + 797660533: "Слово %d", + 3742424146: "Числа Слов", + 2965123464: "Слова", + 1303016265: "Да", + 771968845: "Ваши изменения буду храниться на флэш памяти устройства.", + 2569054451: "Ваши изменения будут храниться на SD карте.", }, - "de-DE": { - 1185266064: "%d von %d Multisig", - 2004520398: "%d. Change: \n\n%s\n\n", - 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", - 3264377309: "%d. Ausgaben: \n\n%s\n\n", - 2399232215: "%s\n\nist eine gültige Change Adresse!", - 3921290840: "%s\n\nist eine gültige Empfangsadresse!", - 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", - 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", - 3348584292: "(Experimental)", - 2739590230: "12 Wörter", - 1310058127: "24 Wörter", + "fr-FR": { + 1185266064: "%d de %d multisignature", + 2004520398: "%d. Changement : \n\n%s\n\n", + 3862364126: "%d. Auto-transfert : \n\n%s\n\n", + 3264377309: "%d. Dépense : \n\n%s\n\n", + 2399232215: "%s\n\nest une adresse changement valide!", + 3921290840: "%s\n\nest une adresse reçue valide!", + 1808355833: "INTROUVABLE dans les premières %d adresses de changement", + 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", + 3348584292: "(Expérimental)", + 2739590230: "12 mots", + 1310058127: "24 mots", 2743272264: "ABC", - 1949634023: "Über", + 1949634023: "À propos", 1517128857: "Adafruit", 3270727197: "Adresse", - 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", - 283202181: "Richte Kamera und Tiny Seed korrekt aus.", - 88746165: "Blendschutz deaktiviert", - 1521033296: "Blendschutz aktiviert", - 1056821534: "Bist Du sicher?", - 3247612282: "BIP39 Mnemonic", - 3455872521: "Zurück", - 2541860807: "Bootloader wird gesichert..\n\n%d%%", - 2256777600: "Ungültige Signatur", - 3937333362: "Baudrate", + 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", + 283202181: "Alignez correctement la caméra et Tiny Seed.", + 88746165: "Anti-éblouissement désactivé", + 1521033296: "Anti-éblouissement activé", + 1056821534: "Es-tu sûr?", + 3247612282: "BIP39 Mnémonique", + 3455872521: "Retour", + 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", + 2256777600: "Mauvaise signature", + 3937333362: "Débit en bauds", 427617266: "Bitcoin", - 928727036: "Randpolsterung", + 928727036: "Rembourrage de bordure", 213030954: "CNC", - 1207696150: "Change Adresse", - 3126552510: "Change Adressen", - 1583186953: "Thema ändern und neu starten?", - 2697733395: "Änderungen auf SD-Karte gespeichert!", - 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", - 3442025874: "Prüfe SD-Karte", - 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", - 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", - 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", - 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", - 2470115694: "Suche nach SD-Karte..", - 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", - 2407028014: "Kompakt SeedQR", - 4041895036: "Weiter?", - 4094072796: "Erstelle QR-Code", - 167798282: "QR-Code aus Text erzeugen?", - 2767642191: "Erstellt:", - 3513215254: "Benutzerdefinierte QR-Code", - 124617190: "Schnitttiefe", - 597912140: "Cut-Methode", - 2504034831: "Dezimal", - 2751113454: "Entschlüsseln?", - 1016609898: "Datei löschen?", - 1364509700: "Mnemonic löschen", - 4102535566: "Tiefe pro Durchgang", - 2791699253: "Ableitung: %s", - 1230133196: "Geräte-Flash-Speicher nicht erkannt.", - 3836852788: "Fertig?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-Entprellung", - 374684711: "Verschlüssel Mnemonic", - 1244124409: "Verschlüsselter QR-Code", - 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", - 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", - 350279787: "Verschlüsselung", - 2601598799: "Verschlüsselungsmodus", - 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", - 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", - 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", - 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", - 784361051: "Fehler:\n%s", - 1505332462: "Esc", - 3838465623: "Dateien durchsuchen?", - 4170881190: "Auf SD-Karte exportieren..", - 1711312434: "Öffentlicher Schlüssel", - 383371114: "Entschlüsselung fehlgeschlagen", - 3048830188: "PSBT konnte nicht geladen werden", - 4192663412: "Adresse konnte nicht geladen werden", - 1996021743: "Schlüssel konnte nicht geladen werden", - 1108715658: "Nachricht konnte nicht geladen werden", - 1081425878: "Mnemonic konnte nicht geladen werden", - 928667220: "Ausgabedeskriptor konnte nicht geladen werden", - 1620572516: "Passphrase konnte nicht geladen werden", - 2946146830: "Mnemonic konnte nicht gespeichert werden", - 1303554751: "Gebühr: ", - 104500973: "Vorschubgeschwindigkeit", - 3313339187: "Dateiname", - 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", - 3737729752: "Fingerabdruck: %s", - 2542772894: "Die Firmware übersteigt die maximale Größe: %d", - 1406590538: "Flötendurchmesser", - 3086093110: "Frei: ", - 1893243331: "Vom Speicher", + 1207696150: "Changement", + 3126552510: "Adresses de Changement", + 1583186953: "Changer de thème et redémarrer?", + 2697733395: "Modifications enregistrées sur la carte SD!", + 388908871: "Les modifications dureront jusqu'à l'arrêt.", + 3442025874: "Vérifiez la carte SD", + 3119547911: "Vérifiez que l'adresse appartient à cette portefeuille?", + 2856261511: "Adresses %d changement vérifiées sans correspondance.", + 2788541416: "Adresses %d reçues vérifiées sans correspondance.", + 2446472910: "Vérification de l'adresse changement %d pour correspondance..", + 2470115694: "Vérification de la carte SD..", + 3655273987: "Vérification de l'adresse reçue %d pour correspondance..", + 2407028014: "SeedQR Compact", + 4041895036: "Continuer?", + 4094072796: "Créer du code QR", + 167798282: "Créer du code QR à partir du texte?", + 2767642191: "Créé:", + 3513215254: "Code QR personnalisé", + 124617190: "Profondeur de coupe", + 597912140: "Méthode de coupe", + 2504034831: "Décimal", + 2751113454: "Décrypter?", + 1016609898: "Supprimer le fichier?", + 1364509700: "Supprimer mnémonique", + 4102535566: "Profondeur par passage", + 2791699253: "Dérivation: %s", + 1230133196: "Stockage flash de l'appareil non détecté.", + 3836852788: "Terminé?", + 382368239: "Conducteur", + 3978947916: "Encodeur", + 4090746898: "Anti-rebond de l'encodeur", + 374684711: "Crypter mnémonique", + 1244124409: "Code QR crypté", + 2968548114: "Le mnémonique crypté n'a pas été stocké", + 3315319371: "Mnémonique cryptée a été stockée avec ID:", + 350279787: "Chiffrement", + 2601598799: "Mode de chiffrement", + 3504179008: "Entrez chaque mot de votre BIP-39 mnémonique sous la forme d'un nombre 1 jusqu'à 2048.", + 1100685007: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en hexadécimal de 1 à 800.", + 4090266642: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en octal de 1 à 4000.", + 2780625730: "Entrez chaque mot de votre BIP-39 mnémonique.", + 784361051: "Erreur:\n%s", + 1505332462: "Esc", + 3838465623: "Explorer des fichiers?", + 4170881190: "Exportation vers la carte SD..", + 1711312434: "Clé publique", + 383371114: "Échec de décrypter", + 3048830188: "Erreur de chargement PSBT", + 4192663412: "Erreur de chargement d'adresse", + 1996021743: "Échec du chargement de la clé", + 1108715658: "Échec du chargement du message", + 1081425878: "Erreur de chargement mnémonique", + 928667220: "Échec du chargement du descripteur de sortie", + 1620572516: "Échec du chargement de la phrase secrète", + 2946146830: "Échec de stocker mnémonique", + 1303554751: "Frais: ", + 104500973: "Taux d'alimentation", + 3313339187: "Nom de fichier", + 1982637349: "Le nom de fichier %s existe sur la carte SD, écraser ?", + 3737729752: "Empreinte Digitale: %s", + 2542772894: "Le micrologiciel dépasse la taille maximale: %d", + 1406590538: "Diamètre de flûte", + 3086093110: "Libre: ", + 1893243331: "Du stockage", 4120536442: "GRBL", - 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 299338213: "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", 602716148: "Go", - 831562513: "Wärmeintervall", - 2300171403: "Hitzezeit", - 3580020863: "Hex öffentlicher Schlüssel", - 2691246967: "Hexadezimal", - 2736309107: "ID existiert bereits\n", - 631342955: "Input (%d): ", - 2585599782: "Ungültige Adresse", - 2874529150: "Ungültiger Bootloader", - 4093416954: "Ungültige mnemonische Lange", - 1422874211: "Ungültiger öffentlicher Schlüssel", - 2443867979: "Ungültige Wallet:\n%s", - 4122897393: "Umkehren", - 3000888649: "Schlüssel", - 2686333978: "Schlüssel:", + 3580020863: "Clé public hexadécimal", + 2691246967: "Hexadécimal", + 2736309107: "Id existe déjà\n", + 1706005805: "Descripteur de sortie incomplet", + 631342955: "Entrées (%d) : ", + 2585599782: "Adresse invalide", + 2874529150: "Chargeur de démarrage invalide", + 4093416954: "Longueur mnémonique invalide", + 1422874211: "Clé publique non valide", + 2443867979: "Portefeuille invalide:\n%s", + 4122897393: "Inverser", + 3000888649: "Clé", + 2686333978: "Clé:", 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Krux Drucker Test-QR", - 766317539: "Sprache", - 972436696: "Leitungsverzögerung", - 3596093890: "Linie: ", - 2820726296: "Mnemonic laden", - 879727077: "Von SD-Karte laden?", - 669106195: "Eine laden?", - 3330705289: "Laden?", - 2596531078: "Lade Kamera..", - 596389387: "Lade Change Adresse %d..", - 336702608: "Drucker wird geladen..", - 2538883522: "Lade Empfangsadresse %d..", - 3159494909: "Wird geladen..", - 1177338798: "Spracheinstellung", - 2817059741: "Speicherort", - 63976957: "Log Level", - 86530918: "Logging", - 2917810189: "Maximale Länge überschritten (%s)", - 2030045667: "Nachricht", - 3928301843: "Fehlende Signaturdatei", - 1948316555: "Mnemonic", - 2123991188: "Mnemonische ID", - 3911073154: "Mnemonische Speicher-ID", - 570639842: "Mnemonic wurde nicht entschlüsselt", - 1746030071: "Mnemonic wurde nicht verschlüsselt", - 1458925155: "Geändert:", - 1845376098: "Multisig", - 2939797024: "Netzwerk", - 73574491: "Neue Mnemonic", - 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", - 4063104189: "Nein", - 3927838899: "Keine BIP39 Passphrase", - 4092516657: "Nicht genug Würfe!", - 1577637745: "Oktal", - 3312581301: "PBKDF2-Iter.", + 3835918229: "Test de l'imprimante Krux QR", + 766317539: "Langue", + 972436696: "Délai de Ligne", + 3596093890: "Ligne: ", + 2820726296: "Charger mnémonique", + 879727077: "Charger depuis la carte SD ?", + 669106195: "En charger qu'un?", + 3330705289: "Charger?", + 2596531078: "Caméra de Chargement..", + 596389387: "Chargement de l'adresse de changement %d..", + 336702608: "Chargement de l'imprimante..", + 2538883522: "Chargement de l'adresse de réception %d..", + 3159494909: "Chargement..", + 1177338798: "Paramètres régionaux", + 2817059741: "Emplacement", + 63976957: "Niveau de journalisation", + 86530918: "Enregistrement", + 2917810189: "Longueur maximale dépassée (% s)", + 2030045667: "Message", + 3928301843: "Fichier de signature manquant", + 1948316555: "Mnémonique", + 2123991188: "ID mnémonique", + 3911073154: "ID de stockage mnémonique", + 570639842: "Mnémonique n'a pas été décryptée", + 1746030071: "Mnémonique n'était pas cryptée", + 1458925155: "Modifié:", + 1845376098: "Multi\nsignature", + 2939797024: "Réseau", + 73574491: "Nouveau mnémonique", + 2792272353: "Nouveau micrologiciel détecté.\n\nSHA256:\n%s\n\n\n\nInstaller?", + 4063104189: "Non", + 3927838899: "Pas de phrase passante bip39", + 4092516657: "Pas assez de rouleaux !", + 1577637745: "Octale", + 3312581301: "Itér. PBKDF2", 721090621: "PSBT", - 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", - 2987800462: "Papierbreite", - 3050763890: "Teil\n%d / %d", - 3559456868: "Teilegröße", - 4249903283: "Passphrase", - 3712257341: "Passphrase:", - 140802882: "Speicher", - 1703779997: "Klartext-QR", - 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", - 784609464: "Tauchrate", - 3037062877: "Drucke Test-QR", - 4278257699: "Als QR-Code drucken?\n\n%s\n\n", - 516488026: "Drucken?\n\n%s\n\n", - 1123106929: "Drucker", - 3903571079: "Druckertreiber nicht gesetzt!", - 2609799302: "Drucken\n%d / %d", - 844861889: "Wird gedruckt ...", - 2580599003: "Weiter?", - 556126964: "Wird bearbeitet ...", - 1848310591: "QR-Code", - 710709610: "RX Pin", - 2697857197: "Empfangen", - 1746677167: "Empfangsadresse", - 364354944: "Region: ", - 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", - 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", - 856795528: "Würfe:\n\n%s", - 255086803: "Würfe: %d\n", - 3976793317: "SD-Karte", - 2827687530: "SD-Karte nicht erkannt", - 2736513298: "SD-Karte nicht erkannt.", - 3593785196: "SHA256 der Würfe:\n\n%s", - 1143278725: "SHA256 des Snapshots:\n\n%s", + 995862913: "Peignez les points perforés en noir afin qu'ils puissent être détectés.", + 2987800462: "Largeur du papier", + 3050763890: "Partie\n%d / %d", + 3559456868: "Taille de la pièce", + 4249903283: "Phrase de passe", + 3712257341: "Phrass de passe:", + 140802882: "Persister", + 1703779997: "QR en Texte Brut", + 3561756278: "Veuillez charger un descripteur de sortie de portefeuille", + 784609464: "Taux de plongée", + 3037062877: "Test d'impression QR", + 4278257699: "Imprimer en QR?\n\n%s\n\n", + 516488026: "Imprimer?\n\n%s\n\n", + 1123106929: "Imprimante", + 3903571079: "Le conducteur d'imprimante n'est pas défini!", + 2609799302: "Impression\n%d / %d", + 844861889: "Impression ...", + 2580599003: "Procéder?", + 556126964: "Traitement ...", + 1848310591: "QR Code", + 710709610: "RX Fiche", + 2697857197: "Recevoir", + 1746677167: "Adresses de Réception", + 364354944: "Région: ", + 1662254634: "Examinez les données numérisées, modifiez-les si nécessaire", + 770350922: "Lancez le dé au moins %d fois pour générer un mnémonique.", + 856795528: "Rouleaux:\n\n%s", + 255086803: "Rouleaux: %d\n", + 3976793317: "Carte SD", + 2827687530: "Carte SD non détectée", + 2736513298: "Carte SD non détectée.", + 3593785196: "SHA256 de rouleaux:\n\n%s", + 1143278725: "Sha256 de Snapshot:\n\n% s", 3338679392: "SHA256:\n%s", - 3531742595: "Auf SD-Karte speichern?", - 810036588: "Auf SD-Karte gespeichert:\n%s", - 763824768: "Skala", - 4117455079: "Adresse\nscannen", - 3219991109: "Scan BIP39 Passphrase", - 2537207336: "Schlüssel QR-Code scannen", - 4006316572: "Wörter 1-12 erneut scannen", - 2736506158: "Wörter 13-24 scannen", - 266935239: "SeedQR", - 1698829144: "Selbstübertragung oder Change (%d): ", - 473154195: "Einstellungen", - 1825881236: "Ausschalten", - 2120776272: "Herunterfahren..", - 1061961408: "Signieren", - 4282338366: "Signieren?", - 746161122: "Signatur", - 1988416729: "Signierte Nachricht", - 3672006076: "Signierte PSBT", - 2281377987: "Single-Sig", - 4221794628: "Größe: ", - 2309020186: "Ausgabe (%d): ", - 3355862324: "Stackbit 1248", - 3303592908: "Auf Flash speichern", - 720041451: "Auf der SD-Karte speichern", - 3514476519: "Wischen um den Modus zu ändern", - 1898550184: "TOUCH oder ENTER zum Erfassen", - 4228215415: "TX Pin", - 2612594937: "Text", - 1454688268: "Thema", - 1180180513: "Thermisch", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Werkzeuge", - 3684696112: "Berühre Schwellenwert", - 2978718564: "Touchscreen", - 2732611775: "Weiter versuchen?", - 1487826746: "BIP39 Passphrase eingeben", - 2061556020: "Schlüssel eingeben", - 2089395053: "Einheit", - 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", - 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", - 2736001501: "Firmware wird aktualisiert..\n\n%d%%", - 2674953168: "Verwende eine schwarze Hintergrundfläche.", - 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", - 236075140: "Belegt: ", - 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", - 4191058607: "Via Kamera", + 3531742595: "Enregistrer sur la carte SD ?", + 810036588: "Enregistré sur la carte SD :\n%s", + 763824768: "L'échelle", + 4117455079: "Scannez l'adresse", + 3219991109: "Scan bip39 en phrase secrète", + 2537207336: "Scanner le code QR de la clé", + 4006316572: "Analyser à nouveau les mots 1 à 12", + 2736506158: "Analyser les mots 13 à 24", + 266935239: "Seedqr", + 1698829144: "Auto-transfert ou changement (%d): ", + 473154195: "Paramètres", + 1825881236: "Fermer", + 2120776272: "Éteindre..", + 1061961408: "Signature", + 4282338366: "Signature?", + 746161122: "Signature", + 1988416729: "Message signé", + 3672006076: "PSBT signé", + 2281377987: "Clé unique", + 4221794628: "Capacité: ", + 2344747135: "Certains chèques ne peuvent pas être effectués.", + 2309020186: "Dépense (%d) : ", + 3355862324: "Stackbit 1248", + 3303592908: "Stocker sur flash", + 720041451: "Stocker sur la carte SD", + 3514476519: "Faites glisser pour changer de mode", + 1898550184: "TOUCHEZ ou ENTER pour capturer", + 4228215415: "TX Fiche", + 2612594937: "Texte", + 1454688268: "Thème", + 1180180513: "Thermique", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (bits)", + 725348723: "Outils", + 3684696112: "Seuil Tactile", + 2978718564: "Écran Tactile", + 2732611775: "Réessayer?", + 1487826746: "Type Bip39 Plasque", + 2061556020: "Clé de type", + 2089395053: "Unité", + 2845607430: "Mise à jour du chargeur de démarrage..\n\n%d%%", + 4164597446: "Mise à niveau complète.\n\nÉteindre..", + 2736001501: "Mise à niveau du micrologiciel..\n\n%d%%", + 2674953168: "Utilisez une surface de fond noire.", + 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", + 236075140: "Utilisé: ", + 4003084591: "Valeur% s hors de portée: [% s,% s]", + 4191058607: "Par caméra", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Via manueller Eingabe", - 2504354847: "Warte auf die Erfassung", - 2297028319: "Wallet-Deskriptor", - 4232654916: "Wallet Ausgabedeskriptor", - 2587172867: "Wallet Ausgabedeskriptor geladen!", - 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", - 1831109430: "Warnung:\nUnvollständiger Ausgabedeskriptor", - 797660533: "Wort %d", - 3742424146: "Wortnummern", - 2965123464: "Wörter", - 1303016265: "Ja", - 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", - 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", + 590330112: "Par saisie manuelle", + 2504354847: "Attendez la capture", + 2297028319: "Descripteur de Portefeuille", + 4232654916: "Descripteur de sortie du portefeuille", + 2587172867: "Descripteur de sortie du portefeuille chargé!", + 2499782468: "Descripteur de sortie du portefeuille introuvable.", + 2671738224: "Avertissement:", + 797660533: "Mot %d", + 3742424146: "Numéros de mots", + 2965123464: "Mots", + 1303016265: "Oui", + 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", + 2569054451: "Vos modifications seront conservées sur la carte SD.", }, - "vi-VN": { - 1185266064: "%d của %d đa chữ kí", - 2004520398: "%d. Thay đổi: \n\n%s\n\n", - 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", - 3264377309: "%d. Chi tiêu: \n\n%s\n\n", - 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", - 3921290840: "%s\n\nlà một địa chỉ khả dụng!", - 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 3348584292: "(Thực nghiệm)", - 2739590230: "12 từ", - 1310058127: "24 từ", + "nl-NL": { + 1185266064: "%d van %d multisig", + 2004520398: "%d. Wisselgeld: \n\n%s\n\n", + 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", + 3264377309: "%d. Uitgaven: \n\n%s\n\n", + 2399232215: "%s\n\nis een valide wisselgeld adres!", + 3921290840: "%s\n\nis een valide ontvangst adres!", + 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", + 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", + 3348584292: "(Experimenteel)", + 2739590230: "12 woorden", + 1310058127: "24 woorden", 2743272264: "ABC", - 1949634023: "Về chúng tôi", + 1949634023: "Over", 1517128857: "Adafruit", - 3270727197: "Địa chỉ", - 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", - 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", - 88746165: "Chống lóa bị vô hiệu hóa", - 1521033296: "Đã bật chống lóa", - 1056821534: "Bạn có chắc không?", - 3247612282: "Mã mnemonic dạng chuẩn BIP39", - 3455872521: "Trở lại", - 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", - 2256777600: "Chữ ký xấu", - 3937333362: "Tốc độ baud", + 3270727197: "Adres", + 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", + 283202181: "Richt de camera en Tiny Seed op de juiste manier.", + 88746165: "Anti reflecterend uitgeschakeld", + 1521033296: "Anti reflecterend ingeschakeld", + 1056821534: "Weet je het zeker?", + 3247612282: "BIP-39 geheugensteun", + 3455872521: "Terug", + 2541860807: "Backup van de bootloader...\n\n%d%%", + 2256777600: "Ongeldige handtekening", + 3937333362: "Baudratio", 427617266: "Bitcoin", - 928727036: "Đệm viền", + 928727036: "Rand opvulling", 213030954: "CNC", - 1207696150: "Thay đổi", - 3126552510: "Thay địa chỉ", - 1583186953: "Thay đổi chủ đề và khởi động lại?", - 2697733395: "Thay đổi được lưu trên thẻ SD!", - 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", - 3442025874: "Kiểm tra thẻ SD", - 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", - 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", - 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", - 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", - 2470115694: "Kiểm tra thẻ SD..", - 3655273987: "Đang kiểm tra %d địa chỉ..", - 2407028014: "SeedQR nhỏ gọn", - 4041895036: "Tiếp tục?", - 4094072796: "Tạo mã QR", - 167798282: "Tạo mã QR từ văn bản?", - 2767642191: "Tạo:", - 3513215254: "Mã QR tùy chỉnh", - 124617190: "Chiều sâu cắt", - 597912140: "Phương pháp cắt", - 2504034831: "Số thập phân", - 2751113454: "Phản đối?", - 1016609898: "Xóa tài liệu?", - 1364509700: "Xóa ghi nhớ", - 4102535566: "Độ sâu mỗi lần vượt qua", - 2791699253: "Nguồn gốc: %s", - 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", - 3836852788: "Hoàn tất?", - 382368239: "Người cầm lái", - 3978947916: "Mã hoá", - 4090746898: "Gỡ lỗi bộ mã hóa", - 374684711: "Mã hóa Mnemonic", - 1244124409: "Mã QR được mã hóa", - 2968548114: "MNemon được mã hóa không được lưu trữ", - 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", - 350279787: "Mã hóa", - 2601598799: "Chế độ mã hóa", - 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", - 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", - 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", - 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", - 784361051: "Lỗi:\n%s", + 1207696150: "Change", + 3126552510: "Wisselgeldadres", + 1583186953: "Thema veranderen en opnieuw opstarten?", + 2697733395: "Wijzigingen aanhouden op SD kaart!", + 388908871: "Wijzigingen blijven van kracht tot afsluiten.", + 3442025874: "Controleer SD kaart", + 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", + 2856261511: "Na %d geen wisselgeld adressen gevonden.", + 2788541416: "Na %d geen ontvangst adressen gevonden.", + 2446472910: "Wisselgeldadres %d controleren...", + 2470115694: "SD kaart controleren...", + 3655273987: "Ontvangstadres %d controleren...", + 2407028014: "Compact SeedQR", + 4041895036: "Doorgaan?", + 4094072796: "QR code maken", + 167798282: "QR code maken van tekst?", + 2767642191: "Aangemaakt: ", + 3513215254: "Aangepaste QR code", + 124617190: "Snijdiepte", + 597912140: "Snijmethode", + 2504034831: "Decimaal", + 2751113454: "Ontsleutelen?", + 1016609898: "Bestand verwijderen?", + 1364509700: "Geheugensteun verwijderen", + 4102535566: "Diepte per pas", + 2791699253: "Afgeleide: %s", + 1230133196: "Opslag op apparaat is niet gedetecteerd.", + 3836852788: "Klaar?", + 382368239: "Driver", + 3978947916: "Encoder", + 4090746898: "Encoder-debounce", + 374684711: "Geheugensteun versleutelen", + 1244124409: "Versleutelde QR code", + 2968548114: "Versleutelde geheugensteun was niet opgeslagen", + 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", + 350279787: "Versleutelen", + 2601598799: "Versleutel modus", + 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", + 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", + 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", + 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", + 784361051: "Fout:\n%s", 1505332462: "Esc", - 3838465623: "Khám phá các tập tin?", - 4170881190: "Xuất vào thẻ SD ..", - 1711312434: "Khóa công cộng", - 383371114: "Không giải mã được", - 3048830188: "Tải PSBT thất bại", - 4192663412: "Tải địa chỉ thất bại", - 1996021743: "Không tải khóa", - 1108715658: "Không tải được tin nhắn", - 1081425878: "Tải mã mnemonic thất bại", - 928667220: "Không thể tải bộ mô tả đầu ra", - 1620572516: "Không tải được cụm mật khẩu", - 2946146830: "Không lưu trữ MNemonic", - 1303554751: "Phí: ", - 104500973: "Tỷ lệ thức ăn", - 3313339187: "Tên tệp", - 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", - 3737729752: "Dấu vân tay: %s", - 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", - 1406590538: "Đường kính ống sáo", - 3086093110: "Khả dụng: ", - 1893243331: "Từ lưu trữ", - 4120536442: "GRBL", - 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", - 602716148: "Đến", - 831562513: "Khoảng thời gian nhiệt", - 2300171403: "Thời gian nhiệt", - 3580020863: "Khóa công khai Hex", - 2691246967: "Thập lục phân", - 2736309107: "Id đã tồn tại\n", - 631342955: "Đầu vào (%d): ", - 2585599782: "Địa chỉ không hợp lệ", - 2874529150: "Bộ tải khởi động không hợp lệ", - 4093416954: "Độ dài mã mnemonic không hợp lệ", - 1422874211: "Khóa công khai không hợp lệ", - 2443867979: "Ví không hợp lệ:\n%s", - 4122897393: "Đảo ngược", - 3000888649: "Chìa khóa", - 2686333978: "Chìa khóa:", - 4123798664: "Krux\n\n\nPhiên Bản\n%s", - 3835918229: "QR kiểm tra máy in Krux", - 766317539: "Ngôn ngữ", - 972436696: "Độ trễ Dòng", - 3596093890: "Đường kẻ: ", - 2820726296: "Tải mã mnemonic", - 879727077: "Tải từ thẻ SD?", - 669106195: "Tải một?", - 3330705289: "Tải?", - 2596531078: "Đang tải máy ảnh..", - 596389387: "Đang tải thay đổi địa chỉ %d..", - 336702608: "Tải máy in ..", - 2538883522: "Đang tải địa chỉ nhận %d..", - 3159494909: "Đang tải..", - 1177338798: "Ngôn ngữ", - 2817059741: "Vị trí cửa hàng", - 63976957: "Log Level", - 86530918: "Khai thác gỗ", - 2917810189: "Chiều dài tối đa vượt quá (%s)", - 2030045667: "Tin nhắn", - 3928301843: "Thiếu tập tin chữ ký", - 1948316555: "Mã mnemonic", - 2123991188: "ID ghi nhớ", - 3911073154: "ID lưu trữ ghi nhớ", - 570639842: "Ghi nhớ không được giải mã", - 1746030071: "Ghi nhớ không được mã hóa", - 1458925155: "Đã sửa đổi:", - 1845376098: "Đa chữ kí", - 2939797024: "Mạng lưới", - 73574491: "Mnemonic mới", - 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", - 4063104189: "Không", - 3927838899: "Không có cụm mật khẩu BIP39", - 4092516657: "Không đủ cuộn!", - 1577637745: "Bát phân", - 3312581301: "Lặp lại PBKDF2", + 3838465623: "Bestanden verkennen?", + 4170881190: "Exporteren naar SD-kaart..", + 1711312434: "Uitgebreide publieke sleutel", + 383371114: "Ontsleutelen is niet gelukt", + 3048830188: "PSBT laden is niet gelukt", + 4192663412: "Adres laden is niet gelukt", + 1996021743: "Sleutel laden is niet gelukt", + 1108715658: "Bericht laden is niet gelukt", + 1081425878: "Geheugensteun laden is niet gelukt", + 928667220: "Descriptor laden is niet gelukt", + 1620572516: "Wachtwoord laden is niet gelukt", + 2946146830: "Geheugensteun opslaan is niet gelukt", + 1303554751: "Tarief: ", + 104500973: "Voedingssnelheid", + 3313339187: "Bestandsnaam", + 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", + 3737729752: "Vingerafdruk: %s", + 2542772894: "Firmware overschrijdt de maximale grootte: %d", + 1406590538: "Fluit diameter", + 3086093110: "Vrij: ", + 1893243331: "Uit data-opslag", + 4120536442: "GRBL", + 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", + 602716148: "Ga", + 3580020863: "Hex publieke sleutel", + 2691246967: "Hexadecimaal", + 2736309107: "ID bestaat al\n", + 1706005805: "Incomplete portemonnee descriptor", + 631342955: "Invoer (%d): ", + 2585599782: "Ongeldig adres", + 2874529150: "Ongeldige bootloader", + 4093416954: "Ongeldige geheugensteun lengte", + 1422874211: "Ongeldige publieke sleutel", + 2443867979: "Ongeldige portemonnee:\n%s", + 4122897393: "Omkeren", + 3000888649: "Sleutel", + 2686333978: "Sleutel: ", + 4123798664: "Krux\n\n\nVersie\n%s", + 3835918229: "Krux printer test QR", + 766317539: "Taal", + 972436696: "Lijn vertraging", + 3596093890: "Lijn: ", + 2820726296: "Geheugensteun laden", + 879727077: "Laden vanaf SD-kaart?", + 669106195: "Laden?", + 3330705289: "Laden?", + 2596531078: "Camera laden...", + 596389387: "Wisselgeldadres %d laden...", + 336702608: "Laadprinter..", + 2538883522: "Ontvangstadres %d laden...", + 3159494909: "Laden...", + 1177338798: "Taal", + 2817059741: "Opslaglocatie", + 63976957: "Log niveau", + 86530918: "Debug logs", + 2917810189: "Maximale lengte overschreden (%s)", + 2030045667: "Bericht", + 3928301843: "Handtekening bestand mist", + 1948316555: "Geheugensteun", + 2123991188: "Geheugensteun ID", + 3911073154: "Geheugensteun opslag ID", + 570639842: "Geheugensteun is niet ontsleuteld", + 1746030071: "Geheugensteun is niet versleuteld", + 1458925155: "Aangepast: ", + 1845376098: "Multisig", + 2939797024: "Netwerk", + 73574491: "Geheugensteun aanmaken", + 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", + 4063104189: "Nee", + 3927838899: "Geen BIP-39 wachtwoord", + 4092516657: "Niet genoeg gedobbeld!", + 1577637745: "Octaal", + 3312581301: "PBKDF2 iter.", 721090621: "PSBT", - 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", - 2987800462: "Chiều rộng giấy", - 3050763890: "Phần\n%d / %d", - 3559456868: "Kích thước một phần", - 4249903283: "Cụm mật khẩu", - 3712257341: "Cụm cụm:", - 140802882: "Vị trí lưu", - 1703779997: "Văn bản rõ QR", - 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", - 784609464: "Tỷ lệ sụt giảm", - 3037062877: "In kiểm tra QR", - 4278257699: "In ra mã QR?\n\n%s\n\n", - 516488026: "In?\n\n%s\n\n", - 1123106929: "Máy in", - 3903571079: "Trình điều khiển máy in không đặt!", - 2609799302: "Đang in\n%d / %d", - 844861889: "In ấn ...", - 2580599003: "Thực hiện?", - 556126964: "Xử lý ...", - 1848310591: "Mã QR", - 710709610: "RX Ghim", - 2697857197: "Nhận được", - 1746677167: "Nhận địa chỉ", - 364354944: "Vùng: ", - 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", - 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", - 856795528: "Súc sắc cuộn:\n\n%s", - 255086803: "Súc sắc cuộn: %d\n", - 3976793317: "Thẻ SD", - 2827687530: "Thẻ SD không được phát hiện", - 2736513298: "Thẻ SD không được phát hiện.", - 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", - 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", + 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", + 2987800462: "Papier breedte", + 3050763890: "Deel\n%d / %d", + 3559456868: "Deel grootte", + 4249903283: "Wachtwoord", + 3712257341: "Wachtwoord: ", + 140802882: "Opslag", + 1703779997: "Platte tekst QR", + 3561756278: "Laadt een portemonnee descriptor in", + 784609464: "Duik tarief", + 3037062877: "Test QR afdrukken", + 4278257699: "Afdrukken naar QR?\n\n%s\n\n", + 516488026: "Afdrukken?\n\n%s\n\n", + 1123106929: "Printer", + 3903571079: "Printer driver niet ingesteld!", + 2609799302: "Afdruk\n%d / %d", + 844861889: "Afdrukken...", + 2580599003: "Doorgaan?", + 556126964: "Verwerken...", + 1848310591: "QR code", + 710709610: "RX pin", + 2697857197: "Ontvangen", + 1746677167: "Ontvangstadres", + 364354944: "Regio: ", + 1662254634: "Controleer gescande gegevens en bewerk indien nodig", + 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", + 856795528: "Gedobbeld:\n\n%s", + 255086803: "Gedobbeld: %d\n", + 3976793317: "SD kaart", + 2827687530: "SD kaart niet gedetecteerd", + 2736513298: "SD kaart niet gedetecteerd.", + 3593785196: "Gedobbelde SHA256:\n\n%s", + 1143278725: "Momentopname van SHA256:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Lưu vào thẻ SD?", - 810036588: "Đã lưu vào thẻ SD:\n%s", - 763824768: "Cái cân", - 4117455079: "Quét địa chỉ", - 3219991109: "Quét BIP39 Cụm cụm", - 2537207336: "Quét mã QR khóa", - 4006316572: "Quét lại từ 1-12", - 2736506158: "Quét từ 13-24", - 266935239: "SEEDQR", - 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", - 473154195: "Cài đặt", - 1825881236: "Tắt", - 2120776272: "Đang tắt..", - 1061961408: "Chữ kí", - 4282338366: "Kí?", - 746161122: "Chữ ký", - 1988416729: "Tin nhắn đã ký", - 3672006076: "Đã ký PSBT", - 2281377987: "Khóa đơn", - 4221794628: "Dung lượng: ", - 2309020186: "Chi tiêu (%d): ", + 3531742595: "Opslaan op SD-kaart?", + 810036588: "Opgeslagen op SD-kaart:\n%s", + 763824768: "Schaal", + 4117455079: "Adres scannen", + 3219991109: "BIP-39 wachtwoord scannen", + 2537207336: "QR code sleutel scannen", + 4006316572: "Woorden 1 t/m 12 opnieuw scannen", + 2736506158: "Woorden 13 t/m 24 scannen", + 266935239: "SeedQR", + 1698829144: "Zelf overschrijving of wisselgeld (%d): ", + 473154195: "Instellingen", + 1825881236: "Afsluiten", + 2120776272: "Bezig met afsluiten...", + 1061961408: "Ondertekenen", + 4282338366: "Ondertekenen?", + 746161122: "Handtekening", + 1988416729: "Bericht ondertekend", + 3672006076: "PSBT ondertekend", + 2281377987: "Enkele sleutel", + 4221794628: "Grootte: ", + 2344747135: "Sommige controles kunnen niet worden uitgevoerd.", + 2309020186: "Uitgaven (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Lưu trữ trên flash", - 720041451: "Lưu trữ trên thẻ SD", - 3514476519: "Vuốt để thay đổi chế độ", - 1898550184: "TOUCH hoặc ENTER để chụp", - 4228215415: "TX Ghim", - 2612594937: "Chữ", - 1454688268: "Chủ đề", - 1180180513: "Nhiệt", + 3303592908: "Opslaan op apparaat", + 720041451: "Opslaan op SD kaart", + 3514476519: "Verander modus", + 1898550184: "TIK of ENTER voor opname", + 4228215415: "TX pin", + 2612594937: "Tekst", + 1454688268: "Thema", + 1180180513: "Thermisch", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bit)", - 725348723: "Công cụ", - 3684696112: "Ngưỡng cảm ứng", - 2978718564: "Màn hình cảm ứng", - 2732611775: "Thử thêm nữa?", - 1487826746: "Nhập cụm BIP39", - 2061556020: "Nhập khóa", - 2089395053: "Đơn vị", - 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", - 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", - 2736001501: "Nâng cấp firmware..\n\n%d%%", - 2674953168: "Sử dụng bề mặt nền đen.", - 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", - 236075140: "Đã sử dụng: ", - 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", - 4191058607: "Qua máy ảnh", - 1254681955: "Qua D20", - 525309547: "Qua D6", - 590330112: "Thông qua đầu vào thủ công", - 2504354847: "Chờ bắt", - 2297028319: "Trình mô tả ví", - 4232654916: "Ví đầu ra mô tả", - 2587172867: "Đã tải bộ mô tả đầu ra của ví!", - 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", - 1831109430: "Cảnh báo:\nBộ mô tả đầu ra chưa hoàn chỉnh", - 797660533: "Kí tự %d", - 3742424146: "Từ số", - 2965123464: "Từ ngữ", - 1303016265: "Đúng", - 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", - 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Hulpmiddelen", + 3684696112: "Aanraak gevoeligheid", + 2978718564: "Aanraakscherm", + 2732611775: "Meer proberen?", + 1487826746: "Voer BIP-39 wachtwoord in", + 2061556020: "Voer sleutel in", + 2089395053: "Eenheid", + 2845607430: "Bootloader updaten...\n\n%d%%", + 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", + 2736001501: "Firmware upgraden...\n\n%d%%", + 2674953168: "Gebruik een donker achergrond.", + 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", + 236075140: "Gebruikt: ", + 4003084591: "Waarde %s is buiten bereik: [%s, %s]", + 4191058607: "Via camera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Via handmatige invoer", + 2504354847: "Wacht op opname", + 2297028319: "Descriptor", + 4232654916: "Portemonnee descriptor", + 2587172867: "Portemonnee descriptor geladen!", + 2499782468: "Portemonnee descriptor niet gevonden.", + 2671738224: "Waarschuwing:", + 797660533: "Woord %d", + 3742424146: "Woord nummers", + 2965123464: "Woorden", + 1303016265: "Yes", + 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", + 2569054451: "Veranderingen worden opgeslagen op SD kaart.", }, } From 79d5900d6b7d8a5ff16c88cee29ca0c0d05867bb Mon Sep 17 00:00:00 2001 From: Odudex Date: Mon, 18 Sep 2023 11:35:10 -0300 Subject: [PATCH 012/114] use LF instead of feed command on thermal printer so all printers are compatible --- src/krux/pages/print_page.py | 2 +- src/krux/pages/tiny_seed.py | 2 +- src/krux/printers/thermal.py | 10 ++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/krux/pages/print_page.py b/src/krux/pages/print_page.py index 53a76dd4a..7c4184a65 100644 --- a/src/krux/pages/print_page.py +++ b/src/krux/pages/print_page.py @@ -88,4 +88,4 @@ def print_mnemonic_text(self): index += lines string += str(index) + ":" + words[index - 1] + "\n" self.printer.print_string(string) - self.printer.feed(3) + self.printer.feed(4) diff --git a/src/krux/pages/tiny_seed.py b/src/krux/pages/tiny_seed.py index 965881b31..f2a731ec7 100644 --- a/src/krux/pages/tiny_seed.py +++ b/src/krux/pages/tiny_seed.py @@ -240,7 +240,7 @@ def print_tiny_seed(self): wdt.feed() grid_x_offset = border_x + 16 # 4,1mm*8px grid_y_offset = border_y + 25 # 6,2mm*8px - self.printer.feed(3) + self.printer.feed(4) self.ctx.display.clear() def _draw_index(self, index): diff --git a/src/krux/printers/thermal.py b/src/krux/printers/thermal.py index 3b6ee3bda..f43b5cc2e 100644 --- a/src/krux/printers/thermal.py +++ b/src/krux/printers/thermal.py @@ -85,9 +85,11 @@ def write_bytes(self, *args): def feed(self, x=1): """Feeds paper through the machine x times""" - self.write_bytes(27, 100, x) - # Wait for the paper to feed - time.sleep_ms(self.dot_feed_time * self.character_height) + while x > 0: + x -= 1 + self.write_bytes(10) + # Wait for the paper to feed + time.sleep_ms(self.dot_feed_time * self.character_height) def has_paper(self): """Returns a boolean indicating if the printer has paper or not""" @@ -149,7 +151,7 @@ def print_qr_code(self, qr_code): # command += line_bytes self.uart_conn.write(line_bytes) time.sleep_ms(self.dot_print_time) - self.feed(3) + self.feed(4) def set_bitmap_mode(self, width, height, scale_mode=1): """Set image format to be printed""" From d7cd62c6d3fa65f4745eb5871d62feac085d2b4c Mon Sep 17 00:00:00 2001 From: Odudex Date: Mon, 18 Sep 2023 11:35:21 -0300 Subject: [PATCH 013/114] version update --- firmware/MaixPy | 2 +- pyproject.toml | 2 +- src/krux/metadata.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/firmware/MaixPy b/firmware/MaixPy index 198dac960..8a30bfd0c 160000 --- a/firmware/MaixPy +++ b/firmware/MaixPy @@ -1 +1 @@ -Subproject commit 198dac9608bad51affdde0d3bf48e94db678d8d7 +Subproject commit 8a30bfd0cb6bb651230f2e6a1b7ab4afcc958c93 diff --git a/pyproject.toml b/pyproject.toml index e22425855..40aa5fd47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ [tool.poetry] name = "krux" -version = "23.09.0" +version = "24.04.beta0" description = "Open-source signing device firmware for Bitcoin" authors = ["Jeff S "] diff --git a/src/krux/metadata.py b/src/krux/metadata.py index 01a82139a..f644347b1 100644 --- a/src/krux/metadata.py +++ b/src/krux/metadata.py @@ -19,5 +19,5 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -VERSION = "23.09.0" +VERSION = "24.04.beta0" SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b" From c812d2ef8abddc4f6028e159981fb872fd8429e8 Mon Sep 17 00:00:00 2001 From: Odudex Date: Mon, 18 Sep 2023 15:40:19 -0300 Subject: [PATCH 014/114] flash msg on decrypt errors for better translation and better irq event flush --- src/krux/input.py | 3 ++- src/krux/pages/encryption_ui.py | 12 ++++++++---- src/krux/pages/login.py | 6 ++++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/krux/input.py b/src/krux/input.py index 259671fad..56d64b0ba 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -173,7 +173,8 @@ def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD): Use block to wait indefinitely""" start_time = time.ticks_ms() while time.ticks_ms() < self.debounce_time + DEBOUNCE: - self.flush_events() + pass + self.flush_events() while True: if self.enter_event(): return BUTTON_ENTER diff --git a/src/krux/pages/encryption_ui.py b/src/krux/pages/encryption_ui.py index e352f9bf9..609893542 100644 --- a/src/krux/pages/encryption_ui.py +++ b/src/krux/pages/encryption_ui.py @@ -278,19 +278,23 @@ def _load_encrypted_mnemonic(self, mnemonic_id, sd_card=False): key_capture = EncryptionKey(self.ctx) key = key_capture.encryption_key() if key is None: - raise ValueError(t("Failed to decrypt")) + self.flash_text(t("Failed to decrypt"), theme.error_color) + return MENU_CONTINUE self.ctx.display.clear() self.ctx.display.draw_centered_text(t("Processing ...")) if key in ("", ESC_KEY): - raise ValueError(t("Failed to decrypt")) + self.flash_text(t("Failed to decrypt"), theme.error_color) + return MENU_CONTINUE mnemonic_storage = MnemonicStorage() try: words = mnemonic_storage.decrypt(key, mnemonic_id, sd_card).split() except: - raise ValueError(t("Failed to decrypt")) + self.flash_text(t("Failed to decrypt"), theme.error_color) + return MENU_CONTINUE if len(words) not in (12, 24): - raise ValueError(t("Failed to decrypt")) + self.flash_text(t("Failed to decrypt"), theme.error_color) + return MENU_CONTINUE del mnemonic_storage return words diff --git a/src/krux/pages/login.py b/src/krux/pages/login.py index c8ad9ab9c..69ae2783b 100644 --- a/src/krux/pages/login.py +++ b/src/krux/pages/login.py @@ -417,10 +417,12 @@ def _encrypted_qr_code(self, data): self.ctx.display.clear() self.ctx.display.draw_centered_text(t("Processing ...")) if key in ("", ESC_KEY): - raise ValueError(t("Failed to decrypt")) + self.flash_text(t("Failed to decrypt"), theme.error_color) + return None word_bytes = encrypted_qr.decrypt(key) if word_bytes is None: - raise ValueError(t("Failed to decrypt")) + self.flash_text(t("Failed to decrypt"), theme.error_color) + return None return bip39.mnemonic_from_bytes(word_bytes).split() return None From 5e89fd9516682819e82d87a585850bc882aed3f2 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Mon, 18 Sep 2023 14:04:13 -0300 Subject: [PATCH 015/114] Other docs small fixes --- docs/encrypted-qr-codes.en.md | 34 +++++++------------ .../generating-a-mnemonic.en.md | 12 +++---- docs/parts.en.md | 20 +++++------ docs/support.en.md | 2 +- 4 files changed, 29 insertions(+), 39 deletions(-) diff --git a/docs/encrypted-qr-codes.en.md b/docs/encrypted-qr-codes.en.md index 0a94298d0..1ad65ede4 100644 --- a/docs/encrypted-qr-codes.en.md +++ b/docs/encrypted-qr-codes.en.md @@ -5,30 +5,20 @@ There are many possible security layers one could add to protect a wallet’s pr ## QR Data and Parsing In search of efficiency and smaller QR codes, all data is converted to bytes and organized like a Bitcoin transaction, with variable and fixed length fields. The following data is present on the QR code: -| ID length | ID | Version | Key Derivations | IV | Encrypted Mnemonic | Validation Block | +| ID length (1) | ID (2) | Version (3) | Key Derivations (4) | IV (5) | Encrypted Mnemonic (6) | Validation Block (7) | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | | 1 Byte | Variable | 1 Byte | 3 Bytes | 16 Bytes
(optional) | 16 Bytes (12 words)
32 Bytes (24 words) | 16 Bytes | -### Public: - -(1) - Mnemonic ID length (1 Byte). - -(2) - Mnemonic ID(variable lenght): Custom ID or wallet fingerprint. - -(3) - Version(1 Byte): Version of encryption method, currently two are available: - - 0: AES-ECB-PBKDF2: Electronic Codebook with PBKDF2 key derivation. - - 1: AES-CBC-PBKDF2: Cypher Block Chaining with PBKDF2 key derivation. - -(4) - Key derivation iterations(3 Bytes): Number of PBKDF2 key derivations times 10,000. - -### Cipher: - -(5) - IV(16 Bytes-optional): Initial vector for AES-CBC encryption, possibility to be nonce for future AES-CTR or other encryption methods. - -(6) - Encrypted Mnemonic(16 Bytes - 12 words, 32 Bytes - 24 words): Mnemonic ciphertext. - -(7) - Validation block(16 Bytes): Currently using first 16 bytes of sha256 of the mnemonic bytes as checksum, could be used in future to store AES-AEX validation tag. +* **Visible data** (1 to 4): + * **(1)** Mnemonic ID length (1 Byte). + * **(2)** Mnemonic ID (variable lenght): Custom ID or wallet fingerprint. + * **(3)** Version (1 Byte): Version of encryption method, currently two are available: + - 0: AES-ECB-PBKDF2: Electronic Codebook with PBKDF2 key derivation. + - 1: AES-CBC-PBKDF2: Cypher Block Chaining with PBKDF2 key derivation. + * **(4)** Key derivation iterations (3 Bytes): Number of PBKDF2 key derivations times 10,000. +* **Cipher data** (5 to 7): + * **(5)** IV (16 Bytes-optional): Initial vector for AES-CBC encryption, possibility to be nonce for future AES-CTR or other encryption methods. + * **(6)** Encrypted Mnemonic (16 Bytes - 12 words, 32 Bytes - 24 words): Mnemonic ciphertext. + * **(7)** Validation block (16 Bytes): Currently using first 16 bytes of sha256 of the mnemonic bytes as checksum, could be used in future to store AES-AEX validation tag. diff --git a/docs/getting-started/generating-a-mnemonic.en.md b/docs/getting-started/generating-a-mnemonic.en.md index 7bc432e2b..3493ee942 100644 --- a/docs/getting-started/generating-a-mnemonic.en.md +++ b/docs/getting-started/generating-a-mnemonic.en.md @@ -4,7 +4,7 @@ At the start screen, once you select `New Mnemonic`, you will be taken to a seco -# Camera +## Camera @@ -12,9 +12,9 @@ At the start screen, once you select `New Mnemonic`, you will be taken to a seco
-# Dice Rolls +## Dice Rolls -## Via D6 +### Via D6 @@ -24,7 +24,7 @@ The entropy in a single roll of a D6 is 2.585 bits ( log2(6) ); there
-## Via D20 +### Via D20 @@ -32,7 +32,7 @@ Since a D20 has more possible outcomes, the entropy is increased per roll to 4.3
-## How it works +### How it works @@ -53,7 +53,7 @@ Note: For 12-word mnemonics, only the first half of the SHA256 hash is used (128
-# Alternatives +## Alternatives See [here](https://vault12.com/securemycrypto/cryptocurrency-security-how-to/seed-phrase-creation/) for good methods to generate a mnemonic manually, or visit [Ian Coleman's BIP-39 Tool](https://iancoleman.io/bip39/) offline or on an airgapped device to generate one automatically. It's worth noting that Ian's tool is able to take a mnemonic and generate a QR code that Krux can read in via the QR input method mentioned on the next page. diff --git a/docs/parts.en.md b/docs/parts.en.md index 133c3c8c6..306733566 100644 --- a/docs/parts.en.md +++ b/docs/parts.en.md @@ -1,4 +1,4 @@ -# Krux compatible devices comparative table +**Krux compatible devices comparative table** | Device | M5stickV | Maix Amigo | Maix Dock | Maix Bit | | ------------- | ------------- | ------------- | ------------- | ------------- | @@ -16,9 +16,8 @@ All devices feature Kendryte K210 chip: 28nm process, dual-core RISC-V 64bit @400MHz, 8 MB high-speed SRAM, DVP camera and MCU LCD interface, AES Accelerator, SHA256 Accelerator, FFT Accelerator -# Part List - -## M5StickV +## Devices +### M5StickV Available from many distributors, including: - [M5Stack](https://shop.m5stack.com/products/stickv) @@ -32,7 +31,7 @@ Available from many distributors, including: You can expect to pay around $50 for one depending on which distributor you choose. -## Maix Amigo +### Maix Amigo Available from many distributors, including: - [Seeed Studio](https://www.seeedstudio.com/Sipeed-Maix-Amigo-p-4689.html) @@ -44,7 +43,7 @@ Available from many distributors, including: You can expect to pay around $70 for one depending on which distributor you choose. -## Maix Dock and Maix Bit +### Maix Dock and Maix Bit For the DIYers, the Maix Dock and Bit are also supported but will require sourcing the parts individually and building the device yourself. Below are example implementations with instructions on how to recreate them: @@ -52,16 +51,17 @@ Below are example implementations with instructions on how to recreate them: - [https://github.com/selfcustody/DockEncoderCase](https://github.com/selfcustody/DockEncoderCase) - [https://github.com/selfcustody/MaixBitCase](https://github.com/selfcustody/MaixBitCase) -## USB-C Charge Cable +## Ohter parts +### USB-C Charge Cable This will be included with the M5StickV and Maix Amigo that you purchase from one of the distributors above. It will be necessary to power and charge the device and to initially flash the firmware. -## (Optional) MicroSD Card +### (Optional) MicroSD Card Not all microSD cards will work with the devices. Make sure to use one that has been [tested and shown to work](https://github.com/m5stack/m5-docs/blob/master/docs/en/core/m5stickv.md#tf-cardmicrosd-test) with the devices already. The size of the SD card isn't important; anything over a few megabytes will be plenty. -## (Optional) Thermal Printer +### (Optional) Thermal Printer Krux has the ability to print all QR codes it generates, including mnemonic, xpub, wallet backup, and signed PSBT, via a locally-connected [thermal printer from Adafruit](https://www.adafruit.com/?q=thermal+printer) over its serial port. Any of their thermal printers will work, but the [starter pack](https://www.adafruit.com/product/600) would be the easiest way to get started since it includes all the parts (except the one below) you will need to begin printing. -## (Optional) Conversion Cable for Thermal Printer +### (Optional) Conversion Cable for Thermal Printer To connect the printer to the device, you will need a [conversion cable](https://store-usa.arduino.cc/products/grove-4-pin-male-to-grove-4-pin-cable-5-pcs) with a 4-pin female Grove connector on one end (to connect to the device) and 4-pin male jumpers on the other end (to connect to the printer). You can find them at one of the distributors above or from Amazon. diff --git a/docs/support.en.md b/docs/support.en.md index f0b9faf7c..718483881 100644 --- a/docs/support.en.md +++ b/docs/support.en.md @@ -2,7 +2,7 @@ hide: - navigation --- -# Support the Project + ## Ways you can help ### Development Audit the code, file an issue, make a pull request, or do all three. :) From b944b075911698553b55cd89d17c9f390de6553e Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Tue, 19 Sep 2023 23:01:46 -0300 Subject: [PATCH 016/114] simulator adjustments for IRQ interface --- firmware/MaixPy | 2 +- simulator/kruxsim/mocks/Maix.py | 5 +- simulator/kruxsim/mocks/board.py | 2 + simulator/kruxsim/mocks/buttons.py | 144 +++++++++++++++++++++++++++++ simulator/kruxsim/mocks/pmu.py | 13 ++- simulator/simulator.py | 8 ++ 6 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 simulator/kruxsim/mocks/buttons.py diff --git a/firmware/MaixPy b/firmware/MaixPy index 8a30bfd0c..f7dc8d6f1 160000 --- a/firmware/MaixPy +++ b/firmware/MaixPy @@ -1 +1 @@ -Subproject commit 8a30bfd0cb6bb651230f2e6a1b7ab4afcc958c93 +Subproject commit f7dc8d6f17494ee1503f52d1d1ba6eb7cf80bde0 diff --git a/simulator/kruxsim/mocks/Maix.py b/simulator/kruxsim/mocks/Maix.py index 1ba92e2ea..38629dd74 100644 --- a/simulator/kruxsim/mocks/Maix.py +++ b/simulator/kruxsim/mocks/Maix.py @@ -83,6 +83,7 @@ class GPIO: GPIO5 = 37 GPIO6 = 38 GPIO7 = 39 + IRQ_FALLING = 0 def __init__(self, gpio_num, dir=None, val=None): self.key = None @@ -116,7 +117,9 @@ def value(self, val=1): sequence_executor.key_checks = 0 return RELEASED return PRESSED if pg.key.get_pressed()[self.key] else RELEASED - + + def irq(self, pin, mode): + pass if "Maix" not in sys.modules: sys.modules["Maix"] = mock.MagicMock( diff --git a/simulator/kruxsim/mocks/board.py b/simulator/kruxsim/mocks/board.py index 0666ca3e2..ade4547c3 100644 --- a/simulator/kruxsim/mocks/board.py +++ b/simulator/kruxsim/mocks/board.py @@ -58,8 +58,10 @@ def register_device(device): BUTTON_A = BOARD_CONFIG["krux"]["pins"]["BUTTON_A"] if "ENCODER" in BOARD_CONFIG["krux"]["pins"]: + #replace encoder with regular buttons in simulator del BOARD_CONFIG["krux"]["pins"]["ENCODER"] BOARD_CONFIG["krux"]["pins"]["BUTTON_B"] = 37 + BOARD_CONFIG["krux"]["pins"]["BUTTON_C"] = 38 BUTTON_B = BOARD_CONFIG["krux"]["pins"]["BUTTON_B"] if "BUTTON_C" in BOARD_CONFIG["krux"]["pins"]: BUTTON_C = BOARD_CONFIG["krux"]["pins"]["BUTTON_C"] diff --git a/simulator/kruxsim/mocks/buttons.py b/simulator/kruxsim/mocks/buttons.py new file mode 100644 index 000000000..b642b221f --- /dev/null +++ b/simulator/kruxsim/mocks/buttons.py @@ -0,0 +1,144 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2023 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +import sys +from unittest import mock +from Maix import GPIO +from fpioa_manager import fm +import pygame as pg + +PRESSED = 0 +RELEASED = 1 + +class TactileButtons: + """Interface with Buttons""" + + def __init__(self): + self.enter = None + self.page = None + self.page_prev = None + self.enter_event_flag = False + self.page_event_flag = False + self.page_prev_event_flag = False + + + def init_enter(self, pin): + """Register ENTER button IO""" + fm.register(pin, fm.fpioa.GPIOHS21) + self.enter = GPIO(GPIO.GPIOHS21, GPIO.IN, GPIO.PULL_UP) + + def init_page(self, pin): + """Register PAGE button IO""" + fm.register(pin, fm.fpioa.GPIOHS22) + self.page = GPIO(GPIO.GPIOHS22, GPIO.IN, GPIO.PULL_UP) + + def init_page_prev(self, pin): + """Register PAGE_PREV button IO""" + fm.register(pin, fm.fpioa.GPIOHS0) + self.page_prev = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP) + +buttons_control = TactileButtons() # Singleton + + +class Button: + """Generic button handler format""" + + def __init__(self) -> None: + pass + + def value(self): + """Returns IO state""" + return RELEASED + + def event(self): + """Returns event state""" + return False + + +class ButtonEnter: + """Class to manage button ENTER state and events""" + + def __init__(self, pin) -> None: + buttons_control.init_enter(pin) + + def value(self): + """Returns the ENTER IO state""" + if buttons_control.enter is not None: + return buttons_control.enter.value() + return RELEASED + + def event(self): + """Returns the ENTER event state""" + if buttons_control.enter is not None: + if buttons_control.enter_event_flag: + buttons_control.enter_event_flag = False + return True + return False + + +class ButtonPage: + """Class to manage button PAGE state and events""" + + def __init__(self, pin) -> None: + buttons_control.init_page(pin) + + def value(self): + """Returns the PAGE IO state""" + if buttons_control.page is not None: + return buttons_control.page.value() + return RELEASED + + def event(self): + """Returns the PAGE event state""" + if buttons_control.page is not None: + if buttons_control.page_event_flag: + buttons_control.page_event_flag = False + return True + return False + + +class ButtonPagePrev: + """Class to manage button PAGE_PREV state and events""" + + def __init__(self, pin) -> None: + buttons_control.init_page_prev(pin) + + def value(self): + """Returns the PAGE_PREV IO state""" + if buttons_control.page_prev is not None: + return buttons_control.page_prev.value() + return RELEASED + + def event(self): + """Returns the PAGE_PREV event state""" + if buttons_control.page_prev is not None: + if buttons_control.page_prev_event_flag: + buttons_control.page_prev_event_flag = False + return True + return False + +if "krux.buttons" not in sys.modules: + sys.modules["krux.buttons"] = mock.MagicMock( + TactileButtons=TactileButtons, + ButtonEnter=ButtonEnter, + ButtonPage=ButtonPage, + ButtonPagePrev=ButtonPagePrev + ) \ No newline at end of file diff --git a/simulator/kruxsim/mocks/pmu.py b/simulator/kruxsim/mocks/pmu.py index 183245ebc..7dd74b5a9 100644 --- a/simulator/kruxsim/mocks/pmu.py +++ b/simulator/kruxsim/mocks/pmu.py @@ -38,12 +38,13 @@ def register_sequence_executor(s): class PMU_Button: def __init__(self): self.key = pg.K_UP + self.state = RELEASED def value(self): if ( sequence_executor and sequence_executor.key is not None - and sequence_executor.key == self.key + and sequence_executor.key == pg.K_UP ): sequence_executor.key_checks += 1 # wait for release @@ -58,7 +59,15 @@ def value(self): sequence_executor.key = None sequence_executor.key_checks = 0 return RELEASED - return 0 if pg.key.get_pressed()[self.key] else 1 + return PRESSED if pg.key.get_pressed()[self.key] else RELEASED + + def event(self): + if self.state == RELEASED: + if self.value() == PRESSED: + self.state = PRESSED + return True + self.state = self.value() + return False class Battery: diff --git a/simulator/simulator.py b/simulator/simulator.py index 547ea30f3..9a3d14f77 100644 --- a/simulator/simulator.py +++ b/simulator/simulator.py @@ -103,6 +103,7 @@ from kruxsim.mocks import ft6x36 from kruxsim.sequence import SequenceExecutor +from kruxsim.mocks import buttons from kruxsim.mocks import rotary sequence_executor = None @@ -202,6 +203,13 @@ def shutdown(): ) else: event.dict["f"]() + if event.type == pg.KEYDOWN: + if event.key == pg.K_RETURN: + buttons.buttons_control.enter_event_flag = True + if event.key == pg.K_DOWN: + buttons.buttons_control.page_event_flag = True + if event.key == pg.K_UP: + buttons.buttons_control.page_prev_event_flag = True if lcd.screen: lcd_rect = lcd.screen.get_rect() From 0031b24922c983aa27368890fb76afaa23e9d107 Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 20 Sep 2023 17:11:55 -0300 Subject: [PATCH 017/114] IRQ interface and simulator improvements --- firmware/MaixPy | 2 +- pyproject.toml | 2 +- simulator/kruxsim/mocks/Maix.py | 3 ++- simulator/kruxsim/mocks/board.py | 2 +- simulator/kruxsim/mocks/buttons.py | 8 +++--- simulator/kruxsim/mocks/ft6x36.py | 41 ++++++++++++++++++++++-------- simulator/kruxsim/mocks/pmu.py | 2 +- simulator/kruxsim/mocks/rotary.py | 1 + simulator/simulator.py | 7 ++--- src/krux/buttons.py | 1 + src/krux/camera.py | 4 ++- src/krux/metadata.py | 2 +- src/krux/touch.py | 35 ++++++++----------------- src/krux/touchscreens/ft6x36.py | 31 ++++++++++++++++++++++ 14 files changed, 92 insertions(+), 49 deletions(-) diff --git a/firmware/MaixPy b/firmware/MaixPy index f7dc8d6f1..e83a88f4a 160000 --- a/firmware/MaixPy +++ b/firmware/MaixPy @@ -1 +1 @@ -Subproject commit f7dc8d6f17494ee1503f52d1d1ba6eb7cf80bde0 +Subproject commit e83a88f4a6ecd2917a3c9dc5d29e2a6965b8aefe diff --git a/pyproject.toml b/pyproject.toml index 40aa5fd47..445a888ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ [tool.poetry] name = "krux" -version = "24.04.beta0" +version = "24.04.beta1" description = "Open-source signing device firmware for Bitcoin" authors = ["Jeff S "] diff --git a/simulator/kruxsim/mocks/Maix.py b/simulator/kruxsim/mocks/Maix.py index 38629dd74..f86da902d 100644 --- a/simulator/kruxsim/mocks/Maix.py +++ b/simulator/kruxsim/mocks/Maix.py @@ -117,10 +117,11 @@ def value(self, val=1): sequence_executor.key_checks = 0 return RELEASED return PRESSED if pg.key.get_pressed()[self.key] else RELEASED - + def irq(self, pin, mode): pass + if "Maix" not in sys.modules: sys.modules["Maix"] = mock.MagicMock( GPIO=GPIO, diff --git a/simulator/kruxsim/mocks/board.py b/simulator/kruxsim/mocks/board.py index ade4547c3..613d10203 100644 --- a/simulator/kruxsim/mocks/board.py +++ b/simulator/kruxsim/mocks/board.py @@ -58,7 +58,7 @@ def register_device(device): BUTTON_A = BOARD_CONFIG["krux"]["pins"]["BUTTON_A"] if "ENCODER" in BOARD_CONFIG["krux"]["pins"]: - #replace encoder with regular buttons in simulator + # replace encoder with regular buttons in simulator del BOARD_CONFIG["krux"]["pins"]["ENCODER"] BOARD_CONFIG["krux"]["pins"]["BUTTON_B"] = 37 BOARD_CONFIG["krux"]["pins"]["BUTTON_C"] = 38 diff --git a/simulator/kruxsim/mocks/buttons.py b/simulator/kruxsim/mocks/buttons.py index b642b221f..84797ea26 100644 --- a/simulator/kruxsim/mocks/buttons.py +++ b/simulator/kruxsim/mocks/buttons.py @@ -28,6 +28,7 @@ PRESSED = 0 RELEASED = 1 + class TactileButtons: """Interface with Buttons""" @@ -39,7 +40,6 @@ def __init__(self): self.page_event_flag = False self.page_prev_event_flag = False - def init_enter(self, pin): """Register ENTER button IO""" fm.register(pin, fm.fpioa.GPIOHS21) @@ -55,6 +55,7 @@ def init_page_prev(self, pin): fm.register(pin, fm.fpioa.GPIOHS0) self.page_prev = GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP) + buttons_control = TactileButtons() # Singleton @@ -135,10 +136,11 @@ def event(self): return True return False + if "krux.buttons" not in sys.modules: sys.modules["krux.buttons"] = mock.MagicMock( TactileButtons=TactileButtons, ButtonEnter=ButtonEnter, ButtonPage=ButtonPage, - ButtonPagePrev=ButtonPagePrev - ) \ No newline at end of file + ButtonPagePrev=ButtonPagePrev, + ) diff --git a/simulator/kruxsim/mocks/ft6x36.py b/simulator/kruxsim/mocks/ft6x36.py index 21dc08d9f..54d6b4bbc 100644 --- a/simulator/kruxsim/mocks/ft6x36.py +++ b/simulator/kruxsim/mocks/ft6x36.py @@ -34,18 +34,20 @@ def register_sequence_executor(s): sequence_executor = s -def to_screen_pos(pos): - if lcd.screen: - rect = lcd.screen.get_rect() - rect.center = pg.display.get_surface().get_rect().center - if rect.collidepoint(pos): - out = pos[0] - rect.left, pos[1] - rect.top - return out - return None - - class FT6X36: def __init__(self): + self.event_flag = False + + def to_screen_pos(self, pos): + if lcd.screen: + rect = lcd.screen.get_rect() + rect.center = pg.display.get_surface().get_rect().center + if rect.collidepoint(pos): + out = pos[0] - rect.left, pos[1] - rect.top + return out + return None + + def activate_irq(self, irq_pin): pass def current_point(self): @@ -66,13 +68,30 @@ def current_point(self): sequence_executor.touch_pos = None sequence_executor.touch_checks = 0 return None - return to_screen_pos(pg.mouse.get_pos()) if pg.mouse.get_pressed()[0] else None + return ( + self.to_screen_pos(pg.mouse.get_pos()) + if pg.mouse.get_pressed()[0] + else None + ) + + def trigger_event(self): + self.event_flag = True + self.irq_point = self.current_point() + + def event(self): + flag = self.event_flag + self.event_flag = False # Always clean event flag + return flag def threshold(self, value): pass +touch_control = FT6X36() + + if "krux.touchscreens.ft6x36" not in sys.modules: sys.modules["krux.touchscreens.ft6x36"] = mock.MagicMock( FT6X36=FT6X36, + touch_control=touch_control, ) diff --git a/simulator/kruxsim/mocks/pmu.py b/simulator/kruxsim/mocks/pmu.py index 7dd74b5a9..0697bb6d6 100644 --- a/simulator/kruxsim/mocks/pmu.py +++ b/simulator/kruxsim/mocks/pmu.py @@ -60,7 +60,7 @@ def value(self): sequence_executor.key_checks = 0 return RELEASED return PRESSED if pg.key.get_pressed()[self.key] else RELEASED - + def event(self): if self.state == RELEASED: if self.value() == PRESSED: diff --git a/simulator/kruxsim/mocks/rotary.py b/simulator/kruxsim/mocks/rotary.py index 00ff8e383..c04127bb8 100644 --- a/simulator/kruxsim/mocks/rotary.py +++ b/simulator/kruxsim/mocks/rotary.py @@ -22,6 +22,7 @@ import sys from unittest import mock + class RotaryEncoder: def __init__(self): self.debounce = 0 diff --git a/simulator/simulator.py b/simulator/simulator.py index 9a3d14f77..04953a41c 100644 --- a/simulator/simulator.py +++ b/simulator/simulator.py @@ -99,12 +99,10 @@ from kruxsim.mocks import secp256k1 from kruxsim.mocks import qrcode from kruxsim.mocks import sensor - from kruxsim.mocks import ft6x36 -from kruxsim.sequence import SequenceExecutor - from kruxsim.mocks import buttons from kruxsim.mocks import rotary +from kruxsim.sequence import SequenceExecutor sequence_executor = None if args.sequence: @@ -210,6 +208,9 @@ def shutdown(): buttons.buttons_control.page_event_flag = True if event.key == pg.K_UP: buttons.buttons_control.page_prev_event_flag = True + if event.type == pg.MOUSEBUTTONDOWN: + ft6x36.touch_control.trigger_event() + if lcd.screen: lcd_rect = lcd.screen.get_rect() diff --git a/src/krux/buttons.py b/src/krux/buttons.py index 24baf84c0..97484ff2f 100644 --- a/src/krux/buttons.py +++ b/src/krux/buttons.py @@ -28,6 +28,7 @@ def __handler__(pin_num=None): + # pylint: disable=unused-argument """GPIO interrupt handler""" buttons_control.event_handler(pin_num) diff --git a/src/krux/camera.py b/src/krux/camera.py index 388a48aaa..92cbf54e2 100644 --- a/src/krux/camera.py +++ b/src/krux/camera.py @@ -96,7 +96,7 @@ def config_ov_2640(self): sensor.__write_reg(0xC2, 0x8C) # pylint: disable=W0212 # Set register bank 1 sensor.__write_reg(0xFF, 0x01) # pylint: disable=W0212 - sensor.__write_reg(0x03, 0xCF) + sensor.__write_reg(0x03, 0xCF) # pylint: disable=W0212 # Allowed luminance thresholds: # luminance high threshold, default=0x78 sensor.__write_reg(0x24, 0x70) # pylint: disable=W0212 @@ -157,10 +157,12 @@ def snapshot(self): return img def initialize_run(self): + """Initializes and runs sensor""" self.initialize_sensor() sensor.run(1) def stop_sensor(self): + """Stops capturing from sensor""" gc.collect() sensor.run(0) diff --git a/src/krux/metadata.py b/src/krux/metadata.py index f644347b1..9c0aeaebf 100644 --- a/src/krux/metadata.py +++ b/src/krux/metadata.py @@ -19,5 +19,5 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -VERSION = "24.04.beta0" +VERSION = "24.04.beta1" SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b" diff --git a/src/krux/touch.py b/src/krux/touch.py index 447c37ea1..09c1cf650 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -22,10 +22,8 @@ # pylint: disable=R0902 import time -from Maix import GPIO -from fpioa_manager import fm -from .touchscreens.ft6x36 import FT6X36 +from .touchscreens.ft6x36 import touch_control from .logging import logger as log from .krux_settings import Settings @@ -41,14 +39,6 @@ TOUCH_S_PERIOD = 20 # Touch sample period - Min = 10 -event_flag = False - - -def __handler__(pin_num=None): - """GPIO interrupt handler""" - global event_flag - event_flag = True - class Touch: """Touch is a singleton API to interact with touchscreen driver""" @@ -66,12 +56,8 @@ def __init__(self, width, height, irq_pin=None): self.gesture = None self.state = IDLE self.width, self.height = width, height - self.touch_driver = FT6X36() - self.touch_driver.threshold(Settings().touch.threshold) - if irq_pin: - fm.register(irq_pin, fm.fpioa.GPIOHS1) - self.enter = GPIO(GPIO.GPIOHS1, GPIO.IN, GPIO.PULL_UP) - self.enter.irq(__handler__, GPIO.IRQ_FALLING) + touch_control.activate_irq(irq_pin) + touch_control.threshold(Settings().touch.threshold) def clear_regions(self): """Remove previously stored buttons map""" @@ -140,15 +126,13 @@ def _store_points(self, data): def current_state(self): """Returns the touchscreen state""" - global event_flag self.sample_time = time.ticks_ms() - data = self.touch_driver.current_point() + data = touch_control.current_point() if isinstance(data, tuple): self._store_points(data) elif data is None: # gets release then return to idle. if self.state == RELEASED: # On touch release self.state = IDLE - event_flag = False # Clears event flag elif self.state == PRESSED: lateral_lenght = self.release_point[0] - self.press_point[0][0] if lateral_lenght > SWIPE_THRESHOLD: @@ -173,13 +157,14 @@ def current_state(self): return self.state def event(self): - global event_flag - check_event = event_flag - event_flag = False # Always clean event flag + """Checks if a touch happened and stores the point""" current_time = time.ticks_ms() if current_time > self.sample_time + TOUCH_S_PERIOD: - # Checks and updates index - if self.current_state() == PRESSED or check_event: + self.current_state() # Update state + if touch_control.event(): + # Resets touch and gets irq point + self.state = IDLE + self._store_points(touch_control.irq_point) return True return False diff --git a/src/krux/touchscreens/ft6x36.py b/src/krux/touchscreens/ft6x36.py index 782fefa0e..19c94b9be 100644 --- a/src/krux/touchscreens/ft6x36.py +++ b/src/krux/touchscreens/ft6x36.py @@ -24,6 +24,8 @@ # FT6x36 specs: # Max sample rate: 100 samples per second +from Maix import GPIO +from fpioa_manager import fm from . import Touchscreen import board from machine import I2C @@ -40,11 +42,20 @@ TOUCH_THRESHOLD = 22 # Default 22 +def __handler__(pin_num=None): + # pylint: disable=unused-argument + """GPIO interrupt handler""" + touch_control.trigger_event() + + class FT6X36(Touchscreen): """FT6X36 is a minimal wrapper around a I2C connection to setup and get data from FT6X36 touchscreen IC, part of Sipeed's Maix Amigo device""" def __init__(self): + self.touch_irq_pin = None + self.event_flag = False + self.irq_point = None self.addr = FT6X36_ADDR self.i2c = I2C( I2C.I2C0, @@ -60,6 +71,12 @@ def __init__(self): # Mode = 0 = polling mode | Mode = 1 = trigger mode self.write_reg(FT_ID_G_MODE, 0) + def activate_irq(self, irq_pin): + """Register IRQ pin IO and its IRQ handler""" + fm.register(irq_pin, fm.fpioa.GPIOHS1) + self.touch_irq_pin = GPIO(GPIO.GPIOHS1, GPIO.IN, GPIO.PULL_UP) + self.touch_irq_pin.irq(__handler__, GPIO.IRQ_FALLING) + def write_reg(self, reg_addr, buf): """Writes buffer content to a register address""" self.i2c.writeto_mem(self.addr, reg_addr, buf, mem_size=8) @@ -83,6 +100,20 @@ def current_point(self): return e # debug return None + def trigger_event(self): + """Called by IRQ handler to set event flag and capture touch point""" + self.event_flag = True + self.irq_point = self.current_point() + + def event(self): + """Returns event status and clears its flag""" + flag = self.event_flag + self.event_flag = False # Always clean event flag + return flag + def threshold(self, value): """Sets touch sensitivity threshold""" self.write_reg(FT_ID_G_THGROUP, value) + + +touch_control = FT6X36() From 42379b091216d98214aa0e18826aef1826e84db1 Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 20 Sep 2023 17:32:00 -0300 Subject: [PATCH 018/114] handle event touches without release point --- src/krux/touch.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/krux/touch.py b/src/krux/touch.py index 09c1cf650..144ca2afa 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -134,23 +134,24 @@ def current_state(self): if self.state == RELEASED: # On touch release self.state = IDLE elif self.state == PRESSED: - lateral_lenght = self.release_point[0] - self.press_point[0][0] - if lateral_lenght > SWIPE_THRESHOLD: - self.gesture = SWIPE_RIGHT - elif -lateral_lenght > SWIPE_THRESHOLD: - self.gesture = SWIPE_LEFT - lateral_lenght *= -1 # make it positive value - vertical_lenght = self.release_point[1] - self.press_point[0][1] - if ( - vertical_lenght > SWIPE_THRESHOLD - and vertical_lenght > lateral_lenght - ): - self.gesture = SWIPE_DOWN - elif ( - -vertical_lenght > SWIPE_THRESHOLD - and -vertical_lenght > lateral_lenght - ): - self.gesture = SWIPE_UP + if self.release_point is not None: + lateral_lenght = self.release_point[0] - self.press_point[0][0] + if lateral_lenght > SWIPE_THRESHOLD: + self.gesture = SWIPE_RIGHT + elif -lateral_lenght > SWIPE_THRESHOLD: + self.gesture = SWIPE_LEFT + lateral_lenght *= -1 # make it positive value + vertical_lenght = self.release_point[1] - self.press_point[0][1] + if ( + vertical_lenght > SWIPE_THRESHOLD + and vertical_lenght > lateral_lenght + ): + self.gesture = SWIPE_DOWN + elif ( + -vertical_lenght > SWIPE_THRESHOLD + and -vertical_lenght > lateral_lenght + ): + self.gesture = SWIPE_UP self.state = RELEASED else: log.warn("Touch error: " + str(data)) From db1bdfe44e75b7828860191c889242df1fe365ec Mon Sep 17 00:00:00 2001 From: Odudex Date: Thu, 21 Sep 2023 17:20:29 -0300 Subject: [PATCH 019/114] simulator fix - IRQ based --- simulator/kruxsim/mocks/buttons.py | 2 ++ simulator/kruxsim/mocks/ft6x36.py | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/simulator/kruxsim/mocks/buttons.py b/simulator/kruxsim/mocks/buttons.py index 84797ea26..f127847b3 100644 --- a/simulator/kruxsim/mocks/buttons.py +++ b/simulator/kruxsim/mocks/buttons.py @@ -143,4 +143,6 @@ def event(self): ButtonEnter=ButtonEnter, ButtonPage=ButtonPage, ButtonPagePrev=ButtonPagePrev, + PRESSED=PRESSED, + RELEASED=RELEASED, ) diff --git a/simulator/kruxsim/mocks/ft6x36.py b/simulator/kruxsim/mocks/ft6x36.py index 54d6b4bbc..46fdb2cdf 100644 --- a/simulator/kruxsim/mocks/ft6x36.py +++ b/simulator/kruxsim/mocks/ft6x36.py @@ -19,9 +19,7 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -import imp import sys -import time from unittest import mock import pygame as pg from . import lcd From e332c33be406c4f884d69c115f43c9469cecd5ef Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Mon, 25 Sep 2023 22:48:38 -0300 Subject: [PATCH 020/114] adapt simulator screenshot seqs to IRQ interface --- simulator/kruxsim/mocks/Maix.py | 27 +------------------ simulator/kruxsim/mocks/buttons.py | 27 +++++++++++++++++++ simulator/kruxsim/mocks/ft6x36.py | 21 +++------------ simulator/kruxsim/mocks/pmu.py | 25 +++++------------ simulator/kruxsim/sequence.py | 5 ++-- .../amigo_tft/_load-12-word-mnemonic.txt | 3 --- .../amigo_tft/_load-24-word-mnemonic.txt | 3 --- .../m5stickv/_load-12-word-mnemonic.txt | 3 --- .../m5stickv/_load-24-word-mnemonic.txt | 3 --- simulator/simulator.py | 2 +- 10 files changed, 42 insertions(+), 77 deletions(-) diff --git a/simulator/kruxsim/mocks/Maix.py b/simulator/kruxsim/mocks/Maix.py index f86da902d..6b446b111 100644 --- a/simulator/kruxsim/mocks/Maix.py +++ b/simulator/kruxsim/mocks/Maix.py @@ -29,13 +29,6 @@ PRESSED = 0 RELEASED = 1 -sequence_executor = None - - -def register_sequence_executor(s): - global sequence_executor - sequence_executor = s - class GPIO: IN = 0 @@ -97,25 +90,7 @@ def __init__(self, gpio_num, dir=None, val=None): def value(self, val=1): if not self.key: - return 1 - if ( - sequence_executor - and sequence_executor.key is not None - and sequence_executor.key == self.key - ): - sequence_executor.key_checks += 1 - # wait for release - if sequence_executor.key_checks == 1: - return RELEASED - # wait for press - # if pressed - elif sequence_executor.key_checks == 2 or sequence_executor.key_checks == 3: - return PRESSED - # released - elif sequence_executor.key_checks == 4: - sequence_executor.key = None - sequence_executor.key_checks = 0 - return RELEASED + return RELEASED return PRESSED if pg.key.get_pressed()[self.key] else RELEASED def irq(self, pin, mode): diff --git a/simulator/kruxsim/mocks/buttons.py b/simulator/kruxsim/mocks/buttons.py index f127847b3..dc6d54a45 100644 --- a/simulator/kruxsim/mocks/buttons.py +++ b/simulator/kruxsim/mocks/buttons.py @@ -58,6 +58,11 @@ def init_page_prev(self, pin): buttons_control = TactileButtons() # Singleton +sequence_executor = None + +def register_sequence_executor(s): + global sequence_executor + sequence_executor = s class Button: """Generic button handler format""" @@ -89,6 +94,14 @@ def value(self): def event(self): """Returns the ENTER event state""" if buttons_control.enter is not None: + + if ( + sequence_executor + and sequence_executor.key is not None + and sequence_executor.key == pg.K_RETURN + ): + sequence_executor.key = None + return True if buttons_control.enter_event_flag: buttons_control.enter_event_flag = False return True @@ -110,6 +123,13 @@ def value(self): def event(self): """Returns the PAGE event state""" if buttons_control.page is not None: + if ( + sequence_executor + and sequence_executor.key is not None + and sequence_executor.key == pg.K_DOWN + ): + sequence_executor.key = None + return True if buttons_control.page_event_flag: buttons_control.page_event_flag = False return True @@ -131,6 +151,13 @@ def value(self): def event(self): """Returns the PAGE_PREV event state""" if buttons_control.page_prev is not None: + if ( + sequence_executor + and sequence_executor.key is not None + and sequence_executor.key == pg.K_UP + ): + sequence_executor.key = None + return True if buttons_control.page_prev_event_flag: buttons_control.page_prev_event_flag = False return True diff --git a/simulator/kruxsim/mocks/ft6x36.py b/simulator/kruxsim/mocks/ft6x36.py index 46fdb2cdf..3fe6b198b 100644 --- a/simulator/kruxsim/mocks/ft6x36.py +++ b/simulator/kruxsim/mocks/ft6x36.py @@ -49,23 +49,6 @@ def activate_irq(self, irq_pin): pass def current_point(self): - if sequence_executor and sequence_executor.touch_pos is not None: - sequence_executor.touch_checks += 1 - # wait for release - if sequence_executor.touch_checks == 1: - return None - # wait for press - # if pressed - elif ( - sequence_executor.touch_checks == 2 - or sequence_executor.touch_checks == 3 - ): - return sequence_executor.touch_pos - # released - elif sequence_executor.touch_checks == 4: - sequence_executor.touch_pos = None - sequence_executor.touch_checks = 0 - return None return ( self.to_screen_pos(pg.mouse.get_pos()) if pg.mouse.get_pressed()[0] @@ -77,6 +60,9 @@ def trigger_event(self): self.irq_point = self.current_point() def event(self): + if sequence_executor and sequence_executor.touch_pos is not None: + sequence_executor.touch_pos = None + return True flag = self.event_flag self.event_flag = False # Always clean event flag return flag @@ -90,6 +76,5 @@ def threshold(self, value): if "krux.touchscreens.ft6x36" not in sys.modules: sys.modules["krux.touchscreens.ft6x36"] = mock.MagicMock( - FT6X36=FT6X36, touch_control=touch_control, ) diff --git a/simulator/kruxsim/mocks/pmu.py b/simulator/kruxsim/mocks/pmu.py index 0697bb6d6..0d8a63397 100644 --- a/simulator/kruxsim/mocks/pmu.py +++ b/simulator/kruxsim/mocks/pmu.py @@ -41,28 +41,17 @@ def __init__(self): self.state = RELEASED def value(self): - if ( - sequence_executor - and sequence_executor.key is not None - and sequence_executor.key == pg.K_UP - ): - sequence_executor.key_checks += 1 - # wait for release - if sequence_executor.key_checks == 1: - return RELEASED - # wait for press - # if pressed - elif sequence_executor.key_checks == 2 or sequence_executor.key_checks == 3: - return PRESSED - # released - elif sequence_executor.key_checks == 4: - sequence_executor.key = None - sequence_executor.key_checks = 0 - return RELEASED return PRESSED if pg.key.get_pressed()[self.key] else RELEASED def event(self): if self.state == RELEASED: + if ( + sequence_executor + and sequence_executor.key is not None + and sequence_executor.key == pg.K_UP + ): + sequence_executor.key = None + return True if self.value() == PRESSED: self.state = PRESSED return True diff --git a/simulator/kruxsim/sequence.py b/simulator/kruxsim/sequence.py index f6187bb81..f4f541350 100644 --- a/simulator/kruxsim/sequence.py +++ b/simulator/kruxsim/sequence.py @@ -28,6 +28,7 @@ from kruxsim.mocks.board import BOARD_CONFIG COMMANDS = ["press", "touch", "qrcode", "screenshot", "wait", "include", "x"] +THREAD_PERIOD = 0.1 class SequenceExecutor: @@ -50,9 +51,9 @@ def __init__(self, sequence_filepath): def execute(self): if self.command_fn: - if time.time() - self.command_timer > 0.1: + if time.time() > self.command_timer + THREAD_PERIOD: print("Executing (%s, %r)" % (self.command, self.command_params)) - self.command_timer = 0 + self.command_timer = time.time() self.command_fn() self.command_fn = None self.command_params = [] diff --git a/simulator/sequences/amigo_tft/_load-12-word-mnemonic.txt b/simulator/sequences/amigo_tft/_load-12-word-mnemonic.txt index 2123b108f..67fe6743d 100644 --- a/simulator/sequences/amigo_tft/_load-12-word-mnemonic.txt +++ b/simulator/sequences/amigo_tft/_load-12-word-mnemonic.txt @@ -3,9 +3,6 @@ include _wait-for-logo.txt # Navigate to via QR x3 press BUTTON_A -# Prompt -press BUTTON_A - qrcode 12-word-mnemonic.png wait 0.5 diff --git a/simulator/sequences/amigo_tft/_load-24-word-mnemonic.txt b/simulator/sequences/amigo_tft/_load-24-word-mnemonic.txt index a1311d4ac..dc5fbcdfc 100644 --- a/simulator/sequences/amigo_tft/_load-24-word-mnemonic.txt +++ b/simulator/sequences/amigo_tft/_load-24-word-mnemonic.txt @@ -3,9 +3,6 @@ include _wait-for-logo.txt # Navigate to via QR x3 press BUTTON_A -# Prompt -press BUTTON_A - qrcode 24-word-mnemonic.png wait 0.5 diff --git a/simulator/sequences/m5stickv/_load-12-word-mnemonic.txt b/simulator/sequences/m5stickv/_load-12-word-mnemonic.txt index 2123b108f..67fe6743d 100644 --- a/simulator/sequences/m5stickv/_load-12-word-mnemonic.txt +++ b/simulator/sequences/m5stickv/_load-12-word-mnemonic.txt @@ -3,9 +3,6 @@ include _wait-for-logo.txt # Navigate to via QR x3 press BUTTON_A -# Prompt -press BUTTON_A - qrcode 12-word-mnemonic.png wait 0.5 diff --git a/simulator/sequences/m5stickv/_load-24-word-mnemonic.txt b/simulator/sequences/m5stickv/_load-24-word-mnemonic.txt index 832ec34e4..c798eca0a 100644 --- a/simulator/sequences/m5stickv/_load-24-word-mnemonic.txt +++ b/simulator/sequences/m5stickv/_load-24-word-mnemonic.txt @@ -3,9 +3,6 @@ include _wait-for-logo.txt # Navigate to via QR x3 press BUTTON_A -# Prompt -press BUTTON_A - qrcode 24-word-mnemonic.png wait 0.5 diff --git a/simulator/simulator.py b/simulator/simulator.py index 04953a41c..c27ff6e7f 100644 --- a/simulator/simulator.py +++ b/simulator/simulator.py @@ -108,7 +108,7 @@ if args.sequence: sequence_executor = SequenceExecutor(args.sequence) -Maix.register_sequence_executor(sequence_executor) +buttons.register_sequence_executor(sequence_executor) pmu.register_sequence_executor(sequence_executor) sensor.register_sequence_executor(sequence_executor) ft6x36.register_sequence_executor(sequence_executor) From e7aa897961e7bec1be2a215227084c765f98eb6b Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 26 Sep 2023 16:47:28 -0300 Subject: [PATCH 021/114] creating screensaver --- src/krux/context.py | 61 ++++++++++++++++++++++++++++++++++++-- src/krux/input.py | 31 ++++++++++++++++--- src/krux/pages/__init__.py | 3 +- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/krux/context.py b/src/krux/context.py index ac9c030af..fde749aaa 100644 --- a/src/krux/context.py +++ b/src/krux/context.py @@ -20,12 +20,34 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. import gc +import time import board from .logging import logger from .display import Display from .input import Input from .camera import Camera from .light import Light +from .themes import theme + +SCREENSAVER_ANIMATION_TIME = 50 +# adicionei 12 espaços nas primeiras linhas +# adicionei 3 linhas abaixo +SCREENSAVER_BLANK_LINE = " " +SCREENSAVER = """ + ██ + ██ + ██ + ██████ + ██ + ██ ██ + ██ ██ + ████ + ██ ██ + ██ ██ + ██ ██ +"""[1:-1].split("\n") +SCREENSAVER_SIZE = len(SCREENSAVER) +SCREENSAVER = [SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE] + SCREENSAVER + [SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE] class Context: @@ -35,13 +57,13 @@ class Context: def __init__(self): self.display = Display() - self.input = Input() + self.input = Input(screensaver_fallback=self.screensaver) self.camera = Camera() self.light = Light() if "LED_W" in board.config["krux"]["pins"] else None self.power_manager = None self.printer = None self.wallet = None - + @property def log(self): """Returns the default logger""" @@ -53,3 +75,38 @@ def clear(self): if self.printer is not None: self.printer.clear() gc.collect() + + def screensaver(self): + print("screensaver context!") + + anim_curr_text = "" + anim_frame = 0 + screensaver_time = 0 + + fg_color = theme.fg_color + bg_color = theme.bg_color + + self.display.clear() + + while True: + if (screensaver_time + SCREENSAVER_ANIMATION_TIME < time.ticks_ms()): + if (anim_frame < SCREENSAVER_SIZE*2): + anim_frame = anim_frame + 1 + else: + anim_frame = 1 + tmp_color = bg_color + bg_color = fg_color + fg_color = tmp_color + + # show animation on the screeen + anim_curr_text = SCREENSAVER[0:anim_frame] + self.display.draw_hcentered_text(anim_curr_text, color=fg_color, bg_color=bg_color) + + screensaver_time = time.ticks_ms() + + if (self.input.wait_for_press(block=False) != None): + print("break screensaver") + break + + + diff --git a/src/krux/input.py b/src/krux/input.py index d9846bb6f..76be527e7 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -42,12 +42,16 @@ RELEASED = 1 BUTTON_WAIT_PRESS_DELAY = 10 +SCREENSAVER_IDLE_TIME = 5000 class Input: """Input is a singleton interface for interacting with the device's buttons""" - def __init__(self): + def __init__(self, screensaver_fallback = None): + self.screensaver_fallback = screensaver_fallback + self.screensaver_time = 0 + self.screensaver_active = False self.entropy = 0 self.enter = None @@ -140,6 +144,7 @@ def swipe_down_value(self): def wait_for_release(self): """Loop until all buttons are released (if currently pressed)""" + print("wait_for_release...") while True: if self.enter_value() == RELEASED and self.touch_value() == RELEASED: if "ENCODER" in board.config["krux"]["pins"]: @@ -152,10 +157,12 @@ def wait_for_release(self): self.entropy += 1 wdt.feed() - def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD): + def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD, enable_screensaver=False): """Wait for first button press or for wait_duration ms. Use block to wait indefinitely""" + # print("wait_for_press...") start_time = time.ticks_ms() + self.screensaver_time = start_time while True: if self.enter_value() == PRESSED: return BUTTON_ENTER @@ -165,19 +172,35 @@ def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD): return BUTTON_PAGE_PREV if self.touch_value() == PRESSED: return BUTTON_TOUCH + self.entropy += 1 wdt.feed() # here is where krux spends most of its time + if not block and time.ticks_ms() > start_time + wait_duration: return None + + # Check for screensaver + if (block and enable_screensaver and not self.screensaver_active and self.screensaver_fallback and self.screensaver_time + SCREENSAVER_IDLE_TIME < time.ticks_ms()): + print("show screen saver!!!") + self.screensaver_active = True + self.screensaver_fallback() + self.screensaver_time = time.ticks_ms() + time.sleep_ms(BUTTON_WAIT_PRESS_DELAY) - def wait_for_button(self, block=True): + def wait_for_button(self, block=True, enable_screensaver=False): """Waits for any button to release, optionally blocking if block=True. Returns the button that was released, or None if nonblocking. """ + print("wait_for_button...") + self.wait_for_release() - btn = self.wait_for_press(block) + btn = self.wait_for_press(block, enable_screensaver=enable_screensaver) + if (enable_screensaver and self.screensaver_active): + self.screensaver_active = False + btn = None + print("passed wait_for_press") if btn == BUTTON_ENTER: # Wait for release while self.enter_value() == PRESSED: diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 0726dec27..4aa0171a5 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -548,6 +548,7 @@ def run_loop(self, start_from_index=None): start_from_submenu = True selected_item_index = start_from_index while True: + print("Menu > run_loop: (while True)") gc.collect() self.ctx.display.clear() if self.ctx.input.touch is not None: @@ -563,7 +564,7 @@ def run_loop(self, start_from_index=None): return (self.menu_view.index(selected_item_index), status) start_from_submenu = False else: - btn = self.ctx.input.wait_for_button() + btn = self.ctx.input.wait_for_button(enable_screensaver=True) if self.ctx.input.touch is not None: if btn == BUTTON_TOUCH: selected_item_index = self.ctx.input.touch.current_index() From 28f4c2d8659fc56e5abe1fd85712af5f4d21ad14 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Wed, 27 Sep 2023 09:36:22 -0300 Subject: [PATCH 022/114] add sd card info to xpub on docs --- docs/getting-started/navigating-the-main-menu.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/navigating-the-main-menu.en.md b/docs/getting-started/navigating-the-main-menu.en.md index b9ba69821..094504430 100644 --- a/docs/getting-started/navigating-the-main-menu.en.md +++ b/docs/getting-started/navigating-the-main-menu.en.md @@ -62,7 +62,7 @@ The encrypted mnemonic will be converted to a QR code. When you scan this QR cod -This option displays your master extended public key (xpub) as text as well as a QR code. +This option displays your master extended public key (xpub) as text as well as a QR code. The extended public key (xpub) can also be stored on a SD card if available. After the xpub, a zpub or Zpub is shown depending on if a single-sig or multisig wallet was chosen. This z/Zpub is usually not necessary unless you are using a wallet coordinator that either cannot parse or ignores [key origin information in key expressions](https://github.com/bitcoin/bips/blob/master/bip-0380.mediawiki#Key_Expressions). From e3df58a3660f248f13f2203f2a08014c56434e78 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Wed, 27 Sep 2023 09:37:37 -0300 Subject: [PATCH 023/114] simulator encoding fix --- simulator/simulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simulator/simulator.py b/simulator/simulator.py index 547ea30f3..5e50fbcd4 100644 --- a/simulator/simulator.py +++ b/simulator/simulator.py @@ -116,7 +116,7 @@ def run_krux(): - with open("../src/boot.py") as boot_file: + with open("../src/boot.py", "r", encoding='utf-8') as boot_file: exec(boot_file.read()) From a99cf184dc587de131f2c28f798548f3debd1d3a Mon Sep 17 00:00:00 2001 From: tadeubas Date: Wed, 27 Sep 2023 09:38:39 -0300 Subject: [PATCH 024/114] added maixpy_dock img to simulator --- simulator/assets/maixpy_dock.png | Bin 0 -> 203376 bytes simulator/kruxsim/devices.py | 4 +--- 2 files changed, 1 insertion(+), 3 deletions(-) create mode 100644 simulator/assets/maixpy_dock.png diff --git a/simulator/assets/maixpy_dock.png b/simulator/assets/maixpy_dock.png new file mode 100644 index 0000000000000000000000000000000000000000..93f9fdea9e154cd8051e05bfefbc90a161cfdfb0 GIT binary patch literal 203376 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�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

4K?ZLD4iyPxKk|7_ zCqgVY_?`1%uYni>vUOwaXEi`-a4$ssA{@YQsCf%StRN3I_*Ch zAajAua+1_|W`)QP+Xov^k4e*Dea~$R7GmtP!Ik|+PTpc=yvGbB_WO!#h!|=y*d#Bu z7Zs=B1JCCZdp#ks4<+B76F26z@A|Ycf2lNdbgBamT5{~^xZQz-eixNv6p>>*NhY`Z zl1QCjU{PSQw?E5eP;n%z#4bG62c#;xmk8eyf}c)ufRf6Z22D|SH({_p2wFN0?aGgG zMB%`Y=f%SS03ZNKL_t*f8#y;wlv>3p9`1PB;vM2w%6Q)iJIrG;hHwN>?-D5uPG#*3 zEerzhUJH@|h5s*9Y?t!(_RXP~X`LnyC>fJcV7e>yZd~@lTJKm}t-ujkk!cR$DrN)= zTA-nB20ctuq|wa@#^o@Hcv878sPC?}EL_(B&*^(G^^4re6~ow7x}RWr$MCLnuxXtX z%Y>xjzrQkwFW-YMto@F?1#{RgipU_a{o@Dr`){_eXD{Mpgy}6$tmhN51lS8J7>^iW z9l56khV6PBuG-kp{lp*wzYm`R4MtKGyf4A?xv{quggH42yJ_x_jf1II#N;2&Cy}jq zF4Joc7Kg5yZ>kqgQQK`037-4ip`c2ySB;${fy5wL6?Pa|edlOD*P!W>g-=gB+ym90 zUl^lS5yi`($NhZAdOm%JXHpgtn{dXsz(XN;LfNMd6)+dnXblj&NEqu?_B(>~8JbDv z>CPDI*v|!gs@M>HwpYpas|<$fz|(bZ*Jb*@iwCZ2g2#ZU;JKep&wmj^yKa>{s>c5J zvQT6Q_O^t8;iN7O9qHbX6%ag^-WK8$9w$5*JIC!sPDC(y;^ND`huHLMljnw7SB|~? zpEqJjv9`q_!J4LmB$w2=G*2EF)H5-gbXUnqYfef@7O_q0lFljA*sj*(tz~-SEz93G zzdd6oud(}!sZ$e}j5i_a7!v`Nk zTubLSgJJm*u5&~(Ig6@Rt4$I^sd0M^o(Lg$f7niK-KnujMy5l9RxmVuo7wv;%8fE% zt&Knb^9`F|JAg5~ z^Ls+@Ea+4SlP;*RiJ*t=T%ZH%-AN}{;8|8ag9&dBD?(txkM+a4)-j>PSbJmru>N+q zEP;p&HXQBlly?783V zl5xm+sIfTbu-%^suysL)U_$`Y&iiFQvlCYp6B;l3Pv(#S>@?RlYtfoE6x-k;XFswI z$R1E^jA>sZt|tjNRu;BAF|X-%b=#pQ*Om#emi<2Ac?u1ZOc7mFO*qa;6cA(6!F*7~ zcdnD!_I|p+JdB(H;QhyU{P^uRldr%a+er^FJq$tM1)(3gpE3Q&hKe|J?fV}dn2$G; z2t0p)6Q?gvSX(31c3|yg1RNI(5ZP-Ltj(hJvqPSOy%|J5aPh>oF3ii=sn7L}=X%1_ z3Gw+iF*=hW2qtKbxjiWG&YY##Y1^OfwILfWN9wkH-mId#kQh80dQ?@xQ#amufyiF- z5P`=Xq2e%m!0D{1qfC@QPs)Gg(DgM5B}+B)Db)>~q1MC(b2Jub!6}H_&>L0qq8e;Y zYe1G;6;{x5H2OU3j_O6unl2?`zQ$}F@m=J8|7=y_!QT`*0{~QK&2e-x-U$t6V__i{ z`Yk{(BnkdzOR2fblBQAoNMA&s(Xsi(LQOAc-I1i1W$2f>;Q!!6`Mx5B=1|+Gs6w`4 zt&Q>hJFaO=x+U8s0@KMBWK*50X_VGZ%C!=}-`Uu90`Rouyzv6W95i6v7P&(~bgdzv zC$T9@mLoNjN&-LwzZw<=;(;YA-8JAv?)m=X_#kA)!eH>U-HmQ7Dza;z_I?7`20{4+ zMR0eQy^Qwnm%5U(;FQ4I7nd-~)i3gV6D+TN|3UUEC3$M%UELQf3%WP$~3g$%aKc^mUm_AYrh z5w2xZ>s|{H=Ms}m$UJydtW}V}T7qIi*kic9a!YDoW5O_4ZDY$5yzF&eYgto}J1Qs8 zvzl{FgZTV*vDE<~g&9d%(jayWXMhIG7lbheBcv3|idC|U%i-Tx-m#l&8b&V~w&QC? z6^d50>V2ec;2eeyXbIp=+h=TURGe2dSfaUS&IX{1-@W*u@9-+l8H54FvZ;==CeM}# z(+s5`qJzMf?9Y`I_6a2fMn4bcSf~Cc-PYe2W7<)Bu}g?t2F;puY0*@r9I-mKsVE<~ z{7gt0k{<31`QRb#x-zdxPXmvXjCn@{x70!lR}8wiDuGn+TnmElP!O(pdAhLgBE%pS zQSk^V@vqBZ3}8B(CDyI!Hmj?PT}124ed{bsUT#`C26WhKs=?1>Y}t6KfN46CR#FLr zW~BXm%P&CNhs`k^4z=b4p82O8vZ9>=QwoOMHZ~uM_k>D}D-y&bYZQ2}Q|GBXNVo0Qknt(uPdGr^VIt8=vS<*)-je@Z zBWd2QS7XW%ic(MZeqy=h)DuYqhllivPa`K>J+e6vhn(K^-DMu}O!~f(*aC&+-9JP2 z&@Nf9VN)H#HewGqH=HHU+-JrMv-kEQ=M9K(UhrtHCF!rIu|KZDK;*e-{yd0m5GmeO z(B1k)G;OZ7sJY^^>)}#!PEefpN$!&Xe=gaHC{X~SSlJ{fV*6|IJzz9!B4MFs1y4k+ zLHH0(`jUv!q)iOY*CH^VOz}Q;{V@c3(+6t&xoWj4%nPZPRS|T{Lu%1sXwEbuNb-?Q z(!S4jIe{S`0kcYbmJ}+=0KGk*@0`NoyU6_>^Mv&M$NT$!?j5WmB5eUSWsek&-jPNS zDdM&UYb2B=nnlCxSu+(Q1<2JsHB%#PY|QAKDd3b6kdkUTXV}l^JFAp36csp)4I7AfTWnwS_s?m(ewhT&9Yd+nB!2oS>KC>9Q}+F!Jy#!j+` z^z!F=;>UWLqsldmn%(mJ;7mPLF(GxhnydL$4l)z#V7Qe#hUO(9LFmEu?<+<;$bG1Q z_V)C2O2!_;E|%rR3I1|Dr7jw7+Qu!*2^Ardf9Xh2(3z%pp#Zv)ehr7fklw0Bin3xX zUxV3Dj`jhMLNRrp44ZTtSS>nB|ZJ2*fn>hNkU$Z@y zy4{u$XvWdtXj_jc^{=kE5&;?SfMKLKO&1&O?1C4INOvi5iG=vqje^}}2%Ptv9@3{E zm*k&F^ZTWUoA&!wxOoQKv$r>qDjop-_WSqW27u>X9O`E$*2PBfc(UJ_xNu@higkwRN zq}GF7PA0t|Yci#5-?+O|9-Eh)5hB8@A$A2t>rZk`NFltlhKlR1yx@B{qa>`d?OIcZ z#+*9r+Yw{6$*Cty(K~j%ez6O6_Xs%j6Qa{xv8gk%2wY` zO46oPf?jJRg;y6E)0~A%NKEIa?lE`3+t?)>QAv#jr_DGZA1v}sERD=1j3_9B-?qEP z)Sj1|coL)n%I8H>HtlZdh7F{_1JI1BC zlVYQ%^&B>eN!!~AG%<70@~fHZM(p9~YM1(UghY#;-|mf^=nt)}wxH7TH7#bgLXw5eL^SXW^8dN(jHv)EXb!bWAGBHzPhi}3X3wmhQyhSmS zbZXp{=$z2ZX_F33WxJ!@2lJE@)I)vB3j*57j&-}SDR8m;8dl}7496e`}y zF6%BgaK>+5qAEG@Sh|I@VifZrWudn_mc4l~$WOsO*inK{k6f&%dNdy=uD$Y?C@mj%vuIp z-4k9oiJEMw;NK95N5N$3&q@^dcn9M9*J{lWqETNvo0Zt1x$_C>VXjfr>}jc;KCD{E z&{>MxEbJ03qR%Cj`+O1tTN8X!7^rUh5lw0>vyDR=ng*(ahj+zj45YZA>5vCh=x(#h z@rQZ`3_&TL67Jj zYSUzYpOcp%jU^o+%hA(OO^E$@CKOR7ScKH#wDbtKkoNjC?{Hn0HJ?nd0Pdf;PFp*`1akvtTz(J1YC&Zhx=}DzZgyu=KRSl2Xs3)0C-6973qc zuxV_I@6goAGVLOcra;orx;pTHU8!~BXY*Cx=|{$CBjSNUlo+} zAqR03OPSp6jg+bh<~~W22dtjYjAYkAes58_K1qjL{cekoy2+FJ=Ozei1XWelr7CNU z8?OAx4>ZSO;{W@a*L&D=g4vWMk*=GKIqtNW(3^ za=*kytwAt2le;R!k+f5oaX=y^pV(z!?HA~FrXjS_Bvk8zn@AX%=sxq$q=Ij?_7qY0 z6cJbByBKh@LJ}u%a5gmY-p2Kskv6DIL2VKgSE&^|73232jCaaM;=SaTX9B+eqnOAN zK`huinY``difN=?th(IOnZ8BK#On;PROe_=*kNuJdrwRN-k~{PxB3n*h*aV)8uif^^zrDXTxfN_F+V!<=auoms`9u1f}7T)bij=(d3zPq-Q8-8{3ag|99Rtbq9%$ON{>8-5^k>nH#%<{T1+T7G!;a8QYdsvJv10kF}zy z1z|>^C9dxOD9=svLjZ(08M1BLgm8I?>8W=8XFzDO>kg>AAp+gO;-yd`FEo3$N%4_M zr>GraGX08_Anj)_*^14knl3E9w{9%KiU^|oJY{3S(%6lf4C4dR*B%+vRtqmkG!iaF zLBT*WqV3ry^j1Vk+K$L26$k7r?em~*FIJE;dX8O>$ntk%jO+mG_le)l@0jWSuF^aR|TU=7rYQ0z8N zW6-wqap;Z<&P21MJ`5Uttmy~-7lKx&JH<}ROwDR-7~e9vI!5$Vw~K#!}>4G?-H z3|wo*`OK2mb6xN;rThkM&#TQmucBb|geG5hnVX$|9$vKiKiEYq%kY~Yna*b@i?|7?^KnS#_=OTt$yCNRL{?S?F+fB7gQpg^<(50 zy9q)znfabMISMs5Wkw*?J(HBWFh%drHq|!&Omg?_0@WI1ZN*x0?(Cybr%80&(EO=( za-YsI`ak{8|Fv$_CBSb>M3(FV4X6xqMHdFcbEj$=z#z+>id|C=NJVL;G}&NU56R(< z5IddrwY3v6sO=hXehnkrJDjGKLx@9mUa0c&VTsSaD5pcy)ky|wCa}*Z z_S*S9$u(=X=5*6tpQ0iQEu{wP@K#v%xSf->&KI(a){Mxg^2vfE&3&QEqCbL`pi&oW zIJmp{BL~DAEKIIF3=_3tVjp~tk1xe!5fELZYoqq4P4h_F0$R0)fX3cZ{A+s{XzX}G zenHLGG&^8v7oeU7;PEq3F%Ibi;ijIw)DC(Qb4*B)1W~V9IE8ehZ0&BDDX*dCRG(9b zHXcDU`aQf{yG+EHl+<9fPNaIZynFq<;$P*+3GB?m4rwMntI1}pwF5cXp%cWKV@Z5I zrJ}QXbaDPSZ;)~?OP!$_SV1MSGgTUWInWlSY!5@|?*Qsb?tI~!F)x|d*iN_z|$NESDPdFtc` zuJLxWEC1;HPyge;q5t)N``;PBgUMqFwctO=-InB@D6*Xnw-ZQPN>}%yZQUl#Q2;GH z;Pr!gFg2;Bz}!bkhX#-l8`^dWkvTQU953Rpkoq**f)FV?)^h?OqDEqYUvLhYQbAr# z^%Ftj=+;G`6N)3Hvk;upnPR;~&rLny$_X;DE9rX_cRW|8*cYH%9WGpEp=fsjTR5He&s~&_+j(*cN(~O}0JjE3>uM&n?o*B@jsfrb>+OM3UZ+ z;b4(=#wCvFH5x2q=*0xtOoIve*`n+i>Sud-lbi zeH))OuHAIk^98%zVab?i)l)3&KkXSF%$VcCH7}lH-t5XhI%{v5bN&qx{o9Z08t>m@ z>e>g3FGl}Hs>WpVecbRirB6B1gatv(W^QliE9BO{SLG`{-C)cX%s`oKoL3xxR)tQ-V$J)t2n!dbhaL3wv$mu5lS?(-=re z9fC*_Y%)3%jLp6bnL^Na9rYos*Vpp3sCIa9A*nV)H9(@Xe}i#!A|7%ESA>t5TyHb zH|S)sCN-YukTNt*dA*Ja$Mv7h*_UF)BD@gkcyDUoUHU^l!aq3*B#KG9!#Ym`vg5Yz z>_20~J*62}t|JacBp2=;@`ZR2m>X=^>=mgM`r@UX`dEXJjqTlk@0f6-v5vj1;xv_@ zVlfqLs@1@^_Miw$O|wXSo7^XG>hNJT-&@22VGptlwP#7Q5sCn441)F^)rl$+jShgJ zT!{oUvRKYJFa}w`*#3SKPyVpTtu^Nue^0=l2*g3FEgqpZ2MIB)j>o%fawi4F;VvHc zlxWY4E7yQyztZfXj@%~dqG3vR?n;r4XIN9aRr{zWR3Iu%A4)P1evPlxmSffI&KG%6 zph21~3-;(Z4`y0}Lu1(=dnRq7hb|t3zB=yZ1(QrT4S7M^V`_`;+^Iq}c~6GZv!!GI7wkb86wO_L%J>Y?m_;pkQTfT|zm)t2GQS z(|i&miaz=QaSka-HeMphqOAd0YA@H|D|A-s2RPA1EzO#)?`5>co*?0_*uX z3iz#9uYEr#$LB77XAvvVoDn1RL2?qV{3*ns4icREx}&}8tA&oXG`AdNG*)~b>T^u} zeR23(T}DAIFY@?2_-8pj6X$0SwV!K(dg`i%rqw+5niQFJl#VXRZtf01%@V9w*_^#C zzeq2lP#Zc>pYhc0H8NGK1QD7r8$;W3a03=UQuvh!PW7 z{EWTX=N+s$V%sHT4(9bR(*ad-wLpy~+!xWWEViUqxpyGFxOo@uksYvhs=C%it8S6w za9<=On>&3(g2eCgx)^T|QmD8)`%BLNSNklD5gyz+P%mt9 z5(jcu*!}UeQLRxnPrcxDCx}|OYwMULNjeD|X(M!Ko5o36Q$ok|Lm%kwog~pFam8sC zkh>xr(vHqn3qR9?Iu1UU=^H>?k`H<_83rOY8v^eSUKTFK_4VBKDo%p z2D?uHM7?Nsbc2f7h>kWmI*>!l@FEy{RcR32D7Y&~Qp3P(3%P9qZs3sH=<(b}L3ssS z3a%|iZ3E%+`Im(7DUFDcI?gg%ki#emDAsPk@HI(Eh7Q2J9>cu58Yw=tk4$La+!76_ z8073kG(A53XlskIqw5o6e9iMqznD=pXBs0)`ZFuV>Wl=4uqc3(4IRa<6h+Kg>pOld z@cVvyJlEp8$o-*&;M!~Le**N+q9S5p&V7sHZvC8M@Yr{Cb-zK-ntO#Hom5_GGb&Ds zZ3|nBe@iv#JGEqG+4=qAJyX0CqBP$sEmdkR>6~&Y8MH>3&*lMV zKyP=v$haoa6aFPV5)oBD{>FzX2GcPy#B1GOpk(s8NjJh9GcwDgpv=*VNrb?spCm?N&6_ z>0t-$HzI0VK`(^?$NsKA7b7+AhBwPTXy#frs4w7bV>I zf*fdT27ZqcbGUUiJz-jVc@x5ArX4}DIk9I!whYQ88&gMXiXa3Y7 zNkSDTuz39Mcx9wu-Ls!RT-ncPk}@6cUzeIea|*F@@|EoBE7K6E-;&(<6*Sh3lcBZS z%qC~+!F;Rtexqyuy7uYR*Ogx+9pEuF4Pq5Tit8|Rdt}pM?)47yM$J7qs9UP}zDzsA zw-Ls+wq2?J{u|gNFC%4rgze|3Kv0dWz>b!55jf#v1M#BM?8F%~-^vJlC2i8B*0kz} zm4+U61-W0$a9kv0TAq=8<4)MogR9%-WkVQ-;ZjWE=E$U4?9`rTiRLDAItrC@3b)rS zpNHPWNlof13Rw$!&0HEXdQBMZ72&Gc*8b$%|~KX`OnBJ=M1+eOqp)m*8QDf(*`(`K6t8m)<>!BGAU zI1H`{uvCN-vLou*jAhrB@O68=(u^VA21gQv=qz+@^FmoH89?7ZNx_PTd|;eSWp4#q z5=Eq>+u!JJAojqMmTzq@%K4gS(PWSGp=Q}-JGIbu(xxJK>yeq8#Y&sDqa1UjP+uw% z2vW=~A7E*UY5GX*@SnrYD2e|+_TFa6vLrduGc!MtRRA%Z5g}iRT=M;&fGY}x91hS` z8P`p@aQjj7n>{hhTtreh0J^IpBW|4IZa=D@(%AZ|Oy-UywROuDjUw7C0or-NuPu|ZXGur(sNgY>wDmnaLNDwRU+{iS zN2MReZe3w?Us3&Qq%qS5Ez`uqEbY!XuU5%1J8{622KX6-QX*42ref7oEmz=RGGwzZ zEh}nH-R1)lePBC40jHb3UVq+@v*U2tr=m9k1w=v6J65^;puzHFp%8tB1^g}x4tip* zXi0&R+LQ2KJ`CWLJ&->?Vhj%wG1L^pOO%oV3ve#qRm?aNrOyBVE)Qa>mv;r>mKRfd z=Weyy?xYOW)qc20L@1&^8?sHOQaWchreYsU^jYVh2@SxeJjo;FXCr`#?y{k1<8d*AX1Z$i%q(xKrfMDlwQ_iC7#Go@>o98)7aBHH~gQ)u~tmy?k7Xt5v zfyf;~*<)09TsItZ9_7s&$NR0eTTB7YC=!T#F=;tkJCBYr(tsX!(U6C{0!_={aa;4( z+BQuA|6LPS|lNF8Y9($W6eP|lBm`pR8#O;8XF*QS4hx)~K7CC}a8>E4tI8WDZ0 z%;#PK$jt>P>T-gV9<4z*xKG9i~Op+z2&o@ zoGen6)$+bPQa+5QBge^GGRXQquKEP`xT=dFPzYhEKobs&R`k_`9DNx&rw!93I%LE3 zGqnfa1%a<>q6Xv5dRZcq*(ub$#DBI-Wvz4gYz_PsQB7#uKSV0LL#sS53i3p#R!ujB zQ&N9{NfnW6r&%U)7A7Q`Xc)<9Kc`k|wd`o}1-%uS6IGSs8SmYkUeuEq?by;$RbN5l zq{u^WMv@gsEWxx}cz6&!5o)kbnxOIbQ9x>?JlsD!NQs+3Ym~g+uBRK7+@XRr@1Af;A~X^CEM|95szxyz4?jFThLOatSiJl3(Y* z;?ILZQR|S>_U>e*Y*lH}aeIM%JwFcuF&}Y(PAUf-Rw-;K^prGUd8pCoFcq1X*{{q6 zoXa=6M?SBbED zJqB>Ul#2XYQL0*SzGizvTOF&z9+Z(y?ZxBpRHOG2-dTI%lnf%7%@;s!bPPj|BWoR? zGrB5+o4Z`m0g<1UnYpALMK@h=+1>XKsvT)5hpE}>X^nixi)iYQ{qloQ3>0B1-A^K~ z%Q90{Tbb$leaZcI{`~QL0NZ~aLq2Zj728Rev-i#lY3>~xIAXM+TF`Gb@!3GvdP9W>Rc3}WDn zyh%}fj?7p*kf{YH!ic${;Tx=%UMs2E6{EpJBq?{iM~LI!DDZ^C%2zaeVVOM9uwQSC z7Ijj^L?m*E5{Ak1g|7>eyR`|qt%x9>B9!bJpqB`+I>O|E@@+#Qvt(B0zbn;=7P)Ui zzA@Y#?5z}arfTHaQDw8~K1bwan@QQYwrIQ&Po!)t>vJVpwBV{mOW90%1bz?dGTCP0 zJprcCTH8Xem}Hm~lUcDnxtL1raCc4^G)a2rZ3fkx*efT3O-@cgO4?4maKeNcMKql= zz{h0`@|dY=?3cZcn$xXyanTRUuJ2P-29k@H*-T^7JK4J?Qy4qBs~10O37CLlp4oR> zP>O*m)55Vy0NID?dg+Ime0OqR?&O~JVK4ok1z6%PFwiLLJcO1?I?K(nmnut?WxnrY zF1f4#0Gq<)s*;3e_WgpK3fP6jWBtEe;{!Hx_ZXHu+K|R?p?q$s zzV8aQ4tDB13xcdYW-|I7&pl=3+Lr%R!Eip%)l^6W&x4a%tS?7YQQf5H?KX zf>X<#7CH}6r~H_^WhvYfUz&0Sa_SHXoexPV9ew_+DA5BhMWwuXF>&og-MbsCQt;|# z%a8*~zmBwDSCeJOww$wOt=B1N$@J5v2pctDK$(CPZnuK zCRs*I-$iH`>o@Y=#--787Rq%b#dYymv+z^i8LKo&uI)gn6lY-_#4AFl#e1Ybz!l|` z)2ck9GMR*gMQ3Nf#C>na{)a97wh(;v=jAWo?w_Rr%c>_0;A+FLt;@vKW$#^FKE7-? zbX6g5l`(bj^#CENc6pPrUq)!UARMUJ`;wSfRZhG)`unUxI_C(lr3e!w0iCQQ;tq%%t5kN=itiD-bclO#vOrtQ=079Z0<!Z_mM52aH6I|K zX5rz9QL-GQq?B4V5Mi?(Vk5x_iefI2`PJy49z+qWsa1&%BJDrZ1YZlGm40;?>6AF}C8dMJ zYlU5tOI(tB!Hz4T5oM4vgp$H52|MICb7M4HQk0at;%*CWaQtA5anklUj#N1rL>0&u z4O&p{7)J(OdG}P*NUT+bkCqCw)Qid$IioqyvzbcBSVJ zcGT>?WxqB=SzBb$s^mQdmc5J(lwBTV0po?pDg<%g`|DnRqDc)MF%8P|dfEjD6lat4m7_=WIO zeeM|vUX%nANlLLIct9r1zm46~-XO)F1h)_)7Dw{JuW?EYksNP}rLr{CE;3*89_wXA zn>(jEC|Kwq6MbC;kusn(dXwcHSWw~$r>jQaU?(I!cvE*KDyx4D7&rbXV0g%f)5-gl z1DE5}x}dY0cMkZZ4lzL1T524bs#_0jtHGQS~ zrQ2+PPV8_cyKMUJamA^YrKoXZeEyh4?g8YAwwn8D5PTwix4kx;Vl|7Y(8+>R9uQT2 zAEVFOe`l4t;vrz$FOMfFjQF-{*P2r_cc}a8asTgR#z@WC(yD;DLFvByrJ$n9OjRY!@- z|E2^sF2Mn_4~Mk#W0~Mky9UZ*upB|Dhu_X=FKMTGr4gjkfzoPB?H47b{>iVj zxu>X&rmit2E=>lR>+g47^%8r~j_2$~ggBt21XMIFW02hWX48@R4C0pFCUhx!JT8@> zP)dP}jt?V7hbnDYPX)$E*sqJ`2s_Ly)PDO)ENE9ONO=sDOv^w8VUFF}-o_71jyh;KI0Ol_cqj8K z*Z)&u*nBzFBw+NA#Y6;oNY^vkHUv`}c7_Ul?X2YfxrpQELh&(}k{L;Zt@d~fghDGL zy|Bq$$;*Id6#{WEYJjwR95{kD^W`ApYVDIyIZ5KOd!MH~?IPnjc`Bd*uWqqkCl}E> zKf*P2wuX8E0hH+RxtD2}=y-6tsCdIhOfDwqxfv`>`gStFlA+86I-x8wP_Rp@a66*O zuRzqw=HtA*lEt(BF@H`UG?u&5E#ID>!f?juG?-i=Z?+g^_G6C1t#?{EN);9(jf<_P z8RuPUjM_RQmKbrjxjldPy%%%JrVQU$?%*P|d#D?w&j=OrrqHJ)p$j&B1fxU z&+v-9`Rjb3A?iTwIB_8zvNIne@c8?!Yy%jp65$yJ?4tcZrWyPQ{hsHMrAr=rP8y82 zLH$fMEQZPYK-PCB_oeXUwZ&gA^N7GW2i2~F;U&a~gNh;)Q+=4Zzg|_kAy0@ zmS1OR;hDiVBcW;WW{KblvnbKm`>-OlUY(y|y&lQiEeTd_g`<;7j}Mvy(ZrI zLLK5Ja#*Q{oW24sxf1pX+Z`$j8f~zgzOK_VTk0`l9cuRwCJPd6Yenq{SZp$9JNdJu zNXAshF0dQFc-c$x-e}Ki1j|>&4Ms&8Mg`j zs?1wiK^U-KDQJ6CiBu$$aHFX=n!(@HZOTZ<9^E%um@~yiQUseUIP8}C z9-qZK<8_A~6xL^C`c*PSbsXpKUTeuC8otitFBT8G4d@Jh_10%XwF_cgXu_NP;a*}z-hQh8y=pbZgSMYkyw7J;ad&jizQ zY7a^lh5%*f?lzynG|pCxkTv(QVu7H-nOiyrbao+j2{urEFCF=SWA`IhY*K!zX@vGx z;SL6u_Vd+%X|iiDri?~)cOk@^@7aQe&E|G~M9tU9^4_e-dO3~abF_qJmCz8z_v%pH z-^f757af-ZXr5@xuX@dK|J3>S7V0V{64pcEb8k9|uUos#JAR2cs!R0bq&mdekevmy zV%lExQhwu3rT|S(x)7gUJc!B`kri2zN~6sqph`^QYgq&CLt!i`vO`4k+AiB+ukHW# z_s`e!eaU_C=f{ta<-Y%I=`xKV`d$)u>#jkzfbNphKBBUdnMeB-tH92AxFGg$LK1w@ z?!|bsGHnOAIvI2|Dl9CZ^$o~9>y&KG)DqUVMTuS8iM(*i%+`CvTu2wSFD{9WA!;#A zSMt{2SorZ2Rdq-I&UNh8LA%b^KFa1jx|n7o^X^0&n2k54)7XR2LURVf=AJ74ezPT8 zy}Nc*8r|k++~ohh;JP$c8Xu)em=q+}cr?6y?&Ckt1G7e6WQ%A@j8|u^x=64hRE1B~ zXf+!YzhlTKDTF^x>EES%HY)eMk|X*VtoW5u@(s;X^9fUI#Z!bz0I>OtUrOlu;jR!E zqpRKY@(&87yk7{Y`#}udlxO`RX(4;oapAY;>E;kxq+OUK8 zrIt2IjlfX9(ypAkaE@kNDcJ*flx8wRuRkrF<`$2%I@@MU$vQ zO-Aal3|V)Q*dyWt%*zaCA(Q~OF-CKh=1w?`?T(@qF)B_4SYC}8@sas{pbifIR3U~- z&R_QIX){((YJ|N-u$b)@G&~6s&-Dc1oYQ zfH<1kd%lbgvJ1kksF7W69K1Tqen>fMP{jo9mHu594d;E;o1pb>mP(a&md)C2UGnVv z$K*SvqnVIkv&gR?h+u}=^`hma8DD5eT-Z^#9`k$dUY&(5{(Idgzbl}5L-6k~Y=_It zGnSU?=YEYMXm+G+I~8m>=hmB|Q7OY-_!^`HpO(|Aw;@@llJ4r*@-!^O70%aXq*k{6 zdV;9la84J`vVUlG{*TdqLheD*a5<=~OyH3Mr(SftXhr9iU1bm6Yt3k;XzP7iN_6Hd?Pv zP!MJ^)+O1a_EsUvP!86iiVi)+=(zAMTFI~P(}Os}PSgJm&MkP8s8MB!Ua6|9&5R{4o4A|K1-W2r8)-z|jTcfI7c zyX?P#7dEzJjxUs8HHp?qAZ^U!T~RxhRGBGo55suN7V=+0HDyN^5Ad4$q`>%CA4Wnn zhH(IZjyWHK&Yb_R@c(5zE$*C9b!sw9;%teKn4bEa z9>$%g1;1@l0?xjZFTGkiULL)AnfoAAdU5h2JAGr1IE6H$LLz4d`v?whk{u!;h0pAhDL< z@s$r|;k`qQuNylV`4yM1#=4{ol=uA&V~31`JxO|l9PNNcNi6F}>)MW8gk4j7m&0(b}grY}tSMHnqt$$YPoNTiI~oru7AvK|BWsJz2Q zTMz^4%KC`as_@wckf{W?xM`gcH%kX)xI6*OWsJ+Z8=6S4=^9H>iPlcJH?sv){{jPSmjaeR)oRHplFdvf}lfk|%V|2f-IlXX#6xRq@!w678!6+nJ ze}Acfq-Q*e*Nm95F;m1ynxHF?td9g*);q2$ys$LrJZFMcAz>w|>-XEpqypLU!j_l6 z&NL$S@U`mw2;J20MfLhUFS%zu_F5l*nEo)+9|G|ZIYcCjC!}Xp#dI2ozQEK&OyLY2 z7Gd!%m=DRUe9ZAu3PZfWu&v5uj$%Iy6gf{Xpe5(AXe!#q&xox-0gNP6TkYF%FrlD5 zIzY1#^FJ4o$84Md*~%SS?i=FaZo2w~oplU}@!Mibh`6it2bTu9001BWNkl?0abWj^4TEXXc6%rK26Q^!9Bk9rD-aP3Y@$XD^fz(DM8VtiJn` z5u}MG#hgispF(mc6M@7PwQ`2jA=fsPAVuC9^C?f}X_J;-7VPf6}%jn%Bj zfc2x$U|MH5e448{qgS$H*Um8<5$Z^d=@lOns^3)JzLEW5#BI|6SGesb8TF*`+Xdhs5 zOQ8*npSnuBjF%m1oG^!)wj@?fqk{`S^0H7{dR*Qnl{e}5zU03A^ZD~7ub&%fh%K5% zEJBaXtVfE6s&M|fV-PgbE>i*(g+NEK?#Q=L<^*JCg@f7`bsa_9ViG z;xMpt>Hv4FiImc}11EPYV{65<9ANmJROn zo1oQp7I>?9r<~}W!OX`0F54lzS0Md4M*4x;P*tW4#|d!0B0;5!WBElAg=lkmsrcfc zWPWw{cRokcb8<1jhQ0&cAOc%xQONmE2(Hu@2h~(kq*YA{lvVK3?uN`ckf1j*h4s zQeE+kc`+)dVY?SF?UTeXv^QgB`rOJGj7wKR09xTIGIZ||3NfG#A%Zs{|w2&jM|?U1KWAt1w_SJi`)6PZ-6rjv!RQt@LDZh}Wsd0uRM3 zz(p~Ura-0-koXw-u>P~l0Br;4ER~WuO%Kl zT4NtEgrLbu!N-+!+Zl|xpQ{emL1uI%7)Asar_}*7F`PquxNGK-A15a;TU2RQ@s{EO zO!|&C?oQ!HvKAl3hR4{=BK^QioyckIolr3C4`q#UC1X1%csLlAuCe>3ac&e5JdZIo zfniW+7!`_2()TDk>lW4sl?}Pmg8)- z-|as6Jps*d1>8VVY*QQsPmC)+Z7!zO+O+5%qGDQTpMBmIQN+k#%gk=>Zq0M#2R%vI zus%#i1=!$a(2K^IO}rZ7E(=xB^2n>tWGbwT$dC$Hf3B0^H8q~e{>Z(MI!XV zw|Z0qYoxNBlip{#fzZW8kXrc#BZD@b{Qr{ZNGBLKJFJH4IEfg9ECk*M`>mm*k<*CY zsr#2iId8E~rKSoRa`aTBIK0ZzwOnvqOiu0aI{pS z{(O6x-a-6M)=+y|^I4`Zh_QYP$2K4OmyvxY*QbJ;v->h<&RY#zg>o9|``O-b@vuRa zavS~GY!cJ>l_&xd2-Obm$h`+Np;k3KvL?|~+a|1z3lI@NbM&ZoJoEy2xy$G4Q+~dF z%E$UBUtPks1!AW9pG@_ec=FYsA3uJ;-Ct`(@C~fR4DrjeSlnbVU`B4Fe3vO9Vk1R(l3FJ!%Czes9-vKa9TGi`XnAUzVyYTiso zig`-*Eqrg8tbBZV3<&OOFi9`11Eu{L{ll4GS5x`${CMyM2Sk=ei^Amuu^Wk~R%DbK zL2|W^83)7eF%3$((`O6@5Q8Hiy-l^X__tEP3Hg%lbZ6oH11Co0lc(&3L+^ibM0l}E z^JjGL*b~OORa_3`e|0hgXmr=9073z_mj3|f+KrTg9woB|C5sym^KXe69JfYUDvCgx z)-l4LVh07^4RWATz*9(s+z5H`33zm=#8PEOX1%}4aXlRQbS@30=ZJlswTe&~U3`O# zee7hbR%7Z2gx(b%C%Rz#y!_mF$@3u%Ql6FsEh|7%l=|~Gvnhrd-#g@TMG&MKBsvi) zF1^mr^DLkLxia+vke{zl`NLoG@jSBDqTTfgzWw}s$+u7Lf8dYG5`isu=y@Q|A(SI< zH4|Hpto4%ZIODb?7N~_-WExZf3J=XBT)t2;fDpuOtbL6a4|8@WnDguS-*#R;(%vT@ zq4(M-^K3`z5v-+M>c~zu&bcKgh-c>99rZX7T)MmN}89UiWND9 zK&o;DELM>T5ddAXlofbr6>a7n%m4cR*DWhJg%6MKt^-$TSNitva+t7?MPrT^u6b`( z`BqtZ=N%&ua-=}F8ur@7Y3y5x46-X`h~kdTMnn<(HPw&tye2;COw~78A;zS0ML+oM*8a{ja09aIW_Dl_ha3=24#LXs(TZL0*x3Jc^d{6Q93L%lS{|uBG zo@1%1vR4c9$*)G}<)N}Y40DnLv4AHJF`YJoTTz%JF&^8FXdUhj;`diF{}j}OAFHe= zxsS!9>{xhRw-9AS-yT7tltd?JldMv^JY;NXCrpT9tRPAVV*#%-87j;S<)yI60$Ot? z3=ROUONVZ-v;v@UXLNMPF8H*LFlM`r@tE7*RFl5(Macq_V^aij5I8of!6&7Z_w*k( zG#qu|vA1>LDxD&sG&^FgOY*h1is;hc>yG2Zp<4Su6BPi6~M?FHyOr zCSu&*$O%K@vmmZV5e(}C zSCzgmWkA3zd{m{n&AQl><2La=g{RA%UOl7AMu3wpxQEETwt~xIy;)C|P z5n=?a7}-X?cB(^l?gEsG!v4sWGUUR%PDGKBV6IKjIhGtm+5_PM&|M=a&I(MjxeF>f zQWWi@!!LHvHQRBN;#0#8;n%phe0dzZl*;GqtZBc@f1gm8?GXaSZY?QD+Ti!{{M~a{ z`oAl29P{~T;);rI7vEl88&d3-2_@$}+OOB=e|^24*Y_p&#h=g5{qytZ=l|(@|1`n> zgljD2VM6pRvh0z^UWadxkY4FD08Xw3W>g5Pk4j#qXSCua&u&wyyU&pk2}?+<-W8Ze z^>&T(hG9Hj)?7}L7IMm_h0sR>oZ@8;PY87VvkZ!*XpR&%%QbpM5!OLrr0;Xf5*ZypX1<)g?2)xv43-F81@O_`bdsR+* zza=E@-V*le2tmRTuZt|Z42wh!Q6IU5EvmV}!qV0bouFWTnzUk@uAh%=z$#od%nZdI z4ReRAJ*wAPfGCIopia^~LOMZ4T+>GX4xMgYT$sK2$61*o%FR1-Jr%PKtqW( z+&v9~k-k9Eio>RO~JR+K74emsV?^lvkKCxd_W$G59Hewn z(lC0z>R_V6Ky<}?J%6?gYK+Zas=+O#(ZY&Esr}2){m~`1NiH7dJo$#Uy4<+dJ{3 z6At!9Oz!3~rU()s(hjKYzvvy43mF5~DAe3r9jdg?N=6RvjX=L29_L3g?)c~`nri5( zE+G`=VXV^0+e)&MRC{{*z|vq}DpVgAasI`PRpU$A!fhrczA9C-LKf|Z!I46576j0a zxJw!aIPch5l~5&B+w?0kDA{%B`(&d!lY`>(+Bp);D8I_3JI{=f(o}dYk!k7Pf*DmA zg>d88a+haefe@OWD9yMUk|7b4s!^;;6=z=iW_`4tMAIe9I?&asxD~Ty|F)j>y_5U$ zl5-eD{}r;9%M!tEZ;$r4a6Rkfn5j$n#^b?+sB0Tz(;r8nko|H}#gzn$Pz>h9#`^** zQOc}3_a!pO=1{}ToCf6b5!H2ckv~#FNnKovW9S0aDJ(__T%2|nCqQzfDBwzcHhCLQ z4Nq7Bt~1k%Fj%ZELtk4-3Q;;Na2=X@^BrYosO8r)(WxdFOhmNb@!BfZCB;IQ0mc&g z99f{Dl&OU`Axzh(I!Bzrl+0uYvy}Mj+X#p+i@u=Jn`L7>dZ~Vfqp2 zz-oO`&zR2C37z_(GahycJpqp&WhAhGyl+~5-BzhOwk+}E@=j&@5P_ZXWh8V)Shb0o zJ%IeLd+$HKFS)P2sgLEKuh0M3`_n~U0^OpriuAS+%x0LCg#%2>cWyJBk zl$7*)YNIxFvp#yt%QhH1)FkOp-2m^edi1$;z4|azW3f6XGQ&TWMI(hC`qCWz}9Y-*KzQv53Nr7}5bqhZv4>+%r6vQKnp1CQSvj$cmYS^fA!?6c`%#zH2$029H`SGOqedbV8g61TGB3wn;j9p$!}0W2QoYfL zcd1codQS~hTBc9;`9Qp>>YFb%)z8JcQ5k89?8g<=A{6Dm%%xK`jDYCl^QYn%EHDY2 zVH2FZeoz)_4b^M@-zpPSkjeEF-vdB=hq=gb&I!{1M8sKeRHED6|0{sc?@R8BKYM>J zVE-poJUOm7^m2c)lFv$oiJt1p$xvzB zl*l_ru0|os4F{{J^q{qZSJ_o#C`kR1L-W`R9aqxvDn7K>Io=S=4y6S-E;lf|rO)Uj zV|47tXl5|uVWZbn1F@GkNC8l1%ofsryTml9%xC@AsGW3G- z{=+MYMQ#hQcJz{Rhud36y(qok+T~>!GDfB=L$o#)e8L;i- z@4M(3ycZ>pDVx)a?r~lHXUcMl3`8=p$#Z;fvSlOXL`DKHROhajTC_)>EsSBc;DJNS zHSMrb4&^yeDpnFXl`1xiU(;So5GPbcE1dbRT3GKqa`NaItM}AY7F2dBDk+s=Q{k(_ zZ*)(en5NSK#;owjgl{8Ky3;;SsrpGVNi_scrgx~QK2@nYT=ss+>-DNE&1XHbmAY6J zd7cFo{mTpL`F+X#(?1^{AG&@2P*u%ez~NNx^8aXFGLb8$X0hBo_^#~sL}q#~#$cNA z;i}^E>jmyd88H_0NTSZ%uB7H0&eAxg`$nUn8NZ{%mW$Ng>{JUQlm^?Lm6tr5$Re%l z4E&jhFc3{GGO)m(M?Ad5PHbjgxsKv5b@Bq`VZxu0Rh(yCETjM|U!Um+jqQR2L-?RX za+#y#ePP1}?XpMD)n%hkjvV(^V)Gn5_P7Y+X9H}8TIQ$c=#e&kZY9h?cP=a(;)+P= zXHFd`dorQ}5p$sY=1QDvdRBnrBR0bHdzvm&)f#s;oO6 zo{N2}XCLBab2)S=VpvM5f=`Cy-Y7~_Jt_VY(MME8pO5FqkB=YveaU_GP5t=5v-i(s z3-CzpRv%JZxXWwrkoC)8LOSKhWxGDoj|s8lDdoD2&NN!+!!V@KbV=%9^6~5H^p8>e zhRQ)44FnOhFT2y3R1qDOqgUu?AMiZhQoVgS5~!!wdz*Vw}mFi8Q74MUQ zm0f(swO*r`RuMYD)YJm0Hi_ST<`Qn9CPo~}128MUG6$o&tj$Im(n z5#GCN{q8@0e8^)N9T8p-2o|>)%Y*>&O+ax*-6EAe~l)1h@z_TkD@c5^HY_J z(V&y}%sSo=RMDVA0Xrj<@MapJ0NG19;4H4ni!ObI6<(`HwH^7B79F4E#LQIG)&X0j z_wgWtPTj2XAF7lI^?k|x`VZXI;m0$Z(-AJpUN06HXN{U9A7fCB9g?N4XPFJBe z1#e+;GWdFZ(f9I@&F#5x?J1=7-_FxTkT8Lim3|$BJfN)a1#@@H^Tjvar*cYoD;|w2 z@KgbE_oh?H$iIXc-Pu!#{;UaY769{}DuDJoHZWx~{1Vlb4d+G`OuP0uP_MnU&{hrf zyD`5ceWC(Pb z1-%MTgjmXAocpXL%a*KV@~k99^?P&V5vFTB-<{n5$UP^J7oafxQ43^|C902@>`1y6 zdBv{IwDXRRQCH(-aN%TVP5sh4`yh3PcPNzV`zRiWkr zd8-`w?^V-AFklMe98ASFnN`QxBz&jCWR85nO3h0>E7z8> zVaqxW#S&;}v;J7?4WgVD%oj`{u~7hl`21}26oeyk;Z+u{ag94U&4d3l?DSZ!x(xgGn}vuK^gMGq&)MjQJhepD zW3m=x@ALWkcKP}FQ(m8+`dYu&weoxJwO8I_Nn&G-nMxuxo z5qtZlqt%)m!6F1YL(8XAjJtVg4NxjWpv7gwM`&h}pN$x9RDNsQlJs^~gXt2^x3orrK+ z0IO}vQxxAbE*T?VJRQ18Qg<3R4Rv3nQKz@FEXs5#rFwG(IxM>~#-kkph>R}0(+$|e zcI!q-u9-M7ZI35UOO)Kmb|iciafRgdr<1kK|_z{@QS%vD9*@K!PMT+d2`~tXWz~$kyrW>Y!;P>Wnh+zmTMdSr!M{>MYr@%-2@80+z@0PvdBrp}0;Ke%a*m^3a zWWc2nh$)RHe#P7qV*l|aL%XeL!?Z*h%$5wrB0vh_?v@VaUxtFN!P42~_#mGfJ+XOs z_5`qZ9%4&* z(KZ#Is!>#3O3?n^v_J+5&U=%_eCaAgSHCp*?Dg}W(+^2=dnC|K)y5A5+<@mu)N289uY=33PzO_(oN;{$P^jAM5&)S{~0r4m8LbuRhUI8 zXY)t@3`UM3ha4-zEf80f=9{~Oy`yzby2$5Gm%V#$>LU6QeO{37o!nP{_Uq-oU;n;T zwz{2BS5v*Dwd9IA#*ObMTF4eh5!l*+SKY^ zTA-mdKHwAEufJ1^F4A!(oeyUt@U*4nK2;$)M-Rx^e#wzrzIl{l5Y^oWy+9l`_Ass1 z!d03dESI7*1Y=j=U8Nqvf(B;u`5#C<}KW#O8T)%0*8lQ5J*lJpoz6vEta zH63<_Cex%89tAGf2vU|&N?5%L9zL?%iCcmoTnM$7`?b|(?$N>d*>!pROv$BmKl?Pd z?)D2i*2x@akB2_%=qXdu5*VnM&>m|mI{f$)Gd?=*p<=yk7m`JaNdN)bSLk-Of%|Mk zOUUBBV?-UA1XtY~e|~QN9#?+#XPN3UdqhOtcYuAZ6pVg8(3s2|Zl(K)g2;@d^P?&GPz88val~M0I_Z;M_g9u%!mrE$RY@V8Z#yI#`6g|K#x;Q60i?O3M-o z`IM1cC%*!jEAtUWn7%a*uk3mRiTrk;r}D`1_fhqWp|#LBhFkfm|Wd$`>1nM1%`1 zi(pX(5o_%db@aMqw}_xxiT7n^N`OLu6`!Y<9l;1k6|EY!rLlI#LF26pu{wZL5S*r=)U&ew`3%6-NRe zKw;2Wk<-DI(ntz+jrQ|l>MiQ6^^u<^bFatb2Vn);yQ)!0+1cR?EofksX8yB)OfvhO z$}JovD|5F~heq-aDIAp*qP0^CrXUKyI;HSqH^SX&&zgOon!1&7UL8>$rdBg!9ivWD z9eHE3G(e4vO?7y`SG9s{PX$vzU036W2UBN|0->Qj=#(3ji)>?-Lk`SbfpydryQet)LA{1jhP(P>4imETITe?o!aV4&3 zGq-YB-1YO-9)m_f`S*?>M@*Ma>l<2ZkQc68S25cbikCMwXdbagxtHW95!#coAVb&5 z41^CX8uzN*CHZwR%zdlys5Mi|Fn4UF?mlC#A zl6UYbT`6qXYZRQ1pV8RT_cWmlmwTDwk>0XWbI$rkg-s{j{k1w4r55$_&JJ_P1yUGA zOJbUH53LAt)Cn2Z+QnLPOYIR`&$&+H2Vd(H66dk=zX1O>gMans_1d!chP#(c&^-eE zG~?J&i4>|{i}#dVJJKfyQcn_0gCszAg7Qj0FsAUqgA#7RQq0Tfz)9I-M2Xx~nGyn) z!YWOQ6cX861HUB{Og^SfMAuhBVio1yXqLA|qI0Ew)1^5G9B36J%XTy_B7fsV277U& zY|o!S1Kx{5KshNd*QJsaTC!UKgxq)dhF0++t9y38q&7UpArFyss(ECvz9B5{!QY^X zQAA0HZ0hJzd%+JLiJP0>!1jbzqk+B)k4M5*fb9I?n z3Y(bbLq!DrqIhRi-8rT`A+0Vh9NW~Q2%e9socF11Fl|SvODBXq*+rfmdZf;&A0}*m zf5@Y{7gXgXa}@uzfDQ5Y<-UAH2U8b2J=@5jTR>1?ai?bj^);7RSb?I$4b!Yy?;U%t zU}P)RkyTe|-!kHD3Hz28Cx(k-5iEZi;i;|u&F#%T9Q4XryV&o>2(^LV1gmF5UEb3}h2Y=Dw zqvWfH7cBkvv6pLg2)aws9`E$!rDI-RN-P{w`U<|%i56O7XJ>iF74bc8&ul6dK#;te zM^7r19$qhEdZMJW;If7rkmY8Lv`9t!1?x<%_DX>awJG$`$iDJT-3EF11PrV0-|NV5 z%Mi(Nd9@g#==?I(cKWMvq-KX|V>BuxOu;qW(@ClxYS2u>RzJVbirs-;j7g$=fV**u z)S>;E6yubw44|yK992idFBbF-0zBMtkg@ zCfN0yaUR@IF6MY&Tx64|Lh1M9r;yBeoF^{Bvs3n&W{!p#=Lpf?YzQb!TSJt!geTAd zHRn_#d}(Ke&{hH`A&@F%dQ;J=K#+_?9z8j143JJmb_t<4|F42dmFPzCFna9miT7$1 z_npDdv5N7Ik%G)fsNRvIFRvK0J6`hn`YEr^mpmU!B4axE!FDDu4s-W!b>)}e)W_rc z)BXb7ftks5>^SFvwQa+LmS$&^Si-|n!lD4BinoGT-r0(Ek?N(0)FN|p@@5;kLpH1+ z{v%5RuWT~pLA}~+Izq%^tXWCFsL|yBz-o_4!F(Z2FtscyjZ?L zwE>yVpWlQIc*#`dh~ywzL-`x&bI&NAx(G;=kkt9YfO+mrZ(6$z;h<7BSRECrgfT`aSHd2`k;B!-ARUHZXl-k)Rzhy-EqbXLJ*h6%3Ri9Q<@mnyZ=ypPxCI*| z{Gg1#Y4FuCs;*v-4ADaxmtrO1aa;SPG)7>RW`P!uFvQzwZ=2t@sf;A<+3m5rJ^Wn0 zI}Dc${^z+gAy>6jsIIiqRxKs{9MX$1!W8zzRT1SS?XQeSIhkXKz0SxKV5xg-`+RUP zsf*3a$J*V-#txU=6AF(}Wk~AB#VmQL=n!ie?>?a=k@5SeR}n#rR_a1l8qeMoo1~)D z6e)}gr3OYYEG;mB@)n|;;$zE^B8^r}NjVCs|2Y(~iVjn~n5)UI9GQ-l2#!%?SVkz} zz&Ji0k!M*%4>dk8-{W=0mAY)%vTt_f*WZ-=@JB!Y{jra2so1D&;Le=V)Umu2Uv8Wic68^l&pQH>|0xpy-{i|!sPc97^MFTv?}OwWS5@m^uysvp5Ao}_~mg_EiQ+RxZv zU$)#?=x1xX3Fpn>N@gF4$s}`cN_#5@t0?f9vRxA^j+4z1CP-#|srl*xw+xZ>!34}* zW>?Kp=JXmDlRu-u;aqQlB>(=_Z8Q6`Q`Dp2P^Hv%3~^IUKR8M}pX~ti^5+Wg4%Ow1 z)4S_d67x89`aI&-%cOCqGiXf!S_0**^Dv%RXmHYRy2oy#utrT5INI|lDq@MfIF}P8bs6}fM*`|Am_t1#(ojb?k zhUWg0XVu=tONmq9GG9#ybjPFkRKbweDb)j`KI7U|zr~}4fShPF`4`|D>-BXfr*Me> zhroBvgmWBLi)w8_$Fr80Em>=c?;WGPI2e5xeTKAOc|Ro=5g&72Hx4xDCCVVJA=(n) z=&ZUly6R0>D0d9UkLWOej*APef2;0-0UW|`MR0aih!K1W-)4AetL)<1I!5H8LBFgt@VV^d(k zf*(52H7{_hpQCq=$;xa)^BW7b4w^PX^Yp-US}kh$7z#VR5)SwxfpBvaV|@l2Xg|jV zG?pgWK2G6w9Am}rVe=o@*EW}S`XT(a%x-2lgkMzFeb7Wr`M(t}$ETPde za`tI?~6H#OAv&;>)qni0VN@o$AEQR*_%Qd-7_(xyaDRU8Jg{*OL4Hz zT?A7DhP#_-B066b8CpgJ97_$3M}iR)=_Hys1t_*Gbs7;P%f_`YTdI)>m-$I2#C4%|~T zv*U2_F&-T2sBys&{z>&0dprzsN^VT2K7tjaT4LPpToBu*(`gvV<}-MeFbd-uP z4@4lRbvkx@?BG`ttTb0qN1m9|h_%(OEcC#bdL)r$qXifh*eZ=>12Ce0yof_M3EA48 z72xj*Rc$pcl_g~#L3CPKY#}BIZmb|~UV)ob2iBb#dR`Jipbn>KEy%BI_(?%gTRBHM zzfo@p_9>V_ELNdxKB4!i3$Gkg8pFEL++5{%Rb~N~+{?m&kyqAY)O!9ItBKOE_K>b% zh^JCtuwys8q@WSL{ct{G_trKJdUwvQ5AOa6_VavSa{p{xDQ0GWJkMhv_9379XLNA! zONmUVM;}qVf`Z)<5T`-GYH)_R8^_W9ML%NjK(mQ zzCZTo#7mP^GG=6bAyjzM)<}=emb%0qkXPLBHqy!GSVAx1LW;h+11S=Q%q%mdaq6l5 zQ9A^AV>)()&K@e1{4k8uy?!c$kr32b^<89ANyt3fy^v&)0yqRbN@1=;2t%=Uy$@89 zR_jm&f(}{GXpDQ3T}UzX*wx!=F~}WGhvpT_&6RqO$U*AA9$Pz&+vXUX%z*`rmfGPd zn=%KqoJQMZ{)T&rZb}G55k)PIxO`nXvW^GO=#?@`P#0DNq7h|Egpr*BEtiUk$w`YT zChR!Qi=ie(!ymkeC@I*TvJ`di@ubps(qW6yRfQ-=yW1+fob_j~GUI}}sH0~?`!hnE z9mdx(WOUq}K7y8lqWQ3?v_?lMoFYq5$BjqA3Lv8U_*u`M*26v};%QM(h%H^uv;NET zd=pQ;0A@g$zy4zY)IUWXwye}s@HnjD;`<=Il3WfsNwrRSZc6hClQ!r&&CPlMXal8H z$-8NsrbF83jS0Nr*yRmnS#*1#9ht{IF-M!nvjyEu%5CzSRODm^ph6wN-I>7q7>II%oA z+O5aPzu3c(!i_Keq?gPDiAm|WKIsOuEXDx8iGhpZzG<1kU1 zkm3#DiOdTqey0ILP~vwY#ScYzL!?j>i_%Kh!RYT>R(RmMq}U%4`DKmoN=5M<~=FzxT|oz9>g#Cuxa zxH#*4vY?*y_naZmwoJ^9($f7zbk*+JrNm=vE&t6N1i!0KZuxrjuahiy5ImM6s(pIt z&;6JD{H_a+MZQ8(TQ4~whb*+_g9ATq26pyEy zSSR-?l8?(s;NJT^IR;p#F(Af>m?hM#M$>w^vx|}XKAPY$l=pRs&_4&48&2FQ)JA(C z8R8FB_6yNoQ`_`jmo4ohz-Tbri^E)o-I*ve^rNnrT|tZe6MWJsOZ5J zy_BFKcfOoVFXki=!ibGQj2rD%1oI|NTTz(IO{I$+J`LW=dtz|;CvWC>O*|P$1vu_t zD_JkwCsbvqrITpHU4J3ok~eC>cJ-r{RJqLa-os3n$t%r}VvlafN*H53LJccKib~pw zV8SUA33d`akzr{hXS^S;8mwkN_|>Mr5rZI$40|uhPLlpgv+%v~&^U|c1+hou^YbtH z`|rQy&p-ZE{#ZX`g&;*fArUQz%eWec+`1}W zNCSD#VMF<1k)$AG#2#WrnFyp)<@V@BVtk@JR^!k_<`b8yEKKNiIXdk)`upB4C#@a7 zFurFu<8i21|9hEgUL=)~AV!t2w@}iJ4o`yo4uCYeKxepcoBaFm<6uzLcZ&~;d6*i4 zNL9#=-07kOuEQz!qDh>fc$9`zqlGM^v+T>zR7TW|T*j9gM=2ZlU6}H7Fm!T~t8<*5 z&$T+4)t$Q8W=B?cUzD56i>EVL0_m|3yM!4uBPTg%l1S7$S5J+4M23{32eDIW8!75) zZ=OXdP=v~3D=Y{YA`MeebP~y^qJDDqY5R#T5a{1ysf2k9k;+yYGgsf|UKb#U2*U`s zL+MjW?@oaUo9O3mG2cBHMRtvCO-fE0ZYHGWv?$E}{&{F8iB~j>NTVkK`7d|u|K{-5 z_a*nGyi$B`{||R~x+bA6J4!?~$g>{#utz@iGnV=kPMFHJTFAyBp)yG6?U$305eGIt z*URhDq;@S5fkt3qL9k3HU%buCCS2_@(@%;ADcZ#Td*rfY5q77wZIwY)G#K)e(FN+d zrJeDF^P&8^j3=T2hRaZ4%AMk!m(F7Fk(BJ%5WiJ3Bu4ebw))Wh~y4Pf4+9?|P-7^Sp3jiti*orc| zbi+^T^mY2@Upn6tQJ0Bc= z1D=j))QE_8FGKbbiLe10g%=tEH3Ix8kGn=i?}L1A#Sqk%+e5gu37m$Wvn-bOX1%+nj2=1!6Q!0jqQ?~M+B5q?eNw7mHWk~R8jyA5{U~ZPa@z0 zMVvuid>CoVC@OsaD2n)b#cG;hs)Oh+gM>nm=O|b_J1AAMK1^?)lB%x9PQO@vkK}P3 z!jXK2jJi5$`4J)S$aa!r!qF*Us1;|U%zj9eIO@FPUMo8tJFOO%-nF@>VyLV^7m;O4RG)LMh(V zo1V83@}AYSJB_NQ+A@ohJPb}`JE~KY=v1rQx$tV9pC>&_x$8^X%aLV2WNp|zZQwm? zeeV64*fm~f)+DY1Aa^~S&N?nZ?QUvdsXLE~^50};Ef#^pN+{8LUCvi*QAO{JXh&Dy zCy%U^#71rI-xJD4A*Q{B=if^i+v9)ue#z@o3L)E=E%Z1srbmb*a**X@ZnL$?bWV!<%$c<*of#w; zKr6gbN_c1&38u#|E)#-VluIKj3U%{i{7d5;9bP09Eu{%L9cpRACP4(M?9#M%ODB@a zhEl+6$&wSSi@0!Ev3v7NyQ7(2r_ubOh%s|jIY@WT|@z!$66( zxCAjxL7DHO$A@Mn(@rZ>%_{^h@4aLu3D}568rmCecB=pt&2!EgA72Y(e<*=cDXbH` ztxZ{RZ=0`m8axNJp2?I~7_fVwzMf-g3hSZ?gsl3(AxX-DM3X>(Bz-zL)Nl7c+Y`gRh5f~EPDiie7-)# z@Cx$CnOtO-ttPd5RlPIhF>Y9nni7tELIayozNyg+kAr(!VWNXI-g3Wh>n2PaJu)3; z?{Qv+U07*naR2!|8w6HbgcsH?MjvOy)$5@RFIvJ?9 zBob*{@I9Vxd>be0Im~*cY+jqz-RD+`KAqPAefPN3SM{-8i~U^wK{m5a+NC zDY-*>{fHX7zI66K>Q9;1wYS|Rs;L7 zqowr6yVwHS>N2#09~l75$~c6tY>ii_RZpl(x2xw;fm|^a_)c{jt=Fg%Rh{{vRJ#oW(XSbyH2Luel^Tt9dQ~cuWqTinf^C3`?e5# z_2p!07`CCAVCV`4opphdX8>$JmIxd!>Gy= zAC!>lQj>`j>raRJiw_RKASw0f+BqF6M6J{#B_dmE#QmUfI(Y_L4L z5+5*kKe)1JFdPId3SjS`{6ZYjolg}=F$yv@(e;SfBf8E7x7NoYLYT#fa-ESgaR(K_ z>{u52<{np^W&bKKrP@CG5nW<-b|Oj17yiAEz}yxf&C#O{BL7IMpwFxlsS`j_N$@&h z*xXf0j@Bre3Z2xTGW7QSh?|uKM`^mkqK-kYDU6toOh>&|0By6-xBYjIi@jrGfXn-) zZ3%e`x0R8ecMqtwGZrJiTSva}vZ&VQQbIhVM)6t8eNtSbSptZxUX7Eir45>4Ua#eKdAW=R zgh}0}tY1b9tz#6|0tS1Bc7g^RG_y<7>r`vf99=Qe6ojYwXtOU%!}+or!7;(lbL{Zi zbnaB89#i&Qjy+n+Ow3FO{Y0r-uP;7_n{VFSf#!*Qz;{ttBD=+q8veqMbZCQH> zd<(Y6n6f=yd+%#Mql1ZqA;^i{t3{y@@?fWry|ZRj4q{h*M8;sd=)KU1xj zalEH{SZb2T(+cbnD#J?ez>EK%y*F8s?7GtR{ZkCs(hF&zsUARP8tGxKm2_`a5g-Y$K|^FF5}DDupS_j_dv)8BRp77&8D_L9l3->; z_&Iy8=KsIHs0S@qO)>|~y>PD3(~4dSqq&Y)2{4qTm~eTPQM<9y2MUz=V?-_Uxr$Vm zX)N`9?m=49#c>2}w4dh~UFBv}$(=#OuaN{SmdairX?c} zK+Mm>Wt8Hy^%xbhDO)K!KC;oKhMKh|dS_bRBy~Othph?VD5Aq4)l>ngXaj` z90zN?PW_J`Q-cO>%`TxKByh$dQyShmq}LqJ0MQs}Dim_qW53^z5nHqIC3{s}{(fRW zhIEG*&}R6wzM^9tAC>W3Lt!c!`DK&T$|U%+ig&1o)1+LfiE7gKC+3GX(~lB15u6S(Nc_7Sh@LOi?UP3Ykad(w{Ok+rjSShN0H${Y*CJkrKZ`0zt)e4iSMS4-2R!*w_yvb zQZ-LAl5uHc^DaOeq@~7;&4#hrE|DXC;(wC%tk8J zr2qL`C-Gb_)%mY;gL^utGdOm(2jsFj2roM1{!kw~CAq%-P6K6xVh#r~v~tQ=^hkMJc)J!wqPDWDS|jLJc_G0tJTBlF|I!Lk)%=u&1Z;j zwaH|+ZR2mI;?vD!d8qxY;e}NoFoSA2L|^TNzCHo zRPT)sb3!s9y-%c)$;_EZ88r4$bsO5Ii#^*dFGzEK!Ny8s=SMlRp=1i?bghIiQdW`@ z&}5F6F#jGZGWu#^NP@lErB5`k?NLKWO8}!X%FYQ#{Js(zqw>1gf{wg$S_=ZqDc?S> zrQE;8<<5l(8KjU_lzlYw_DT|Y;}KIc`S~iP#zhJKbKCF3{cM$3k=)9XkUg;kBTqhP zDeh;gWKAg?OT-1%#-zp%Y^EVZv47v(I^Z?~P4pY7#>g-Zaa6wQktv)86`s)2_+Q5G z#5@M-nrcWsioB_rc|fI{WUBT=44I-|as=u-ILE)a48PZCazDm}UK9M#UnmxFlsi|2 zVv`!wJ0h*Q-E$~wEiCKLt91=w6Az{$hC-UhMa41!+Z03O>kB^G0VG{)oH?C}ACz1n zKAYfGXVQ3B91M--UAg$4HB^oqd&)6!Y*}Pife+Qse==gs!m6X)f680N@2Ias^fyM7 z&CW*4P85Y|SJgM;${+lqMxfS+m_?OFl3S6ylD){<1wue)K@YJ+R`+nQYbmu<6F{03 z9>PRk$sknXbaMALV(;0jS?e-8rGR%b@dn)11QnAkJuB-NsuY1s{+|+B#Ly zgBhlMhs6-P=*lk0P4|hyk3+y;$iJlJ38G9Ts}N7Fvl!jcoXG5g8BFO1{`s(%@OG&u z9fthU%i+S~*Tq>WZizLD)d6Yc+u;7_; z3MR4H_K;SS8F?iVwi8mzR3b6r;iSSiG`1YGRg8#h#=q}O9gwo#)>yRH3oV{jkBIS6 zlFl&O5Ra6OCmEPkVV8$=!x5-hOTTGa(qa^(HkQgn>IN_<9CioV!VS8G8jLa0PQrDC{1zA1OLbvQp0cVPCC9Gw#n{RXK9l!1L$ zM^x7H8hdue3~#6&xFj$+{tF4H_uXLy==jLppAYkCvPGUXA}l=i(Gj7g`8*Q6$&>rx zapitxC~gDTGJ||%4fgOH2#GP=>O(dmo@Ym3=4Awj@C z?#ynhfKYu7KUKkXL!4b3aS4c|l=5bAT*xXliQ4|2=9Q$NSj+rD<~Y;E;)hCdR5AKe zl1h%q8HARxC!UB-^*35ZfhZlIdgYwtkzrU(G0-%1EFramQk~Kf(n@C-bvKIyRYA$o z7;GqPrHt&dl+Qa(C&FRMsZ-=Yobf-IFK5*-A0?$Tn{~kK15t=&$Ej8E>tj}?f%f7C zYH12&=};aLcj2?Ng0mx9=aB6rP#r8q7v1oz=Kb zIi?Qc>JS4XOi<}EV$+iJK3)C=7S4?(E<$bqW*=OtFExlJ8J$)3%#@;-R4~^3J@sk& zM8F-qN)3PMw0kXf46Qyq5%U&OTFpQ+G!@y^Nl<7Enp_p&fy#sJA1S69@JvjzFz^&o zRpPy*D9ooUL@g0lC`l%4N=yLg=xfKiu6EJ6Hoyc&l>WN4uhd0On!F*N{NUI1%?+)x zZWOW+?bNlSi>Bhx%(Sol$br=k=vI8bc*y52!eUup|jo`;JSgBgq;``;N7Q zN+5`GS+B8(&b+n)QFfJ>l-aw^U0WTOT7Q^|D>uB?(S+6!-Z=Ew##hM#PxJ} zlXtW%EGjs^tiw`L#X(d?r|opC(mq5_V+sv@y<6zbSvcOcN(A*ATtL;A8a%Y^RPb0(fB zUem0P$y|zwuUW^4Dg`W{8NM2Arl6>eHHukrC9)2I2~p)dY7lqS@pWi+nMrst-3Z^@k6zOn_=((G~0+b<|uTe z7DaX0BwsbVJF)k)6}7e=iRWlqj^y`edIbTx9H8hCrG*l0)_8mp(${7EcZO*G_lfmV z(cb%h?OnQL1iK^AloVZ8^IcMbi<%hS<`mhqctl^xTBfbtA7 zht~Sof{Jvqj#8=YCVi|4B2cfeX|9^-vWuutXe}^cEm>T1>`x%lv|Pnrh10BZ^&XHs z^KR-8G{&~-dkR(C(dH!#z~~K`7D1s5Ehu1;;^nuf9P6Yb`JEKaF9B{@@DwqJ8|=9a z^<@_sgbe0ENg2{OqneBgeON<=_=!aF@8cAxjDp=Fr=rj>!4|c+Xqkb{hOCe~KqQYz z@4CwQ9<7fCU0+Nfce=Og;45LdWZ;xeZ%3#6LaN3Q|7G|*XtJ5CTT_$xDZ zYwu9$8F?5{RfH}vlS_Xl%?@uL^>!^gW}jh;7SnVQc(`A!04Lyp37d#;1*0E@HgnL0 z6mu$_OqQs+28hjF*&B0FM^alcYb!SFpV(1Bt4FX?_s3DhEUSK@;&rYf^J?Igf7jP?u+dRaXDqd|h97&Tq?>p*HTF0zaN&u#G7^UoVC(T= z6*5HEco{tgK1Nf@#VBW=jsM=6ViEwenvCq%nkcS+VdSjg??a4(DaOFjy@l9`V|V9R zw{ho~pL0C4pteB4V|+*iUY4Qo>uZ?o*_wN{&W+5v@nEVJ#8%qsw&j zb|KdK!_6o!zo4RULybrVePrCMVCDtg#LYv-z(42Lj`^`v345(J$2ua21OsGQaCl~I*e*a%c~lA5P#ws1;w;9=b< zB`hIE>s3t|(xaneJ`1!^&=z}uBe8NsPm>^nO9(u-QAqT%Y7hv>GAA==)&ymmRtDcQ zyN*ap&~Q!YibBJt9_-3#yPy}O$1G!@bm}{43Uo{5Z?|Oeh|IAwX3ZNHtp3SLOalV8 z44wG9m3Qe4fu9#SY8~5$F!Bf0T8lWv-V`s?nPN1qqFDPH>mKT7nPt8(P&aPuHikl~zamD^&BrDd;EDdHT&kz-RH zO#!ZcRJs9kB9I@+u+@}iT4w$lhrl!#Dc&Fi&L`{-B^6t|JJl)6r}(=xL=iOth=^_8 z9{ph)e8L5KMVS^(RM1~q_A8VNbS`I|XQ5F|tS!mJ8BRbES)w|RH^~Z)iD+MG5U*wP zrKhSU4&(-g3c1}y08|PrXX?{L`uB@_Eb2K%qu#_z#jKG8Nl_4E z8p~03PVqM}c!F^k-(&%%lM#l3PwBNR5Br5!(cl?r@$C>t4kZ`--FU}*PncAmh*&zd z%lJjlS`>;}3M)J4kGyGhLK1cXuKQ>$5O~B2V&K_ul$l8Rdn@Wp$$@y;z@ex^$L}Zv zE|z+(T$RnKzKp#b9qkcKu+^mxMWyuN(UbfEMY@3Wng_r7%_aA5eQnxCMD!JuUWqG< zV=wI$3xjE~aUw^BIi+>SNR2{0C)Slf=ec+yfBGbX(BMJxsJu93#4#F!7Q-w}futej z=6rDkMcHOTnDKXr?Txr($cg2enfPMjqp1C_w1`P0E6ChzM^!$%>2y|!mAIWSuIuXu zoWL_1^tG4Sw+nGVBPs2^D?FB^PxVboc;m^I z;bXKara*rBNE&4M&r1}MYJ*hPB6}C1Xkm}YqRRDfgR5)56J{_k1{{}I{5!Tn)$=a$ z3Y|aC3>K!k$1I`|2OTtK2=_5I>{XnjCI2sdTwFpr$HkH6b|;W%5f#OVy&}3MYJ!$g zDo~|S+5G6l%0%7KM#t`F!bpKoEfG=`m{2_~sZ=4NuRpI;@U;$RBh+^eA6qIR<~*Zh=kds7FQ?rUXCx7_l{5^jZ?vcoi0) zmn%hUH>D{Sa9Me$$ejv6eNkibbmr%HRq9TSj_qbz!cc91QmqwK)-W|HY^%z`n%I@ZJdJxL5N)}1V=vKO<4t1D_nQh; zlzsU4bGuz!Y~yfd9Ci9x;9&0M?RSJ^Xik9dTB)28?A}pqE zExWOS&T462@(GEHS-9llmEyK!$HufMOzTwznyIhljI%Y2tvOmGr%NU{lnd1X49ty} zWp`(@*)DG`xgY#uVs4wp%dRyZ$hfRSp;*R+MEkL4;}TTnuQ|Ogt<~3pBau?bDF}hU3 z#Bj3~TtL&~VW4R&W;lsE)h`J{s+g&WB4HhlYr2AnTIc%(MKFGk;>=*)#JRWGG;B7@Iv*!W(ww4}NWT8|i($T>GK>!xk@|J^HGMJEXK5VaG!Zw>mUIFSZ!ClQiur{mKT;_@X^qU1+PgCzLXAwEApm@qOkwc_jRrzMW74tKS6nuE!e5B-iLYe|C5j2yE;Zo1h z!>pQ1tda({2LcovZ?i3ofcIQ%}l3P^qNmaWHRG>3rJ?)YOd%!*cMqSqWO>36 zA%!BK5Eh{1j=M9WD0Ao7o(Wi-63qvjN0j)H zK?Cn4HqsJJJ|GH(lt@DgKgOs&deYe21skvwX)4|PPdX(UXjA7CPrOj~_62O1ljz^r z_HiOXHfahguB!arl%f6(vKB%{0tftp%gY>-H3K>)!snP(CYei&s-vjP?mht5$mEIR zcpf&RcsH0N1;bUd8}rV~i%17O#1tXrFsRH&IPVjM_9I!?mI+E=`HJe3O89cdc_AzU zu07xyKSVqg6;zVGk8;bSkQfL+3So#Zk88)rR;`hpc@EG9fJQAZ>`I)nnkV*wQAjIw zS$Bv2W?cD$Ukxmc+VytX31I=WMGS^$x5}&=rbwZBK$pxp(i&*!(Kedo4N+4}g|npy z76^ryPH_pkQZ4IzAD?8EC=u;bs0NN*65jzN#5mNIG?Ja&v?{hUhyzMd5K^8XjUpnp z1KU@Nq~*HdC<>G;oKxp??A%w5ozN;;X|hwyN69oV`;sEeDWU;St@iQCIB1f|Ss}Ha zZ8r&C>WHQu4)$4imy;qRDltcCNf=#R(p2b3ZcrvbCSEuiJJ-*RX8)j%%cZZDH;?5^V221G8GTjPV(%j79mKsahe)l+bUB7TE9i*kA8KTY$C;qzK~H z-l=zKMDoTA{)0O?ZgjF)HYb}#o_NcYCQ*mswgxmdaza0#_qBv4A`Ut>#$PJveAb?7 zA|DA=H)uU*{E+t~+$x-)3f`@IK1!qLlyX%h(CT}?U`ezoo!AL1m7_OeReFrlsEVYi zq#0NY3khcmLQz?2*fPih8Exl5B~!YPTbr4`su(~k+DOYDPt`(C=aA0)8ESM1CNYW9 zEFbs7nN1ZpVq-Kqwj5n06-CP>!`xEib9#i$v~ z<(aIpJ&9&x3rvk?h8ZLrzj`K1c<5uS&b32!Ri!2{S*069rmzd)VXWmBZX$~^oi&Pv z{Yz*4p&B4KCIR+8?HHdmTgNaggZ6!>?{{R{wMJ*yY(mo706ci`sry(Jvn-kC%)_y+ z;NV^g<^CBWMh6+sfL3;@trD_@@&d%^!UZT+JH)cpWTi+~_kV(kW)&!o(zccDy_oGz zT&EYBA|jP;qt)bk2E@FaIjU5=epTUF3NuS=5bjn;RBT=!g|$y;d`GPm-~!D zp<`JTBr-lb8{3OOrK1bsjT!t0JGo60KrTSCZ;iCIMpCMi?&JktM|zbUpjfTSJHB+t z6~DnajL};p4ohK3ru1A{;{QKZTE;G~gs_qaN)|O<{GIA1VaivMIUnM%MC?(G5>sMQw2(mZdyzb% zieJn}<-%G*D$9l9U~A=I27*UNN8HO(mJCPVHB-bkNiteJ@+J;#oryH0kvJY2VdA+{ zughgu`tdMRXSJRngmO3LrK^grJ>!A2G<)pXi<#E#DdT`Yqa0$Sx>pa#LJ0i+c(0KANuMdaE7?=9HIrc14vzYh83O>HD0Ddpf7j?Er3=E zkTI1aj7wF96mVEaQZEK7M1*vh*?2SHrl~rtyRp|$QP%menb}F_XczD4dQpR=T8$zb zOC$Ox5lOL|QJp}(lW#4$t&D3y9k&XA;)(OU92K08S9>%;mFF$pyg8uPb_@6m+`pic z#6HvEY%c50i_mvje(W+QwrTRxQHnM~3a?Z=epQ}d_9>dj2dPJ|mo0CLX!9WUygh+aU#v<*2cXl zrmP&|0*!3A+=uCrq7R`yuJJ}W8q+y#ex9Y2i(-g#*hYoETOacqnfR_m1Z_OUHU;%& zcu+Ex!2Gm+35fLEM%lU{3OD;1I{`u#>lMItDHlgk@bdgQMp4W(6`nb=;8Fo&o~pz| zp~_9Y*s;RHFLlzu4@U9ki4cuU(R~$_e!lJ_IYc$$kj%m%F;f2t$EFT zb)-SF{ZB}HHR~lUelnuzC8MyD6^cL2Gk1^Ip|Y6wQjVv9&7_y4=vfmUt#iUcwF#yy z+yxmry=-)p{_DF)u_D6XF_GC&CrF^PlD#-u$66G!<)Y)jyuv95tgBfyUn$aAzRm%f z&EKo5_Nb0Nz0?pKi57Bq<=r0&_b>OYsoG7YAC)}8a#1U=XxaA|f~(teDY}AqL8Hwu zYEy~k>0SX#99}XZ;&S=V%xG;HJ6IE;gumVPENp(tF>XfrJT;3XP1_86r;6h}5W;Xg z@)Xqw8@;U4jCR3Akf1dYVf=e`bQR5tXX2_@g(Y3vGv_v%Dd~L>{58g{h-8OI>Nt|d z8+6g+@PibRUB4dfuS%*mBPfyGck^r`NzG*KMn}mSUQ8VCl*`J*hZK@BRx_FxJQzl( zE7QC&_Ou5vgj(YiJw+aztrKYF2mKM+v}1?| zS~F?D)03Ihl9EkLS$Jbi91)r1!G)`LTO^K= zW(ZA?%Endz!xNM`l2tMNJQ^hPtkOM7BSj{OIr79}uA!Q$!JniOy%FfBLQY4GWkH29 z&-(MKx+L=g#&SLODaCwMFFLkg zl@pjN3z8_z*hH3hUVN9~8!Rk8A_Q3`CkZ8}7nt|_ID&xJh#St4w2DkwrO`VT`^+)n z1a`@c-E+bSxvKz3$t~}?DD^j&+z)+imZi&K{homrr061QK592kk4jR7pu!LtiO0lRb{Uw)dXvAb z$b|n=T0t@Z#qz1p!RW6l@x%UGvb zh)x&NsET`)FBXNOSMoABsZcm~`7_kzxmSPV@Z#dcnq~E@G+6-DP-{%Di%r6#gc+Dz zFN>hcn3zJ!AyvslZX)*eSJEKzlGS2h_Vnmu24EcQHDftaDKZ>2iV91o_0g!0o@1P? zg`&g8SR}T{D7FgUKmVmlR4tfm&r-W6diYvx@F>OR^@@Pou+4e{j0+^u! z4FsDYDECva10BTyVaCR#;uUk$l`YhIKEd(lFlFfLut4+#h8J1~O$8DrGd5Ltv5A&E z632hW${GznoIN9r3XC}lKC0U7_-s)D>XPv|%`QF{wIv%f)z3t^OCDot0TnK&cV1z6 zn7KA-L9!iMWFp$nmNtUo^^9&_r}GPjtJ9(>aGQnS;ZBuljnP^Q`&REAYhUMa>zhmN zUr|>s3!R+o+Tm~@wqLSqf3~d+B^nsZvH_@JT@{CQ#oE`ryr|B(XSxH5SRr+U9HTrv znpuYc(Q4#)fxN;ejz5o%4iA5mq=x+z@UKQ?G^%AOxmk1VSUGWZ_4)=de~)xsFm zB7Q+hl1_ygPY5@ihSL5bTgUCZPIVZwALPCdqV!sFv+BeJ9g>6&8iE7QDU`s64P+bH z;mv0E5FxAF#|6`PJli4wq?fVjP=~Vp?o~{^i4yY4HI>~=9?E4xA+d`b``u=i6+KcJ zkM#hz@%>;K2W(%ZY{oG8*1XfJUN8;8OKNb{1UWT`*!NUUgJE$&h&^hWHXk`EhH80| z6AMmMmQi>(tQEeeDuS+~YdLq?g|HI{xBRE1cwHhCS8CDd&rnTjFUUCe`&rUMwRiaE zP_0b0Q`54`l%uJSQW3&fU^%y>LAfwTs0I~smdebKvO-|^7+K?z>uX2fG;B8;FgNsW z77!5;>DMCdO$xyeeK9u`(E~s?qN<`j<9>i{&MugLUl-#OLDk}9-eDrp9eT=Q5XhbX%!!~{LfL)*f!OY`RwhZs#s z|#7%{m~_FfS(-txeG`SpaBBD8MvAo$Uo0id@ujSQ!($_=Z^naO=uOHg8dk zs(6f`78-jUaV5AeU}Ch*7Rz>P`xSyRa5$`hjfk0-@yy6-7mgvLde8k@vwck05@aa_ ziKZFqS}|)i{8EZlgCzDn9?8>9g&4r=<9L~3)yuRA1a-v2PDyb@>qm^&!mEY+{uNog z`1%1Rwa;fz>~nYitLA%O{IKlg5LAG}jD>I|Du|BgF*EN`{GHRkkUs3G;E@QY^FN{~ zh$;X;>jcHdu9+hzMbRU{qBL8FPFj`m%=nolzR%6SOB^*wxt>tl$&*fz9auJOendML zxOg-vVHlz+tH?`MIlQ^#erP8*F1kjbg}D)QWFkc-mkQRtqRSpY2eE{*P$1QVomG@4 z0ca7F#GySrADWcY62O|#ICM0Ms$GZHBa{*kgo5}Q`EF%wQSb~Nj!Kj93zPbh1TjW+ zeH|+bThq~08VbZZjQ383IOXmEqy=Iu71VuyDYz&|Tp+^UAnFWuj=e_uu$-GHlf=Rp zh1v}JG$#^Av7$Y*0Vh>z9z+xRDfUWP@w1f?D2J`TnN_S2(JzAHU*sU8#28$%lVcuA zM754h{SaoL)u}^k7QAUj_&!Eb+bx56gJrW|X}RwbZD8tQ7in!XqH*Ma0~CUT8SOW= zQuToS0MTzGXfU44UY zZ$a#`!x9lj4GJY|V5_K-ai~0lEk<{A1b0XHM`_}f4m*eUloS?#n5Iw$o@(*SX^gBn zI?7gULZ!2G0iD##Qnj#h^Jn(zOQL9?X@43XUGHTjeT0?S>eL#`$C!7KA)ZbK(dZx< z`707AS=5gxgcJ+6@jQs2s~44{+99Ts(K)=iBiDi}RFXH)bqG zwAd^QNLO^nW@&Z}nXi_I@bKPce2CbGZk~_0B-JxaXbOqX;*BUCq2}YHa=~d;qS4W1 z2z^~`;{KF3Hx~F&&38Q1QCWn;b`}rOe+81&apq z1ZS!w_gN@1*^7fh?*Ld$Ri9y)2I5Kr#Or?#jsiY&%|x#SS5E2HMf}6o?P!4nkolG- z&-66Fw$F3q>{yp>pA9p>%jn{nlK^6b6SAB*l@%ahV42`o-z1)k*inrxRA2;Ly6D2^%BhA6M#`*yOj)(SdJ?JCOYtG9 z(HR0q*{R;|$1aaTaXf?$T9A5pt+>*_8fVAlNf%>0Ym)}?ZrjJ0G>Mc*=(Rx8Na_fN zttKk3+506jrGZagOZ^Lk&+=~CRyU?KOoUE74G6xArJNSllabnW|tsw_i$Vh6P~D2xT$MX|I!T3fJKw;-tU zdy^|mMqG@C(T%BPZRJaQO~xaWlwF%!3Zyb&N1R9TxMe?-fL|)IXfis1Hls1ouULN=Q+$@B^9vV8hp_#2m@C@M`X;;-R3cgBe zb24SvQdPE=2?Ev1MG{CbNvC~eW;TRWNq19Er{Y*uqHv`G9-xV%swET^B?AyI}GgnEHO#lFTblY0+e?FN|s?Q~l%TW`@ z)+akod3SWi^{D{sL2$S^pzl_Y?67DnLa5Q7_f@%$cnsYRt9Y?S*JWSe*tyETszo~0I3u#FtG1Q60dY_W}>l&W6} zap(=~j>ZySBf_RxC57lfYX;j;*;)Um^T@4+4oBL#Rbbtx5~Y*Ll|WH1Rw0dtOp-=e zVvQM6?`X=;MN?8G71*pTskPe}wVHrw@@{xX=}z&QS|DZjiK!&Pq;QR%Evy6*V;KDl z#X(G{%Q%d1j8a#Gmfy5gt*=HlxfLD-tNrh>Hw% zS0ri{ZV0s@kbrN+#8LC-iS56&XJM=&sNmGn59nR1gvo#GJ9+X$=8|2sX4Y|87dYdx z0Jtc-vtdyvuwCG`)_&@ieY1Go?M`2pdRcCh1;3DLdsb zlna@XdIUU)6|mG=d?q7>U=(v*R;;o{;mC0?S~tJ0=zZ;1S645H>EF#>?%!!>DzI!f z)U|I~+fd^rKWG?{0G^7QIas0{`}JT#gragXLO_?aRYOwb?dr%(4)^>(&pR8{qIk4Q zQQ;~1a6pe3g>}plR_74Sj6YK+WRu1M**iE1IZJg6cn~6s#sZy96{ppI_-2)y+9Jjj#})x&o|dU{G7YoAFFCwjgw@vS7b&SPvb&yO^VVss>Q7 zd=6BOmCM!>YGdM2fj{sjY*g7c41mtizH!zr6_j;;EF)aSi5$?x*p=f z;<67?(E=#0V*{F8a$NGMR8kEY2fO+8M3ea!hH5`SB>}usau!u?zn0W$E#o69)oYSD zM2gpmD69zX=NUI2T2M8T z8iM++d67-JGu6oxR4oEymEfVNlA|@>*D?jt3$Klb@@a99VipBQKhwkM~!eeW*r-hYI<4~T2sWK?O%Ig^?I zVOEdm?|CTsn5`Qz=Bj4#BqGIVuSFGDxT}#&UemETCGB;`j1*Y3Vxy6YUGsxG_Rbm0 zrByjt!(7Xd6y^C#3Xo;EmG~rB7e*~3b;97Sr3?(Hf`tiB#N4#{<;20>;qo3u#8jwo zG3~XrWX|Q#cqR?y7}N@Vt>Li7M9G}lxQHcuh(}R68B{hVUshXm6E?Nh(3Xw1wt3@| z`)j_mYlFzG#?*Y5QNof!YD*w2ynyJCU6j^=hbCFlDnTyQx*ASrFe>w~jQl3gyK<_2 z+2!Q_$Kk!Ia=ZIUhMcpp%*r-TYcA4i#0n(W6o7^rx6Kw$5# z6u_~}89wfrUoNJU%va)h<>|plB;5# zl!@0=bS(!01+Q_8Bgdby7=gq)k477uo}OT{*`jyB_02W9D9&!(!QJ~0@%Fp#=taAi8VYV6-iK8MX}jzaC0f(4%~X@G2VUW z9&Vj3An7<<@A2~d9M508z~zf`JbU&W-+c2YeDlqp@bdW!9B%e_`RY4doZq1L0dd~7 zhO^TXv}FsC18#1vad~-#i_2@=T<@{2-Rx0(No^ckz${wQ&h`T;c13yN|0-jqsOFB_0=y7cRF-10 z?uFd0Ji$VyVA-Yu+V8Pb#lt&ic>Ccgw%f7cWj)2adKZWO4%X`xmls#~?z`vs^EY4N z={HaD;`wuY`Q;z+``>?o7tfzzm75S(?YMzA4cqO4&1Q$~_6C<1SGc^q!n&@h?z2RW zR4>{y)kabRNsFU$70L0vJwvRSIH$msf}Ku|vNE>d)JdQ=ET@kl)O zO`bLoBSVz;ujno*$FcdSa57viBsB_Tbr!Cci!6(kDJGr$; zs$g+DcQXG%OQ%+n!aM~%r9??M5(-5$Q(;`@_$LH1d1XZ$bMq<6W zXE%T?Kv<hMwNEKMdiq}tuSmF3Dgn?!$kGW zE>wr8XtG%#J zadUYA>WoE)kEZ$MXhNl>F=(^k-t8UUd3+Z?`S4wwzq-Kr%UAgNo3HTs?>@(Ge)Adr z_{T4BadD1yU2$`Bz-H6XmWI>Q4R+fzoSojn<>dvguC7NI=6)aae-Yo)GG-JQgPZTG zG+3bOi3qGkeT#sRYu)5Z`pzn14H4XHDpmqmfSR_ZqQH?)rsCiR^)nyqz3(81Fl@VNB_Uh z@9e(EE99lFsM4t1U6K^bP3W7W_@?4J1PNAM(Y2wApxb9c>QfVqw2XD#)-Vy zx3t#oFt^rdi6!areubL{qOLYtDLGu_i8$`oWRjL2Rn#Wk6n|OcaHp83ry02@@e~0p z#*FHlJVe#IMb*qq5{kCOgw1SBiQ#MgJ2V-1$N6engdcju*0Kw?S4E?XTFU4d?R9=7?%D& zZH=&O7$>_0+udfe4Xl00vp36vW!d1-qqp(V$3MZ(fAI-^{ot^*- z2Na+VYkhxo(}6>mA(YUu3#m~~(mQUhuJP>KSAecq+7|200sE^JOv|{~N*<>Bte6`% zw@z{E>;#V=y@j{md4!KY`VhbP#ZU3sXP@FXzx@sV@cZB6;`|)fHyxY4V0W@$x7*_6 zuMavMvG z#wk_IR7Th?Xwe=;WnQ8cTyAOfAfvNXnn)ICh$IIM6(^Z`7(7u+zsS)ulB4(hWu^)It71izGYB@ZF z=xDt$#oVW`fyjLoQvvv?919M>0%hDL)>trnz^dYFyV@>KI*Qe9s*!RQ5zPrz22_x3TV6k3+?fXr?+^ z(X!{MU0s;)i$Ry&E-}%y$zDh|KBL%y>*cH^ugw6zJ_;rmQOM+_Ys}bgw>Ul7VYk~2 zL$(rn7wr2U{m^mi>Fxw4yIWxFae4j}fB5_* z+R1`Dw{PS0^aRuzmW6P-ZP+y~+{tlS-@QBj*+-8a;Jx?W#YZ1~h~Iqn8GifQ-{PyU zzQWbz75du2)UnwtI6J$A-N_kFPOh=rZt?QvOPrry0J68oEDvP1@@h4RZ!6V;nwQEu zJl}KEl(tcu`HZo00ua$Wa_4FPI;I_I#7+qrmuEUuAX>3>2vc>&PH0@N6($}SG$-^O}#jcx4S$<6+9GNsRIR{J?KD z+kp?%ndcKatYT1`BvD^wy_1G}$8YsI2INR~i4J@?wn9RpEhTD8iOeXj z^KPf?dxA)>^cTb%bNmg(JU*eZ!NJs?^zSOOD9S?dgn>dwAk7zijN3SADP{a5llp8V z18dii-zPt8K5(i8T2$x2(!#i8cHge413Pfl^N+hJ+TFw}|!)#B~9e}td^^ym1=&wh$0AAN+k zfAk*Sy8jk#o!!Cd$%%P~M!@IwVa55y6)vy$xZEG`-Kz^cd;SvN{P`&^UcJKA`8BQ& z9pAoqffuh{L2p*H>rHdtE2!p0d@;M@>hgaMFN7yioV)+76E2zP^Nim)5> zn0+PPC*Or?JSI&MQ=PaB#-@aSEdfRpLa7Oet|&B|R8LE>t|a)C0(YiFfhAM)IPtZL zHT)LkI`tX8RaON%d`uHO9ph3hKchN)jSH5Q3v8QX|F7zzIsd(J*pMO!7Q@CuBnG4| zY*orLu_Dx<8MoAZ7w7wO&eU%kHs!srk^vvT}~j`P6z^2chO*_cC-9D0JegwB<*^xVsH&4dg(nOb zQjRTU+z})dEpZ{ac-AuJAuYKjWm!DV0FFvF)J;@K>qw}q`fkb&Y%Pki_~Cgl6+8OK zAtTHV8GD~yW4=+_PXo%U7c)qc<22m_|>m|iC_Kl@A3WzPjLJ0J#027 zXl)?KF0U@}>imHHVULT8OFaMn6~6rH8+`libA12m0^dA;j%Uxl!^NvtSa0@_Lq}f) zhu-n(`U27gr<<)Eehn&*AwPbEMgqnjP~dQLg+G7w2mIrI{%2gCAAsEkx8Ayq`w#Bn z!w)~ehwp!Y2lwvdt-E*d@U6Re>;7$=p6#&NEZA%YD(vpvdpJ8i!~M7JU+fvNF##t$nHlE_`I&z*>@pZ54sm*$i>;xDmBYJI3GlKdTR6I?Y%iI!g%-oa zvG;YHK15UncvSyGXyt#Ucm^l);Cq%3X~$6=ULuk#R)s^B19q&sPyt;694vMdgV zx_Xt@h@m_xzb-P51?})31aC14NJe64@qndwMhnleDlj!FM6QQ5!PeSE{GvtlplK&a ziE>_s?553FhNl`d7W|75}S=`wa#uP*TNW*R3MAQ{}KZr`~*y3}RCTlenc^yCZ=9zMjQ$B%IL!F_!C>1TNH^f_c*(T)9j za(aq8HsZLvxWIbYF-py~fKI424oI>+Yf51oh$ySV zDfe+HO4_~J$|7McNfl!DQL0TAM6E-y-Jk8)!qO0)(m^|M@mY33Mw!vHLU>|>Q&Buq z1U2cz5-7X~o+5}e&Gind4uly~S+yJ;k7kZ1nhWnq*%ZN+)%Kvl>7|lvPsA~3q}Yd} z@NO+&RfbR5*`R?{^(R0@G)=v4F1dg6Yv2#MT2gM8QI?BoWyg!bAZlo|U}*~)t>_GJ zm%!o#`UvisQB(9ubPIFGfVnd>b2lp&s)@vhoB2*Du1FkJ+6>Y@M;W_FN5JCZO$pT? z7j>kK61D6doeZI(16O2!fG8DyVZEMx|2L{{=`zgqk?74aHWeE{cAcy6>OTwRNrgZY ziufe$2s&@zAu3piXVqp2sH6xlJ(4BP**K|OEB$*VUJPzBgImM0Fm|UqY)?+mmJJBN zL4dQ94c>eI9sKRD{vN;jn_uDG_aEcVom<#!cG&L^xVXH+`NcV&KYNa^zx*0sfBiN7 z^!3+x_VgKEy}ZE7^K+bETw;H{$J#ptI^fHj?Z9w#zvR~NQ+6Bx1~%Ih5Up7I-h7|q z`&thjmzP(#*jp2H6eSv4+{TU1Gu-l#C?%msX^yof*^rMG(_nmj~;fEjM z{SV&5sh-!QH!e@xeRq;dh_?27mhUPdGn6A7T?`+&VqM zt}!ll3ob4$aB+1xHdKP~b3h@iU@{AUOU}9I|H`S%u-K!B+Z_8MwY)e&DrH5J$67`X zVXcXHr>e4!v zoLt`f6l&RAhD^Z9vC$ZfMR2%5&<3%Jxe0A@dcN5<;~&U5dV) z)0E(&H5<278NU79bfju@*|Qc5kc}fr(>#yJzbo+S&gFMfjY6**LNkIW?GRLlEB?aP z4y!1}#Hv%amx+ChWG1-EM}PoV_-&k=Y#=Il`SK-Re*X$zef?*A`|UG)_0`w-@(+K+ z*WY}NXD^;(Jsi*veIT<|MwcN`CmwQtUDu(~v~*>+rFhOC3t_{+w(*GFSQc!ThP59c zvd87cE8N^%q4xu1Rj@8#X7mn77wr2r_WKJQ4(GVMe1)&S{2HH~{08s5_YOY%=tDet z@&r$we1Lb}c?S<3-pB5Ahg-L9;m03-j2}ICg!kTl2fzOHzu-5&`yHM>eTu{WfQ1OV zlM^g$_yx%#Xx2Tjir`>k17=01HL7|!3L=h?Uz9KuWR%hEDMgD@wMF}%W{-jRE@WKoCg#|CK>OR6gl~c6!7D4SBssppVRliqAS!AxWVi}9q~H( zpBvK-h^02Tkfkb8bF`?=A*75L@{6+(GNi_i{MvE>zS2xEdJ1&JKoS@aBat=tXWlMo-P^yo2(nse9HwS_!_X;^J zNbilSiCGh>jG`(dO@E6_>cbSaye5eu&D3LZjs(XDLn7Ijrv?9Hf-m8iC>d2DEb#xe zBbiW13_4{gbIIR|2$sn|$J5Ii^VyP>Hh{~D#v^fiv)ke9Y;-cr4V%qotT=H_X7ehZpj$x z+uldFO{D1kfa_~OI^hb}c%k3n>32`@r$7A>zkT#JKKl5__~<7e;lq!f;N5rL#={5q zadviw-NT1CJv+mlJ9qHl!9)D|*T2RWUwnbfiwm^Pg5Aj$tuYo5v>$MOSaa0f2u%np z^8gp81zKZ2M2Sq3R2vd;#oL8(9y&csHJ#2!z(fo# z?_Z2);Q}C=%owY4ykBj+>%PYDXs)`hP(hbrKaj4FWpuXO8XC1g=Q+4qRK~=IxN~c7 z#+84~*V*aGUb=j#s{5P$81oPhv-iT|Lz2GQ1KH90Y6S8E*ew^ACts7+{n`9-z%J7e zZfFhE;1cG^ljkQ#2U*3EEy*K{bNWjxu1AyjU*qob8ww!VQJgSGbsAI&3s#J9Ow~df zL5vNlWOz-e{j#jqs1Jt%%*U1P@sY`YmqC&!qa#($>d>l2F2BvcRO`7PiHkhC;+2SI z!n#I4s-ndur?Hk}22M^kxP9jqPEOCTY?ci0B*x>%kMVbZ|9AM+uYQTgk00aKt=rfw zJIH>;^JmZS*=L{PpZ@8;;`d+t9?!mgf%A(?TwYuZqQ8%YMY3R_UZP`Va3sALqG56- zD~z~|#X*YA(y-esXbkjqkG{V_-`_yj1LUxdT^%^486pzkT?PXJ^uqx{1i^~+@*4ec zjf?MJ;`!5O_|u<$k3W3z1V8)9Pw~r7evbD)cpta!-p1LjGra%g3GUpvi`!?n09AbP z`R6#SH((G>Pj+BZT<@=Nv)@CtTOZN`p(bpkli1U63KztlP0SRP;v^`x0u4Um)U`oE z8SUaTqU>Na(myEBTTLqzyf9FmbHd?8$*e*xmy{^Enf*T4V35T{IRM(U#2)^e`c@~GaH>Mt9pl1`2B;HRa#wRLF#&iZ< z?Y-v3k_u8xH!L|#m!;iomPOuNa(~6w$@cW-g0BDARraf_=yEVdWka}#Tc$k{wL<1V zs5-cSM_oeh5i_~)margEu>`u=B5Dtd}4(p2h z58lE*{KJ31fBaAX3Gcr9E;h@8!+yofm#^^Mx6kpr-~JB&`2YPQ{^_6p2~VFrhpc1a zzOL)wJzB?3+M>fB)wvX3WBL_IWH3UDjF2GU#yH(=ap&{|XWI=HQmE`9{R)t4VBJFw zHdxk{`}21c=pY=xW2f6NXLgCeTcI=x3Sr7 zasS~%{1m`pJz&EPfBMrOaCLnJX2$MhgL`k?hG@sDmlvbJ+^@hYQ9wnguqSHRh2kQQ zB6WT()HZFS61iq5;jFp4;smr(9a~o(ta;dqIynB^3F1)pzUcP8n`%&UfGEba^|b(s zFk}>TZ4@-BA!I|fF@)_mFT(LYb4h_n6{Xu_{CgIa5|v|JlTf5ufvUE2bjZxb`IpSS zvboFifvS3ZQm0ZB?&9!uXbNKNzh}z4z=c^F@f8#GH<#RBJoZ}TAITrj@38^kiV+Sa69-MmYKLRFVlFnxB#DPsQ+VOxgk$I%TIFVGCvd~ZB zL&ll<3lumtJBzBz$1gAfMTlocEsm){fig1c|Mg=MqB zz5Dm^%U}Kt&Q4BodU}d4KK~ugug=jH#=U#DlM~8UP!U|;9P(fn9pW&}3rIb&!)zW= zY899Ew2^Y2q)Jg7Czo-)C|}njO8b^Xh@bLaq55LZ;HJ;+f+o18<{(?I?k); zs}cL9(Q#tBy!>-^`$ER_)IEP4)~g#I$a~Ms(i5Z?PSnP}nt(etFhQ8l)tXiZ%~Q#` z^J0WDMVu)M@0l zo!QG#Jp#5Ir6YvNyC!_&2sJiE^;C$jhKda+yF4z4u#(#~r1qA|Zl7Rd#%8YQj9yaPHO9nS5YDzcoNUjq+itO0 z7!^%&uIkHGBuOtkIO+su=ery9(u=j&z|B_?Km6`c=hTP{_gv~ z#ZQ0!Gdz6!7~9^Mc0Q)rC+7uWNh#eDO2F&FwW=BkEK}V9ksq={c>jT_|9s%(M$yWtlNnb(R`W zR12n=rl5lwITSV}BvTdzkkI>zb$s9fgeYCb@{CoM4IhoM!wv5(OP4ioNRID z_8D&9I>BzsSml6CYk2ql5AgT@@xR3{KKTR>A3nrxcZRF$8+`fYm-zLsKgB=(=l>U< zfBHGT{rb=~|yp=*3C}j&ZP*j{d?I52RkJ;ppeUdzt z`GhG2-ACH(VsOd6e=h==cXTCGc$Ro^AnC$y=M#S_3gprTM^JN_SWE<#@}Kb$lp({L zwQSkze?I!Qum}vsNv;vN?8bfdLJX!2APusb^=Rn`lKabFr@O88 zzOJHOH7L?brodCm4mJ9;(sk7;D`^NezBQAmmj7&A)NLNiA}s(z-mk^e zgUEkFWl>tgfPz<2JJdqeST8tB(4Ku$8I2>Q5Q&%m$V98Y@wAaxiaZLLzYTH=H~jzX zz00#@*>T?YWv;#VIp^M6udeO}Ky>3lNTeu>1m&Sea)iSUYalr^kz_~Mj!=aEAJ07Y zKjKF?M9Z>B08M}Z2%sAcpx@Q?x^*9C@0IDn%FLDP6df*l)QqTNG(k4H>)twd@3r#r zeZLRW1RM?v&Myww?I#egm<#acn{VMC|HuCr|L9Nu1aCZih-q4|9tDrTe1f0<^sn*f zfAQz|`Op3uk3RVV*Uw%Ue4s$pRlT`q?Ry;z69Xg>!5FvHo&zypZZj$uZb{1X%vct} zeqqd0!#ZupTUIA*G2JbVA{QjqSuPEzUxyyr;9Bnjhnx z@lO2$PDvUPC_GAj&qPY1{)M8LOy@*XDYnTDy%gWo?KOFuij!`tk6RfiKD<1ErKkN} zFBodK4G0DZGct)N5*a9L1dbyV0}&J(?FtEeCaSujN{!DPA{{C%0wGpaeIcr^$Cauudc#C%6o5+08LDXn%>ifs&~cAHG47fL^SSeW|wQWQfUL~|nl1&B_vF1IUNt8pLcBB9RAOJ~3K~w`O zdr}p;raq6;hNNx80V#QemcHjsLg5tNn!ZMYKYQ2L$G;R(Yxnkqmrrx=rY7~)B%5wx zA|`1R3hHAoNdgmM6RI#U%?0O&1$Xb>!Qrq6NFdno)`Pe4{qO%N{`gP+1aH3m7Rpp` zyj}6>C!gadKmG~c`{8@|`A>e1Pd@z=H!rRtX`Z!vsfMwvx>C3Afr5<~`G5%&oDRiP zh&Pvlc{gF+G0N1&t)dm{dc@`P7m&4LHW+t>rdSJl8EmYj?^D=`_??E&)TbcZy5dF! zpMQSD?eV4^UiR~N=iBe#{LUU1_wL}k-}^4+x!Ep$`@3Ib+cwPegq!1vFP=Qb^kQn4 zjBGJMp){6Om&q%oEZ`JtMP2AXCqK$EJWZWnojl5ycC|xE=sog_{U8tt0Cf1=$@`0~L($0=} zxDqK;%M>;xa={xj#PQi_XbPyPR}gHL0wkHcCRa(80BVY*ck#nZD194ivIUL?qtU%@K7*!K z;j8D)W%GcZz?oCLMI4%uK;98lno<@5sfA2rps2W+y)sKKTsqz4w>+vp@TH z`0JnkH6DHb2)9?)(5fISrVvV1iSG*@X_O*mX{bj0Nsv+Mtz!Y<+Yx5Qyj#F?L75gz z(+;;)aJ^Ps-ZT?9xMP%vPPe%%hN|TV&-K3B2FyOyB$250%&{3g@5bn57R6EBp@0|mTpi%4vF@(m8 zJj7RN-QWq}9*itzF)1{m5Qn9~LCFDv$di!#{u`75wWq8^w0wJ* zN-1%WiX?+)%4`#8kFe2kbfD=0Rq}Y8ymwKIL2^E-W82du*d9Nlapo$(@rm)~>3<1+AIb zp0(PMdzI9kNRd2)%sy=~jCUwWpip5<(9X#VBTpg5GEX==JHz?;IhJJx(T4N0bNt~S z{zLrn_x}`M`^N8~%rmyN;?d`i@mGKKQ~aO*?%(0PAHRnuUp$7a6%!G}^RdvGqiROi z)>-D(+iMC=Rt-%fur82+eRh=8hh)3DG8L4$<=O3aJFHv9aV6ZY4L;r`L)1*X4h2YK z&=?t!qlM{t{FgZDn3&yt987yZwZ-JLh=k+uy|X z^(Ag@j`;lXmss`(y!r4g)V1yBj<+lN8mvtadM0%jYN;lpbSm^X0}@^`gLm4Fzbj1A z>_o1T&igCv8Ffm1#2283=*py70Ae-a3eS!s$ZB57-c;?PH630f9i;t3B8dxvti!G7 zJKEuubb)c)PGg~n_*qi#Fm3YTb-0@OJN^XJw}xKe29(0q3ndiRrc)*j282YknDZ*N z@1O0R7u_HhVEy`%dzCwm2~@aYy~>2GihanfbPz+{_+i3ax*shEH`*c4r)c)jlMEfm zz+V&{5{<*eiA*C;u{`M_q(Qdd;}sQI>fWEds?yD4Jei!0Pq`GqI}6yVF=Dd`_BK zYf;&&jAV8)PuzaD!+y8NGB03a?3Ocp_xFDvfBdK4$M3!KE|%RMDuT;rPw~rN`~rXR z7eBx+e*SYj{qiwxZ;mLb^X(aA?dx@dPBWOh7mPTkDQJjjhWT@hbmS!H)t{kOKukPi zDt)x36=0pPRX}Nue7|hqf5}2(L==-8+VjIhrdzjgAiCvkTX6%$`sE|s{^T#QZ8x}c z?+kbDAMo()H&G_W`JD@V>)YSOvnN-0`urNQ6+FEE25zrz@%YITTwh-s-9v(;;e`TH zVuoMH#64|$NDGN*7`Gu%noDS0bfc;(PfhH3RqYqUNse7xadh7yyO@e(KmhiF=}Hr^__xFRg&6WA_&*EezkI8g9%-$(z*f46&4Sj)9Z(uT30hOcp`)|J(oho)$s2 znWrdBse9$9hsu)g0~y^SVpJBef(sHyxPoP}|E_ASb*)={Z3chETTT?X5f$O^iBa6WFvS8T5Mk5GPTBnT82yd z#B=BpY2UC#K`q0c5NV&6ujw8VtAh^^waf6q_A+uaI=BCxK!(G*I6L65+o3R{l!C8+ z$|^?{n-VegzFd2@!53$1|&VoHRg`#qFy`)J=~Pq?LlP5% zuy>RgGy#f~rxyth;jA~zjL6366cf8p7p17Cc(PW!`Z%(xB;YlW%@)is(Ur9P zKz43DM=X6O6T3G}9i`+8QBxk8Mx4i>Sj=Wv z-|e_{KzqD}QU^4L*_(RkDuy(zKJw_^_x`;*fu$+sWMBgN(%Y{xLEj_B$RbYIl>3&` z31TFic$M7{6>013Few&*nuHyG@Yy)DFk_h}>~{+ehZcUi%oFb4zlT5ggFnFczV`<> zySN9Ug4^30eEi#w@Pj}90e<+SAK~MVKF0C-h`J?Xzg6={3w|y%T*P_vB`(#EaS*lr z=HMlyG}=m~Jpo(_m>6Z+VcDOx0NbRlJ0918R+BQPyZB<*&FN?-A@nr)Q}1LVey9kf zR;U0gj(Ga`8Gin=U*L^59^(A`9N+tczlX#5Ip*Drx4-c=zVqw_u3lVW{qhq-)Y&XJ>6>@Q9Alkm#kr>K#&kx0(|cvgHED- zBv~vkh>{qn1Est1zCUigqhn8z)zPIcS_jKQe|P%su3_Lz{3beVPeQEXmknW9kAV8s z&ZGP!zUTg#X_|nHwSw9OcdG3aBh>hQ-q#k8o*GiEk=V8-RGKDjG#>(rPRxn}wW##h zm)!s7H^wYXbfZSg>j}F}5vZ!zAT58 zwrsc=XNNuJsTsk)`OZ7|`+xWkaPPrGFioi2ibtP+h9CX#NB9r_;fMI}!{6Zg`UbLT zPavmc*+>W1sn8<_XQDUeP!yadJVX~u9nW?$tN^BKNV&qMH&~Aw%I${RJRl1AQ=AQP^l?Q2r3tx<&`S30jhme)E>Ml&Cek=W?Adj)4jRvGsKl~ z+Q%49`|p>YW3_x~Ew&rtfD!jaa=y>{XhGBn>#^fN0wJ?`W&mM{DmthBdJ=HI?`(`T zJV@I8G3mXe_`ZF4-yd=rGUQzF(6@LVH>7>~AODVX{4`yX>DUhvIecB37`ls{M7$NKI;oZ}}U&qiUC!eAy$6JfWXG0g>F!u>ZM;_v;z-^bU#`AtmA z0#)GZ@&(@i>tEn6{=*OP{`()``o%Rw6jf>h2J{$}tn8KOd^kGIJoHU+;B-^x7%Pc$LmA39j1J;d5Y3OR^Y{tsi*H7 zl?M3^!bw`bC!49M9$Qf$VQtF52zyS6(qu~dW$FMU^{Gr+J)|)gB~NkzVRE)mMDYNH ztqoBD>!hN!ioQ-Ec*Q#o$93I464hIeya50zrA4sUt~i8wu&VQw?6Ro=f=p^D>0H5B zjFYD1Y>mU)>D{b7Ln<$`!?4Rm zC-~Jbe}(7Io*9Zr`_;_@Z#o^0X>3h>pX41y#3@-e+Mp{LO^#71Bj_7#X?1h6;p0!f zzz=`?Gkp5!2JBua2fGG|k7`a4}cRRNvkGKjvC@T$L7DQik8CMcT39wd_X+j*67`ZLoc8p%d< z9qlTnJBnB^7c*%#uBX(7q><8-d=O{rmSP^xz{erfsx2>1z{Ir7%d%UR*A{|T`L)dR zMnsP%o>xL?03Wi-!VY(L<`-_ejh+B*hq^rsVal|*5eLbGx-SMEb??2s#NiUbgC^O9 zQew=SaGxZ&mK5DmN9m|!6DTs$ypIadV{%-?;#3f}m0XY;(#)(^lyq|Sq%mrKITc9` zOo{KA%Eefq(_oEI>aycbp=e_rrPg7)rGhXfq=(SNd~cl4U9K<9Rtif0lkXoddZvl7 z-_6+XXPnWOe}so`z6CA?bzAY|i%0nBPk)A={`6-p6m;F%jUauzM@qx~ z);pu2iv~sx=V|(pkBF?m(vwj~?MKfBa+IyLT6N z?%cs29{vFiX9t{}o#Elb`?!Di0^4?j+x37uch7Kpdy8#r*^Zj%bL^2Y*3~hky|7(( zu?b~|GHarxuqRKaGO2eQs+!`nFqrQPPfa9bY8Wv9xyK-pg&70=y=ZCXd}14*Vd}u# zMcD*OLZrUOCQ3OR6dB`z=8FXGF-s~H-bmw2gvV7qGtbANsu=T&at5;J-6iplk!d8U z!W96OOjaQiB~?tyW`}BJ$5aTVOzr0@)W-En!d$LOnO>(5yxLB#l-<1CnW*r@Giqtf z2UkcFRby37C@d)ECe|&r+nUfzUh!z^Z1V9Q(t8@H3gczbt7Z>I^asX`*1o8wDlvM@ z+mx<|V^0!I3bB*0(@=sLqAR<}!h5UH1^K}#l;-KtQH%;kBteTLhG6eb?Z74shhL8< zNuiLZ+*($bLv8@}3OZrwgcA*_NM`78>vi;!NQ&$)_ zfH>uI5Wp5@Y2+9fI{Nn+|6X~SJghL3dCH-fN7EsXcnc}&d;q0j?hzSdN+GNC+{s;?OaOWaON^E%l&!3 zpI={cukh=7J<@U8cmN4O_P&!^RE1zIy@;W6a>l%BOHWQ8xF3p~SH3hniuT}ixG*94 ze9Kq9-QTBxxUaY<-v2%+lRFPO%T~pO;s(%>6*> zX~|akTOlw_O?1*!l{+j`!5a_m<6GZ)7kBR71vBG#JmQm&KEjXRdk??(#V_#W@gqAh z8C$J`Y)CULggEvoG^iTWXf64`I(7O%@jIM3g};6M?mgtE($~@csw*^S}6W+`V@JQsCa* zJ6LuTF7DpJ;qf`nZ*Fk!?k%1_eU2wjE*r;G()i7maFl`=^~Ay>IiQe}AA-0)i)s0w z?sto>tP5jv(60N@h}$zbVa#v~FDB&!KksLgQW2-4ZM^jVbo5}Nh!m&JnBiPI=QHvs zEkjRPZ5-Xf@$JvRebSSP)Gj==J-Ikmtfbv-_9Pn9ba1%(NRxVY+>lw=F4CnmDvKJ( z-X{x83}zNpeIX*R*_E&IYu+zP6K_IVYc;U#%nBAHEU5a;<6VP}U9mu7}mk+2QR zAoH&+fD*}z=OYf~c$KwO!ES% zg6Cg8!Owp3SNO?KeuB?F`wZ*4LX@GpVy&iRD^rS2$$JeNGSVqY%i}3Xrx}Wh>hl&hx-Pk&^BF!$_6(ncGi|;!{ZyqR z<2(dbRB`$28GiAzpX1F3Z{WejeU$Hg3(K^b=ZRPY=&M@c$7PsY4^2de(l3cuGbXx;eclt{Aj=3Nt@6yJa zP9hW0kz*30McaAXd)cFK+P6+(jMeCVDE4dK?K`-dJUkhln9G?Vp#lh@*a+4MF3fgm zX}3WzIMHDGv?Riw9Saukzlm%9f@%1J53cpB{=V`i_ zr>QWNkjX}zgtiPT_lPk!68*|G4hf_eEcOt2ER)!JLv9syUkG(M+etQ>y`=UsczlPO zYeoBDD}oD?;3CjtiJlNST1rXst!b=~v++itD)J&a#1ildtNWIQB=Rnt$l6Ixip|aZ za!`hPDnL?v5vN!g%Esul<#MH=bT3dLv`dG&*C%2?^aRoyUM2tBHtY{G?%p}W`Pl{D zeE2oI`|i6qzjFr!!u5+w{Px!$;-^3UD}4OBk8pK;jS51o5_=+0TcQ&sHK>UTm^dIaUnz^uZz z9k596ln46{v8adv?>9^A+Ei|4qxeS!0{ zJy!rOmFfTJ|UGezQ=lIL_-or0{`Aa-|eu?$CLMn`i^YUISd&$Ve z2-%CKnS)4K-0pCS9*Q(nG`5td)RA^ElJw_M`#x85JWH6<{omy@x=b5o8dEeBk|qWe z<9H>5@k$4POBni1)a87s=vX?AY+F}+{OL#d*)M;Fx4-@ncki5|lnLh-XE>bgu)Cab zesPBL^A`TPt%7ZHV>plE*x@cqQ9E8Ry0FF2vqv6lD*3gv{(D{l&N4@7`y$9 zGBM_faB;E6H-7IS?%qEKk>dLD5+DEeWBl?Lzr-h>eukTyW23Swg`kxk1E)R$#PD+z zO?%JeIaK5*w=9bBi2)_jNylc9O8Q#;(u*dLII`v(7M@v)6wh_)C1Wqsq1v9j-7O_P z=F|{4s8lojVkkE9!pY7|YXHb%g%s-a8@PAxE)Ito=XVa+ zKbvuJc7}U*?_j^*a_EXRhwloTo)d)t?`tDUG0S zt@;s2Kq=JXJqRcTnCBUX!vXj1-N)Nse}J!l^8xl}d#F}Cd;A3N|MGqO<~P5^<>e)6 z&6#dlVVXyg-Zfz8l=Eoq|1Fj&Co;6XC4~Vvz8d>(Ow;#ahTxD!QH*T^|3>}q7o&9` zm@yaq5b~r~q{1Ws03ZNKL_t*Pkqeh_g3nXy z^ANF7?d|vYDWXPh$`@IQVkQ*|iLEPPz(J_F*?p1eEa|>DPWw>|o<2IUG5EPtrDC$r zXxjwGO)$@W1YcD#39xNdZ*SMvO%}#T$BH8FMWi(N-Xc>u} zjYb}sWq`dj-tiF!r9TV8IuZ3FkJYLsRi+!^DIm`rAZf7$fLF*h4B2)t6Qc|&Lmj9b zA@)kqLOp9N7a!KO1%)Axg}S2B_kZ)uxHvz<`QaSrXBT+*<{P-Udq61*wpH=u(Q~~2 z!H0PC}Z=q694ZB6mv5P{I_zy&TqH$E|3c%#g(i0qmkn0_BcOW;Qag?7ZhC+zNu~<9;I>DI^L| zPa6;g3JKVVC*l{H-|KGV=Ll+wi#9W0HFus7za?X25ivvrg<$6GlRP}P12BO~d!j44 zp1=ccqo8M3peKx1?EczFbgKd-#=OjY=i>Zuet!0vUHMACR8fj57ZH)8uG^8Od9odx zFPxi%SG1!z$*GC5@2vkBoYAQ<4oTxy6Pxrm z%>KM2X795q&JIO7!FM@o2sSDOQyS#@Kg;R!O6W2B8yus&hTtM>DCG=y&d+gnIK%$z zfQN5B!2WOs5Mw*u;>qJ@`24d+xV=7xD$mt$%-TJEF{!5LRLDs2l+=DvK$uEV|AvGY ziB6$L!Q`Jo58b40c2|#jq6QJro;nX`GYW%4t}=2`8HL*+B_c^2lc+ZCf3)rriJ_`P zBib%+XTuisG<(wK#Zv1oLQPx+H@CNV{PatF`q`&={PxzGH1aw-R3)*0D!MB=OKU4&PQP zf;muJh@Y9{6bL=BjIb4;l9b(ERC43Nvi6;NOSoqPkuk*Z@dEVjmCHE@d z*s@@nXPxG0Ei0o$?a!dH;n~y2`1OY$;Mvos_QFo#P11Cj4gfErVLzEc$b)*0 zvWKqsuR?vy>O4OcTiZ%6PTI$3!iv0Ci!^BpVUBkX>E4T8nuyyWGcnff*mqo-K-2O0 z77MdXX$gLjDZLa=8n`ka_o;RYiN^?OQ>k8FzQCuSeu6K)_!MtEyo22`W7+N61y_Kn z6ij77Db)qbYT@ijixY{vnI+Pk{O8zxH2^6&*rzrqiUb*ehmidt7_oEq{G)*<8JCOaFmLCDc~yHqTd;AIa@#A=C=VuH6xeLP7XblPQA z1MLZ?mL=`&VZ~NZh%2q)T`VvIhgGP;WYYzy7I`4a=2{lG66xCh~b9018jt-%Y=n6}scD^RzWdk+RK7|03GT8{Q zV%|;o+M93U-u(wCrQqi362JZ6SNQdZAK>ZbGu&)z@ZB6*OHjfgk z*1_)alkhRR+E7BtYEM}9NZQX{Qt3o?Il8dp`sx~=efk-`_~Hw^`|j^yzud<>?*MAk zmEE$#GA($a*WDUIBkNr9&s@9eFI!YPy3Pe83=FDQ4Ul%f;4si@T-mBVjX+Om4={uk zf=I-WAo&b?a+4%kO1u{)eT>ZgrzH$7wyF^8B00r=v8ELF1a=P{Wc&RmE-2j8lkAXE z5m2ou?^08KV_sb#nUjV=S?@kgu+---S-@kU0cp?DM1+acK9vlGrYm;5K&0}vu6TXP zy~3|~n(MmO=cx2-;zdfCvB_%7dRy*;G4TQ|8>Ui+f)r$msN`o!qG32&I6=BwJ3=Yvc0WM-Y@=zz_y>dVch9 zBt}@!G-9Qp1C>x{>Pza(uC&v**dR29FkAPbW(4F6x3>^h;*`avGhCfw^7UuY;v>U~^N6j?2Xb!6bEyfb_4S+RVJ17nzh*c3s+?0lL+a7$n7+ zQ8F(}9)$~qL0BTMLXq>DG;-YfpRcD&YwUDc`$M7v+}zya%P+sgC!c4|;9zvCeL5Q<%D4&r8NT@>3I z!xPDimNwoLfov5l{SuVadistpr$BX4o_&338IBDRx1vUA&z#?s_GxwQ#e<{>}vk7Iz)c0+q;iZdwEH15`*VX~XiS3t42c-v#Pr{?s4>tmh zDnR8fnt)v<@!~taOQ30y++XICS)dX|cvT;9G#)Ugu^Qs=cOM=3xXl;Q$dnd@3Dt!g zlu7#0>6Y-$Ne1s~S1-DFg^94tGwz<< zx;k>M{ZEw^HRZvbZfO+TqS0JYICOzmI|INp@pLZ*llUvmGFT4Zwqe zn~_oha-w_YcS6R+w<2X2O5YhPr4Fv|sExa16M^=RC`NIM_e4S(Q6Nf8`TmDIlr_LFtMqRr6rf!!)&q>UNOdgA(babk9EQjv zgoup$+FccO6Cv>JJTI>=xmW#FwXRj`qpG#4HVAVe@4`F=rh-WzvPMPaml(t1F`~!u zeN-6*8CkAxBg58_v4u%m6gRa_t>K{Dpe!8<>kmWP!R4Js2xdZ((A|7KD)9q04oo`9 zy29vZp_H)dyC?Eah>^E*Y5vp0Jjp~Sz8h46Sqid`tuyR29R#7`B<`%i#=v%roP#?C|i7dpN&yW@!Tz*Dr4H^l>Bi-yV;swSCGZ3`V`M zLFyDf&`Mg4)lVliD>a_cSF)j5w=g?)T@hDvq~DJbCgIkDoln&CM;AWrxH5 z42RtTQ)wcxp=;p;O{2~@&4HwT`HH7w!&AH+Xxvq|FYgv9MO}5vNH_EQ$h}|WI8kDA z-rIAsl%U7;a1!EV!AeJQd3K=WK&Lj==26n`Hit4zSeB(*9;BOATH<&+L)cP-i$9la z;v^PGDebYS3A?4zJ-8UtN_-+#QB8K)F7_$epKSjD;?j1?OxUDis~eb$UDN>6gi;nM zJU`h@yVpLsR~A?@s}gS@R_59ECDIslX#ZK*DnOOwrDl7$Djb^=y9V?Kd7q6-kh=Rs zyDj)jm?WoZGBEIh!esyzJ3mehxVvr@b*phXp-9_xi9`^ii!JQBj&TPp!b2ShjdVAq zh@Zj!k_Z^F(=$o|0hl8DDyb={8^hJ&TsS(yUg^fTlX}!Zhs1X=hsJ@!iTh`J0;S-_ z=Zn3Qkka9h_Del0t&NI2T4!Du=NCIH`=vnv)+3%h{Swcfe2MM2Vj{M#qJY5dc4#&~>b7pUe13(;j~?O0F=aX1_>mC_E- z+PXvc-sK@3Ld?=>=H2_IDNQb2**Yqf!^fz74Bw{_+!NEy1DNVaYjSmfIrykH_IT-X z8>b@@qj-m}$KKZd`I??2?}DqHQ^hU_B4C*&%*%{`2)EHm3e{Z+! zFwJ`qF?REWd7fH^k{vUJI=8Y)g;H(v@v5ksVB0FzZNn-X>L#rdJn{T!x~-OL72MImF=@Cg)wo#ZolB-&N=2~0<_}h<`R#ee2PbpK0#fN znCvsD_Cjhp*?KUfS~i&-oDx#AKs>dvv&ra#3Zqd(#Bohs)Xu)2BR0|rg?V2z#TP~<=(%2;_+=-7Tl4a$Fvl2^ zxkPN0cU9sdk`%2&ls6Xcl&2vTgtdDPv!sI^lAeZ?szZgEF7q~uETw^u%d&u{VgatX z+mh%+b9ta@J3jL@`qv}$y&Kz3Pnn?`L5{15C21)1V~$E8dyZl_G` zXKSekrKv7;p64qNeLT<8?dwbK6@Tq_b6t<+x}PB(UDF`H+%l_NNZH`rsNNkVigv_Y z#45G7L&0uy&KncvdB)k{9Q(sQlz5Yk29(nf!;doqeTsPEO zA+@#o4Yeeld#QairABBkP8H8m_qf#&4`;Wi_utbGHuq-Huy5m@`rYS<{i4k(5Yj*l z^*~YSUOZ$893}H?f0e>mI%xI!8BBxFh6k0I2e7osOu@3-<8X0~^NR~ig`rY$eR+v5 zAAN!6&tE_`j}7AJT&q*x?ZSmrP+@ouTc|jwqtrtUcg%969vvM5A+(K}?dO zD3gWb#FjxXOWlRUCKw#CNL?0A9gK~Re8R9FrQs5dM_+Uhw+!8q=m>zO_DnWoFo7)o zhnR7DtayBRgBLf)7D%hGuFdwSOpO~FMHr{T>tuhW*_Oj;3)-g%l+EhCA58g&92Z}T zg&L?mX;kSehuFbO60Y?zee9#q{>;98Z7S9r6_o;;)8uG?cU!?WF=3txsFXG_vR%6P zjz2yHR_s%r|90$yWyTRRCN^a_ zZ2(JGBKsv-icHJ&l&A9izxr?fyVs$qul&tTrR#JKxy-g~orWxCed)PX% z&GsF6v+AQi9u!oh;v3WMAyHsr#%{OZ{OlZuvop-|+?Z|K8uE23ew!JSF;trV(lCH| zYKg?m1=FQE7c_H7$ktMVDxL!<6m5% zN+=<605rb0=#<^8Oc)MSqE0Uv4(T|=TKteEiFI%kv%)RJ5e*2OU&9=;*>(?%WxvDW z;?SyJ5nMidfzLjBjH|2FECU_Ic6u3wut#aQ7~%p}8ZcDw@lC!28KF$n_&pOYEqsLN ziQbxX+VmueJd^nSw`yIWO1HL*H(9p~bU-niuM_>}Y#)SBN|8p-^b6RrxPXcx4mQ98 zns=p*l;Y3cab5BB@&%s1xNfA4X~HzkIIbJk<7$P3cz_`Wsi=;&g3y$z?ad>=x2MdH z%BEh{aq6OCEFY%m+W3>|wXzu0phF)-$Go^G0mu@)Q<_7b#&pq+JyYDHdWgHIClKD$ zS$pkVm`z|Jrf9?vVFM#I$x9iFCicjw119pRKCLPY5=NnR7P(Qijk5jObWdRtWreoD zQdo*F8(L7ce@Pd{C+}<9skzlKBgup4Q!Qo(iVcL8ROqky*LonGcm%6V)kNb`g6B&u%gxtg$QrlyNAP} zN!9Cd#r2C9xO{eltE*$XjOO1C#oF^Gwrdt?{faBS9{`XSHouAp5z^D$JTpvM8&HJ>3gX^x1*7;0R`-}TD zrg#x6gw6Kh9S$vnz$jRk%Av*;=}8Kt7-P5W5-hgwuc#@5uz0i^l`@)2InX%vRaX6e|S!UY@tPriJHm>QjQKNVWbxvifOhqb$1QQjMserj) zo{M==7=<^`3OkS+0JS=5HNsju+umvN3BYbDw0>!``~4u{Lo?NM5Y2O-WCsN|L67!e zwA4eTzm*cd3v)z_P>dLzh3VC>k9tOIAP@gHC0w$;WQGqBkqByCF&DzUyLYkQ?b>c{ zTX8%du^n5c6{LC8HfRV39PboV6=0CDYsQqi2nopy-DBfB+&9bF&HLy`GEEeBRcV3> zH`pnsZfu;`vH$EPuf!Y#Tq6Ct9q`g*^^^~7+pjvGGcg{$$QkJ%8qbK|DvH|o)7sUf z83EVL-R&~Hxw^*Xi!0PxvD;6WmIa5y9?LSdfmzUGx|x!qOSD6nIk7h_-2&s7Z=eaM zL2DSE?NXs686|^SNAswNsf6T0S5I^FT#(kIpPXcreJDEQQT7Q-3N8%r1E{5?&-0Ak zvS6AgcshJa=V~fY3rBCAb{#=L+V{j$z{P1mlC`3xg1P(T%2dpz;$f?`7aKZ$uAsix z3oMv46{V|Y{d{6(F!L%RzXJ5d>r3u$C9l*~R2~swa{`HIzrdJUMdCX+AsYY`>Ofk*TJ3Dsl!lpvrp29T{U$;Tcxs13sbZC~Fzj2^U@ zc%4Zp*BFBo6a9chNUsRhjrZAg=HOuI9)xy+vMP`E4YW%m7Uj#~Y>`pybTc&%8u67F= zhzL_*9QF&&c026mx$WEP7Gn;n6)M~X8r+xUoFS~?2q(T1ZuOceCbEJY669tGn< z-YR$oozBAgGGAQW;Cr@y*-#qsc%nk~@=;PEsQLYhfncYJ+cwm=qAG&R%jbA@`52ei z&#>B3p0Z3oRlqq*fvEHYQA}+~*1#l!|oZlK`EhO?hJb1FGF?P*<2OFdoON9>3$%Xfgjujb&M_R9jX+atf6L_xIS z=Jp0xHx0Wtl?ltT!)|xLG%uiuPe26JMIfXg;g`pL=!L=Hr9%!o>LYPV9ULX)uV#;^ zWgvFaPf8s~!_x=|2KQ8RpO$D3mDRkvwMRo7d#1g(@hK16yS>{jIGi0Y%~PB)l*Y8; z?YePJmAY8WF@_FW5b8VA*d^OYmk$E=l{if$F1U&n?OO=c>(|?BU})g?Y4$XwyfQ z8sdz)Rj3Hob;WATLf=FCXub<_lBwFBN4955R4l6zW4JDI9^J`OiZn&_^v^ho6mTnK zQoIzWoH_5etBp$?;g`vyNYosc+b1JJx9$wrZ~J}4{+!HBDLqe1iy)fW1ZTc7Awy-g zSR$zgl(5Uyk$}|{jh>1gF+rl>Qu@>&gqR&NK;d}bm`o`1MZiZ}n?;*xk}4zd!GGkC~@$OhuS%WY9kJny^QvG)p3S zPg>52$~o!=q?qS|!+wW(nIY8n8Ke@6*RIrxK$x~;vgbp5S4bL*=BBu;sLDVEwzbcN z*r2&nnX%iq?`o|ZuBvodd0LxiOi&&>`r!vj24?kctSd47B=o&mqz%Vt!p)r=VXHwN zNsU@ysubgaM=2sFiCKoSduXXBkX1N=TnSEgRSuw$_U9^vO>)gKsuBR03a}KErGSoG z?;!oewL>qbkH?_5TFuL&cu~oyC23dT7dWK^3T8&((*FG_LviHFQBQ(sY*ae=Oj065 z98TR%p;_eQ2T@WPx}e3W7J*HRygBN-x0iO26qg$uU8RXwqv@c>%i+LH2*pqmc6R1IR3P|4{i%MRshGMu0X?zMJDY+oIh>$UA zobo8USJQi=S|z2ryTzsFH1-a^@A%wqQAz=q37fQ7rilBo$paI`f4|w-GE~XpB&DWD zaDS{v^RT_yu~&4}TSVwzWhyAk1eDT71tOTaRV|xVJ9SDpiDGN^uBq*JKYs6$n~vh?cM*?AdW z8^Q%wKWmEXIN3Kwbc}ZHp7wo91eT~Y+l5F_C6H3D+B;Z4=`hd~zfR#tkhri#6l>kE zZ7WKdn!z_d>jtZJgjXlkQ!K~>d6w3(*~{lzd7C5w)AI{jkk0rNkIfI za^kq~G)F!eL>cUK4YTZ#4!LVSlFWgb?U3UnGSH-^qoGTTt(AAbF`~9EO|lm)rK*J# zzO+#)QK$Hj+RuTZVk*nyin`T^hk=r*4QYsjiYbWM3R+T!@1eTkyO68iDaBuD9N^v1 zu8}fNQH3K?~kPAe{&l7k-yZ|?KNw`+|*X{0xpdW*D+s->*!X1NN8V3^P zQI;a7CB?sMFMEsKX$Mce-5^&-=-N#7R0vc!y7^Z9$`JR`J#iLxD->OvN3Ak?$L0l% zNb{7nWqb=QmDIs0QD=$Tj%U+q>C5A;F}Rl}kOQ*Owup4wxKVYQ8dn-&rwY`+wzz5z z2649Wx~6@keb4^;4BkE8k8PApuFg4l`ua_O=*Sxre*#svNB%DnZYptj%sDxw<>NqmjlkvpuFY*KxMU@Sk zZ0IXZr*lJ@0>~%DJM}!qFrh91Ldj?PxW*qkW_2O**S3`+|JG#;OthiD?UzuykoDOI?zlmIH7yaEEs)Q(Xp1-p61HqXu1 zRci$%Mme&M zsy+&1=KnvxJhb2zCTKwhXg z7R#$w8s?UW&d3#}lyX~|!c}75G5mydByS9jui^wHM}21%VJI;SNYgwkNGEM(}nx~Kd`M>(_<@F`^ z|Kr!a2Y0S-KfC@JGd@(scc!xJlm)fkHvfo4;HaR>dewM#*{!P%U+rn$RIIh{85!s@ zH3b)ooe+)X__}V`wkAvg0nm!<(XqSL{+=cu^Vf395Qy{1(N#Cs=?&L8!$}C zOU7YoNVQzMaT6lt{Eg&|_fShuMVik;KFWA>Tuh2196KcGAkiTGlZ|dOE0g_FjPXnteR3Gi zHO6ET(de4zgXxdcxrssW7^>g4J1ExahzP0*Zr6&nN+T>7C(&m>Wt!qpD@igMzP%u; zOB`yI4R;j^xMFm82J%QZ{S`TbX^brPe5LcGLvQ12^HAmI@v#$ zshA+V#7K!_+{j(wiY)Z#eeHk%OEgVS-iUo6ij*#({*>4= zZlWAfIpM*&Xh$Io2)F;#C>W)$8glU?_8xQJbqzTarlO1>T`Ove?bwPjE*CD?O%vwH zcF+NY=;~2O%wM|w1-(Fm7O+lWonjhLeWf58HYA`zt=(rPl%inrLZV>V?XM4q!@u3_ zmY@E!fBkQ6zp8i0SH6>L0+jPFq4K}oyLb1WtVg+!DrMHq=Gg$1=A-HlPkMF5BS|!v zj-owAq%T($kQ!q+N=x!870306>zf;F+ZNs;wvp#|*NF3aZ(I8GK&IKtw z9WK46F6$9W7fsObTlJvm(tSkoHAiM)9BLRtg8IITBUYzfkcNU9jSO(MTNl6A_V229 zv`IM|Bi9zF%7w7o?{V+$U0ht8V=g63Sn6m z?3SHnJyJdF5AW}m-T!(x>_7V|-yeS`F1h`FcXf61;{QH7JNzGKXV>4ly}h}^m{E@_ zs;qHYc}xsbUnuu+f`%srU`(tiw(t>uz$8~|zM~Sp-s1MA{VW=)3)n3)rpf3UEXfz9w&5Cgn6YY$`&9?h1(A_iLSmo&ZM}`n z7im|9>adxK>45f2V%V>WKW|N$*Jps{kK&GOYGIh8C0aAN0?Gf7J7?=W+{4-L3lpoj z&)rkl$<5>)VD2+*MhnO#RTKplF1R>9$Abs=u|M0REHj9J<95WluBdfOpLZvc1|2Ak z)}ts%yE&%LFAci|^*@(*(zo+jV~0H!PM|anhe3>uC_?%-6fwZy2X&lR2(WbcDYOm^ zDHg{Q=RFveebiW^&UA5Ao^|^ucJj^Mu`gf3x53{%oF?AN-5|`hR%wRlYy? z@4_YbpZ?Q-sfXSE^JSj?_rqcNa+)S(o)#H zOu0l;`@QN`aXcQILXWxG4yJ;6Y1wA`vjcXAJ$Ac2cJl%Av^Nit2YxDQT~qbMD83iu z)>XMmP3d%X-Nq$i261Jtg!4X&Lab2{aF_PAv<(=29Lda4mBwGT5Ax1XY*!=H>DPhR8IdM35q;8W{d#~E>?00k>sDJCren@ zSl5beYpTjng1a>(o?kQVi{NHmal3A)u16TscKfJZrFD+t`U0QyXa!_zDs_>;a-|`% zV-zZwxS$Z>uxrzjiD&GWy`CQqkLRiU+hsR>@>Rb-{!Vmq0C4}_y{qH#_UGppXCLmL zU;Z9QXWazbG)4RaNWn!x(!&NbOCpqRA^_U%rP&YKq1~#=hOc2Npy~)FiiN(4g68(` zP4f&cEs)Wrz{~}uD5To58%`0~P-Qb4g6UhRw93l4a9T}#V38e8Hl{R=(w_dMWLU90 zcG470lMZyEp6VMYS85VFN$}jh2k{b!B2uPf(Q=3*hrQk_VM#P*G8=_guTJ!rV2n~f zRI{E{6SmC$s+;1)^$ngqf8JtTq^aPRdBJX;E$=T)7ZU@MF^17bva(CdMG|SlyU#Av zU^m~AoJ6yA&~QcfU?K&Dc7el~-i{%GIjt_KkKJ%$5(%Ym?kcT|0hP!%4D$=o&`CMI z3n@If`}X<{S5iQ(0|x|ZMWl6C1We0%bTt2_Vwr&eZ%_)(_J`}kvin~Omw!)0S6}tJga58va{tMH z_Ag}Km(O?m@{_|E-%L|Q;T44|rb3B2lEF&-P|)}Rr%Ki;r(&KDGR250HKv|49}@A4)4DAGAlD{(2Ry|88CL^=%B-Z3>K2GFa=_gL4d5LJKBzR|0^9G z-4S-!ri}+sTQ-A05CUXc*i2>+Ai6;yiBe@{Rt_)Uc!zV&-h1^Adpuc0M|7ADlT~+D zC?r*7y?5Vz=kC4NTHo*IJKccd?AnSqmAWu5OLKsU;kB4eQsD_pVCopN7|9B@khzD5 zpkmnXob}wi(nnVs)&GnNqV(gX&9vBfIP^ySVBbK67xLm8JwT{k#5JjCkg7)o~-2Zyt>Gn`*s!kR2RDg$?=$ghZw#3+qnisA4Isibz^WBCNr`T7JZo=wjwqcUN~xacaB)(jP@Lk`F|m(0>4@n@h+ zKS|y)e`yxZMZcp&Lv8e#I{%#e{XO0 zOz^}3A@1EDGR7LPHK1|yf{{vr!<=n2Bl_JA!!QK0i767LQ_e6Pd^R2jTDUmR0F-#3 zxKfcQ8M74Bh>E77ic}0GfGj3eO;&zo$(KZeeM;r>S$Kt7AheiVL4Pl3Btrf}S|(#l zk>>4aGV6+lN5Q7>qTzy1K;G@DZtqn?bap6x9DI!cLOkkwFvGK@xu!71v}~O)0K7eQiYoA(ak4 z=VG@;3L|Fb*Sj z{T4&t`;_rY0aieyJeZX3CWuueHvlDX>{F9zVycHZTyBq~)}`e9ud=g} z6T;&M+oeSCh*mZ%)Nlo4I8&DgaK5>N|&y0iC8cyI4UtSjdM%5-0DMBsQ7UaN#0b`-+%mDz9N5t z5*-G?7lptv#f0+jf4(@IO2uVSO~y+Kg0x<}odb7WZM3#y+qP}nY|z+hlE$`oY&LeI z9Xr{vn>02W+qO>LGtT!HzBSelSmWWEbKdj5D#4LrOgjb+b}$|ixnr z>jYwW=*Udy8_#2c*0*RW8M1ft`tYlfhw-gv{1)?=)%G1%!mE9Jm@T>0w&kOk-J1Nz1XVF1e*E)cW8BmCap5C4}ki@ zxu@u-_zI~@;N?GKk?|!#GzJ3z)Pl^p1Y7Dp=WTUjv(p1O2lC}^X_2Dc= z9=y!bqHw|j#AnA6)!2joK*YX z7@1Kp4nY!ZNHfGr!|abYmU#)~K?- z{LMw9X13Alc=`2<5lDc8sLaqbNBq@-wuCZJH#|fc=gaz^;`?#Nk%z?d*Z5KfgIbK3 zjwtQ}vnbY10#x8P`$r=9G`Kf9M`h>)H?x^oSgXA6-)x>Ve&PDIq~sWY3#y5!OZ~+5 z`)jA4*#D7W_X!U$-9?hIEvP~zrG_WFGBH=%DxjJm2+2UMXv$lr-GU%U=r1qHFc{mT zIgzH4B05uSk%NqiVqtN$7z!r0&LXg1Dm>L2x8xjOt;u&kcXYGA_eI(eqCXtQbpHe1 zd%OAg*dlsO`T6%U`cKaq@(mDB55^56R>SuT~fT5^k3x= zeq(wGP40}Tbn7*oNj!tR{N3%Y*ES*H+YJ@NXQwHOW&t05`o&2X5D@8+wrxE$bYj!d@oemRWuDR#Log z=10PiOJT=W)qVO=5Y62#VwzuKlte0nv;ro>izlXw|tJ;{z)mYASuS>k5FVP^cjLf7 zL_YyZRCDJvZ%B?{Gn~s~Ev`^Bsc+@L8*#xZ3yiUo?ZA$jG3R*IeVv+YJ z^JQI&C6&7<9vEg00wd*uL?P4DZU6Or!j+X-wcU?%&nw3aERg@YY~?IkBCC*pDL$thN+ z&pv+x1H-;3G5WNU+l2S3nW?P&C8j`?-Yt#-M|Es@=j+`a{J&s_y0xnL-yrWa3po%mXM`6jo?H9>;x4XXByE>0Jm;gH2+v_Key3Zc zX9)eNAYX4PvnA0X7t)V39<*o#WCjzIPk!<$(xr7`Y1%Gd{!NiarUd@ZJRf54u;x|d zN51|ol8nmyC;XW5A|3AgtOMWsbw~eyLIz#G>!2hQOAP52Is{a}S!JISO(*~2O^CIl0g zyFcV9Pnm^S)C;yq53wjY8LC?dbBX~N%X74}^ZX2*F@jjIg36Vg(jXp5+c{z=Ebt%v>+& zQi=i~gb+E!S^ts~MbLdNvtjFzB{8T*eBFAf=|$SGLWTSMEbP&5OY(*)7gxoC8Wzlc z?%%q7Yrgf#K@SjkQaL=MF^B+EFJB{o2`%(=3YVygiTE`<7M%9bV^{M2#yGYs*}Zi1 z1}?=iygKq#MG>&gVE-42;8ouUA=>cg9H0aLg8JhdzUQKsj%}pFb@)|=9Z}tPmN{HZ zBAzJa^63}~`wj2K6n}|tE`KTC9i6hc`Ra|xaSpv}kT(7hDJv9g@^Qj-m+^TfMFEh) zYC6c?V4+K}vaPZf4%^N00z>1X{8Pu-V!x=6P_4$D09o3v{yil7%6b92nF;K>5{VyM zkZL7jol#VDVh_F8*r`fM7Nf6JVW+?+ewQ_!*==+4Z1%!U4TvAU*EM^PRt@hI#J@fY zt|ijxvc&&DGw%M3q%=EY|6HVEF1RDcSqY-oC8sIqAo9dSg&)Nl56uh-OLQD1{hIpW z3BrsCg1Z5fN0OwAYybbJ1rX{jZsa`k&_}XF%IE%utu>E5@(fI+%I9-M`uSM@vVUcV zc6jyA<>TNdWyv5OJuhptcjs6Vtt=z9-I$#EbphZ?{yP^nH8zdRH}Nr)utF|(VVZzH z(}j^#fo5Vqp%)2$cM%6m#N-VKO_rs}ZRe&^_@W>CUkA(yb(B5nNi|^by7LAw9bW}WSA~CCL5o&I{PPvL+P2qR z%FmoS6z$1jt;PDOrcewdn0JpT1s3X3FX&*Qp}~HDb!-hiC{WU_lbS8w3W^du{&#-;0=1(}n#tLeU-#pj8s~3yNTdBCL1Q4C5nvo#N1< zpS-z27M7_~%KaV&%bfHC?*X-FC79Fc7Y@t1IpEMLZph6iB+zfy9YoeXHK1o8oB@dzW=*!wM8)sx> z$=S^fxr&RWw#Mml|BHF-kEM~ueVRU6X_DEPL4SZG z^QP6n*zT06k@Fu1_fH_q`$y_pd6i!?fpNa#PIiB`f=I={5HKx~g;g%mCqJq}2lk;M z_>t*p9)+f$#&-OG80Rkz>|c~yUBGjvdyKbd$Lz_R!u2`rb(NPHBR`l9F^LG;A6C?X zD`h?7w|x-MeT|3QbG$DeJXA=A9Tvidp$X|6j!pqqOsP?eykpe7pDx?_y8u@*L9~2{ zB#Zo`S_3+@{~rS-N1AZ=AoOtOMbd_E2n_(Ld_@TYtW+-+EUTKxGWwEBgV^f^1R;!% z3Ot*RE5q`^Et(735EYcdce%l^qP~44ev3;Sdx1O$OF0^pj-l20coUF0pW>ke;qSG@c$ISFR z> z^dE-R4Aa9dXYj2vaJR7BqTh*fV^UD^SM3zUb_stY6lUdCM#|)u^OSU3F!X0xgh#H~ z(#%Ns(z28W=u=hEYv|_e`mw~5p^cp{j{WNx;G=|4d7C7P6P4aF`oiL2vERn-1dBN+ zYa>PCgw*%;oI`)3(}Xuu=5Y3X!&aAzEYK~i)@Q<19JgX-sFtGl*X6yRns>iHU9URN zA9M}L-;=x`?AiDI+S8)?+Ao;5D`!=?&9g1YC!mlT?vobrxu$Z4Ts=XeLznF@YpC*5 z7|r$2h>0If+Nye`RJITE_i&9rZf2MiWHBJHfu;Rb3ITJR-}=W{Fx4n7MgkW@!pL4S z&2AnBd#Eu>(h)y+;BO&Ws+3tY9O})AAt!jlCIETB6W z_Jj@jW$MrG6hKV}Z)c2mvFt13GAqFFD>OXoEXZCXC`N)Z%V&SXWsD!}R~Xiac_(2N zp(+6#Kd1cMtE@qVFdAND15c@sNXImtJ8NuT_Z*fP(r2J~jv`PA1HEh+&+L9I%=sI8 z7O1Z(cl+oGtu?PZ-lMdB!{KUYJ>B{8L-MX;rj?(%#|Adr3NS=YY^+j676p|vD2pzB zu=`U^`Tz)!5POuTkvy=P)0S%w_xLF@wT%{;{QQ>l3zvf)NRxfw(tdmnhIeTdQ*FeM zze!;eaYK~t!jqD4LLigj3?@F!!_2TA@<;aM>5;-sdobJ~LOETL90Pxz@mI#P7r z+$~Wj)+5xN#*Ln-if|@-G?f_*@ju702PbZ|v|Ub-+{^dyU*z6VUGLroqaV?VP=@{r2*X$pbumPpTXY6Zo7XPlw=VT;A{ ztg6Pkd;-EpK}B`0%L1SOvS9Xonnh&YI@#gSXq3aY!-*fXp~kC591@{1ZT1@K8>leM zufB^{M{<~nXWH62PITVxMbdP!*{`&?OYcWh(TE1|t;iL%qH+1Bt+Zwx7DaQ$4NGT3 zHndJ=^wGN5o&&P8Vf20?`J*<#P%_CV_>Wc@#S6)^8Jv~>1~Ah)kWIL4qn-s_5K5*{ z9LEe)8Aag^HrWH7UBVqU3Tte&mnQz|9p`JP_S~P7zIE)T_{dzP1pIlQI1KEqtNAF% zX8xSm?wd&mc^oiQPd9U~YDw}U==m~$HP+6WIXj+3c3-liK!Ea%Ob5y{-WM>_MGET5YUqc3L6e{)x>PrI=x zO;gQ6j|{?8N~0+X8Js|D#6P6M&&+IKUo7Dx&ejOH9?qKgW0{>Twwx--G}oH^F`xDa zsyKT!IjRX9G59+32Ud5mPPs%42{hcyvcbz38eTAjjOc^c)fE)0-!aPMWDQxglb3xk zA#Vbk@noSJHp~ad%GTUAA!qwoTyu_K=_5TgiSaN{gXuA0vwNyd77YH15Q-NZqs`fHUgi2=&-mvB+@l4I~k9!?Ax9kbtlL9 zZ?vB!0aAaiZ+8(s|LJh{XQ7+-4Di`G*JW%YPYK1G$}UZFRR@+-yb~X+obl&&C#P!U z(&7cXqM4h@LQ;eQ&kLGD_y|Mt{IipDps~}cA^|mU_S%ItTnyDEKUZ&CY(+NQ&uI@E zpI1`+Wav5(76V@)Hw97F`t;ZxJtjMqr5F$jLx%-2X1s0u`8y&lqL;JN@nnnr?UeYY zbDGHxqyIHCttSu`#cW_Y0Zk~_sggg*jew@Heb%wC&G9t$p&CdFH$q6zLOfH@8Fa|^ z#c%m#MS~XQ%+=_bD}P3{!-`6N(b3Swb;vPvE`#XZPQx;ON5UnKPyUuOp`Q*j&=CLm z6^9%YS(hRaD=@PlY*6s&9EzUVuWw&H;l&J4r$W30#LUHTRxR1;?7Cr zrk7;>7_UD+MYy2F-e6_Gj%BxNMynF~(3X3Eac*c&wK91-DgW z;2_JVnOHWlm3Jyz&SG+SSG(4Q`!$P{h;OgI?e6G>a{0#kp-4nRvVAuLE%Mkd+85L6 zXx^pkyRA_k`|f&zJybDPFiu^95vHKqt}{u*UOzf|cc{EaFviXs1~;Ou34WLOW7KH- z&&;I_Vt2(JkG(v>SjvFBEhr~6?Y6r?5iN|qLc%grYDK!`t?YTcynxMZiVAUH!&nl4|iitQZA4qhIuVBSiG^EWICVzIsW_r}CV`ClT z$&>KIpFydW|MoKDh_6y()q=NKkVwjQ{t*_s4R< za17wwc=^>Dg6DPp5cBkpG!W(SVsoH|wBe?yj(-sR$Fa83bHGq=lHgn_w6b)FSNCsh z2>LPcHp~FNv0CgsRbetAcB=;!#oS1oR3|2&^>=Z7r>{QKS&e>mZ*}Q-~0V7Pg&H>vxYjq%DkSAHcIUnw?wO!vK6OG5$8yF14*{bYb^g({nyG^-x#v{x$ zqlTiuw%riB?82CKLV0$sy6$C1e1U+m|#@X!Ogd49)PRciZO| zU5_~acBPMT*qc1!-RCEwh8&7xK=XWvfLQo`tXWj($`D%W;Cwr*EcE!V(Rz)5wv5*6 zdeUA<$UD-oCmT(=bCqjcklwCb&4cy%F*6whA-6ihYHsjSGurfqy2g3|N0Sx(6_H;0 z?W>DDVd>YOH0JryA7%nuG*!!k!lgG5T<)PoIj|66s2njrsdQsQfNRgw^Y;tbJg3}~ zli%ufSe%;l3Nt;)W_5^(iY$>K%$F{mTs%SwH_aMX`j*jJF&X&b7ydbL1$iZ7@aMBg z?2*j`^yOKtOjvz|yMui;Vb6XSIJeK|H9rIWL{0SD#;yc2GwU;J&FZ$YBSpa81Lz{J13Vr96DeA==5u+19MPWYl|BFE~fI_*0YblPCqieW$S$D?up z+A=jyE5s`18VKbMG)_;0l){#fS;1D2t!Zb~3uNrx*9M||{p~}O z_Z^Q){tLL4&dJStzL4Q!FVoeyu$LM#M}mxt&{t@Osnv+rjFkL4ojL8iL-(LEU zk&LVHiJXi9aLx8D)QnJKbUk)@zl}gpBW*h`2j`OupsHp(sYO3nbsk}-S?2)s4~+rt zLCq+GP@E`u5hSNEh~=d+nhQs(DDDeEg>3P{9&5<4$EN2;k{Y?l&rZqhWfZ}wnLTBc zm+1CDm`2^WA-muqvoHVv`=Id~sKr-9^FBcv^b!REl6F3>iPF7FUa&5|92|;rz0J#h zj$SGp1`M)}5FsLTq7?jb)utOpDe&sWIzmdl< zB7jp#AE#arvmQmd#1c8B4P7h!XtSYDXR#v8;Sc%w@1XRYGBsj#uQ7gnKDA0Fdwju# zM(+iGN1P-DjN&Daz*h+bmFl%o{KH4s7vC6CPkEMgc`43tQ zhRi*jOgc4l>Iw`NMFbqH-X3|~=NT&VuBy&L3oDHRG^Y7Y7hWM>x;Og`1?Dy5Tn+be8e=-;9g9?Mm`?4*@Ru(J($ITYU#)uVztY_Ye0(}4?8as@ z)ol5!7TrfIhm99yS)i9gg$ma0uZg!dWnHBWx`Qp0`XhkBTa&5PvD&1 z6J(#mtW8X2o4YnGL%}Fw7@F7L6df0;`>_>;aIRY;)<>G5%rM}Crei z-fqR|()B}Y7c#Gd2sCH>m%Sv5$mcWb*7g8wpHX5yF~v=H3r9E2S0cnDZ8Lv4Io~>c z=MYf7)i4ZM(Wc~7dRJDQbJM5IL#3KA_4f|BMB}OR52NMu{u#fK4BZW7$_o$Xw{|;2 znP3ESj+nScANoS5pD2^i50j>DBypDGaON6`>*9esW>VsQ+%iCe*^u|WO{tYfpmX$j zWEG1qI{SEP<9)ZLMbKNw?cs(4o@Ri}qgCCmH>g>WE*(A*iP z*y>P^7K_XsMGL>u%fT9WX6sO_R-EjvCX0y$ikpJ3IDP*${StRecyQGy5A1KKWt@`Y zFKjUQgU_0V4C9N-PEW71`0 zF8ttBqgsnWqp81mrW#De)McN%I%LoUQA{S-GMOCRxa9=5U2k!Lwv1-llY~l{Jlpd= zOhRZtv`y95n!z7CZh$4M?vW)4ebgXSE|)4M5J5F@y>n>{ebwi;v9n^8KipXBi=w%( z)dzTenq&0?M5`xgglV!!aqpV)jd^b$ts($ zNMjm85@nzXkryH~irJfo`0Ri;i&Nc}8rPmIOfj?6$9v@0$~3?`+`aFk&ZlC>K0fF( zV4>4ke>NKs_a=Dv9At-`9>FK?tj%Jen3+h#nM(cT!qY7)Os5?5~ z(<9z8St&I1&|$*yV9#H-U3;Nj1HD)&YX*8Oieze}Ed3*YT-tmjzOeedNA2Ot_RM!% z>@;r`e#=hR&Mv;!oU&gl`e{48Kv3MMs^v=|hG8qm{_Dm_0KK9prhC6o?OneRT_F|l5PQH<3&x%i}S)@?()tL^)@6= zgf)>$RqwSX`F60BUvw8Sw-wT zci(q@!)&ACI?cnuc|Kzv+e>1t&F5g{D}|AAF}O*xv9iCWIwYT|q&@k1ng$S5h?~aa zEL1Z^sZ0)*mxup>bD2S#iuxhHEzE1SP4orTSw!Gk=swp4R}E2MU)3|Ox30@!X1f$< zG6XF2^%IejuIsWKl2&G)Qpr>Z8eq7P7SP=POJ zfF2^K;?iMvSO-OUcHWNL-K z4>R*LU*@7=9Zy3$8$mNeDT_q^or|I}6w19_#Qqe}^vIPNDx*L{%&GkH6^#`8+ALxD zYppcZ&0rdlUGVmrrsaB)w#apguufQybTz%vegDK4xOEoL(5ja2@Ud~|&e2Vxq1~(N z494qnChT|}r)r36y1(Lv4+&md(bY+isNd47h)}2AREYLDIV{-aXH9~g=tu3xOkmCw zF0Aaxdt(=V_rZzFoI@++DvnMK9B3BLLpTTX&QeM=o;+tx83l$)G=*xpK{EbNBo>l_ zMZ}ZI3s5DR+$WU_^R1edKiDw%B%1eQYjlQPcU5i_G z`;D?$>fU`mBIhiE7Tjo*QOL(;DIaD{e5!x8*m_ruX-z9vc80!-=izti{ivn3Uyj@&0@e!S*t@Yyq zvq!@;mM&5w2#b!m*#)m$oan<2a3D6~gg-vx$ zB@w#Lb|(m1s9_(ebl9$!>;}hTi-BfDF&o@~UkayW+zCc3j(=6FROyM~uva&?1`Gz` zhY3O3y-p?*WV2{=bPvCfd&O^hF0h=HailAiUwv*z`p*W9M(I-zf9n&S^)`5 z^(fK&un{!%@u-mrvkyPtN}iM(%H=5S_%JPRjK8V3xQTo-lR_DtzcbW`e|0oh=Db-Be)5~Z_bESe%w%fF!8&Xx+-P!_k^xGx88s_amuPi?62mpeC z;ljvEiECg-;>7^)jUI;y+X8Ii&54F*`oX6`5+$~uzQMd8fFDO&Y>Rv93hKb7QEiGRqJ9N*Ph*YdEcyxid7xX z9P>73rSTQKA|k6Og|~cka?)N~PpA0z;JslX3NrBG5Xw(}%EK)a2>a1q5V!(kqB{(%n~WwWp16`Ml&ldG z?^zY6C6~fq%Z+AQ*@()iYOTL26RQWf=`lm3e($fMTwC0AcedLRRr>y*`E^=2J~Ty9 zw)lhU#fN4Bd`-<_dq$*Uu}dF~xNv;r7kgB}@Ppro*Vy6<7SaU}!qW7Cf~koHWRs?N zBX!K-ZpK=L5N^RviQ*{y=jrOrhn2+e%*+xcZnGdnAL+K0BYJ%OqVk=kD0woGMYSC^~mv)D!zCp%X^;Y+GsAc9; zjq&9jSkt}Se7>;M^C?MbM0v{X{HN>n`O>rJ>ig%NLyzkxFdN_3uk#J=_GvK&u>!_? ztJj*T(19Vg^y@@B^9$vKp)kLh)Ig z38)h3HCFX$o&!Xy?_CvezjvDdrDKrboERbqrU^W?kd}AHEdl(7)07qw2z~DqAAI7$ zI@S0xI{4DR0Sf%>@?U-daw!LTQVLam`~T5Sm%BDpdb``?3Gy zOU;NEzg5go^3g7eFDaI!^zSQum^_5r4UH$y97Te`Vx?(lzUa;;Ae5Y~vU#%k($X5o z>$si_tQqhnBd?k#{RP}fT^K=ECs8jW*OimpLc)iuy^@5*n&!KYq7-nqRn@Ea8G9Q2#=rk|N+pXXEj7Kp$w~h- zueaG!&48S}*O15gQ(83)C72y%Opk7%Z^7LQ8KDNjfkpe-DhzwIG|Ux8&z9{E{v3*y z9cpi+vtUrGjMGqbYcxBDDQ)Pv^?qtvfOu#?ZcsX?W_29oQ;q%dB|NuqrF)F{_xbl_ z*zvjUeX!?a+ZVKxZ!0L0F;VGgz_c_~&AVoMsw}#BPuU1D-|M6xW{=zkzJrzFe+sQ$ zcnLj;zN!bCma^$K!Dq%LY$jG78KnD4m;=XPiAE$N_;mCv=4mzSgd*aqh^|vH55u|G z8x^LtN*IVqlqHtsUsCFZM*o!Em`~l%lWA*wjxQL##txl>`WoB{SMWBWS<;v7$jqND z9M;}KUmW;0KCKt5BgPm80(O~kQkT4HrHOVz>%l`o(rExhI#5*qiO~}e>p(;zLoyhP z!|9?i1ZE5k3Q@p0nhZ>=a+1CqcFyGn8WRaDa+byMbI7w z+h?K*$h+3nnF`APf}Z@oz~+)7)-#2a4M#btH{c~-FpAW`hjRO`$_@ZyTxg!Y`Pk&F zm}EliZ;?}32!HEp(}aT#_xh-nB%`Tmy@nqjpRgb2=riyVP8+xr@%h{SUQ|ej zS=8Ol{%P!X?r&|No6m!>arKgleT2AiwdX%aSQQ&>2x-koBDHe&m>SbWa}5I3X3@P^ zY`pIS83;j+?`>>ugi5G~L|o4Rxw!74S-oe}sM+pyaTer|s`@^-adLj0hzUcCix_M` z8cY(YUI!Ki0$oiP7a@uXqAfPv4YwxR#+r%IVt^4HPm>*A`2ZK}8JetYrK5kTl3+xi z?lSoFV0reKqZe84Nz)7*mPSb*c3}HH1j)YwFw+?jdWkJM`swcocYS0=RUkwg z4O$X~%lMcUuthJWp-5Ad4+EW}rr(-8&gQIB7q6t*^;=~5to<6ww|~P?11|M^fd@F% z5!WlcrwTYmuK~dmEsu>ubUUnMef;zi7{t)+Ebxu^z2Vuu3P@;UM%8S_vC--bC<;?* z6X^V@N9=O5o>9-%67Ud-(hQ?lxPuIIE{*i6Mh$_J#x;KXC7RIHj0PPZh8s7(c#S)c znH`@z{{r?u4HgzYhpG%!LomaEMqLRsPB!c1z$ufNO>cz zGL`U3T;WwV!vW*cc+wgttBi|AdgPup;ag^vOj&4^R6q9B9Rk$@xJw*GjPx?Bql+O>IpEI15t44-mdpU2Ys9P%KJj>mp(bn&}Mf$(d9)dT1_b9V=jQ>cDru z7zVy_`xkT_pz?!xJ+^*qJ?ZCvEO)K5<5 zP8gbmN%YcO_*v@N0nqm(!p+p0sV;Cb5733Pw*iCd2A>4*2 zcD7_rA8n;oK^Pb^b?myDKSx9$L$OmZE-}}lin+I>8iAQn)sX;jMoXuXtQi#U#s(#! z$Yw%x&kFbR&?buT3lMMyVR5w{HKo9Z=-)G6JZ{>B#`+`@oYihy@bm>fpLw%Q!Kn?s zL{%iu_z8Ic19D4{=)ub+ysaY-;TS0Rv)ptUP;LpQ-ihO!T zs(hLf0>%x{oGEx%2B%7}Ext-pS(3X|G_)5mC zkEZ*t=m$Jk5H5Y1wps_?+HSsY+}k=!zU^2A{sJrHeJ^=zf4{C1-OF3P*Y0_Mg!oE5 zeC&*T9yb82>)M*?z-KpF-{^tYB!a(%~KE8#H@Dg>)$rq> z9;hLxM`?-Yp+H|&sfT$Qr=`blyY$YMcMK$9sAe#nK_3)A4_Ta`JiYS9KzE)+S1WE- zhXP_ZHYDzv5)o*1YE^w30{KEcmVp*0@w7QBN{>%$Ay&}$G;G)TW2AcsKmX`Gn$0!A zf`C};Ut&F!;`MImQ0~)G@+|?u^3p|pijN{bPl?`OlYJOLuHkkV5q;Zo4Of_LMMKS8 zXUlUUn;{{Lxf)<9&~2S7?q5S)nF6||fj@qwN6A8r-{&@bOE&oMYJ)+>o)_($*O!cc zCCNLM2Kp~%6xhH_CoxJpkyMhjtOiso&9Ma#ujqI)ZLrGZ$LOqUaFlJOo?h-&sYuX1*;wrXsdabHI_mFm!#nY)qrK(FL*%0 zHW?OYj>7EIAn)?&)c+Fu#vY?}2GmQ*SK+`!*F6-I`rQnSt9R(Ye*pmv=d_|DBmMD* zPR|b>Wo@e*1RDnExa+x;H8GR0(QRQNoz7pJ?_5!XY_zOb@qr-qLRT)GLn-g53XBN7 zPz$27VgTS78l06A=!tpiIGKXzg&ziIPal0L5J^i z_8Exw%P9jkNyHaS>>QF)lJellVBWDJvxp?b!hIQDi%Y;dDV011+z z*)!4te`|TB#Wc@RIjkT-OZ#(Su zYq3L5PJZD|E<3v@lCL54Hg(}i1TSqdw~=strH>eB3bP81l4APm3a>MFQpPkMD1?Q{ z2mIDJIRr6T;(o)8>_f$tT2xtTfFzbCoz9<@iAhM;+nsk;SvT6Q=RdzR;di!6@wK`B zbGMr@~{n;*{!Nz2adguKSBYxX^lXKy!*Mn1=9FS&xWBVU~NeOOxB z3kBq?IrXW0GnR*W+LEBC(3;0x9{V zP?g(FQ8qb1ZtpA0ZSbGyLatuy-K(uHF&1VgK8MfilPSr?2$(iMjjwN0a)?r0hrEr^SOxUqDw@ z`bH1*>%E?l@%_c+ug#a|K<5SS^GiM}QgMs*g_jRIwVpd z9b1zStc@5Izo!x`HTcXEa(cd0L>{_`WjwfO;J9g#NJ8uMNCWh4;jirpxCizSGcoOM zW_S!P<+$Bq$yNa!LlR=+*Ij*H$G6$-?Kez4&HVcKsh-ckr`Okqy}%vNJFKYeRM)NW zD}$Hu==oB>`;Zaq+r<G*P$@R*?-@ZKM+X9(W)1 zUY9k!N&PjpVx50x0Wlx*u*xy8qWZXIN9ea=~_o zGYK&aXIIdUcPI|F(MKkC5t1=W0--~%Wmo0rgW`RbX{PWKdV_MLkBh|5Ijhh%?%6MR z$i*~00(RG?xh=3x=i}l_5LeP-8_*Z^`u1IRsde)iAlfAQ@4+_k&(|!TryI8hep-1S zF^3n{4y~|q4hy-q>jr-BA?$uRaq)Dj@AjEHURl}c1IXST%|PeoRy%vw4?FOh5J6|3 z2h9-BO`shPG32EaOH<=4wv!253#pld_9N4p4XD0}c4|2zG8|{}oJXaka zh5!rKhgP>Mth~7&$dm^pQD@zkl%FPnZT}6{|1Pdi$J5V`w7|-t_8Q)7Pn2O1L6jRG zPEf1;>-LL>r@Jd}jdAPxor+E(L*>TTN}HloAd=R6FaU%X(8k~S(Qs!S@2`A8CYYp&m;;g2U)Kj{Lbb! zRt3FCYP^j!?w^@{CAHo?Jij8Gg^Bf6zop0Xh2+;}<5x+Co`=(^_J-Hy{DN}_SqL#( z%Lq02oNzf?WcSmFi@0wy#_QG3C6$WpRQTzO$d1Ofys`s)>V}#CEiZgC)>w2%@=VV- zGp*GqAGz=;#vxRz+m{;bcF+mz9J8fEea5z9=V!+Q?Aq4}{l8bp%T#N?sdhlD#t;`u z;wvk%#!t4by9G-`PQ8jIv!T700CV1KVk|}?CM&jLfIE|&Zj%`i$>iRtNL}sX!`G1g fe|bN4YCd75F}!f*B_(CRz8-n$Z&Ec9CL#X=Rbw$i literal 0 HcmV?d00001 diff --git a/simulator/kruxsim/devices.py b/simulator/kruxsim/devices.py index 6df384c20..2ece5d057 100644 --- a/simulator/kruxsim/devices.py +++ b/simulator/kruxsim/devices.py @@ -33,7 +33,7 @@ AMIGO_IPS: (480, 768), AMIGO_TFT: (480, 768), PC: (480, 640), - DOCK: (440, 640), + DOCK: (440, 800), } @@ -48,8 +48,6 @@ def load_image(device): device = with_prefix(device) if device == PC: return None - if device == DOCK: - return None if device not in images: images[device] = pg.image.load( os.path.join("assets", "%s.png" % device) From 12c4e1abc8fc007a89361283976124a63d609342 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Wed, 27 Sep 2023 09:42:02 -0300 Subject: [PATCH 025/114] minified boot SPLASH --- src/boot.py | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/boot.py b/src/boot.py index 0d8071c4c..7ce8f36d2 100644 --- a/src/boot.py +++ b/src/boot.py @@ -31,38 +31,29 @@ from krux.power import power_manager MIN_SPLASH_WAIT_TIME = 1000 - - -def splash(): +SPLASH = """ +██ +██ +██ +██████ +██ + ██ ██ +██ ██ +████ +██ ██ + ██ ██ + ██ ██ +"""[1:-1].split("\n") + + +def splash(logo): """Display splash while loading modules""" from krux.display import Display - SPLASH = """ - - - - ██ - ██ - ██ - ██████ - ██ - ██ ██ - ██ ██ - ████ - ██ ██ - ██ ██ - ██ ██ - - - -"""[ - 1:-1 - ] - disp = Display() disp.initialize_lcd() disp.clear() - disp.draw_centered_text(SPLASH.split("\n")) + disp.draw_centered_text(logo) def check_for_updates(): @@ -112,7 +103,7 @@ def home(ctx_home): preimport_ticks = time.ticks_ms() -splash() +splash(SPLASH) check_for_updates() gc.collect() From e80f99209c9506830dd4b4da948becd535a3a374 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Wed, 27 Sep 2023 16:42:53 -0300 Subject: [PATCH 026/114] screensaver enabled on all menus --- src/boot.py | 2 +- src/krux/context.py | 48 ++++++++++++++++----------------------------- src/krux/display.py | 22 ++++++++++++++++----- src/krux/input.py | 10 ++-------- 4 files changed, 37 insertions(+), 45 deletions(-) diff --git a/src/boot.py b/src/boot.py index 7ce8f36d2..bdad50df2 100644 --- a/src/boot.py +++ b/src/boot.py @@ -109,7 +109,7 @@ def home(ctx_home): from krux.context import Context -ctx = Context() +ctx = Context(SPLASH) ctx.power_manager = power_manager postimport_ticks = time.ticks_ms() diff --git a/src/krux/context.py b/src/krux/context.py index fde749aaa..da6d1a5d4 100644 --- a/src/krux/context.py +++ b/src/krux/context.py @@ -29,25 +29,7 @@ from .light import Light from .themes import theme -SCREENSAVER_ANIMATION_TIME = 50 -# adicionei 12 espaços nas primeiras linhas -# adicionei 3 linhas abaixo -SCREENSAVER_BLANK_LINE = " " -SCREENSAVER = """ - ██ - ██ - ██ - ██████ - ██ - ██ ██ - ██ ██ - ████ - ██ ██ - ██ ██ - ██ ██ -"""[1:-1].split("\n") -SCREENSAVER_SIZE = len(SCREENSAVER) -SCREENSAVER = [SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE] + SCREENSAVER + [SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE, SCREENSAVER_BLANK_LINE] +SCREENSAVER_ANIMATION_TIME = 150 class Context: @@ -55,7 +37,12 @@ class Context: duration of the program, including references to all device interfaces. """ - def __init__(self): + def __init__(self, logo=[]): + self.logo = logo + for i in range(3): + self.logo.insert(0,"") + self.logo.append("") + self.logo.append("") self.display = Display() self.input = Input(screensaver_fallback=self.screensaver) self.camera = Camera() @@ -80,7 +67,7 @@ def screensaver(self): print("screensaver context!") anim_curr_text = "" - anim_frame = 0 + anim_frame = 1 screensaver_time = 0 fg_color = theme.fg_color @@ -90,22 +77,21 @@ def screensaver(self): while True: if (screensaver_time + SCREENSAVER_ANIMATION_TIME < time.ticks_ms()): - if (anim_frame < SCREENSAVER_SIZE*2): - anim_frame = anim_frame + 1 - else: + screensaver_time = time.ticks_ms() + + # show animation on the screeen + if (anim_frame <= len(self.logo)): + anim_curr_text = self.logo[0:anim_frame] + self.display.draw_hcentered_text_with_full_bg(anim_curr_text, color=fg_color, bg_color=bg_color) + + anim_frame = anim_frame + 1 + if (anim_frame > len(self.logo)*1.4): anim_frame = 1 tmp_color = bg_color bg_color = fg_color fg_color = tmp_color - # show animation on the screeen - anim_curr_text = SCREENSAVER[0:anim_frame] - self.display.draw_hcentered_text(anim_curr_text, color=fg_color, bg_color=bg_color) - - screensaver_time = time.ticks_ms() - if (self.input.wait_for_press(block=False) != None): - print("break screensaver") break diff --git a/src/krux/display.py b/src/krux/display.py index 83d81f616..9f5a08253 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -302,11 +302,23 @@ def draw_hcentered_text( """Draws text horizontally-centered on the display, at the given offset_y""" lines = text if isinstance(text, list) else self.to_lines(text) for i, line in enumerate(lines): - offset_x = (self.width() - self.font_width * len(line)) // 2 - offset_x = max(0, offset_x) - self.draw_string( - offset_x, offset_y + (i * self.font_height), line, color, bg_color - ) + if (len(line) > 0): + offset_x = (self.width() - self.font_width * len(line)) // 2 + offset_x = max(0, offset_x) + self.draw_string( + offset_x, offset_y + (i * self.font_height), line, color, bg_color + ) + + def draw_hcentered_text_with_full_bg( + self, + text, + color=theme.fg_color, + bg_color=theme.bg_color, + ): + """Draws text with full screen bg_color on the display""" + lines = text if isinstance(text, list) else self.to_lines(text) + lcd.fill_rectangle(0, 0, self.width(), len(lines) * self.font_height, bg_color) + self.draw_hcentered_text(lines, 0, color, bg_color) def draw_centered_text(self, text, color=theme.fg_color, bg_color=theme.bg_color): """Draws text horizontally and vertically centered on the display""" diff --git a/src/krux/input.py b/src/krux/input.py index 76be527e7..635b2ec3a 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -144,7 +144,6 @@ def swipe_down_value(self): def wait_for_release(self): """Loop until all buttons are released (if currently pressed)""" - print("wait_for_release...") while True: if self.enter_value() == RELEASED and self.touch_value() == RELEASED: if "ENCODER" in board.config["krux"]["pins"]: @@ -160,7 +159,6 @@ def wait_for_release(self): def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD, enable_screensaver=False): """Wait for first button press or for wait_duration ms. Use block to wait indefinitely""" - # print("wait_for_press...") start_time = time.ticks_ms() self.screensaver_time = start_time while True: @@ -181,10 +179,11 @@ def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD, enable_screen # Check for screensaver if (block and enable_screensaver and not self.screensaver_active and self.screensaver_fallback and self.screensaver_time + SCREENSAVER_IDLE_TIME < time.ticks_ms()): - print("show screen saver!!!") self.screensaver_active = True self.screensaver_fallback() + self.screensaver_active = False self.screensaver_time = time.ticks_ms() + return None time.sleep_ms(BUTTON_WAIT_PRESS_DELAY) @@ -192,15 +191,10 @@ def wait_for_button(self, block=True, enable_screensaver=False): """Waits for any button to release, optionally blocking if block=True. Returns the button that was released, or None if nonblocking. """ - print("wait_for_button...") self.wait_for_release() btn = self.wait_for_press(block, enable_screensaver=enable_screensaver) - if (enable_screensaver and self.screensaver_active): - self.screensaver_active = False - btn = None - print("passed wait_for_press") if btn == BUTTON_ENTER: # Wait for release while self.enter_value() == PRESSED: From cdfeec1d079ccbf9badac9783f3b01eac46aaebd Mon Sep 17 00:00:00 2001 From: tadeubas Date: Wed, 27 Sep 2023 21:20:50 -0300 Subject: [PATCH 027/114] black and pylint --- src/boot.py | 6 +++++- src/krux/context.py | 34 ++++++++++++++++------------------ src/krux/display.py | 2 +- src/krux/input.py | 16 ++++++++++++---- src/krux/pages/__init__.py | 1 - src/krux/pages/tiny_seed.py | 4 ++-- 6 files changed, 36 insertions(+), 27 deletions(-) diff --git a/src/boot.py b/src/boot.py index bdad50df2..48ac45032 100644 --- a/src/boot.py +++ b/src/boot.py @@ -43,7 +43,11 @@ ██ ██ ██ ██ ██ ██ -"""[1:-1].split("\n") +"""[ + 1:-1 +].split( + "\n" +) def splash(logo): diff --git a/src/krux/context.py b/src/krux/context.py index da6d1a5d4..86f5fa8bb 100644 --- a/src/krux/context.py +++ b/src/krux/context.py @@ -37,10 +37,12 @@ class Context: duration of the program, including references to all device interfaces. """ - def __init__(self, logo=[]): + def __init__(self, logo=None): + if logo is None: + logo = [] self.logo = logo - for i in range(3): - self.logo.insert(0,"") + for _ in range(3): + self.logo.insert(0, "") self.logo.append("") self.logo.append("") self.display = Display() @@ -50,7 +52,7 @@ def __init__(self, logo=[]): self.power_manager = None self.printer = None self.wallet = None - + @property def log(self): """Returns the default logger""" @@ -64,8 +66,7 @@ def clear(self): gc.collect() def screensaver(self): - print("screensaver context!") - + """Displays a screensaver until user input""" anim_curr_text = "" anim_frame = 1 screensaver_time = 0 @@ -75,24 +76,21 @@ def screensaver(self): self.display.clear() - while True: - if (screensaver_time + SCREENSAVER_ANIMATION_TIME < time.ticks_ms()): + while True: + if screensaver_time + SCREENSAVER_ANIMATION_TIME < time.ticks_ms(): screensaver_time = time.ticks_ms() # show animation on the screeen - if (anim_frame <= len(self.logo)): + if anim_frame <= len(self.logo): anim_curr_text = self.logo[0:anim_frame] - self.display.draw_hcentered_text_with_full_bg(anim_curr_text, color=fg_color, bg_color=bg_color) + self.display.draw_hcentered_text_with_full_bg( + anim_curr_text, color=fg_color, bg_color=bg_color + ) anim_frame = anim_frame + 1 - if (anim_frame > len(self.logo)*1.4): + if anim_frame > len(self.logo) * 1.4: anim_frame = 1 - tmp_color = bg_color - bg_color = fg_color - fg_color = tmp_color + bg_color, fg_color = fg_color, bg_color - if (self.input.wait_for_press(block=False) != None): + if self.input.wait_for_press(block=False) is not None: break - - - diff --git a/src/krux/display.py b/src/krux/display.py index 9f5a08253..312fc0b7a 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -302,7 +302,7 @@ def draw_hcentered_text( """Draws text horizontally-centered on the display, at the given offset_y""" lines = text if isinstance(text, list) else self.to_lines(text) for i, line in enumerate(lines): - if (len(line) > 0): + if len(line) > 0: offset_x = (self.width() - self.font_width * len(line)) // 2 offset_x = max(0, offset_x) self.draw_string( diff --git a/src/krux/input.py b/src/krux/input.py index 635b2ec3a..618ec6bea 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -48,7 +48,7 @@ class Input: """Input is a singleton interface for interacting with the device's buttons""" - def __init__(self, screensaver_fallback = None): + def __init__(self, screensaver_fallback=None): self.screensaver_fallback = screensaver_fallback self.screensaver_time = 0 self.screensaver_active = False @@ -156,7 +156,9 @@ def wait_for_release(self): self.entropy += 1 wdt.feed() - def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD, enable_screensaver=False): + def wait_for_press( + self, block=True, wait_duration=QR_ANIM_PERIOD, enable_screensaver=False + ): """Wait for first button press or for wait_duration ms. Use block to wait indefinitely""" start_time = time.ticks_ms() @@ -170,7 +172,7 @@ def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD, enable_screen return BUTTON_PAGE_PREV if self.touch_value() == PRESSED: return BUTTON_TOUCH - + self.entropy += 1 wdt.feed() # here is where krux spends most of its time @@ -178,7 +180,13 @@ def wait_for_press(self, block=True, wait_duration=QR_ANIM_PERIOD, enable_screen return None # Check for screensaver - if (block and enable_screensaver and not self.screensaver_active and self.screensaver_fallback and self.screensaver_time + SCREENSAVER_IDLE_TIME < time.ticks_ms()): + if ( + block + and enable_screensaver + and not self.screensaver_active + and self.screensaver_fallback + and self.screensaver_time + SCREENSAVER_IDLE_TIME < time.ticks_ms() + ): self.screensaver_active = True self.screensaver_fallback() self.screensaver_active = False diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 4aa0171a5..c17761b5e 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -548,7 +548,6 @@ def run_loop(self, start_from_index=None): start_from_submenu = True selected_item_index = start_from_index while True: - print("Menu > run_loop: (while True)") gc.collect() self.ctx.display.clear() if self.ctx.input.touch is not None: diff --git a/src/krux/pages/tiny_seed.py b/src/krux/pages/tiny_seed.py index 778dc4adb..1ab23662f 100644 --- a/src/krux/pages/tiny_seed.py +++ b/src/krux/pages/tiny_seed.py @@ -843,7 +843,7 @@ def _detect_and_draw_punches(self, img, gradient_corners): page_seed_numbers[word_index], bit ) index += 1 - print(page_seed_numbers) + # print(page_seed_numbers) return page_seed_numbers def _set_camera_sensitivity(self): @@ -983,7 +983,7 @@ def scanner(self, w24=False): rect = self._detect_tiny_seed(img) if rect: gradient_corners = self._gradient_corners(rect, img) - print(gradient_corners) + # print(gradient_corners) # map_regions self._map_punches_region(rect, page) page_seed_numbers = self._detect_and_draw_punches(img, gradient_corners) From a06219af8d368547f14183926f32237f322be316 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 28 Sep 2023 12:34:47 -0300 Subject: [PATCH 028/114] change dock.png for simulator --- simulator/assets/maixpy_dock.png | Bin 203376 -> 195634 bytes simulator/kruxsim/devices.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/simulator/assets/maixpy_dock.png b/simulator/assets/maixpy_dock.png index 93f9fdea9e154cd8051e05bfefbc90a161cfdfb0..985f47c43fa85b9ed9979939a184ee2d359d2edd 100644 GIT binary patch literal 195634 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

-6I$FwbMhY-0i7r)pmg1xz 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

QB->+1{fh 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 G1p0rE7s}ND literal 203376 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�)fzyJpU&J#lIi2iDR{j0!3ajp96(;IaeSv17;UMTk<%oM6`GaU6!uHt8|L2~Azd)C6_qk_4oswG=NMRyhaAGP$Zf zAl$vAobK)KNAB>txp7UtTv$WZ^?OaQd2pEAn)$3a2!;oP2X8;QUx~|1QU@_n7zJ9J z4YxR9Tww#^T517Mkv0~fdsU@HloZwCr_JgP<7)$&8^_1U+wO#b>7xNoG1nS5a*58i z2PAhgFDGCHvEn!w$1z+22r2ALibWoH$BrE@mgKH!2BTvb@|(-aWbm-*O%~WlLskQC zAd{S334M&%9nG~Yy&SDc8h_UlCM~#vxYv>_PG#AZHdtCh7*O}U48@kfBml+(bWWhi z#GHFv`P2CQ?|(nOy}$pqVrAu ziwL-;VF(6W&K`qtjDeGE)pA|)sYRNeCds`$4ib5Md3(H#F&H?TQ*^fCg0Qfm<|55* zT~p53Qm)Lz4gOD#iZt~ARV?#qcx&IeA~91>D;<$^%+}PDD<|c&duiTcp>at$4wben z?!H`lvrE{qW5+AS@pu?dF8t^E2$IZyQYSEu2Z)9zIK~*37(?k_Zcq!3kB-S^a!Ja>uuN5@$$+h6 zMbV}*paR8VXwGnD=CG~ctmc4bm>ISfAP8$CoA21MK^V*~+AL}GoU-w$RTz^Xsd3~o73yT~n*({)*$(cb!~Z%~I>UEvl&&ix zGk*nbG+hN(Tusx&-QC?5hu{!`+v4uQHOS%;+!hTkiv+je&f@L_ch}&S1dDu|=RMya zxM$AXndz$P>TWC6&d`daGG%JMjXv*fv zqIL)Rbf8Opx$}<@qjQa(nw{^OMb9Dpz7li?Q^N-K$q;VchR1Zdii=Sm)uzz1P{X)^ zWD8rtqy*lF+277VE@+H3<>8IHj8vh{+U2F{8^1died#i?L#wKi2-w)b@qQ`P`iY(G zpQr}|WEZQ%N<%*kH%{!qmTSl4UIO5*g4UOY(CH~{dBlffa+VF*pwIYvX-D}?Ahew> zM)N4e1Q1EWm4C4EvH8*2LUx&rrm$54Z!CHm`|j8NqsUiSkMm*we6k|)8WxBK(klLr z@^ws6v3ipv?`W96S+EG%gz}Gs zlNkdv$rjEyZWb?4Kvq7f?67&|{abwN{i}&V9Y+jK$%QRt*RdqhPqSZt{7nX;{&WS( z;YCQPw5H9antFTbRm~?IK<5!g%iQup)W?JU7X)%-eBaG!pJV4w;;wmFfz|U)h4W5x zN|dz*_;9f7@~X2}hehjP=)VYoAqppo09U=}kQdj61*=W|G;h&EXZ)!2QXfcDh&=lq z@q>LUi1mZhLl~n*zz>BlgL%DGIE>@@7%kHQ_h9$fN)%E7TwbyWT;BKB3jJ4|KB=3q z6MMMV-u>PxWCSSz1SjIbF27SnY89ZJIqb&sB-sHzko^C@fr7cghhr_R{W z45;dr+0=mT=PI?qEL|wBfiUPr2Th<0(5!W6)&4W~L28Tm%v)uO$f;+l!TsR;>v*G$ z`?u1RxDxz1q)WX4+CSN!4*OT@--9G}sB&gSXkwThSrR~dBA2T$5)eo~Mz4A(3~Mo= zMx0EifUcurR+MWMyQ7(Kwy8TZ;`dRa#6154tD`NB8z(L>;^YCVeMlTn;9^7?!(4pVe*fk1PyFI zIdwBe3&%DO=}uDk4Y%vI{phj0yHL$OFuCT7CC7|kvLbkWp#{ea9@c&8BGzeA$#&Gj z86RqrP}f2lPRXVpDrvuSWNRQ35MjN)3cZFsQ$JGky70iiB{t8QkD6G-czjN%2mHOa zSGjYRQgxHke=Y3Yv<-?w8)Y0k&;O>59?GNc*|42(Ha*y3>am)xc#Gl4=(*=-)ticl zcQ%Hx_RXE-HqMhpoL#x>iE)We%e%<&p4wK^ciLnKF>uP22dR-`6sL8Yux54OI`xp& zmW&G+nL+y*KI*i*RIw)+UM%woP_TRxvjKJ#hq5nocR~^D~CjTr3XBSSO@;rv1taqEv{Dcm|l@q?azbHgx8g! z9}&~GQ@J~V-5!EzYxY|W%^*c7SG}PFTrsp5ww?TMzkCq zZR<+xj%n^K)Q67-p8b|ak-Yr`a8(e@!ktNbeHfH!>9X45WohdUHzO@z=Q5$=^1)7- zITbJ4-asri-%t?_tWnKGxWx}}TCohmAVzmpPAXak!db|BvrK)wh9Vrd4H5Rh>8X;B z#t?#%sdn-9^WdQW7WipQw&=;Hz{9+PEq%LW$=0PX`-ngY7{9~xx7p;7B}}KVM02(6 zqi$%jAVAy4BmKc8>;9gk56At?=_E{nR=7z|5?wCL^9W+wv*IUxHq^NT+eOSMWj_aA}6+2GHGlRMCD~>PlmzNz_;{D8Cnm}sXrUG3+B%_}?jM;ny1$ApeeL&;3%Bhr=Fjg0TB0_xn z6N7BXRF!|fs9d2jCBAC5IP$=3&#Ezkz|Xa0P@Uu3MtWwXjJ+>Ya3O58?N@BC;+#EB z<)i_>1b7Ay-v@2y$%9`LhmNURd8Ad-!Xrn1jPmg6(S77u6pag)Yw{axg|e@pi2dR$ zO<~Fc!~W{{!*K5_b9 z`pqlMUWZq)Ac~keH;H<1abQ-jA7az3>htTWupV(Fckim=up>jim(S-47y1;c#M(zL z(FG8~igO8ZD98ld6BuuV?qJ$czpg~r#x-FPhu&9zvzt}nxAne?fW}Vm)nq&!mYuJ@ zrVlcYGS%1E-hKyrl}BLD0Y+wCoX<89(>1JXJDhUx3Ls;OT)Y&fvqeX@^u+Y zcIvSyTPxlmv4pM>)p>mKU-GUrSd5mpHqZJJmT)3!Bl}@vg?U{d7oH=3pecM*eb=DV@HOK zOBv*dH{K~^A8^czA)!qJsW5Wi zi8U&~J`|qDZROa|?Ez z#p;)i9;5U1p~1+c-1L76ELx_}oFdM@wh;qJGnImM%J93oK1=6FSF~8rR*qVza2#_- zx`(JfK;CpwTUCffp%#cIQ<6o6VM{#w=iS`+g@j}|n`a(ZPPjBuQ{j*34v4~m~{ zDl`jJWG8iGWiAKANPP!luif32orxbq>~R8=0<*Sg9Q8tof>1d|YwZ-NR)xZ|m3WG= zxV0k8(z3}}4;ZDfdOBV%V!Zka*w)1oB`roX;d9x}*p1DJTARtFlr98h2zc7Dr}{sw zdM9lMtOlh^bNXlERp3t1sgoiQ4w0fZeuH&&1x(;$(~Nz_pT{ST^%I}HUc;`y#j-=? zt-d)bE%p5P-RRcL>FQB&qQ+HNtL;8@IsIuz4WLl8|5yK1n#4sckQ+yo=9|p-gjx3l zcuD&|UD~pqr|mEhD@?V-g2yYymSjTDnSDT5cmG7NSSqZ6Ufq>Q(R`c9 z**%exR~?@&?_=vhIL~{Y`F7XeT(bhx^r8B7<~^GDS2q}k_3_Zu%19L))yCHXD%n12 z>JxKB(tcY}5$*1FRPuQYFZkZnY%?kBOANa1^{50%6-*wKXqM!m`bAMH>$VmGUM^om z#C_7b%Los?Ol{YuNq>!BBS)jB9I4tz=m-u9!_D6!bF zu7#tOon4;Ay8Gmppt_4eZ?$Pr`qjv3^dKtC_5GZi+EXnFdW`oB*yfak5!6Ub*F@%f zxP)p+a`@!Ml*!@x5jw@Z^m0i^N@?5RvX7IyWj;YFqIFnHgb@8Q!4w~nVGfo9DX@yZ zS8<$wzQ}1TpxL}c<4ya)1nh#4kAYfJw2c-tjoH)c-|0)o?v0h(-Ctoe0Mcv@nu$^4 zHoqL#$oM+)ri*yd8nIw$KsHjla3bZ`K)im2(Nq#2s);`VKZH}WaWul9As)k^=5IoL z^3K(Bl`XhYO)MH8sg~^5s`xTJzKlU%94-?aOqtvW=aFCe!Hc!C?G7%r+s)+cY}~dG?1I z4He@VQam-87FN2eSO)V@#-th$;c6l??ivoHA@S37F|nu%ET7x*)_ea>B1lpeS&Zjm zy4ad>c!p^wn08u(W(Z1Ws+rfWQVa#i&%jsdJO`M`kVd}A|gY9pFCnJ<$( zQ5&Y}p_pyG!qOYZ5D@)^Td-7TF#bQ8lJD5b8tC+E141L+2}_gufAAhl0s3hnuFKyD zGFq0s4BviDWCFxb2@8^zw+x8?zZU>$>mk<~M}*bvrblXQ(SBy#5XBUD`>Z3FviWwBsj z8>XSE=7p>EcleCAwg9R1ZEI!$@zoh~>k_VK##j}?A+k_}MLu*n2ei3;r ztxpj}Djs1>7*vb~U*|$~cPF9(LaLJc$AaOtFq|npDz?2MAMrzx1lltMoTSVjycQRR zFWs(HDcQT{=K<6y>WRwV?X7kskm2HODnYiadNJzEtaFkX9h8 zxOSXGg|TwlA%?wM3-itILi#Q_S8AI?)^w+{Zr^{8phK!B=@lQAK$ZgmbX)wI%p44F zEbxK&4Np|}1X?Yj$)hDYin3fgbi}r@LV!p0wBy*E%bOQbiU3ahlulMV@DW5s#yHH+ zJ-$@ycYop1JLK)LD%dQGA@@mSR8EgiKFtnhX(gKVsLIoP(Le=#WCF9Q3TMDZ3Hxek zAh*i%^QTnnldgJcURcDSIe+nyfyVeVi3#|Hy}9D>fyECedj7;saT)Vu!hZblhs-(G z9S_lfrB67lb(5v>BHbkKR=EZiDCur^Z;%$f1b^w)#B&7Kv&{6HhaEi$h{>|(*oh_W zpR-z}Bf#TGG_1wlFg^N{ksd-%h#;O~7xO0H$_MP?=-T>J$hc$>YGi-s$3&k{&@hYp*9QbHONJ*Hb%8EShgnAoN_w)WdZOW~q3;Slcpbxp zXv$UZ7i!B13oH$SU|+B}esXTvf>|);a@lbru@y0Wq-k_EP}n|QoL$S-RievBaf59M zDQ}*@DD*^%o)Cpr-k2cqRY+t^=YYo4KopiW<55D777@IjFj=a@l10l4MAU(n?1@ecb0UMNfe8_4_`=xSGdO|dr@ zsB>37@~Mh8>{fC?{^$$!=%kYcg_0;wvL0Jc6T{D;QuN<~IKZ{A3wER8qH*nQE3{G{ zzeb@Ksh}MigX^`sg%o6dL5)+*pQJn;)?xzp!BECN?2p@u$+dyb;Jb}u;K|TjPEFva z+AfnN#HxvC|3?yq93-lbp?ALc^$|!sM>KtrdLhPlTG|lA~#$fOpB9x0x9PVcoJtR$h_0B)+jlc<|p% zJB)>i>mWRQR7gy$hoUX!mL=51%l1{HL1hf<)CS9`e(m}5UzD+n)U`}xuVRJ`FzRE`w)Dl! zxa0q5bu_^WP{d|aL>E0PpOqY9_)|J0mxhFi1+SmekckDb86GaMPk`T?cSO9pVtQO8 z8|w#AogRYnLaVSEs+w~j~Lpa|bgq~aX9Sv~>eapRI8Y^@EwI}}wCPqvQpGc*F8os!T+J+KG z8lg=|1mi6rNAFK8_)ou_OeDNRk)t&$D(uIp-}xbUV_?S7X(#35tCh%;p!meq+8xC5 zk4sbn5kBxEAZSD#t^%d&)C)~>`7(Qf<{HJk1)Z4kDG_30czIjd0ToncrwH38gPt|N z!zJD;y*6F^N|clBVRXP^99evIQ6N0^Hqomk@mG3nRp1;SP0~3?P9vGrT6py-rqqxP zDM)VIOgMGTWh*7H(F0!UFys|}&av%*FUc#UBY;a%d(KtN5|w!xB~Y9eJ=-ChKb+*8 zpss*_EwdX2)BFaQNCSWPTh02KTB$RZ&6OrzS#9osqUT4K-|kPA^kS7w ztnsXMbbRcFNYQ@$Fkum65Htwm_6Bp`e^`F|X+BCs$*bwxQOMI+U&!S7FGsP?2Ql=y zdZgbn(^$SmwzM48m}$oCZ%oyv<}#Z_%SRmw`{n^0>!F;-$D{3&WwA*@YE#*I720r` zY+pC`5kLeZB@`I56J}`4g!It!{(nj>AC4p(y9q?VS}3T0W7A&SX|WKQr*LXJ1I@!V zPZ&c5VVmHykOlC4r&r>%(BUP*La;p_pWoW=^5Pte2(LQk(4uMf>EynrhrXampKF-P z^Xh;8`W&pDQ=OedCRKaogU}(eC+8)jtWwRf?NQ=+9>2Z6JZ{Rt#J;C2T;rx6gS{VH zOl`ASA*uszw66+l{zURC#bKG^s}{3f)6gT)&_5{joljyylo`WurKbDx$$3&X#}JEG z9UTo_ott31T+=Z^I)gtl=|GGRc`5D=dSjKLJt7zc_i5>^Z5j{FP)dPW@({rR8B9YV z>bGO`4C@q68LoS5=fe{cfx zL^TIe2g^Au&K<5#WR-}OEWX%eGr0|Qg&Gqk$EVEwjIzR-j8sVx%&qjYJo-f(3B_21 zt#9Q-R!15Z}WU4hp0ETj&7ivL`R!- z`=yV80mZI`@6E>$*tH8#H^fK(?U#9~a~gftO9@<1ziReXHKemZNu8>SbjktwsTySH zYq%Z6>^e`b0a-CO`cAmO$9&YITQ*;#-zT0!Xw5r}zi*u#qzSgqwjtlpbz$wKrNzWq$NR71aZ8x9Ry{Fd{cSt$L)g zHnM%2gw?OQ*k{~C(5R=LJ;Plgk?ZuXjiRv5&0@D#|Jdfu*?pZ(6wnQQuU8`j3((bW zNassxemFag)Sv7;(MT|C7HVtX3HzOICT6s;`5L0v)>6Od9LU{%@_AeuX4gzh_to6i z!ZH(Jhq9E5Vn%vOoleCzH&+^gk(+d;xHG(zd(Sjy6P(peb=+sBz}I2gxM#y^D1W2q z^kI2CKJJsEt@Ic451fJev(k|<#d*kd5)S!%fV=*Yb&Ekmj^5`W6cwmy6O>rXTo6%N$v*_ zMj-Vk#!2D{BjI;O9T#^-c|YtbBvoTuHb9&AqFK>Gy2`%9BUM-)sqW;fs}d{Gt(S!1 zjdXL5`wguj%)I;LY(A{IH!y`$<7*T#AtyaClCAZPAw2SN)`P66)z$4gHJ*pt8R1qc zx{jGKmXRg%%Vz~y87;~z$fY_oOt=9vrfgPiB2>y{rS~6dz${;Hp(TgNTy?AZRf0VX z+njaxk{ZyP1J$-1GBU-%9?Rh;eC{*?V0Sq<)<27UH65x=Ir#E5XW7hM18mxkq};w@?%7B=iTZ^gUZiP3Z>WdANmc{`9O&hQ#gTad z)Nta4xZuCTzip}+=9Tzp%Lk8AqqK~3-8NO{AZ)MPyLrG%a{>ACJgTB$o)*%bZ#sM` zTJZtBY#WS?+G5?{IM6Y8+bgtx@=6k0$6@sEkB~pE90k8R5ExXoI_2buRpf@x_2d)& zC`lc?an)J0#Gd%CZn%gPT@odS;`W>!tKKy?kVlX!HiDsps6^tWeq@V5S_~ad=8f(11^_v&)0kZ|eYi2BNStVt#EG_6p zN^Fc@)xau8GzzLk5L$8aQ&KH;5nw^#ksyqxAfrnt3`jLj50kts1#uE5UfuRbW=lEI zniXH@X)k8hd@}OY%Xw4O4#GPMbPYTHEhlLeMR92$=;Pi`mLQ5wD&~P9tZ@2oZGdt^ zP_TK{E~%ngG+HR>ILoem!3Vz9YDb;<+=aXxl~^X^yrAhdOb6!BNXdEXnBVZ+SZ0V0I2^h(als^m3vWfEupy zxv!|lKl~od=#tk_Bi@}48z8}i!B+mTw`DA8*$nww5+{WFX(&EZ#;iEL^iHV~D(+Wy z8cMABMrgP8pJ=;2+?WEDM_Ltxb$Igy6`HHILoy)(21@AFoUy|S5Fd@~mn_7!bf9cj zwS$4fa|u7QexVre(*=UadrIc_^{&cKZ=Ioe(~Q#o(?iSy-Hcnx*QfNOsl9Rx6Ssp0 z2CJHkcFFFLY>GZ?HQr9ml-v2jp8c5w-q9QebV;pRWOr(uY^JXa6+^-YHio)}#TP2< zzQr~UE7C-s)nB`QdtW3z!?JEkS#gKFW;~nr_#{55g`o}?al0rG>WJjf4CtcVcCwzq z#DHe-d5Apk6d#i}dpR)gP!o=?bjr=b{&}!wW!Dk<;yA;zj?07>;zzts z)l;=<#ZO}l+m%iydAsdzE7m8nA~y26Y}z^OjCQpHSk@xIJ-kI%L6&EFj6Zu`PpI%s zeU*MvzeaF3RvgP_PP-il9G;q)w)t+TqBc$w zYM0E^^69tVg?X%E>$wHiPGzTZ#m1tQn<^Y7nC%=aL;v$1Sw$AgRwiibh)a*593d1) zMJ$X0O%zG$;8QTBxC*boq>C51CZEGjx*%>2uY@r__O$fXp8h0}xJur79x9mZ)c*iV zj8Wc6 zTkHy?)5LMf-EyYWrd7$>p6AA+|Kqx>lxqNfs>p<}&W6>IKs4MnT50W{jc4`h=;Qe? zBRu8ptYZcNR)zcFx5--e_jkxR4rkR-Z2Nvdb!2nCH##WT9mW&;3^T&`FJDoOW*)gm zQy3|c2-EGs1ad^47+{uBLN~(#yW{{WRIoC5o3b@b$dEexpuk0SiNLhw-Q^^Gtrfko zLOS(t!$bMmXHS6sDC-YEfX=pS9%m_0oMbQ9=Nj~0T83-SGGw4c>cQf4e7J(3D%e9MW#_kWX)X=@LKdLy)3TO zRNj!tV|$B!feGuJ7kAN!vF2CIX!hi(RW#5ZKL6I3Phoa5%}45+5IfhrJn~@ zd4fD3P;{dCgCq(~2nqvkt5?Uazcp2Z@+c{FDp5jBR(V2sS6%k|q7?H)8~YWa>5?6i zgmva4r(`O8-K)1f=^}4BA<^7IyEoOt3PfO@O4FLsX={SJU-5mvHY>V23Rs>`q=rkaXLOZV#g&qBNiN>51Z`>N zEt%pwDd$lv{u#JUj34p1#61l8$E|yKEsR#{ZEL7l*z>n<(+MriF>(%)gOveNYFcrK z35=`c)mZs|fNY;13mjrs8g15(=zfdDYjnps5C5hR30p!pZ}FGyCioum>+o+IY^Iec zRe+hN`C_7MkFkXYh7K!~tcl%HU1UZo_3FKN1Ixl?e=<=}FL^d>ipG&7BkDPuCb-Rv zhKEtf`9V=n znWG-I$44Q?m2QZ$i9Qu%xa|)|_jhzt1uPA4@X!*XSu~Y2#z{SF`gJqI4Sil!ZCjOV zoGTjQ@Nu|#*>9phAO-fU_D3?vbkj9NW|@pEC76>)2c8ZM#kr@MFG@^wi&lio<`njDD`bCl_Kyg3h61K&9J-7e(I*3(0BlTt2GI=j)vPj(=ID0XcTO z&6TZel~_$#=T#gmV5;*aJ=c(~3uUm&Mg}vkowz8)W&V4@;<4H}1;V&hZ>zF$9G8A# z_ukRDYSRuM_9_Hs1~OF@xtAK}OxC6i%lrqZjk*0yjG%8*IXbJ0X(d@rvSnzpXj!LQ zmcrvgbzm{T(!L%Fk$R)k+&qpr$GVa+EVWZpu`K5W+Q9Kl5i40JIY}{?+{dCB6<^=T zfZcGXIsV@hu1Z8?Tzyh`rzZWvggOic((G=cuaL8Ch_Bbcg&@94q^K`5#L&MZPPvd% zcFl_1GJqee2e_izP(-R~swC-ckzf)D@KeRx`Fmgg=Nj&7?%;-~eT6{U zmlq%D)l5!0TMcV@l#(AC@}C8M8Z^^Qq?MfYBk3o)?zwt#+&Sd!%g87uTInumTd^(= zhhpDUpHbfmA;@%-xE0PNVd7cuPq)0e0q7#X%D-LGQv&<;==X0Xt6=ML9!=)?*ed1= z+mCoREnYH5#y>ruQAY4f^fb6s;eZcZV#5Jxh;Nn2c9MjDt1_H=zHCtHz{8 zR0sEJJFx=qR-)Kd_^Oo&p^F${ym?DF>>(0bjYtrlG!&^%e}DUi{7vT!XC-iGyXi#` z8zIc&k&Q(YfY5oo`~ofd52ZRZSvlpKb)FA@fO4&!s@Gn(~0ZUA1MJ zC{L+62qg-11@TCvJoQXGarS3oORP5@62s)f&t5()$xVwPGnm^QsH0#rDxQ4(_8_y0 zO!Qb%eUcu=U=aMS8L<{mPN1GMn_+E0fEJu1KJiR%2$-I}qQ+ohm|p z2F82sF+Nfdj1mGVtx^+ctb{h}9OW;=!Hj7knWVBfIfXcYVquF|U zID{U!^tL?JRgS<>Ydhg`we}`>H3vs}vvzF^!a0_jFYIv~qB$OEq1k+XWYuq0grk>q z`P-hK4MLvVVRHGQ&}YkQ#1D!5eB-rrsT75f=F|HCPv*bZ#U@6a%`*spzmd4!DZB=A zcL};swcF+@#@B}dJ|hXNqGy^5ftZH4Wz;`B_)*lcu9}9L^{ReeYqNrdo!w6lV(>C? z6s-8B$fEmLRspj`-s@}Jo)uLe)gyX=e8CXMy;vCQh83B}gB z)6%6MCsw&o9%XbB09swlaFnQUREilhL3WofP~(p3dGZ60v*t`$2sy!97r6oTZh?S^ zql7;Z#Sj0;L`90M<*L;@4T*&j&1v1PcW!QjD-)$%b*fn|8H+`z*mS8o6a|TViR=95{NN!+@uT!-tyE{T^KaRA?Mxdg*QJwwnIYbF!LR7p)hOtf6BOh* z{9`o0EO})G?_g&z2hd$g*C@XIbnsrcUrywSH>w2`o(Zq42^vivAOI9UkcboqpE#pn#;n%Iqx*R65<10IqkZ#coqm4LjmXkv3xSt zy5eLe|B%AAWEOA5KlU9Y5m;v)!nHVUtDy*$AuRoQEd zpRy-sTZVJdGvN%h-R~ZD#-&WS!h(q~@hqLXdi-UCRywBPbU|!y_@o0!OaK~cZC@JT z6QcEj_SXdCg|-320qN^p(N=NV@Wylg`_ADJhuBMRkCP6S`c)?zaLR;OaM;h z2#=JHILY|ln<+MCG=W@m7an16q zt}Zjjy!@xS)-8*wKAdbL4+Nwpl0)s}PfWXb!T+qmQ}X9qC+D@J;esPMXL&N*X;ED| zQmS4Q4OvZ4jQ{rn49ieet?P>#u{p;H023&J+Q)pMaQY7?(9dGoBg)6BGiS_HxJ>ta zu^91ae}``V9PUi~zKxhP;LhnF=}REIvZ(jB5nQj+yH;m!~gMVb2T$VUdHo*=sN!&`6kn$ zg2zGOptDd#?x1gqrN~P3KwD4V*?t_Z)NOUOByy#(gTN1AS=V$Fy>miwm2;yljFg&Yu`gSJ1|^9HvWBQpIjXff$*Se0>pS{-it}aN7NTVN$#X2Vg1l~A zkJOHth;<0ejI?c@*KAZc#}4~NqA}$;=wjY+Mfj`Q^%k^>g+Q2m3rOoct3~+x}s-x5NJQ`uGqfS+|pl{EJj&^ol@#alSl`?#E-N@)(Mn5~o^cDs%eGc5D zXGTNvG+(|y{gCgG(+#5&q*MlCdl9kChn60eHc)@FL88BUn7Rb)%AFMzl(hgVb;wl` z_b4;VbJ-GAZw3T1VNYVw`{*egk@v2w4EIn3=e1qLdkUo(12F;8^6UNYAG;syZ)x?V zRIrLed}f~U(C~4w#QLvMNqsKl7IeEe*C+vuvw0~?$5#ozj%_liJUqGiP2_k zHVSy;?mHTmi8TSBL={tRYiUDmWl?7xzSc zE;6J)VUk~j!=o`ka3qnIf<>Oe1%DGditR?F*&5LC$c@6X!f9PoA-qb8@<=kr2V^c`9b*c%B2`GM9&_CJ-HRK=7TuxUSnG$73u1kKBRZO#E41JY! zyLfZ6c9%-;R4A;!nyQO%(ZQU)k!UMTyVaSCYpa$CIr9`Y#!))H2hG;GAvbQ@V#hz^ zQgxO8ViGHI7adXxs1~ZYFZGR;iXDf{pXN!uRZFF;Vet4vlf5ff5r>vDC@94{l7?qG zD=gizuHt1>Z&whvYz;V1E_YglqpOXB@8zg3tNMP`66*C0SsM!~9kgg6n5=gYn>kZj z?7VXIuRd)kj9H5XRfP(P=2C}R9ZyBWJw4MRTA*9_2l&fxz zC>u&>%1R31n0jnL2z`@K=6<>fV^SN7G8(yfgBCAe=8%dV`3y(w*-;xSmzxGEQ_5_L zGc=UW{t?_1N9H?*QB#ZHKAbhe_k{HpS)9|-)^sD(V5<(C$KJb#AORR&LSoA16yD^ns$Hxf?{OLKcJ2Edzl%kX5@sxXw7d@+8Rn6F} z{js9zGQ88|Ys4EPbKlJ@Wfq8etM#@4U|+EEKSzT)_wY)q&&9b^OZq7Ex8J4%$asF*h5z`MF)<$}MNw=! zDnm26j+7dMY6L`=dv7T+Uz~(~>bblAW6QaZ-56iL%^#oXpi(0mZ`JP>Co!&G$DfAA z=XEBs9N2@Z&VLH@eqNNL$|zQz?N|1wa3T>K$p9|jB-fxDazh$*Cf&Acd^P8cW}ly+ zbo$4XzRan%Y+;y4b_d42YN?ppWcdHuV+bDJ`86+O_LyKO%RI(g^VA7GephM|qC4}h zo>Gw~$geMmY+74EZ|OoOtNQF*FZ=tt1;NbA?sy0N*vnZSv8#WWOdZ9ZX5BJ1LU+_6 zfzK-;h3yB-Dmgcm$hRZqCua;#rt*gK)wpxNxEOlfT-hVfY*eBK+^j-$xr5djZB{nU zqc}0Sd)oZgOjM?s)g~*n%M4qpynOAe+yY<5Sl9ovhRk$$iGgiea5z357r!nT+lKO1 zVik53F!4pKkL6PHrpkw0-3*3LKMe?9N>xi}SzkgU{C{y}7)DjgRO~HCMO-lKQ2hxne9*<#_1LB~IX8dAIvzEswUg3RnEUtq=EAO0aVVrx34_*`h8jN``e z#9LU)ypa*TD3HVbLf8XWG&$EOe@gTV-`ISA=9zI!%o?4 zG_H8<9}?oBSYmxE%$K^gdJ0Z1q~bR&Gf^%DIN=+HXS2j^P3Myq`OyLcDwx$E?kO9~ zO}^?NhdP@*r(QOh_!aY)(t(=k2zDMFA@7Eds4HZC$k@A`Ji%exseS-+ zNE2F)jON3lOflbxLNuwClir3{;*OOF9;8IY z%LNiRuvBCEG-5T;Z114`9Y6c-nCu$|9m}_}Yz9?iiS_)g#{&?R#Yvh}1^#6en|M`& zCr@Z{=N+EIC{|!$auytKFpQEbY0mUNj-lxLC9a8KDPg>oW(anIrG;S1 zXEXPlFw3*8-mq`IDkN7O_sp6^9V*SS>z%Px&SE@s;b;KF*Dz$o#GFXDf9nIk+q|U*lN)ikVnF3m*FT zpG>CHx@IZyt#9EiJ@|;8qR*!{`OYYah>-k{8-m1=0X80)8yG0zB{-ZEi5JUIt=aB=F7=EM^_Nl4N*;TH z3vH1Nufy?9_Nl`%GnDFkV>u0Mwm1EF?9VhV=j>C?>;IU7dcpN81`jY&;EFb&T4T{$ zk$=3*-_l4z<(s!)sIUhU(szDv-k@5G`>cd##nmm2c#evCd+fMz+G6&ZgfA6cQYKxW zj@X_%IpfRf7QZtbi6<7U;4n`GUYY}4#GR@p{}8sad8RRVG)H|gm&sDyiK-Ayz5%u@ z_c_!L%yUH9*9Gb4)?CC}LBIQVkKJWqNA69+t!R(9mX&L{xD9q~kzI>F*xnX?W7r8?U+6KFU&*>&x$O z%h4XGcD@5wjg)^!!kF~C{q6scrfcA?vumQU(V%f-+eRCwF&f*pZTrTyZQHhOr?Hdo z_Fe0{>;8bV&NH)TX3w5E#dR02tYY~YMZvb}y)yr_?8c!Ha*VzKG15L`QF;g#-(yooNf4#MKlpA%wt+vF9scf>tZIOa##yW_3kn0 ze~@R*3~_pDDL(x`DWx7js6M3XrI-fiMIkfh59Ydy3pK2(i_2O$3je*6Qr{lV&Z|Kw ztGsusX>o{dqa=WpK@Ul*#7A!*$D!o#NuEdhcs=Nv$Cd8pS9W<6 z8uw{SY+lm+!Em81X$;q@@H(y)?US>DfqKxm|+g&6yz21JPSU z4eRD6K!}mH2gTVPz@~i?LqbYFDrmzaf|d?%Xa$jLhcla3&)%81d5L$bw!Iv zN;!BZ6MC82j;Se#KMt1!!jBr-86tpRohdIYzw7w-n1YUnl36(+2kT-yw9+)QT7nq- z&`aU~2o0`6-7E;}iA4kydEqLRt|Qnj#T>c58bFq%z?(OiLP0Db^ z3iI8M;xewiZ>aaAKevfvQDOK_Js?rBykkIq5tpV`jYVEI-S0TxajvF*xcb|smsUw0 zg`uU^&QDscw!x@(#Ji-rena=Sn04NaP-t_2``b@db-nNGCb-!m48(D$s|aJO_+UDm zecC;lO!p@opumj2q~y5ekE;V&{$D_cvXQPSsVz15EB_yJsrBu@~orrLSz zgA0rGC`GjoP(yO#wNb@*ph$$^QhA+0Zmb0In*Dhykb&->?X2IvevP4!k9O&pncIWz{dm*J;J0@zz3oU(y@4+ zFPmj3qAR?Tv%kh=c2pU5sp56EP})puUgRc1V&CWbR_<8;9ZMO$QMGpL3AoT*z8E9p$% zBq`3%u=ygbtwk+}1k|Vyx#9>9`DlYMRIym5QzunT!Ve**?Rz!*F`9tKQkI3~XG;P% z2Pzk88;A7|X`0LR$!sCx9`0sVtTaDYHmW}zm<~_m(scIwv=H#~p&nBhkLsXhXMKNd z^SA*U3}^fM0i@Z!yhOjl?>&1KTQUyw+XBP55f9Mj5r%$~QBqgdr`pqCe3f&hh(T#? zmXjVrUue-`_SoUhTa8>B&w!adyF!C5(b3OCSLFFF4CdF&9{??Kx$XG!iV*GwxMhT} zsB6mfCC-gX>{nOIR{l2C#}gukXV485$qEiccsOq;D>ci3 zJRX3~4c}qSHf}%;Jb6%M(MIy^&SZTwOnTn@Wo`C%{k=|Y%Tg^W)| z7I;vXm#HaflJsa!k%JnCN{cXI znefnWTFL%rkSbaRc96m2AexI>a->%66HwrI*csva2E^~Sesgt;14$kYe4h28Wb~-b zNXo`dMHoUKgJp8-=wTy$lIy|(f`2gZ-k`MGb*Rn7{s~D>pAi&0XW?V*-g3jEY;|QGqp^H}>EM|=#>)yCNt{QU~chhFN<5z74C>g#8?Fyl- z14cMDTINZ(^!wQJW2s{Cr!(RYu1$zAL{ZzoEffh8v6YN27md&~IJ~Tbp*CLWtL4LXd4EBiq6)e0 z(AeVRG0?pJMvA9L-2|{gXJanyd{&ZO>{KDmt@ym&)(AWoc7-&7d~0cm=|q2}eW&zM znZmHQ00R6B46yN%VwrCMefZv4&Aa*tNO1Z9p{2$Oo)CCddhGpZ`!lG0!k|6g6g$KQ#}(4}((+qHGX3 zP898%fs!%_t>^ZBnhD5$H_r?cCMa&@vd1JEh;qres;0yKNgYO&nt*Ei%OkWexL7vw zd&umgH`taz`K0ZOjOC@1DDw6`}sOG*y(KA zYl@{+2E&7-bzk>iZ+ca08>&l>mbUG>2S~`^<7+Shl$b}~QKOPsWI2}cJV##@wi3(A zh^eXbv3?@{hG1pdF;nJY^?)_FP#0%GM}p}K z`WK9okfA#1>#BEl*FAo#g*qMLm-k<|^rSPRr1G6s7!PG19e4%+90+Cwp5sUHmtzNw z57VetOO@mwvbBH~RXV1_NuoffdEjPIA92morkcN^<#bV@?J1$&d9v|*hTqP?C*?mJ zf;D#_naqy(XdP0ClXG(Xa{ZYW=tdoT(LQzoLcG93(nZj{x1f<%(vN}O47xQmm@J|< zGa6%tMGQw)22_ow;qk%Y4mfWk@8MCS3%GV2`PTQGdfvxkta+xOifmi)=c zowacsx{Vo@?K+e-_0fY>k`Gk+QRET=21Gm!Fs}7fN#%N6p*z00VA(tgRTLD>vfFfm zSeIQzI;%s0 z1eUQa8E-hNhvu^CM>HL5`7$5)m-V<}TBbG8G`{fwKd{HrUnSqTwK{tOiS=KO1vBhR zq!8(5kj?NOZ1i>5G7S~uRVY~vd_)~6(r2B*W#g~(INbVG4o;E4fdJ-kaCzg~Sw{(f zj;<2Jt8rE?)ReoWD0J>68&%wdIL0D5ab#j@sX{FewRjif&YwPXDehOH0O}i^{+m#xqNj- zuBxcfh!S#3`l-l*p7w<=nR#K|!ea00On)G51bDcvhfC)GW8Gd)I)vzIstK4Q7x-v? zZ1DeU0TiMoJDsT%-d!-oN2Bpl0e?5Dsain}GyH?iB^*woBBwqqcA}+7nXbd$vd-BwYCdk4E%IjS)ZI|Yy&g?0%^mY%Gb$XyE?r}H&Az@1( z-AIGX4-~EEZ>be;i*b5WAxUd{y(P~3 zUD=WhDtAyy5Kq5xbOOpkKWx6vzr52nWV2y=T|G6wN`$;A2qSL0$+H&*S5XKZZXJ<{`Jugb{FJ zmgve~&>^stE2knMVMx^`$xse5(3QX2V5`0>nawN-bUppU|G@}CtqU4g6u_0;a_j*4 zO)&S?cV|rZC+J3}4>?NERrOG0RB{I*S))Mykv zCB9zm=l&%U)YgJH0xYcGMH+@%?c+a))L3Kw3?XRn6#p!(L@l!D}#@v%v-}n8z zuX|ZBil+z(naCj@ls(+#V#2sjEkz_vh%TI=r|ahJEGX;N<`YF$ckj!Mg4xenvfygI zbvPcaz+zhvo8}~}gLDw`yQ97!U!%S>-bQWM6s>t0hZ&Z!qW3mn`w*A!m@?zVIuGAwj_I*n$)(Djaw8xMn>yk>TG$0^|N zZK01H@YlROb`Qyg8%9vS2fHIz{0@+uk5i=1EP{ z38MOG#a8(cl7CN@kh(1Z8X(Nb({4Iwdg6Y)g*E=Of(QgwfmU`R$O%^kh6o30>geEK zSbQqebxlw0_rB$Nji3!M3e45*mcl#~aDKYr;xJ`2B9XNwzoRo|!6DU@wTzUoL0>q1 zHVMr2KQrWPzM5m?ZmmygW1WJ<6Jxu6ViiYG;t>~t7Om~PnF1nRd6^y-6K!~Gus-dUW{J+UZgXrS&ewV( zV_yG_8igyh6lkaxfV&9#C_O3vZ%_*m$KH+Bq(r}x&>RdRmc5l{we?~(OJWXQ6l?O` zK&aV|;|ZHeX|uQ0x6nate#jk~*6EJ#DwM;f^(ft4BsO}!8}GcASqJJAjegu56X+WU z^z@6fQKZf2qu;hbr_;RlrdSfz`x85iWBCvI676@79t->T6k1UW2aIAX>wTB6Hh0sQ zcicZZ(o|s4xOk>ro_ZlvuwNGca>|V}LQ;1FVtrDf7p50mZqx}%(TyqbjjafAVA{MA zM4t0)T7#i~AVDs_Q_xYfE1~cu_&j;Qo?r2br`z(TPr>;Zx6AjKVesV^U3R-|*-)@# zP1x=>h+l*=ETbQJS8q_lhLMuOY>S_BDRG97;moRlNQfJ`D~~*D1L`JU-zYNJ?pEQR zGXE*xgo00ImfekabdtM_*Z!f;sEu>3bcVL`-@=2*WGQYW6OGqQd_b?_qu|n!OvOQ8 z^LHl3TwIMlizOTXnaZrI1hcfP{Jwm=sUeoTC)L2oqhIj*I3X5Zio>V-_9CLj@4;ya zQ=}v@!mS8T@v~v07{M2A)Q4=~n%$}pCX@VW|8@M@XZLIT>lQlH2b9UILpdu$FlqU= z4YU!$+DdRVJlRA>w0!i0oaEHazC5{(%wL0Wy2P)i^=RGv_|6Y)C) ztRp6QSB6!bGvUkYCJjl@!R+3`9RruHbMYvo{3!LJ=b+LbrEYTVmqg3X13Nx%T=$Qv zsY?kz{S9-~lKOBkAx1|*BQICuIr2Pxx~sm6&HJKTg||w|ASnLZYR(NZtr}K4?Io>^ zqB`On)kFG1RX#=+P$mukmzd1%e?^5h+cAz|aK2pp(B%ZYM-fVa&7m=c&JwCZV8eyz z3JXPhX?zD2{UtP z{iP|2VT4nFauefeDMeD><*Rlz&IQK&AZK?9dI#Hgq#O<<6w~ylzKqsersY7c>y55|7-y~8Xak+M4T*}*h(%+2rNyMyC(e5;o%_QU!c1--bq9Stob!S z{%(()Ak?nw(IE+g%c%Bne6MJF{8Tbo1bJ>*!5cgAl))8mMg>P!aGBn_BH z(OJCwQ4SAZ4d0&4r7N#<1sQ>7y;ZnQfcVO`H9Rwcf74wqYUd6az;>mE(?g@If$u>a zeIJng>&OzZoZEU9_JOy6eIkQfmu!2`tCXqdlEyZ{I7FLP^Uo>2Fu3%0j zuFW~orV|{AMrSl_kNwq?Mrna$We%LR#>Qg+I|_Z8EgxoJr=ck!%XyO_xVlHRhjHeJ z<;=jp*k5VgUcX8=Ai?A3ajH9-yo#)Whg8~5qNq_TPLh`Z+u5*;K!AEzTH~KjCiQo< z!`qI*FX`kcT#)z&aKNo)hy2aC1%s1nOcW@_?> z@DwlVs6CysX;OYKu+n@^XPN1EC|26fIN&XA>DBYc9?xHhFX!<5m2TAsQ?mlEHBC7KS* zo}+MQtQZ}V8!_tXbL#(+L`*VXd#LSC6!t;;<$|TTvqtOP`3k|-23Tu=jkpVA6fVOu z=zSe7_#BX^NNiz;;sA&@6pGtUl6>WG_#`m?I6V`rdS(IqUB7!B|CJA;pi=LtzyxCL3-k}d>|JsPE;wAa$y0d=4PY5o(H^X>!Qq?ucVpF*7& z(puCB>bHV*n=Nwl_5Qd%d*BwED|f@!h3gCnCpD_5mr`QT7*7Wa%7RBfa}jC7QZGXM!_6+h zMu`*5Ag-)tj#wo>X)KwO1$`+BZ8}PAhz*;S4Y}j=5V+~_>`;=X39+<7J;jg0_yWaO zf$Ar0b}s$>uQZJ*3a1VTwNGJwEZO;N*$u~l#oKX>-I zV$>s_n2?^Rj8ZbxWWG2MP?uwGWR0?)zY-n{a0G2Z1J8Ha&1%d-&|(i{OQ@Be68@$k z{5zp_BYE~iu~+0FR^7A#z7$Rb4^s9k1~+=7_#OP6c?J@JLhbrNU9MbjljfS1fn-<0 zv%6Sp!3%O;3sk(2pOIqJQ>#?rF?aROJQb`xj1`i?p{vTLRx{y`GNI~PRlX<7X51>R zq*@Pf!vM`%Hs|JNIA!#pdL|Zkf6X-XN?bHAHJX(N%DDo9arCy@j15})AMIMcW?Q~@ zLl3ASwJRxYmzQu$ywHQCir4D*P(5V(6bg=jg}O6Oa5+ZZs)t( z`$i`)&ZH+8IxE$h*pnJ?`+R4=vYa}7ZO1ov{WcCn&1PaalaJiywPVS`)Qb9{G2X6P z!pYFty>?%=Uk{QWbL%%Ef;mx$TV#;RM>pxuRXJlh?L95G?DN9-*suvwF3)PPTIaci zZ;BuW5@j-gxAceOW}6geVEq#T)qGNxuKXxX(u0r?KfJvPX4FHeOS0c4BqLEEQ zds~ljrs?^J-D#AZjB=>yPrkwBT{>jFtbw|`PA1|O`RK|t6|-p7z5V1*ew;JY12kjJ z*l?Pz;5Q@B)_@E6TAJ)U|6#coLMr3jkN^g*UDc+aeGkHo@}vR`)&Wg6w3#54do}#yoJl_dkq7h_haWmV z8ZtPVekvSfhOC3n0Gt#llE)^@E#EpLJnAhUxh*SxJ2x6zq~PAfuRQt`1M#vO$6&$e z&zV2|yKey&sbuZ;tXjesZXG-KqF~=o0!TGGK?=HS0Nehh0a_LjIZ}r>xX(PPMf0Mp&8=?EN z`uBjHogf+!-43P_M(Tt!Bx3dQC^K)2furr;3WOeYKW~xWJH}Z3L;spbOThWI;nFR; zEt7X)h$*A+EOsvK_zKU*lM(e#OF8IqK{|dcdpX++(DfSme7<~SA7}W`|Iy!M(1)NX z@-aT+$YA`9)C@A&(}N&x<-zPa4<;%q-xHPHOtYA@)5$ScuwW0Sf5j+=TvX@peYT{G ztZY0{I4Q#s%D*rMbeGnw>FaMJ;UM$S!J)XgF2RL~x6)%6GdHEdsA}m)cy$~13JT?z zCUbNKFG-?XGX?s3L#$ZydZefc6(Dt*Dk}|x#3U*_P&@4X9TdSx+U~nI&z#a%#~g$| zg$YRMQQ~q9n2?(-HM)HQ$)XeWwZqr7;Q*t{LUA3+oSh`@yi`0ZBV5l*6L$fOi_16gCU z3tvRwg~{f3Ni~%~EW1)nK`U2K`@9HEBkkR|BKEPEHD-;CAtnGSBT*_KDB)$1=XPlu z)9H93!cc@H!|uV_B%%&hZkCCoO>At;;4mD1IBjP2McM10pqThuK}n$Uzgbr%Cb8OK z%Xqx=M)6QJcvMq>MLGIcdq?d0E$y$DZ9z)_ z)?r%#_JCyi{TvdLR{jju!KFRjBwxRamE<zkIMRZUoX4RM2uHpY4YwwmjRyEtZ|a*;N>t`Fnx*?P}qF6e(R)SDH*`4a-E&N7af{J6td2yGen zKrF0jo#g1p2upqQ%C)p1^LTo*P^xI7((n;ehmMnAd5M)X@nqfhXe!Ave1)wO72(;K zv3(=5%4Qp9N|=|(OivbLPOe?ar5+%nB6Ga2ex(?wH$@Tr8xgjg>Xz%;#&wJXrpwU$ zY#Als>jnBK1G6VY9Bj-i;JY-vSuH-Kp0Ndi*t#|K8XsNhW$^qynRZFN)j@UUs<()_ zH%+;jTJs+4l=1pqr%Z|ipZG(UMR!ZZuuK5Z@U+gmvcI8tdh#;2uujw1SW3khfI0XV zwJNL%^;-dV0ez^PTtu!+m9g3Vfw5?-%7Gu0l*L2Sz?>`X=!x5e5%SEYwE7SPW%?;7 z?hW$H$g+vFJAd%_`tgMPK5ihVRMg%ID>2-ZnR)`qJOjyL6k>z^`irncPVaW3eMBBv z5mwcoTzA;x6y)>u#4K_+UeFrnM3YhTE5*2%?Z#|M8*;yR76{l$0UHtg&5?lR-^NYC z2~zlaHi9LR&+rQ^wD66jAnRnE*(}kT5@x4o!SquOFzr=?=%G*bu4GBoEXPr&!hDJF zkV!*Nen^Wxd{s9wPhQ9%PiFQ$`JcN4pZ;IBI#tD?o-E9lOK1JG#38E_LFZ{LNmW9S zTL*0*8e`_einhSVF%uqq9gXMR85_{-_}oKI!XVPm!^~CLz_&d&(pp+(sv|<1B z8=785%K-T-7rI4@kFaK=8QQ$jdlf2u7z2~xCFX)bzs7ztap$+-CKXCkVqBh#D1vROrJ!_TN>`CW(b@ygI{~B!Gd<8opljhn)_kPRf9I}xLQ59jbCGh!c zWkFocAkTgn zzVxo7<}BZr*{}0mRDRoSsJK>ao`?)lm$QYpzC`>}GK)fmyvrjps;KNfP5_8`_l#tw z`&`-&c;m?X8`jLf&y0vd9_P^6p4{7DY-KDJcZ5sJ2tU?a3#J@H$n-_$#BDopiZjSV zmOn|bxG(1Phy@SmOb^Ie-gL;pRQHB0?vKco9H$RGN2oP7B*++=Q>d_HHA%kssl9ZBM)7PbNky5-M((# z_PIW9)|&;o4=A6EwiYtbKHqo*-7^=wF?|^%M&kEv@DnNFDjztlhe8GnVRQZB$hb_2 zf^O{UJIEd8i03(?vELMHj^RXS;7BK)C|+_Hf2gNij3KRcrTxqXRyJPLD?6~b?g0TO zYrbsF`IffT$?Dw~!S9t2n`qjULldaABn zKUk8)lC94|d%vQ85r`_X%x@$HnFp*|``RMG;AVst!U%A(Gc>n+0pDS_Y;FUp$i#lK z(YC1IhGTz^V%wuD5YxK1q;RpMdIHrwO`9y~Ggx!= zX|qn&0H%v)@@7qGW&8>$TYlufS|u)LwJT_4xR3Q{_rndt zUjt!K0f8d{%MUjyi!omwk>_t__5z)tFO`1v2&rU44s9s6){~G3q1qt8&3W=T$q?Ss zp8E1bh+&M~THiOjJN6ModbNO3zj-Ql^0L*uQvoy~8()yZc+W!NM44_l#s3-r27r3& z(ME9`q2S?w@28bA5N5R+PE0!GiSZeUh|JA6ry++L3I2qoBIDa{O2Jc;%3mhP7fMNcvQft%Do=XX_H&4$COi>~~2~t&BIr6NFpRz8q2n|FngH zbkk?3awLH#@(HMkO}Qj?t-zXXiO=%4qhu-1PiATBNO&kIIBPJ?()#!}I{7D`d1f0V zkBTcI?6j8qpotLZ^y_rj&-ff3@cWU>uIjgiaNN!8H^efIuDY&OVjqk-2awT{EAa5&GU#Nw#g^Yu~GQtOUaZ5V;-v3C=x zCs++hoil(fx7cb)!dPpTXS&IzU{}HGvwsPu$J7Jf7VG^SL3e1(NW9-#wZcdx$cRWn z2i7-@3UHzdAgAm}D>W37AzBPvyZhC=W+1dXR5v=p(NvJ1dRpd4$uWN@&v&p z@V43m&Co20G%K;86z}VaE|_U&C~XT5w1O@qU%CvN0Et+5b>faj@Q+6eOF`xShhbbnz_ZaBPjQ*n?JTEyWr#D#uca@s8>fpmsAml0;7xa z8X)y9P}eC$$dJDn4TSbsfY3pMZD2kvD0UpC3->_MdIu=2;br=vTSErpU4AP?gQN+p z4?lP+oJ252T(RFgl1cx^Ii}-n_Dw72v!u%faj>y^{03hDiTo`fAx37V5NImC)pGyG zo-kEzhUIuE$m5m2GEPH#iKw)EKO8b%l${79{fKChCR1eCwseWRSSc`1pIONfPop|J z=0(WNS$4l;@{0G^?3CqfD-I>aok3Q7N}s6q(L7RKV7S0sKlG4cp<8=xq&mI#7E1a^ z%R-hQ2AY_QrJ0C&@2t6fXa#faEw>LtbD^Ye1r zCdBntu_eAo2T1n3dkb`@&nPY0d_x>Tf{IO{K*Kuf&{CZg-Nt-ssUS}tUkN?f?U6j0 z2ad~62GPfQRU8Jd3${O03?^P8LW_m|^q;=EIP zK_}B`#)j3!*c9U{{2Kce=B`ZwguI+_O9%QbZ8S{>ffw9q3*Lgv%!T{|i#dR!X53_{ zN6el?1b)-gnwC1@@ZveJr$@JHj4kcat)vQG3NUKJe<|d{MT`jaSJh!{2GB7)H~^p7 zg{5T0G3JPNK@OixC7V3ZvFGT-Up7Z`;O~TnS4!%A&mi|Fq7E3&d0DQ<^M1Ru^Ll%{ z$)#3T=O~I8d5y)WXx=+uOHC{@NH05?WlP6Az(7#l*~bW>{y@1DH?S~Ow=C%7ka%;G zGPk}!y7SA|Thp9^m@!ycwy6x0u6`qYm& z7H&1Vb@!4@s`zR`@;hhS0GLpHiC>(?JUW^=q zVt~+Dm3wyc?VMxLh7`53gnyz@sS*NAA^b43=)ty!ke^n)_+bnKTwK|AXY1SSbBnq> z+UK{!$w|H6^_XHdK76AKb~*=nmi<@90~r*o4?qK`^lNTKEe{Mdm~cqB~70Ctj}2Ul{M2h1!~RVJOx|^1i{bF;-obV*k7UWTnJRR z=XRXw_C>A{;3pFN#`>o@d7!a^E*!x=?|zW1lQoe+IOT6IsAS)JT`xewT6>wxbN*}2 zw}P0ssN<1L=BPHWUgd*9fG>TW$r?*pvv znd%*()Fc(kD@a}O0xNK%53PjK_r+m5Xh>vm*f&?=KivyhP3uF+AM@7{#;l9^h$szA zshR_lKUEa7y{|g{fv8Xmvus08!dc&B%Dr(tB?LRatGN@~^tYlAoBWSE2i9ei?9C2^ zH~9rG+NWTu+WDJRWN#*w#qZxqulD@aNy4C@^`uzdO;EhDfU$^!8QlTr%B;Z_F?CCK zZfN|*6g^caL$CGTQh7;Z-F_*Ix=tW;q63yn9PM%`=r>JG2U%_q!bL65snM!8rI3RB z-#!af8gUaupC-hAoXT5*^m0#JOYvSWd_Quat#KYjyyb4uY$%?J=0=RZ_j#!0*xx-m z2#FlrUHV|C4$feSv7|I6udM1%fNII&9%6_48*_R^xL~j#rp{ji!?2j{Eys^PTO+`Y zq+iG~_Tgt}#OM`AY)VW+x5*dI8+vT@E22x>@ONL4zNtJ;ip?1<4fFOAU{WkhnevU&?ClU0B--NN&dmAZ#7|NE@?O<>GDP% z6sO?v&YF6lSO7)y;Pie4@Zgz7`BTZ&n^AE~*d#-s!qW}nO@|2k`SWAQ3wI&+w?lI2 z`Ya1dc!_7|jwE|4L*Z6CKJt_qc^*Q?nu?|59fR-TrQzXlZ%RHHAY67Xe>r*z zfSUl*@ZW?hXINx{b;s8_d+E6&_js^1ecyVmo_ssFfGeFka%NrGgN4wc0VO*grU;_w z(g(Ww<226GAzY@(py{Jpc3Zu>(D0Nz!~9)iRO|XZ z^{=ATs&#^vHloW`hxGspOXC^JSNg`VQ4;S@=!+x_4^TT^4R|QkRJZuow*TbZ->cIm zH?uY7#{eNwcwnwz5-evQ!u0alCvYtaI;(+CR<8H-ut|lHeoJh<@dp^azP(AE9T$kv zh)w8hF6rtfNhP|vskX6LtY<2G?OjR$MR_D_Me(%^>o0OE-eh!HhD_MCd*$9zU7aE2 zVw9McoNc)t`Xz)(EfT-`Yr;9&wzl=r^3SNZWsXcuAJc`}zk!eo>G`W%R6v(mm#Fe2 zG}t7r3XzmRM~CZ`3OHEY(I(0poHJSTXKDpOOb>sT>^O6GDJadB^rEYKIaId;Q~oR} zz<9m^=E2})B(oJcoGH?cquUbrEw|V0FfRynko(vW{i`Co<4Xc3V;<>YUN#lK@4tcd z>7M$*I(N6SPZmDUZs1?sy~fk4g+dRR`cBUE=*>GQkE6>XPDl1W@Lv}Ei-${Wt)K5P z=nCzF$)FBx10a&xKaDocUS1&7qnM8c@0WmMb~EE5cxsYl)4b@v+4~=K#I)B2`}0>d zrP{PoM$9c^h7HUy?IfEX+J9ofXCw?fGc#!?A!m%Oq~TSHUq=Ne8`)7VEn zC9PHNqI&k8Ra3@EJ|o7#hvb$StIY_fxND|>&!hZc7KxF$T5cvxPhl5v_lC&qr3^f= zrFFaHBq7QuAqRaY+#{!`WY0J@-NF`W6q7_TO5b6>GyZ|wKuQ0p*=KENYQ7cm{_A@) zC`X@xf04;}ZC$?W3I(vBAk$2(m#JhGEJeQ}0iYSzy9a4FVh8+KMNINoF<<{1S6M3o zH@@tXARIYDt`gdrrSpzPcK?)Egex+Y;ZVh575JcnZ;2iU+siR4#QS2zhmV|_ z8U}-@QFpsx=~N0518}?zcNQ)1JeUo-vib$E^s302ik78#5Lf{wE0tb2O=cFeUbszXebBH$4ng}v(y!ZV` zYRHIdV|T$e=n0EzV;kfhM+hSg<4LlF`NMqCCcbejuX6~LtZ&gU8A(7prW5}W5%-=j z`#O4iy4GQ~IF{@zjTweM;>#8-HTz*iYp!fuL_?P0O`;#Y?7+p*oG$9X6Go^A4>l?e zGlyEQtv^|_OeH(sRxW)m&sQ>JO6Sw{3p~6t>~~Af0ex+8$aUV-Ki`&>NM8#U$B|nY zD~Qc@RE9$y8`|2cw@-035|PD_WmdsUpRV$eE`T(2@41SsOUc|I?@bYj+VC%q!_i0f zXl%vGG8PP|V4DM`6P3pfYph#=a!N$I&|y#<_H-5jsOy-uM|x#{yX(iNC_5KfeVVc! z>3+J49qqTgsPx&0lUveL5K%UxYtX-hS;a)XOiE9n#%~0sd}d7(0?XUy5yRX61lx;`veV9Re3fa+TFXYoXrxKtp0a760%eDb_bL(W4Gmb!Kr& zB(5PMny4Ky8|yfcX4=69t;Z*H%ycMUMF`m+_MsHrw9N&6*Io9_gR`MO9^Oo)o11n- zsPg5_6jvf*4$_+XtjEXTip6k+Exp(|NvVX@@fCXziLghW3}v4GV7j7y>k@~;da>(u zuA?ja1QO@he~$XB9h&lJGwSB#-)|)i6cGAYyVB`GQ0%8v&qn@a2uaibOkG!Nyj-43 zz{kGD`*vn7S58!H1(#+_kBg@hj6%*O`-dt|R{rDMDGDv^^_(1fjzS zI_hh@OHw+wjpF`3==Ptq=3A8`nC8*g3rHg`b;|vR$YFLR?Bx(@X#F5XO9RD*T=prV z5(u?A?{A(EobI3D7fo7c9HLM3oXC>>TfPx~GBZ*W&pQX#cTM}Qx8u+U3JCM1Z3%0w z&*&Tk(z%XNmviyfBu$+@v47X$U-PC3^7Pr7;&{PSMB)#zu6E*RD554|zd6W!nS}6_ zcEtlaoM5f6bApRRjNv^lU*w8=fwoxHNETKzl|by4P?Vg2?hJo0$da5RjpeaZRxMeh zDS4t$#;T80Zxkhg%;3%=eG(s4{BvTHMbZ2NOf5}!5x(G{p}1{o+6>KM%YFK-`S|Y5 zj`!s-y%p*RFOi^`k2lODDS%_0d2zl!e^x|DlTTP+T8s+qMBmoJ|905}(f$UPov&<7 z!F3&c(;+z)6!!&R&@=TlC5wTAA`}>5nyu`y+-B*^KJ(Vo!%f=MBoeegJH*8Avp}@* zF0GSEachM=W1935oU(qUt=@H+M6j?%-gxvwVfYs@FSU(q`vgiD{7SW-z9!hV0TL}w zyu@``sMuxJWc8+Xdws+DEMTc!=Q8WRxKBT09EXU@uUqT3)ip(a##c)!n;~1SFE-lo z&wH+xG{Xo=&f18apIfG(sRs9BBwhQ2{5Qp<{oS3N9nsQ4H}M6r%o6I`XejGX-Y6aw z+Ryod+upSH-<~?zTXVNHI#-3Mil#)O8iq1t=;(M78&8*lw#k~1LVR?nLEH!U26)bg z3dtBCf_Zeo}9~k*&$mF;BZ;RGH z2cylAwor!BOsVEU8h2*%z*Hm`|D(kB>lnkb!5!S;{O%J!e)GespcNd`r`O(E+=VG| zNiu8LG2t3P92bAxjU{4aAb!{#o8oe50N$efF(d6qE}j&c#2qVJCivQ>ms z>{SfP>()uI$hQHNaa9SrERYoAPv$Aryp9>KIJqN9>)wApQZb}jGRGGDCUBK(U?-iy zRstM9^m?AImM9b6H?6F~!C>#iUAd()2#>hVU&NYan2UCd0fq{$B&Wmshe8X~*h`;#Bpr^B#oa4ArQC0(8;oMd(k7G*Dl`;4PjXK% zO~jX2kLU3lM=?kbAwdaD(Y$aGpFTF?(N21UibsLIk@fx8$cLb%Ssq?&9KD~*dNPs3 zkE{=}=%?pTT2ESoVg`@|QwT0(v&qEp!Yhtt!n$uvm(GD!+sRY17g7!qbsJduk3qD} zQH^ydFTAk8;wnJ?t90mChf)b!0dcUAtRV}vhEKgT6(EjWd=a6Jp0z-br@L~U|<^9rHD#62O!Ti3V}qWC%)=X1v$bo`wp$FNHdCPD}b}M%yVy zFt3v{ltqb8&LMq=>Vs+Hh{}=L^6@MH-9WveVL6}`3g=jH)TFI=cTFJ+?7}_KvGata z)L^U{=$@$B7U`^5HO(x1GcInLnk(n-^IfF{*HOzhJ!l`2b4d-r zo<|7iwVb|c3iV@Bo8o%tx+a18`V*BXI1ckJ>8!xQPj7OO`f1fVKbQA&4z2SJlnMjh zoqqoFXF`at;}3l2<*Tmth<0?`w>rX6I8Q|Ogx6{zGIE|I-_GvOe}>o6H^s2${GNwL zk%T5`s@amyI7wd<&1;)hEnYz0KC}G_)VAVLkG-+uq;fZy$#H*%9d--|*S<>eW#Yx& z&0RuG1zdifH;GvX!j|BAbxTl#B23|TJ)Fr4e7+F70vUw@rV>SY3A*G-U;UNuju$cZ zN&BAb9#F|W?Wv2=C77veX}u&LZQ3Cj5t14xHKpQeMLeK%+fznU*^33^$_qc zWqDA2!zhG8EdgNs9-b^lVsic ztgmX}NUhzpr%Y#^%}}aOE22rc6mM}Qm07p{S0+}zVqrPO=Gmd8GPK_NuI~d-vzkV}uqQo1@m1@6)@N%3#w04za{l0p zwL-TRoB>FbYz&g;i4B@o{#~c{(#Qx*kqm4H#R7S@3{B!Z6N_(#R(=WA`JrX9hdkDh z=gW8uVmLcbeJJ1l&{nwyk46G`Q#giWNr{9G1e_0dBj_!fD}$X;#z`@l zB#PTxaKH+;U`g{tPNM)c*@iYx@7~8X#JE^p-?JdITXRNh_{-CMSGw(DXpl}ybazGI zBNYWBLNOhsvSv^J$sVSHQXwTNsJiMp83BE5O-`Z(Acb(|QzVYji8V#iU6rW%b!n{m zdpS2B3D~?h_cUigcpC**6fj#C=+s=f=vZwSdkwR))t#1Gkt#q;vfujKkDtHYaN3Cv zp!KtpqDTA(6AJ86tOzUNvj*DaWSHq2scwSEEcI)J#CeJinXU-B7+YbCO7u4F1Ddvf0_e+31t=5rPDP^d9y{ zvb?~TRNq^rl>%!lv|}KJ{AXjzzZ&ZN?LKoLIo3@5do`qu=p;jCdNMUdTVlL0bhk99YryuQp#D3BG2|!;oncw`CX_d)%z2Y2`x+y zYvB<>vZnDXTV8v}hOg=#fQLFh#DY3Yl3C=FpaxyF?w5W$qgcoIYv~vP8+0whpXEHWwBuE#Iob`k+wp;l zDp;EweXKGS-qu`4t)H6#W|iQo(r-ip`Q`pFdbAjEpNe^{;{hfdb+h9z^TKg9G{bGE zC6n1L8x*^pp8V{a_}^C{opW9|s!;(bw>{NmIgrX~?F#RyE@m?^yE)FXMO zU&*|_^I^iHdpsTLL=Q^ZiGH{?$ZZa#6G-vo?~+Nw1@( z{lt}OXHz~-jg#@{m!NCTX3*Gg6)?8&R{Af_;gta<&yf=&iQa6IDlTpWxA()6CC_>W z4FVK;>YFkncc76g$4yCMSs-h|J6&86>Bys1O#pc3a#ftH+g+HMusmj%kJF^{6BWIi zdE<0kvrXbG{Kz3cKD8?vSA4~!~z^} z{7|HFK_-Vi*D)96RIMw;?z~OYwguN~KsrLD3=68msd?GUEg9Fg!QLLIw=z0+Gs(D6 zCQg&Wo*`W*j`aFMEdE1cF>b#-s3Oz&1cfsPv|K++`mkdM(dLc@ItdsZLV?>`+Ni~_ zMKY!R<+Ny}M=PDLJ#y{r#iATSHjiQpnVo|3)nh&p6v=h|P&cTGA2~uWceNFKBe-c^ zU!73KUqqC}zN+`N2`HGbQzvuzy7j|R_)O!}`xO>IsD-ft+hm`Hqq8BgiSZGR{^kJL z>Z*F~aDI+SKI;qHjX@PCA45v#aI}N)MAH#R8n`LyzK(aB(O1xNK{#Farm~n693LA? zU2aoPwya-O=EkyIyrC5tye6iR9(rm%Zen8sT^vSF)(W~>XKbmp`gu^Vke1ZX9#MbD z8`6DRXeXN;g9oF*?|!xy^&WX_-iMC|(4+CXEYc+lYt?r9u1c_x^_^<)CNrUWx(Q&i zR{ya0apL8%2`x2&OWINXpre3rax_2qe9f&^`(M!vq8_*i7;GJlUbL_$zK3$0^TlL; zo&Dg>G?KSoo?>pww)Dntubd)t1&lE-&?Rr+@%IQdo3~`S3nsw~I9HqfgdO2La*GD3 z{_5p)k`K^7&P7>z2WSy{Dd|&XBsBM)v(jAlUjP15X{k;VgTh;HDLq%!X^)YPd3I~8 zpX#(@cW8l*KR%$$gx>TQlw`XFZ3$5#Iu}iZD`T)4fL%fmzbyOLsj#3@Jz;yXi?CZR zsM(g2#yVH*NE?sj)i4~6*dU#I1ziURzdp?zPhVuO1&GRjCq)QN0S3*+v1m6yWf)Hr zSPYadbj+d<-ObwQ?K`O)by*#>)UYJv3!^wfjg1dm_dUe6BD;0!Lln1T6nl|0bKTMTYqL~a5}f2 zQgigaQ5J0az#q$FZY5UZF)Cr;m1b)mR;nrLZV);rS-;faRFPvFp;5?m?TE&POL@_ zsb6e()eOmc`!5|Na-)StjHN?|5K@L{324W_)IancuL}7WwEHdVkK{@MJ9RM?2@Csb zS9Xj8zeZRIR{S0VtAS>QWv2F4zx#f6s;i?#;aSZWQTcq`Xz&n~i3e?ZVj8QiiiCRH zXF=lyzY{UPe`5~5Imbg^K_c(#rMf02qq3Npw-526K~FiV{^8korJktIwj&DvE_f-{ z*_ovb0CGIJw9IQ8cqV23MGC0Z+_6_OeP3cbjvB=M9?kkeoqU@LvRNxXXJuJ%%dB&x z0i$*)8a>(UAfL>gYeYr@3~*R%5_GplnyIbOI;RnXj=Qx>uu^J)+^k53V?iYA16Xgr zrjrtKV18WgA~r64%Ybh?E&pL(v%mE(X;;E?ls`D{a+fQ0lai;ooANmoE#q_!8R{Lj zb5h%zwZDAbz$cT%BnC}R#EhBTucDBdr~MJ{h6)EA6=x;JcGxvN!h5`j9(ISHO0+lj zn|CsO%_B2W7tl430*mHm#rIbn!7>R`%l&-~0ZNm+X?EN$fQCBgPkOE(K>YMKqutr| zzDyUJd+1Hrx%JD7tbClCU{G-?(M^Iji1#e_uyL`2pf5a#Ld9Up0N)CpXULZfXBHj0 zlcpGXl%EF-m5Y`8$+Q#|hi&PCeY0>mBOj2UkcX^fomjX|7|aR*rdZYjXJ4T?T)sqZ zOdk1D-hxzAoZ|hU3WZxrEiQzaczVUJUyd=F!ZC3rkTa`Jo)5Sw9$FSf0DPm0$U77Lm$U=CLhI~zs$3?bBlRJiOF?AQ4J@ynZRcb2x`}(ol#4UsY?fNs>FhTS z8=m!|j<~Wnzv(x>4?~i_FQDEY!$nkcjy4@{LmJ%%J${?B8PNP$m`CW4toBvf_zPgdK z+6&Wqw(Ua&9M)@&k?%<0i!gls>1o!3dMp+XlVQZc8|GCfgf=J2(m0r&tj=8M-%^l( z-=YStdd{WSl%mk=RY64>Z9)V7j_>b3f1fU;Vf}c=;8-MBU0Lh}@{X)FGydNT(Du`| zEoCszBtZ6v3aE>rd_-RllQ*tV>W1ZSjqee`q+7xLHxPkW9Mm(XMf{_8vu`jkOlUcu zo%7s{GEgln(WZ);DC?iQi(dn;X~P+Qu6d#$oIlhEffk7x6C)TpYIT>A5tD|h#+;2A z;coJWeCMp(kT>IUt8K^5EDDUcUXWML^#ppn4z_tEFl3UJ{QI(68R}BL_@_6G5C~ls z7@kd8@dTDhTi~&VQ_Q{a$>Vk;&bl6GN_@UL30v z{tomwm69%pvy;52<2~kLKZ2Io`(cXu$p>;{D2D26gp}Ip=>HxS7n%V)-|J+m1P4^m z8}r-KK#TdVlzik{+{+LZeFm#JetS`+`b#Sq1i|YoGjV)6xZdBp5^KZti;4!tlguDF zf9Zau6u@2%vyq-0*BDr4$^D;pAWbUB*d2{zGq^s$3Z$5Yr6m3$b!70n4v|$%1&o$9 zF*wtlc65H!$;KohhMH1rR-${dM?;UQt_o^}nd6AOZ3yOHSK?tK(*`&5mKtJd_?GXEUoyn|!3WnXue0@=40rl#0wj&+pT# z9eBwEgJ(*{d4@%~l7dX`=JF9B8XylhJU9MNK>#W^&*S~svqmW5R}~FvUWrAl1Ei2{ z_0CqYJS}FA)(rAt43v3U2YSCabI!XJlWd2Xqr^j_t6(Kr3jhhT6YlP@J~`1%!#-lg zA6h{Hlk-Si(k$$(*@DU`&^2o7qmvmh%*pa_ClQFH%05LGy>TpT1DR0s!JOZAAY{kM zGxqU--hCF5K$V6lua5wI$%n&pUcTqABW=sCG_F!{}a={XHUgY~`D?9C4|Uw$UMwT4gosbi9+AnHSnm7ij8a!{+&Afqb$d zvYmg;G!)WcVzi|;G2^PmTxTLO0yG_@+J%X#Oe+)d4S4xa-PkzXlgF+3Q7OEfWj{1= z7Dfha5C|$F)7sTxjmXbj=MH+d3z8H=n*}I~9HO z*)Q35_0hdxC3&+i)%2>VgYXhRe+EUrz~JGn_W|?TkL{)OUy!`q9T&5LMeYkjlxLVI zX#*KOG*h~Bn^~3wT#K@eCE1-yF;?Iz#ba8i!yGJCSI&>7vTO=WPi_b;P2}^gz>&t1 zm5OK>tXJ4lQdv`Ie0|15uOd0yM>u6Z*aOOmO-fGl9rk*@&c#@%k2v|yX% znC;BDrP2aOM1XeC>1*DXMM*fZ-yZ~|Z8w?s=A)ffT~0h4CNPbW;uwDsllz+;H8~n< zgL6YUGrxxjS#?UWCrJJAa-W&uJ2i6forSBVaqwCX3$+w*HQ~&!;i6xvA8e(Hse%(R)AL3vNYMKP6oFOrUm4L z(w`fzd!Fdlf?_CTigv~G82YY#to1c9VzPC1L2O|P0Hm&K*v9r3MUYDns`tV$orn3( zB>MDww1wgX8V|m3*GpJ`9V=8fM0TN+TUq@b2Gswtcc1!Q)#X;%KT?sMOwQ1eZi}+l zp2UlTK;M$YjUdz4Bog}Yjl(N@L0}+L&^Y-Nky!2bN(ps;Nxi8z31b*%7*j9RA7p5n zU=9jUdIjO1pY->&e6EC3+JxYR2Osp@)?N1uI`Bnl5L49rc8HJ`cj0wSz4~l%(J7U$ zKT?=fP$r9kQb-7ILx!kFKei_Cc_@S!e(Z0(LMjol)!aJiuaM>Z{eyo%$BxD%ht_i` zEgCTwFgf}4G~8R^b2h+8gD#5(ov)M1Jt+%m!pX=tHs$n)$5R?Ep>7W);hSjO5fd15 ztaskchukS}Rj9AHca=!>p8?7p3p+q=Z&9hpQ9*3Y>M)%Y!tE!wZ>t6xuP^=s0=r-h zb$o%seC0$-f`wB=8^(v)H<&UAy%icU+2=3NMu`EygtWf}p(`sv z^rDS#ABj2qjeY~1y8{iLdSbkL24g!ye<_~z%0^*L8oOxMvM6=Ym3q*$qyOkn;$f^K zK+gVQOL$M`&RU^bb_6FiUM(Q>k6GsV$L=NLxjZV{q^guM26E5S1XX2m>BxIh(#7^3 zQ+`eR1#J_C>Q2yaE|f3RqHDR>FkdE}9mMhmNmG%IMLo6PF<3j$$ODIPh<%iW%O}0x z+HVL_f5*yDGS)EihB&0=EOC-BlJm&DZjpQA zG&1x{9u2uOXQMXqDKyU+!f9(W4IYjjzxTD6xWWsVVvK2zM4IEmMb#gC*;)h~T;#gLN4Kh}X zNflB)O$k1e+sJO{hc<;LNQtqiAIQVdwbm|LRi60k+IBUlifN#g^AG9PlKW({O_jFa zqz;-G5^ziQ&gY^%?b&rwu{b>^tUuRNh8!yh%hR#-Ov%Ve7s^r?SzWRByZ zueh2Bqco^TJm8WL{@C9|AK&>}GL$}3CXoTtW~A}}>NWo1LLH7XJJV$F;^>yXzu7@m zyD3pdrV!!wnYiCUCc&V}t_vKWWr~#TN7g6UkhIahcHSo&c)a=wyym?sv|eCymPst^H5xv#5xkxz+GAprk9 zXKT<`Q392Zvga)8Uwg$q<_hlaX)ys(9cP(DrXDqcU#Br&Eb+-!HC(Gi(8svTL$_3 zxu3}zTFCu^|{h$AwED*#dVf~7JvPHy0oQ*H!b(deLW z{!I)0JVdT#UOou3R=s+oU9dN7`bqEv$zr5MLVV9R*pxZ;Nk4E&iu-OvoiXaV{WD~H z=kK}I7VTg4Nyb;Y+nwT1Ld>JF-{|#tt0V{8qs}v{Yij?|r)N>)))?O!AQuXfxn>EH zGAT0A9@Hako%kALQX_aYpQeW(nN3e-cNlNm?d*SUF>4xhF}>kQq7G2(MK#82_V=#M zh|@_tVB>}AzgA|r!1sdhQgooaFW2j}?QYBueY|=KI0`$=R$E%xhQzn=u3_Kca2Htl z5KTu>+6Enq+!tP`8UtN!*U$N}Ewa-UM9$P8g`MT%o5ho$30Bkpkr*R7&H>PpY%2Zf zlhV=eIs`pxjB61#FxV%_ooQ{}5$#`VMsEwDHT0Sq*aA z9N%>d(CK1uXSQpwW_Dd?Cggh+l{+&ss2b!SyO$s=rC%{-EJqLrU-mJMA4jQ5xJB}3^&z0aID z4Je7)Y(gcngKWV7wz$^xS%5(rQ~^ZLosW=k&dl+n;^*zB07!liAmtl=(bsF%?|GdU zSfQ)2Q21h{M5JUjtTNc78UEY+2SzSY@bcn-3P0?u51kxGyEIkBp;=wL&R*rlHq$4k zaYTv77*!Qkc>SryzZ|3iM3znrb%fMQRC6J|4QG<4KZDp@-KfDY1-T~%%=2Q(al{X^ z`dz6jiw48#?MGn1gXjl%&0tL=`TByCCC}0A{f-P8rgg2HF(o91m57iNeQ9aVA}NDW zC=O8qeXiGvjxb_|r;Ptxj&?8YNadSg@zzWBd|^i2-5#w#)0SlqBwqRAT6n}cb=d%6 zG?R=#D;lTJ5D345N!LMqVLz1UFaPhDHCQJx(q{G1n@(_Aql$T7JC>=|@>b{iP2_53 zt%iQhq)z1pS$}^@CD`U09|^4p#j8W5 zqI0wrgj@9si}YcMbs)XqeuP~m$Dtza=%R9IZYc}S#VsO+I$@@KianXUY?Zh zw0AM0Zf)B z+N$tzG^@}vDm!=?So(CWB`Q#8Q_-6*FY~xqQQq>}^J;gr$8f`MG@tM-aV=`$s+9Ry6=|RT56OK-!9X3egTI!j}OP3k>c~hq$`%`PZBQkkjdkwe6foY{R6+d09*aH_s|Lk zb>(;hP3Go(`FQ5lCvB?LG7B{Blpc`iS}x7A!1|)F@M|)fx-;aW}^^B=bOjHufbH#1+9I; zPJZ9|{R9RhM<*|(clNW=$bRKS5^EoneONP38;S|MHHV~Fb4$jmzylo!Kfi(8u@r$-#c2O|`0fF%n zd1l0zMFt%!v-pBnigxg#Lf&#n@q`AR64JDFrP-+bdy8Uwi`Z2DL{$z22~uwOD_&QF9Nyjulk}%I-1Mi3tvHuXk{~Yqz8v#oSPu0!o{O^+sVKtjV zS+b<2L!tG8A^hE5Pe$DdEL$&h^I^k)O7mG)k!AN%I$ZHT zs4?arx}!|mlJESs$lKN<6cefYjPMh!1)fqAQ)!>eBQ{;Y2NTmqMu{|ozXaw;iA=x5 zQ$gLB41swshBPr1ZR;t{EuuOr{%(Om((=N)VD+4Ci?CdL3)tHdg zogp*JwubBoJ->bqseL{0=6#Nel0eruaaq$B8#bxJmtdSpz(-S%yD84Hoy>S?0$LgD z>|Lq(jOOm+SSLSh>B}O1GlSJqk!1a8_t%|=Uz=>RpdszmUEsB_ae0`t_LXpjdEhLI z^0vIF7^sdR)0Hv1;7Q>ZB)ZJj{us64Clgt8b5;z5&+89`(91kxl-w7bR?;n%5F8&V z{Ejb5>C3K*4;~7oD3JCndj&e>-3X6`nGKeHpJU@AWX3?J$`*weZSw^S5K^88&|e5M%on{Ga;<(>YLH3W)%GexB#+k4kYQbV;xbk`x1Ho zEFUoTKY3WJ&Zdh7i?UxZuC^~?XhVyUyJ`5ZT|hrmx@qSt6A-<09bwr3#355nBDQ7a zr4|RpT*Rae8W0B4q%yWFk#(SSjeIX|zES^!x{En(^OseMLoHJe9V;~)AiTjZp;yD{&_ zV1wzq@tOU!8nNXG0-yGk{5c_;a9pStc8Cg~b^@|^cQn6(`|^q_;lGvs)z{~tHSfQC zZxr686_v+H1o4uyhQihu`_wXM2$`P@iWMo^cq?QDXB$~)_bg1B~yR-DYXsx7-ZB^cmZK6K} ze}#SqM!QJCcMIiXa7ur~uLP$Q3$^APB04bB-5K;6w%9}4vk)yNSy?>E(-K{i zQjM$^>cQbWN}1}_*`OgP8{@&E3TB~hkvCx-@-qi`0aod1sP&!9oLUQgfRYSYabz^j zV$Sm?td;FFi{ASD2Ycm;XTY=OjQ^*@2Y<(rX$)(RX!tVMvN56^T3$su&kjbshoW)h z{$Z6>=TxYQoPYK-Rk59Ic`HvewcTk2Oy3Uy=dY&JBhxy3@L1~4N6vw1_y`pYfyJ+5 zTXBcJSNB*mxC2z|4(^OrYKgriYcK0&*o!{aKH%#0VgpAby7qvY9|&KL&1{{&>r_Cm zA)ji81KOa}mYDkTmfG`unTIcq@Ka95a{TcUPw?IbCLw0|7p7|d4v2%*cLenU+w7ETGvuQ-7%jdJ3Lj1Q5z!T2oOlR(w=IsyD~lV#=tg{)~=__DuaDT)snJ}zf{YL??6p!1mhkO4hb-DX0e1nT(&O* zLDB2}=@Q9h`kD7wnDt&|2bhoBKJX2j^8izy7}vDJxU4-n$-@lER8WlkeWlIBVf+M> zR*1WNlTNDmTp}Z?m~vkQo+fe#j}(%-llbkk8w+w^g%ZM0a-rfv2$UCA1OpU(#5I2_7??dlnqdx>BO0&BvxEvD?<9BCx$$$BF0niTW<}z~_ z)fk0t`D_GbTOq^iNnTdL4Cox5I5eGVFUlk&O%DpMd{h2vJ=wT-^frM_X)g&ss?@kn zJ=H2$S?SUw6kpu$oJ>c;&6?c+(Yz41Q0?i;}drY@s z<2^YO$Ks7ggBbP3X_TBEI~&7#Cu2wUZ?7v( z2m+ovN8jhtP|#_7anMeWhD&B0;xCzOIpnJBP#}q_(9Ie=7>8n3vp=>~3HB)=_Z1kt ze0lidDf8sLh06Cd%K>i5d?MWsOX!-5hcM2T<6EHX#49laI)`HMd~POUPX&WHae3J8 zyVD2cLs^i=wJEfP=CweA%QTgjmg0Uh)70NGO}1XiQ*6*8mW}^j*AtCSMz`uMnj-Q9 zQ66CYk;eZp+_K#%^5?p$yT&`=ZH*Nny>DXJr!08D_km7oKEobCh)bvv1eRLn`$UAl$!M0G?W!`C;O-&A-o(?do(L#~a(nXo zrBAu%5$#LFR1gc3sF+zX78iQ5I7Z&$m1=Ezh#zWgvjc^9DHuC@Ec&ovt zs#S=Gnx0kj-O6u{DPNU_68pKOwRWwpcBwguVJ&yM|l#UP0ZMvo{^~P(_?!R30YbJlOz)#kicqcZktbR zQW7?+$y}iWol2GqFGh-CDF3&$;?L=~@nd@DWr@F}{>N&NJ8P>lNkbNh%(nE{RU2t3 zAJ~VUTY|KzBIQ`On6?Ek;41ga5oYc(YW{`<&};C7JGVG>pm{QaB|(g8;P$g-pS;&} z{|c-vQKk~Ad&?R^9;ZLuwip_r`|-a#_lLVB!vyhpiH8`k&L{I5dzji|(9D(6C@YDl zJQR!|;@Xo}yOXjzEhvj-``e#VtzWLO?-)|i8H}<1!sRJaC%w5!#>ilG_*cCrg(bq` z`{SnN91M7he=8>lbNk*E50zFD9uxZRHt!F+W}AznSbX zIPxWU%v}u39Y80MmACJ^M5(_UuQ$}EfN)65#q#LCaO#oi)Y^C6-rElsg;m==UoWl7T$+g5?nV9G!>5=_!_$54}aKAtk&&9ro-a4o-6~ z1WmMA@!Vp&p8q_fRfJF)FO)kq2N@DvJEP_5hcT@=u0CJ;c(3@0#^S=vb>|)kN;OC_ zUD29qWIO>eae;Jsd+1;@T_J2~(Q-9s=75sMMN+4Y-5-=>xz5E@aG~dsjO`*B-aobi zFEl8Th^BrUPy9R?-U;ND8gEJ4B3X#c4cTUvXA#;xe0)t~nfwDVu(8|P2m|2%N?PMo z%TXS#5ADX;Xv+E#gDy(h{4cE1BP7!kB16z*1zn z$(ZJK(SUU8^z!WUQ4qz98q1rHsdieYv5I{OO>hc%5G;!HNmsvu9u^kOEFx|ZTrc05 zoKCkSuWCuC41!05A(~nuN!K0;OUP`PS=n(TcG2$cO{z-OzAk(=Hpa2#mSgo4w$09A zDPuQ$xCxcuqdEyW-hQ@cCN}(GGp6SE0fT)Dp^i{pb<70?D|(_Q8}Sw#xUY$enR-ra zy7i<`MTq!rjZ53aQ?;qSl^IM|R;#{4U#LQf+m`{180_x68IJUMH^u?5 z!PK~$h*y`~7WX{|@0qLbkc2F!R`%qCHgZ|YfYS+t-Mab)bw(HXf4hhIbun#QzK`$#Dv zpnp^TD-HXpA<`!XiDdB0hr-2^imn{h!VxFQD} z+Wq9rPcrP{aXl6GkPjGJ#ROMWC`}X@#k7|>@_%*`^fb6v90YL=rC&wlFh8l$az=?# zf!`eY37-^990D&&d@HkF4qlUtGH2!2MZ~zq#YvrQSH^29Srcg_v);Xj1}2!~X4wYw zQ4?({T^>a`cT3u%T1k@no`FuFAiGAsBA1RP-yhYkt+QjqZxJ}RxF(q(`WFSxOXOnB zXGPi*;DYvGwu>f<+H+7?)?`a zHdR+;#0X1tf3PuzZWoaNZWAp|uKBEds89%ez5FVvD)gZ5Dty_bJfHMUm~5^JK3a=; zX3j5{tp&Dm(~feh-D?Tkp3w7S^cuvjoeuFUaxXTC6W>G!PjLZboWhQmyX-Un}pr{T{4F3q_(3+&CnRt%i#zjKM zV+v~@FaC()JQtb6xRTOUM!xP5AQ7{q${QQY^2|F*cSiU4zo2zn)$MyNbm6ikxgFFs zb2n}5u)`S*7w@#0=iU=Wp>2hO*GxqCXP#0&3m1)!=vn{y-nX7pg55;nyq;!#ciSwa zBSd(~3j-0cgcahsD{|9NSQoAU0NTpi2DTrRVA7fk{JZ;Z3e>g?jQhC5S z{{BkSDo`@6(ZHRdy3hgz8g`HmaVl92m01Fe83s_xG*f=VZ>#cCgX<(=xkC3-ffebT z@%$@rB_tG<&wyGIb=NNU@5r1pxa^UU;Cu#EVGX>@qqUq9?Hk+x`1tJdsc&m;uoB8< z96k2jDWnBd>^I-&S{4v?TiWR5WJ{4LA~N9m5OXj#BK0^vLVd>LSPS}ara-)fu&`|K zNh&XNY@ZgvTK+0QNw1Ewioj+p%dj+sviHCnK`f3Y8lmZT7j@tC;>j?zIq}`aBzMT( z`0E!JV7>Y4Kz{giNizf@ac*~^s0Tl?x7D>SsCsc%PX zZP}rBO}9FkaMg$=0e}%cOYCg(FAw z7VZnGO=19GPmy!0^Mq0hbs4XozrdAdkwjz4c3DabZSi50DOkxZw$l#f3P}^h2pB$v zh5SNN(g?lXWC&lKJTjF%*Hokk4$*dYrsf>AfjBZ2a9H~(->$)G zbT1seMF=u(FdhMYXO5ZjUNLI^_QiOn4Kf%WGg)=znP2kM5~*!>6X6$=s;^f!vO2_! z86tJ9CXBHuifjEqfq!LyMSNqpox|geN@G91K$cq27j5*Varm1~=|L&Oy_&^vuKAiO1ch3S1C^FLU4ium1)k$Em4qFN{nC}#A> zAU8#8!@S6-Ws(c)z6h`!RwQ>>ZK1wsrl>Ldty-i*1NV;(V!XUlCk5pfy=)DGqX|?w zVEm8#AQ^U1C4@?1NTaedkfPyE92?ptocp`hD}1QVCihe|iD(ejMU1s!G^U(sDB*0H z@+-7wyYFMsR*Sr^IZp-ObNH0i(iyROhp3BpiG9D0t#L5HUiqGp3HgGX&46cW8z|aN zV7H$&-sftehGTJ_DSUc~swsUtoK|nOeF{)8OJs}YR*4{vOpQu;de_;`Kq9yVddVV> zPVN>uqIq%g;NcB-aRo~(VD!H`u+YOQ_Fd|~&YXrMrEec|n#m9Q36b^N12HfXuyAi} zsVH)_=3Bc5lO9$H$BQMBd;~C)doUli>bhmv%?&Rij`U!YqZ3QSnE9}qt*7{_E)gt* z3ec;?$DvprX9xew3vNji&nM$0nnU~jZ6?a)^NMBWsu4KM_Zda&p`1l@c~gH98+z)F zIx!LCzsM$dn0p#%T$Fc~H7z0R)g-o2*hymkmS~b@kr=K~L#BMyKlr!_3me~7+`954 z2kxb5xzk<;8*}`9#A;vyY_%=a-66`Fw>H4_@H9FmvMB+xW##QvQVge7K^EP=x7Jjp zlBHD#+iHYmZQ+#`)L7bH-@l^$BZKbJU`>AtbCdM44Vn zRiLFxmq9B~22{hf!jU)|voeR!i(@yG5k?Wz!Vprce#t1y8LU2)8?_Y2P zhTU-5bAx9j|>UqGFU4l9v{)^dZ^p~VZxl_ z?=Wb)85sB9cRHBFQ}7#gCD?5ebgE+9HT0DJvX_BUgcNr8*h~rcr4&xtLGZUteuy8K ziK&|A%r=2ctkA0HieUk)dcQmMDlHKP5F|d)LkzFTpA#Eb49?p>NYwR}Ey!gHY`^I} z!1m__%3xf3a=!+^Aj+~NvmNpW$()nrG2|^0!{bP_aKBaYZq7NlpvI2P?M}~D_7+pz zAT!Ek+NeZCA8^s{xMR((j$EDZfXX==35cQi+E7ndL?jjvMcs znS>E#-riQ$EUwDdYV*j5r&0OM}-}SLavD2gJs1hx3uL+q`+d`UJ$RV3zVTIE z6xhfAWnQW{d(E$#UpSB*WER%kDZ+igU(Qo4$F0LU}|;8`O6Jnni?I1*^M}!>5$Bp72 zKAO>64H!9_Ce~fDRv?p^5<8p4$Bk_bizw22Xv-LbK6nPD zOJw48x-&G84ce`&-;@J407u+nI1NW4pxGy)OI#K7cxw?f6)b1Z6)J_Xf*OG4^ZnWU z+<60WNCzBcwh$Lo zcT=}LRrixzhXjIU9e^1x{54%Iqd zv`rb4T+)~DYM_P7!siVoc?-rKsy(Mfafj^&RLee@Ni$?O;#P=PCH%_l%Yj$b?BCc& za&Y(^Hge$qqWSq~^s|ATJG%Se6iTA^>3yGc)|_?_6?$QCn}B1rC)EfsRdsZsR28DU zm|x(TU+kRi6)BPUDWkyz(c8e|;Jm!PqZg4f*iurz6}BH2W2H?bF?*+2%SLpuLu6~& zQ_sbSg+QEv)Dq$dcgOmuj_X_j5#q@}%ZAro%;;AyG`L}2+Z@5A%(UAM z)o?j)R2qbV5ybJasTjq};w948HXM?$YSZk2Pil*G0#YA?ux6XdboC-7af5+oh!b|k zEi{!t)oG<6Mo<@@}E%q0W4{}aM!hy$c{J%b5uqqH%2tB<8z*th~YCxMTOu-OG z4Ya()m+vgK&`SsoX2`yv4i#AwRra7x4*0dE?4LNT(JJMb258qm@r(3s><6}IOf6&aWE_lIrU zlu+to&eCKlf`g1*qZ(CpNTKZIyTscwT?jn@x&W9VB6^d^Fi4kUS(@`fo&v8RYvkw^ z4dP0uM+~L0iW$Y~i>A`J>i3N0<@ybd2>WeQSGO-ZIrs$W`8PrgmOeyZYwa?A*~T_| zPsbC>Y!9)AhlEgZ#KMFkQIHTfvLA!p4sJ^srMv8<8v6CMI{5$b{~ ztIzkgW4_)62H&w^g{X3{RD)U?(`NeDMJTbIp$)<@*=e#=15eRMSmd;7de zt!zA!TpiyVj^2kqHbDdHvpmW1W+WNs4&-TWOSTDAz&Tr~{80cpqIqn;re5Jf%~KaG zg?gtb1lDbP&(>NkFfh@KDD74^2Cw+H{X_Zjwr$IimvqH$?n$f+$aVb^t2-eRt+@0P z+_{ocOL-Cg4|hO_zYwjY#cIxVns0K>VWDNixs%K9@)B5B7j@H-bm8Suyqa}Jt1p3u0Fxc5R0vcs?nbZP3zJq_JaxmLpGq;X6fVcA_Y91P(u!hF7(UV1 zesqihgFN9nQOi!ugEd!_Q{QFQw*$ZZt-&-a+XW^7rIy()Hv2xAZ)*TmYI#W-O1 zfTUE!@*ba0>*|NSpM&f3Xyhw{-3Lz(R-z#wl~xEnwwXz92z-$ zFPZ@bTIgmp?~X{s^UK}=TYjC<<{}=*w84f%ZP_F$mzc@rUF807amxc+MC^fzw_Wps z7l?bk*;q&1WCf0QQz6~;26p68E3SfGSSW|RxE>F;$@zit++Z4bJl=3!4-oUe+#>&e9=fB!7bY`Amcu?`baKp0j3&}#_EPv8LK0eHj5PHg zJiw~hv4cLG)WU*AL4z}01d-H1gu%vC7B*M>!CtDy zGLnm>!dvBa@ORVcT7>_G*z|dYB}WzYgsA+dM8P z8xp0uAs7<*q(>_=V&dd05sGYzvO$G4Pmg_IvJkto3dm zoTe+BVB0NbQY7c46A}+0+w(EpMhJERB|FHWKVnWeh}oKlF|43N6l-tj_8>?mjOi>_ zV(=K)>Qn6;mg}`wvf;=lI{V(PJ7V^x0GP}^9g9QK4-6*k#aPd$yU_aux5a%7-F2P` z*L7ix3E6_ZE%|wl=|Wt`uOJ{6Cv zwz5eikRb?Lu(vUyg#;qY;IcU|nE~CFL=87v@Jal-F3h0mi|sD2#~a{3o62{*zkdg> z6MhEJCTGUdZGayS41{UJhSK)eXJGP$IqW%G>uJ->wgM7Gai~pYb9fO`-#_vIv0}?R zmJD$2P1#v>Wi3M5TCI%Skp$E>Y;VbA zrCI`VX8U_%kT=GZcU=t%ASf;^{>okC{^}u8B6`kiN_wg(gW8*EFoe{F>r6{xae98s zcuOdX@F4_(@Y4O$0sE9`v!w1sLBRab-6PecA_xCm!G4z+*V0)MJ9!ps6tco&#G1>wVc|$rrBq3$A(L zNtPyzSxtpFBQ}06yBG$@of}jMvh730V;Fga;{yyUblRZlm?i~QWUkA|3}Zsp2FnvP z2Oe(^fRUZLDiWRrm0sz&pMWet4K6cw?=#6MrxFb9vd7p}orj|YS{CKDin=X&}++=}6x6N4{@Nj(M&gm3uP z^34>_webGF>~lNZ+f|mql5^tX305n7ven!*27@O%;-H4AEPIcL3=vUPY>53{9G_!x z=#g`etZGfq_Dg+4Od80|C6GI8aT3oMz$E*O$}TAY0vTby4Ons-8pBxDV=(rDf8MkZ zpSGVh7*!jBq^&`3!8)0KA|Q>#arO6K+*`6pa^rpsG4<-NqGz>lfZ~#%#E?h zY5HvBG+)ocQ6SQJ@8tejHEyaXEhv`dpAr!jWj6DY^q?5{L&kW@)7W~R#M|o~Io#P6 zapyGFKusdgtINfGEr-j8vI^osQfSL+gD|)2V*vVL4$?dsZ*On-n?L<6-rjxzc);bB z2B*;g^97XwQo>#f&-DY#U2}L&z%Mh%b_WCiLvxC=j6DmHWxec!OzernQDp4$vz-%x z$5l`!0rN7LOC9sS9+$I43-aRmz%}2TO8mt0xiKzrSa0Cl^{~lkT{ek@SErbOU(?0G z(rJkZ^0fC6V9d#QqhByCn_NXVwrl{5F(#O1Mil8r{#+O~Wlo;HdUzUx^1*n#jVwf> z!28-Z**U~(EXEDY%gh`|ZF2SwpV=CO^?YJacYP1|bU%H+IE~%Pp@g#CCRCvF9U{vh zt}$?3Z=f;3B6u!#i1f1WCB_Q0$!UTwV^HcYSec0NHl|Gq{(Y8gED^916i9vN8G*xN z*o6&P6DB*~pV<2u3v=0&1%PQm zb`+}X`P{NM6{XQ5ZCEq9V*6!Q?4X)>g8UPmnO$7ott%bOGRikoPnKCbJh=UI(u|^C z%$upWUq(INo~Rq~7mD|%VCxeC!5kBBZ-2r!VqA}hbyjMd80HCax-fyT*T7s1QQPO4 zmW8mEU~L7M!H)qRl-;x4Q!#}Yq(vCmqS(u{drSfz6W5&H)rqrIH$*oc*Gz-fBJ2

4K?ZLD4iyPxKk|7_ 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 diff --git a/simulator/kruxsim/devices.py b/simulator/kruxsim/devices.py index 2ece5d057..cbbbdeac8 100644 --- a/simulator/kruxsim/devices.py +++ b/simulator/kruxsim/devices.py @@ -33,7 +33,7 @@ AMIGO_IPS: (480, 768), AMIGO_TFT: (480, 768), PC: (480, 640), - DOCK: (440, 800), + DOCK: (440, 820), } From ae36e2b46e4b620a44d73ea56975511fa7908cac Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 28 Sep 2023 12:37:54 -0300 Subject: [PATCH 029/114] no more screen blinks on screensaver --- src/krux/context.py | 12 ++++-------- src/krux/display.py | 22 ++++++++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/krux/context.py b/src/krux/context.py index 86f5fa8bb..3ebcc36cf 100644 --- a/src/krux/context.py +++ b/src/krux/context.py @@ -67,8 +67,7 @@ def clear(self): def screensaver(self): """Displays a screensaver until user input""" - anim_curr_text = "" - anim_frame = 1 + anim_frame = 0 screensaver_time = 0 fg_color = theme.fg_color @@ -81,15 +80,12 @@ def screensaver(self): screensaver_time = time.ticks_ms() # show animation on the screeen - if anim_frame <= len(self.logo): - anim_curr_text = self.logo[0:anim_frame] - self.display.draw_hcentered_text_with_full_bg( - anim_curr_text, color=fg_color, bg_color=bg_color - ) + if anim_frame < len(self.logo): + self.display.draw_hcentered_text_with_bg(self.logo[anim_frame], anim_frame, fg_color, bg_color) anim_frame = anim_frame + 1 if anim_frame > len(self.logo) * 1.4: - anim_frame = 1 + anim_frame = 0 bg_color, fg_color = fg_color, bg_color if self.input.wait_for_press(block=False) is not None: diff --git a/src/krux/display.py b/src/krux/display.py index 312fc0b7a..fba5ba200 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -303,22 +303,28 @@ def draw_hcentered_text( lines = text if isinstance(text, list) else self.to_lines(text) for i, line in enumerate(lines): if len(line) > 0: - offset_x = (self.width() - self.font_width * len(line)) // 2 - offset_x = max(0, offset_x) + offset_x = self._obtain_hcentered_offset(line) self.draw_string( offset_x, offset_y + (i * self.font_height), line, color, bg_color ) - def draw_hcentered_text_with_full_bg( + def _obtain_hcentered_offset(self, line_str): + """Return the offset_x to the horizontally-centered line_str""" + return max(0, (self.width() - self.font_width * len(line_str)) // 2) + + def draw_hcentered_text_with_bg( self, - text, + line_str, + qtd_offset_y, color=theme.fg_color, bg_color=theme.bg_color, ): - """Draws text with full screen bg_color on the display""" - lines = text if isinstance(text, list) else self.to_lines(text) - lcd.fill_rectangle(0, 0, self.width(), len(lines) * self.font_height, bg_color) - self.draw_hcentered_text(lines, 0, color, bg_color) + """Draw a line_str horizontally-centered on the display, at qtd_offset_y times font_height, useful for screensaver""" + lcd.fill_rectangle(0, qtd_offset_y * self.font_height, self.width(), self.font_height, bg_color) + offset_x = self._obtain_hcentered_offset(line_str) + self.draw_string( + offset_x, (qtd_offset_y * self.font_height), line_str, color, bg_color + ) def draw_centered_text(self, text, color=theme.fg_color, bg_color=theme.bg_color): """Draws text horizontally and vertically centered on the display""" From 836ca00e544678cd9f29a59585d81f267ce98b52 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 28 Sep 2023 12:41:18 -0300 Subject: [PATCH 030/114] black --- src/krux/context.py | 4 +++- src/krux/display.py | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/krux/context.py b/src/krux/context.py index 3ebcc36cf..af6fe07d9 100644 --- a/src/krux/context.py +++ b/src/krux/context.py @@ -81,7 +81,9 @@ def screensaver(self): # show animation on the screeen if anim_frame < len(self.logo): - self.display.draw_hcentered_text_with_bg(self.logo[anim_frame], anim_frame, fg_color, bg_color) + self.display.draw_hcentered_text_with_bg( + self.logo[anim_frame], anim_frame, fg_color, bg_color + ) anim_frame = anim_frame + 1 if anim_frame > len(self.logo) * 1.4: diff --git a/src/krux/display.py b/src/krux/display.py index fba5ba200..170da00f6 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -320,7 +320,9 @@ def draw_hcentered_text_with_bg( bg_color=theme.bg_color, ): """Draw a line_str horizontally-centered on the display, at qtd_offset_y times font_height, useful for screensaver""" - lcd.fill_rectangle(0, qtd_offset_y * self.font_height, self.width(), self.font_height, bg_color) + lcd.fill_rectangle( + 0, qtd_offset_y * self.font_height, self.width(), self.font_height, bg_color + ) offset_x = self._obtain_hcentered_offset(line_str) self.draw_string( offset_x, (qtd_offset_y * self.font_height), line_str, color, bg_color From 5958a52c1e6c3d5219effd907856acb548a62dd9 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 28 Sep 2023 14:14:01 -0300 Subject: [PATCH 031/114] screensaver settings --- src/krux/input.py | 7 ++++--- src/krux/krux_settings.py | 15 +++++++++++++++ tests/pages/test_login.py | 5 ++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/krux/input.py b/src/krux/input.py index 618ec6bea..5af30d561 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -25,6 +25,7 @@ from fpioa_manager import fm from .wdt import wdt from .touch import Touch +from .krux_settings import Settings BUTTON_ENTER = 0 BUTTON_PAGE = 1 @@ -42,8 +43,6 @@ RELEASED = 1 BUTTON_WAIT_PRESS_DELAY = 10 -SCREENSAVER_IDLE_TIME = 5000 - class Input: """Input is a singleton interface for interacting with the device's buttons""" @@ -185,7 +184,7 @@ def wait_for_press( and enable_screensaver and not self.screensaver_active and self.screensaver_fallback - and self.screensaver_time + SCREENSAVER_IDLE_TIME < time.ticks_ms() + and self.screensaver_time + (Settings().screensaver.time * 60000) < time.ticks_ms() ): self.screensaver_active = True self.screensaver_fallback() @@ -201,6 +200,8 @@ def wait_for_button(self, block=True, enable_screensaver=False): """ self.wait_for_release() + if Settings().screensaver.time == 0: + enable_screensaver = False btn = self.wait_for_press(block, enable_screensaver=enable_screensaver) if btn == BUTTON_ENTER: diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index 10ea25fa3..78350e916 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -334,6 +334,19 @@ def label(self, attr): }[attr] +class ScreensaverSettings(SettingsNamespace): + """Screensaver settings""" + + namespace = "settings.screensaver" + time = NumberSetting(int, "time", 5, [0, 30]) + + def label(self, attr): + """Returns a label for UI when given a setting name or namespace""" + return { + "time": t("Wait time"), + }[attr] + + class Settings(SettingsNamespace): """The top-level settings namespace under which other namespaces reside""" @@ -347,6 +360,7 @@ def __init__(self): self.printer = PrinterSettings() self.persist = PersistSettings() self.appearance = ThemeSettings() + self.screensaver = ScreensaverSettings() if board.config["type"].startswith("amigo"): self.touch = TouchSettings() if board.config["type"] == "dock": @@ -362,6 +376,7 @@ def label(self, attr): "persist": t("Persist"), "printer": t("Printer"), "appearance": t("Theme"), + "screensaver": t("Screensaver") } if board.config["type"].startswith("amigo"): main_menu["touchscreen"] = t("Touchscreen") diff --git a/tests/pages/test_login.py b/tests/pages/test_login.py index 49530d8da..cb04a7e00 100644 --- a/tests/pages/test_login.py +++ b/tests/pages/test_login.py @@ -1671,6 +1671,7 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): # Leave Settings BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, ), [ @@ -1715,6 +1716,7 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): BUTTON_PAGE, BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, ), [ @@ -1772,6 +1774,7 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): # Leave Settings BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, ), [ @@ -1820,7 +1823,7 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): LOCALE_INDEX = 2 LOGGING_INDEX = 3 PRINTER_INDEX = 5 - LEAVE_INDEX = 8 + LEAVE_INDEX = 9 cases = [ ( From 13ada9d59dc9537a82ccaa1487b0b22ac0dad83f Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 28 Sep 2023 14:16:12 -0300 Subject: [PATCH 032/114] =?UTF-8?q?tradu=C3=A7=C3=B5es=20screensaver?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- i18n/translations/de-DE.json | 2 + i18n/translations/es-MX.json | 2 + i18n/translations/fr-FR.json | 2 + i18n/translations/nl-NL.json | 2 + i18n/translations/pt-BR.json | 2 + i18n/translations/vi-VN.json | 2 + src/krux/input.py | 4 +- src/krux/krux_settings.py | 2 +- src/krux/translations.py | 2320 +++++++++++++++++----------------- 9 files changed, 1182 insertions(+), 1156 deletions(-) diff --git a/i18n/translations/de-DE.json b/i18n/translations/de-DE.json index e9eb5cb5b..be524f446 100644 --- a/i18n/translations/de-DE.json +++ b/i18n/translations/de-DE.json @@ -187,6 +187,7 @@ "Scan Key QR code": "Schlüssel QR-Code scannen", "Scanning words 1-12 again": "Wörter 1-12 erneut scannen", "Scanning words 13-24": "Wörter 13-24 scannen", + "Screensaver": "Bildschirmschoner", "SeedQR": "SeedQR", "Self-transfer or Change (%d): ": "Selbstübertragung oder Change (%d): ", "Settings": "Einstellungen", @@ -230,6 +231,7 @@ "Via D6": "Via D6", "Via Manual Input": "Via manueller Eingabe", "Wait for the capture": "Warte auf die Erfassung", + "Wait time": "Wartezeit", "Wallet Descriptor": "Wallet-Deskriptor", "Wallet output descriptor": "Wallet Ausgabedeskriptor", "Wallet output descriptor loaded!": "Wallet Ausgabedeskriptor geladen!", diff --git a/i18n/translations/es-MX.json b/i18n/translations/es-MX.json index 281ae6634..9c830b2c1 100644 --- a/i18n/translations/es-MX.json +++ b/i18n/translations/es-MX.json @@ -187,6 +187,7 @@ "Scan Key QR code": "Escanear el código QR", "Scanning words 1-12 again": "Escaneo de palabras 1-12 de nuevo", "Scanning words 13-24": "Escaneo de palabras 13-24", + "Screensaver": "Protector de pantalla", "SeedQR": "Seedqr", "Self-transfer or Change (%d): ": "Autotransferencia o Cambio (%d): ", "Settings": "Ajustes", @@ -230,6 +231,7 @@ "Via D6": "Via D6", "Via Manual Input": "Mediante entrada manual", "Wait for the capture": "Espera la captura", + "Wait time": "Tiempo de espera", "Wallet Descriptor": "Descriptor de Cartera", "Wallet output descriptor": "Descriptor de salida de billetera", "Wallet output descriptor loaded!": "¡Se ha cargado el descriptor de salida de la cartera!", diff --git a/i18n/translations/fr-FR.json b/i18n/translations/fr-FR.json index 7edb57d51..093c12545 100644 --- a/i18n/translations/fr-FR.json +++ b/i18n/translations/fr-FR.json @@ -187,6 +187,7 @@ "Scan Key QR code": "Scanner le code QR de la clé", "Scanning words 1-12 again": "Analyser à nouveau les mots 1 à 12", "Scanning words 13-24": "Analyser les mots 13 à 24", + "Screensaver": "Économiseur d'écran", "SeedQR": "Seedqr", "Self-transfer or Change (%d): ": "Auto-transfert ou changement (%d): ", "Settings": "Paramètres", @@ -230,6 +231,7 @@ "Via D6": "Via D6", "Via Manual Input": "Par saisie manuelle", "Wait for the capture": "Attendez la capture", + "Wait time": "Temps d'attente", "Wallet Descriptor": "Descripteur de Portefeuille", "Wallet output descriptor": "Descripteur de sortie du portefeuille", "Wallet output descriptor loaded!": "Descripteur de sortie du portefeuille chargé!", diff --git a/i18n/translations/nl-NL.json b/i18n/translations/nl-NL.json index b3211947a..0b2ac09e9 100644 --- a/i18n/translations/nl-NL.json +++ b/i18n/translations/nl-NL.json @@ -187,6 +187,7 @@ "Scan Key QR code": "QR code sleutel scannen", "Scanning words 1-12 again": "Woorden 1 t/m 12 opnieuw scannen", "Scanning words 13-24": "Woorden 13 t/m 24 scannen", + "Screensaver": "Screensaver", "SeedQR": "SeedQR", "Self-transfer or Change (%d): ": "Zelf overschrijving of wisselgeld (%d): ", "Settings": "Instellingen", @@ -230,6 +231,7 @@ "Via D6": "Via D6", "Via Manual Input": "Via handmatige invoer", "Wait for the capture": "Wacht op opname", + "Wait time": "Wacht tijd", "Wallet Descriptor": "Descriptor", "Wallet output descriptor": "Portemonnee descriptor", "Wallet output descriptor loaded!": "Portemonnee descriptor geladen!", diff --git a/i18n/translations/pt-BR.json b/i18n/translations/pt-BR.json index 6154a6d7a..485fd041f 100644 --- a/i18n/translations/pt-BR.json +++ b/i18n/translations/pt-BR.json @@ -187,6 +187,7 @@ "Scan Key QR code": "Escanear código QR da chave", "Scanning words 1-12 again": "Escaneando as palavras 1-12 novamente", "Scanning words 13-24": "Escaneando as palavras 13-24", + "Screensaver": "Protetor de tela", "SeedQR": "SeedQR", "Self-transfer or Change (%d): ": "Autotransferência ou Troco (%d): ", "Settings": "Configurações", @@ -230,6 +231,7 @@ "Via D6": "Via D6", "Via Manual Input": "Por entrada manual", "Wait for the capture": "Aguarde a captura", + "Wait time": "Tempo de espera", "Wallet Descriptor": "Descritor de Carteira", "Wallet output descriptor": "Descritor da carteira", "Wallet output descriptor loaded!": "Descritor de saída da carteira carregado!", diff --git a/i18n/translations/vi-VN.json b/i18n/translations/vi-VN.json index d88820240..502a75496 100644 --- a/i18n/translations/vi-VN.json +++ b/i18n/translations/vi-VN.json @@ -187,6 +187,7 @@ "Scan Key QR code": "Quét mã QR khóa", "Scanning words 1-12 again": "Quét lại từ 1-12", "Scanning words 13-24": "Quét từ 13-24", + "Screensaver": "Bảo vệ màn hình", "SeedQR": "SEEDQR", "Self-transfer or Change (%d): ": "Tự chuyển nhượng hoặc Thay đổi (%d): ", "Settings": "Cài đặt", @@ -230,6 +231,7 @@ "Via D6": "Qua D6", "Via Manual Input": "Thông qua đầu vào thủ công", "Wait for the capture": "Chờ bắt", + "Wait time": "Thời gian chờ đợi", "Wallet Descriptor": "Trình mô tả ví", "Wallet output descriptor": "Ví đầu ra mô tả", "Wallet output descriptor loaded!": "Đã tải bộ mô tả đầu ra của ví!", diff --git a/src/krux/input.py b/src/krux/input.py index 5af30d561..9a4b5c480 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -44,6 +44,7 @@ BUTTON_WAIT_PRESS_DELAY = 10 + class Input: """Input is a singleton interface for interacting with the device's buttons""" @@ -184,7 +185,8 @@ def wait_for_press( and enable_screensaver and not self.screensaver_active and self.screensaver_fallback - and self.screensaver_time + (Settings().screensaver.time * 60000) < time.ticks_ms() + and self.screensaver_time + (Settings().screensaver.time * 60000) + < time.ticks_ms() ): self.screensaver_active = True self.screensaver_fallback() diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index 78350e916..b89bda44e 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -376,7 +376,7 @@ def label(self, attr): "persist": t("Persist"), "printer": t("Printer"), "appearance": t("Theme"), - "screensaver": t("Screensaver") + "screensaver": t("Screensaver"), } if board.config["type"].startswith("amigo"): main_menu["touchscreen"] = t("Touchscreen") diff --git a/src/krux/translations.py b/src/krux/translations.py index df72c8451..07410d7c8 100644 --- a/src/krux/translations.py +++ b/src/krux/translations.py @@ -21,249 +21,251 @@ # THE SOFTWARE. # pylint: disable=C0301 translation_table = { - "pt-BR": { - 1185266064: "%d da %d multisig", - 2004520398: "%d. Troco: \n\n%s\n\n", - 3862364126: "%d. Autotransferência: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n é um endereço de troco válido!", - 3921290840: "%s\n\né um endereço de recepção válido!", - 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", - 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", + "de-DE": { + 1185266064: "%d von %d Multisig", + 2004520398: "%d. Change: \n\n%s\n\n", + 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", + 3264377309: "%d. Ausgaben: \n\n%s\n\n", + 2399232215: "%s\n\nist eine gültige Change Adresse!", + 3921290840: "%s\n\nist eine gültige Empfangsadresse!", + 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", + 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", 3348584292: "(Experimental)", - 2739590230: "12 palavras", - 1310058127: "24 palavras", + 2739590230: "12 Wörter", + 1310058127: "24 Wörter", 2743272264: "ABC", - 1949634023: "Sobre", + 1949634023: "Über", 1517128857: "Adafruit", - 3270727197: "Endereço", - 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", - 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", - 88746165: "Antirreflexo desativado", - 1521033296: "Antirreflexo ativado", - 1056821534: "Tem certeza?", - 3247612282: "Mnemônico BIP39", - 3455872521: "Voltar", - 2541860807: "Backing up bootloader..\n\n%d%%", - 2256777600: "Assinatura Inválida", + 3270727197: "Adresse", + 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", + 283202181: "Richte Kamera und Tiny Seed korrekt aus.", + 88746165: "Blendschutz deaktiviert", + 1521033296: "Blendschutz aktiviert", + 1056821534: "Bist Du sicher?", + 3247612282: "BIP39 Mnemonic", + 3455872521: "Zurück", + 2541860807: "Bootloader wird gesichert..\n\n%d%%", + 2256777600: "Ungültige Signatur", 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Borda", + 928727036: "Randpolsterung", 213030954: "CNC", - 1207696150: "Troco", - 3126552510: "Endereços de Troco", - 1583186953: "Mudar o tema e reiniciar?", - 2697733395: "Mudanças salvas no cartão SD!", - 388908871: "Alterações só durarão até o desligamento.", - 3442025874: "Verifique o cartão SD", - 3119547911: "Verificar se este endereço pertence a carteira?", - 2856261511: "Endereço de troco %d não corresponde.", - 2788541416: "Endereço de recebimento %d não corresponde.", - 2446472910: "Verificando correspondência do endereço de troco %d ..", - 2470115694: "Verificando o cartão SD..", - 3655273987: "Verificando correspondência do endereço de recebimento %d ..", - 2407028014: "SeedQR Compacto", - 4041895036: "Continuar?", - 4094072796: "Gerar Código QR", - 167798282: "Gerar código QR do texto?", - 2767642191: "Criado: ", - 3513215254: "Código QR Customizado", - 124617190: "Profundidade de Corte", - 597912140: "Método de Corte", - 2504034831: "Decimal", - 2751113454: "Descriptografar?", - 1016609898: "Excluir Arquivo?", - 1364509700: "Excluir Mnemônico", - 4102535566: "Profundidade da Passagem", - 2791699253: "Derivação: %s", - 1230133196: "Armazenamento flash do dispositivo não detectado.", - 3836852788: "Feito?", + 1207696150: "Change Adresse", + 3126552510: "Change Adressen", + 1583186953: "Thema ändern und neu starten?", + 2697733395: "Änderungen auf SD-Karte gespeichert!", + 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", + 3442025874: "Prüfe SD-Karte", + 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", + 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", + 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", + 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", + 2470115694: "Suche nach SD-Karte..", + 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", + 2407028014: "Kompakt SeedQR", + 4041895036: "Weiter?", + 4094072796: "Erstelle QR-Code", + 167798282: "QR-Code aus Text erzeugen?", + 2767642191: "Erstellt:", + 3513215254: "Benutzerdefinierte QR-Code", + 124617190: "Schnitttiefe", + 597912140: "Cut-Methode", + 2504034831: "Dezimal", + 2751113454: "Entschlüsseln?", + 1016609898: "Datei löschen?", + 1364509700: "Mnemonic löschen", + 4102535566: "Tiefe pro Durchgang", + 2791699253: "Ableitung: %s", + 1230133196: "Geräte-Flash-Speicher nicht erkannt.", + 3836852788: "Fertig?", 382368239: "Driver", - 3978947916: "Codificador", - 4090746898: "Debounce do Encoder", - 374684711: "Criptografar Mnemônico", - 1244124409: "Código QR Criptografado", - 2968548114: "Mnemonic criptografado não foi armazenado", - 3315319371: "Mnemônico criptografado foi armazenado com ID:", - 350279787: "Criptografia", - 2601598799: "Modo de Criptografia", - 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", - 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", - 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", - 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", - 784361051: "Erro:\n%s", + 3978947916: "Encoder", + 4090746898: "Encoder-Entprellung", + 374684711: "Verschlüssel Mnemonic", + 1244124409: "Verschlüsselter QR-Code", + 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", + 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", + 350279787: "Verschlüsselung", + 2601598799: "Verschlüsselungsmodus", + 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", + 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", + 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", + 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", + 784361051: "Fehler:\n%s", 1505332462: "Esc", - 3838465623: "Explorar arquivos?", - 4170881190: "Exportando para o cartão SD..", - 1711312434: "Chave Pública Estendida", - 383371114: "Falhou em descriptografar", - 3048830188: "Falhou ao carregar PSBT", - 4192663412: "Falhou ao carregar endereço", - 1996021743: "Falha ao carregar a chave", - 1108715658: "Falhou ao carregar mensagem", - 1081425878: "Falhou ao carregar mnemônico", - 928667220: "Falha ao carregar o descritor de saída", - 1620572516: "Falha ao carregar a senha", - 2946146830: "Falhou ao armazenar mnemônico", - 1303554751: "Taxa: ", - 104500973: "Taxa de Alimentação", - 3313339187: "Nome do arquivo", - 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", - 3737729752: "Impressão digital: %s", - 2542772894: "Firmware excede o tamanho máximo: %d", - 1406590538: "Diâmetro da Fresa", - 3086093110: "Livre: ", - 1893243331: "Do Armazenamento", + 3838465623: "Dateien durchsuchen?", + 4170881190: "Auf SD-Karte exportieren..", + 1711312434: "Öffentlicher Schlüssel", + 383371114: "Entschlüsselung fehlgeschlagen", + 3048830188: "PSBT konnte nicht geladen werden", + 4192663412: "Adresse konnte nicht geladen werden", + 1996021743: "Schlüssel konnte nicht geladen werden", + 1108715658: "Nachricht konnte nicht geladen werden", + 1081425878: "Mnemonic konnte nicht geladen werden", + 928667220: "Ausgabedeskriptor konnte nicht geladen werden", + 1620572516: "Passphrase konnte nicht geladen werden", + 2946146830: "Mnemonic konnte nicht gespeichert werden", + 1303554751: "Gebühr: ", + 104500973: "Vorschubgeschwindigkeit", + 3313339187: "Dateiname", + 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", + 3737729752: "Fingerabdruck: %s", + 2542772894: "Die Firmware übersteigt die maximale Größe: %d", + 1406590538: "Flötendurchmesser", + 3086093110: "Frei: ", + 1893243331: "Vom Speicher", 4120536442: "GRBL", - 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", - 602716148: "Ir", - 831562513: "Intervalo de Aquecimento", - 2300171403: "Tempo de Aquecimento", - 3580020863: "Chave pública hexadecimal", - 2691246967: "Hexadecimal", - 2736309107: "Id já existe\n", - 631342955: "Entradas (%d): ", - 2585599782: "Endereço inválido", - 2874529150: "Bootloader inválido", - 4093416954: "Comprimento de mnemônico inválido", - 1422874211: "Chave pública inválida", - 2443867979: "Carteira inválida:\n%s", - 4122897393: "Invertido", - 3000888649: "Chave", - 2686333978: "Chave:", - 4123798664: "Krux\n\n\nVersão\n%s", - 3835918229: "Teste de impressão de QR krux", - 766317539: "Língua", - 972436696: "Atraso de Linha", - 3596093890: "Linha: ", - 2820726296: "Carregar Mnemônico", - 879727077: "Carregar do cartão SD?", - 669106195: "Carregar um?", - 3330705289: "Carregar?", - 2596531078: "Carregando Câmera..", - 596389387: "Carregando endereço de troco %d..", - 336702608: "Carregando impressora..", - 2538883522: "Carregando endereço de recebimento %d..", - 3159494909: "Carregando..", - 1177338798: "Idioma", - 2817059741: "Local", - 63976957: "Nível de log", + 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 602716148: "Go", + 831562513: "Wärmeintervall", + 2300171403: "Hitzezeit", + 3580020863: "Hex öffentlicher Schlüssel", + 2691246967: "Hexadezimal", + 2736309107: "ID existiert bereits\n", + 631342955: "Input (%d): ", + 2585599782: "Ungültige Adresse", + 2874529150: "Ungültiger Bootloader", + 4093416954: "Ungültige mnemonische Lange", + 1422874211: "Ungültiger öffentlicher Schlüssel", + 2443867979: "Ungültige Wallet:\n%s", + 4122897393: "Umkehren", + 3000888649: "Schlüssel", + 2686333978: "Schlüssel:", + 4123798664: "Krux\n\n\nVersion\n%s", + 3835918229: "Krux Drucker Test-QR", + 766317539: "Sprache", + 972436696: "Leitungsverzögerung", + 3596093890: "Linie: ", + 2820726296: "Mnemonic laden", + 879727077: "Von SD-Karte laden?", + 669106195: "Eine laden?", + 3330705289: "Laden?", + 2596531078: "Lade Kamera..", + 596389387: "Lade Change Adresse %d..", + 336702608: "Drucker wird geladen..", + 2538883522: "Lade Empfangsadresse %d..", + 3159494909: "Wird geladen..", + 1177338798: "Spracheinstellung", + 2817059741: "Speicherort", + 63976957: "Log Level", 86530918: "Logging", - 2917810189: "Comprimento máximo excedido (%s)", - 2030045667: "Mensagem", - 3928301843: "Arquivo de assinatura faltando", - 1948316555: "Mnemônico", - 2123991188: "ID do mnemônico", - 3911073154: "ID de armazenamento", - 570639842: "Mnemônico não foi descriptografado", - 1746030071: "Mnemônico não foi criptografado", - 1458925155: "Modificado:", + 2917810189: "Maximale Länge überschritten (%s)", + 2030045667: "Nachricht", + 3928301843: "Fehlende Signaturdatei", + 1948316555: "Mnemonic", + 2123991188: "Mnemonische ID", + 3911073154: "Mnemonische Speicher-ID", + 570639842: "Mnemonic wurde nicht entschlüsselt", + 1746030071: "Mnemonic wurde nicht verschlüsselt", + 1458925155: "Geändert:", 1845376098: "Multisig", - 2939797024: "Rede", - 73574491: "Novo Mnemônico", - 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", - 4063104189: "Não", - 3927838899: "Sem senha BIP39", - 4092516657: "Jogadas insuficientes!", - 1577637745: "Octal", - 3312581301: "Iter. PBKDF2", + 2939797024: "Netzwerk", + 73574491: "Neue Mnemonic", + 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", + 4063104189: "Nein", + 3927838899: "Keine BIP39 Passphrase", + 4092516657: "Nicht genug Würfe!", + 1577637745: "Oktal", + 3312581301: "PBKDF2-Iter.", 721090621: "PSBT", - 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", - 2987800462: "Largura do papel", - 3050763890: "Parte\n%d / %d", - 3559456868: "Tamanho da peça", - 4249903283: "Senha", - 3712257341: "Senha:", - 140802882: "Salvar", - 1703779997: "QR em Texto", - 3561756278: "Carregue um descritor da carteira", - 784609464: "Taxa de Mergulho", - 3037062877: "Imprimir QR de teste", - 4278257699: "Imprimir QR?\n\n%s\n\n", - 516488026: "Imprimir?\n\n%s\n\n", - 1123106929: "Impressora", - 3903571079: "Driver de impressora não está definido!", - 2609799302: "Imprimindo\n%d / %d", - 844861889: "Imprimindo ...", - 2580599003: "Seguir?", - 556126964: "Processando ...", - 1848310591: "Código QR", - 710709610: "Pino RX", - 2697857197: "Recebimento", - 1746677167: "Endereços de Recebimento", - 364354944: "Região: ", - 1662254634: "Revise os dados, edite se necessário", - 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", - 856795528: "Jogadas:\n\n%s", - 255086803: "Jogadas: %d\n", - 3976793317: "Cartão SD", - 2827687530: "Cartão SD não detectado", - 2736513298: "Cartão SD não detectado.", - 3593785196: "SHA256 de jogadas:\n\n%s", - 1143278725: "Sha256 da imagem:\n\n%s", + 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", + 2987800462: "Papierbreite", + 3050763890: "Teil\n%d / %d", + 3559456868: "Teilegröße", + 4249903283: "Passphrase", + 3712257341: "Passphrase:", + 140802882: "Speicher", + 1703779997: "Klartext-QR", + 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", + 784609464: "Tauchrate", + 3037062877: "Drucke Test-QR", + 4278257699: "Als QR-Code drucken?\n\n%s\n\n", + 516488026: "Drucken?\n\n%s\n\n", + 1123106929: "Drucker", + 3903571079: "Druckertreiber nicht gesetzt!", + 2609799302: "Drucken\n%d / %d", + 844861889: "Wird gedruckt ...", + 2580599003: "Weiter?", + 556126964: "Wird bearbeitet ...", + 1848310591: "QR-Code", + 710709610: "RX Pin", + 2697857197: "Empfangen", + 1746677167: "Empfangsadresse", + 364354944: "Region: ", + 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", + 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", + 856795528: "Würfe:\n\n%s", + 255086803: "Würfe: %d\n", + 3976793317: "SD-Karte", + 2827687530: "SD-Karte nicht erkannt", + 2736513298: "SD-Karte nicht erkannt.", + 3593785196: "SHA256 der Würfe:\n\n%s", + 1143278725: "SHA256 des Snapshots:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Salvar no cartão SD?", - 810036588: "Salvo no cartão SD:\n%s", - 763824768: "Escala", - 4117455079: "Escanear Endereço", - 3219991109: "Escanear a senha BIP39", - 2537207336: "Escanear código QR da chave", - 4006316572: "Escaneando as palavras 1-12 novamente", - 2736506158: "Escaneando as palavras 13-24", + 3531742595: "Auf SD-Karte speichern?", + 810036588: "Auf SD-Karte gespeichert:\n%s", + 763824768: "Skala", + 4117455079: "Adresse\nscannen", + 3219991109: "Scan BIP39 Passphrase", + 2537207336: "Schlüssel QR-Code scannen", + 4006316572: "Wörter 1-12 erneut scannen", + 2736506158: "Wörter 13-24 scannen", + 3593497655: "Bildschirmschoner", 266935239: "SeedQR", - 1698829144: "Autotransferência ou Troco (%d): ", - 473154195: "Configurações", - 1825881236: "Desligar", - 2120776272: "Desligando..", - 1061961408: "Assinar", - 4282338366: "Assinar?", - 746161122: "Assinatura", - 1988416729: "Mensagem Assinada", - 3672006076: "PSBT Assinada", - 2281377987: "Single-sig", - 4221794628: "Total: ", - 2309020186: "Gastos (%d): ", + 1698829144: "Selbstübertragung oder Change (%d): ", + 473154195: "Einstellungen", + 1825881236: "Ausschalten", + 2120776272: "Herunterfahren..", + 1061961408: "Signieren", + 4282338366: "Signieren?", + 746161122: "Signatur", + 1988416729: "Signierte Nachricht", + 3672006076: "Signierte PSBT", + 2281377987: "Single-Sig", + 4221794628: "Größe: ", + 2309020186: "Ausgabe (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Armazene na Flash", - 720041451: "Armazene no Cartão SD", - 3514476519: "Deslize para mudar de modo", - 1898550184: "TOQUE ou ENTER para capturar", - 4228215415: "Pino TX", - 2612594937: "Texto", - 1454688268: "Tema", - 1180180513: "Térmica", + 3303592908: "Auf Flash speichern", + 720041451: "Auf der SD-Karte speichern", + 3514476519: "Wischen um den Modus zu ändern", + 1898550184: "TOUCH oder ENTER zum Erfassen", + 4228215415: "TX Pin", + 2612594937: "Text", + 1454688268: "Thema", + 1180180513: "Thermisch", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Ferramentas", - 3684696112: "Limiar de Toque", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Werkzeuge", + 3684696112: "Berühre Schwellenwert", 2978718564: "Touchscreen", - 2732611775: "Tentar mais?", - 1487826746: "Digitar a senha BIP39", - 2061556020: "Digite a Chave", - 2089395053: "Unidade", - 2845607430: "Atualizando bootloader..\n\n%d%%", - 4164597446: "Atualização completa.\n\nDesligando..", - 2736001501: "Atualizando firmware..\n\n%d%%", - 2674953168: "Use uma superfície de fundo preta.", - 2402455261: "Use a entropia da câmera para criar um novo mnemônico", - 236075140: "Usado: ", - 4003084591: "Valor %s fora do alcance: [ %s, %s]", - 4191058607: "Pela Câmera", + 2732611775: "Weiter versuchen?", + 1487826746: "BIP39 Passphrase eingeben", + 2061556020: "Schlüssel eingeben", + 2089395053: "Einheit", + 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", + 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", + 2736001501: "Firmware wird aktualisiert..\n\n%d%%", + 2674953168: "Verwende eine schwarze Hintergrundfläche.", + 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", + 236075140: "Belegt: ", + 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", + 4191058607: "Via Kamera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Por entrada manual", - 2504354847: "Aguarde a captura", - 2297028319: "Descritor de Carteira", - 4232654916: "Descritor da carteira", - 2587172867: "Descritor de saída da carteira carregado!", - 2499782468: "O descritor de saída da carteira não foi encontrado.", - 1831109430: "Atenção:\nDescritor de saída incompleto", - 797660533: "Palavra %d", - 3742424146: "Números das Palavras", - 2965123464: "Palavras", - 1303016265: "Sim", - 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", - 2569054451: "Suas alterações serão mantidas no cartão SD.", + 590330112: "Via manueller Eingabe", + 2504354847: "Warte auf die Erfassung", + 3992434312: "Wartezeit", + 2297028319: "Wallet-Deskriptor", + 4232654916: "Wallet Ausgabedeskriptor", + 2587172867: "Wallet Ausgabedeskriptor geladen!", + 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", + 1831109430: "Warnung:\nUnvollständiger Ausgabedeskriptor", + 797660533: "Wort %d", + 3742424146: "Wortnummern", + 2965123464: "Wörter", + 1303016265: "Ja", + 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", + 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", }, "es-MX": { 1185266064: "%d de %d multisig", @@ -454,6 +456,7 @@ 2537207336: "Escanear el código QR", 4006316572: "Escaneo de palabras 1-12 de nuevo", 2736506158: "Escaneo de palabras 13-24", + 3593497655: "Protector de pantalla", 266935239: "Seedqr", 1698829144: "Autotransferencia o Cambio (%d): ", 473154195: "Ajustes", @@ -497,6 +500,7 @@ 525309547: "Via D6", 590330112: "Mediante entrada manual", 2504354847: "Espera la captura", + 3992434312: "Tiempo de espera", 2297028319: "Descriptor de Cartera", 4232654916: "Descriptor de salida de billetera", 2587172867: "¡Se ha cargado el descriptor de salida de la cartera!", @@ -509,980 +513,988 @@ 771968845: "Sus cambios se guardarán en el almacenamiento flash del dispositivo.", 2569054451: "Sus cambios se guardarán en la tarjeta SD.", }, - "de-DE": { - 1185266064: "%d von %d Multisig", - 2004520398: "%d. Change: \n\n%s\n\n", - 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", - 3264377309: "%d. Ausgaben: \n\n%s\n\n", - 2399232215: "%s\n\nist eine gültige Change Adresse!", - 3921290840: "%s\n\nist eine gültige Empfangsadresse!", - 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", - 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", - 3348584292: "(Experimental)", - 2739590230: "12 Wörter", - 1310058127: "24 Wörter", + "fr-FR": { + 1185266064: "%d de %d multisignature", + 2004520398: "%d. Changement : \n\n%s\n\n", + 3862364126: "%d. Auto-transfert : \n\n%s\n\n", + 3264377309: "%d. Dépense : \n\n%s\n\n", + 2399232215: "%s\n\nest une adresse changement valide!", + 3921290840: "%s\n\nest une adresse reçue valide!", + 1808355833: "INTROUVABLE dans les premières %d adresses de changement", + 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", + 3348584292: "(Expérimental)", + 2739590230: "12 mots", + 1310058127: "24 mots", 2743272264: "ABC", - 1949634023: "Über", + 1949634023: "À propos", 1517128857: "Adafruit", 3270727197: "Adresse", - 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", - 283202181: "Richte Kamera und Tiny Seed korrekt aus.", - 88746165: "Blendschutz deaktiviert", - 1521033296: "Blendschutz aktiviert", - 1056821534: "Bist Du sicher?", - 3247612282: "BIP39 Mnemonic", - 3455872521: "Zurück", - 2541860807: "Bootloader wird gesichert..\n\n%d%%", - 2256777600: "Ungültige Signatur", - 3937333362: "Baudrate", + 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", + 283202181: "Alignez correctement la caméra et Tiny Seed.", + 88746165: "Anti-éblouissement désactivé", + 1521033296: "Anti-éblouissement activé", + 1056821534: "Es-tu sûr?", + 3247612282: "BIP39 Mnémonique", + 3455872521: "Retour", + 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", + 2256777600: "Mauvaise signature", + 3937333362: "Débit en bauds", 427617266: "Bitcoin", - 928727036: "Randpolsterung", + 928727036: "Rembourrage de bordure", 213030954: "CNC", - 1207696150: "Change Adresse", - 3126552510: "Change Adressen", - 1583186953: "Thema ändern und neu starten?", - 2697733395: "Änderungen auf SD-Karte gespeichert!", - 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", - 3442025874: "Prüfe SD-Karte", - 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", - 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", - 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", - 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", - 2470115694: "Suche nach SD-Karte..", - 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", - 2407028014: "Kompakt SeedQR", - 4041895036: "Weiter?", - 4094072796: "Erstelle QR-Code", - 167798282: "QR-Code aus Text erzeugen?", - 2767642191: "Erstellt:", - 3513215254: "Benutzerdefinierte QR-Code", - 124617190: "Schnitttiefe", - 597912140: "Cut-Methode", - 2504034831: "Dezimal", - 2751113454: "Entschlüsseln?", - 1016609898: "Datei löschen?", - 1364509700: "Mnemonic löschen", - 4102535566: "Tiefe pro Durchgang", - 2791699253: "Ableitung: %s", - 1230133196: "Geräte-Flash-Speicher nicht erkannt.", - 3836852788: "Fertig?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-Entprellung", - 374684711: "Verschlüssel Mnemonic", - 1244124409: "Verschlüsselter QR-Code", - 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", - 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", - 350279787: "Verschlüsselung", - 2601598799: "Verschlüsselungsmodus", - 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", - 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", - 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", - 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", - 784361051: "Fehler:\n%s", + 1207696150: "Changement", + 3126552510: "Adresses de Changement", + 1583186953: "Changer de thème et redémarrer?", + 2697733395: "Modifications enregistrées sur la carte SD!", + 388908871: "Les modifications dureront jusqu'à l'arrêt.", + 3442025874: "Vérifiez la carte SD", + 3119547911: "Vérifiez que l'adresse appartient à cette portefeuille?", + 2856261511: "Adresses %d changement vérifiées sans correspondance.", + 2788541416: "Adresses %d reçues vérifiées sans correspondance.", + 2446472910: "Vérification de l'adresse changement %d pour correspondance..", + 2470115694: "Vérification de la carte SD..", + 3655273987: "Vérification de l'adresse reçue %d pour correspondance..", + 2407028014: "SeedQR Compact", + 4041895036: "Continuer?", + 4094072796: "Créer du code QR", + 167798282: "Créer du code QR à partir du texte?", + 2767642191: "Créé:", + 3513215254: "Code QR personnalisé", + 124617190: "Profondeur de coupe", + 597912140: "Méthode de coupe", + 2504034831: "Décimal", + 2751113454: "Décrypter?", + 1016609898: "Supprimer le fichier?", + 1364509700: "Supprimer mnémonique", + 4102535566: "Profondeur par passage", + 2791699253: "Dérivation: %s", + 1230133196: "Stockage flash de l'appareil non détecté.", + 3836852788: "Terminé?", + 382368239: "Conducteur", + 3978947916: "Encodeur", + 4090746898: "Anti-rebond de l'encodeur", + 374684711: "Crypter mnémonique", + 1244124409: "Code QR crypté", + 2968548114: "Le mnémonique crypté n'a pas été stocké", + 3315319371: "Mnémonique cryptée a été stockée avec ID:", + 350279787: "Chiffrement", + 2601598799: "Mode de chiffrement", + 3504179008: "Entrez chaque mot de votre BIP-39 mnémonique sous la forme d'un nombre 1 jusqu'à 2048.", + 1100685007: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en hexadécimal de 1 à 800.", + 4090266642: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en octal de 1 à 4000.", + 2780625730: "Entrez chaque mot de votre BIP-39 mnémonique.", + 784361051: "Erreur:\n%s", 1505332462: "Esc", - 3838465623: "Dateien durchsuchen?", - 4170881190: "Auf SD-Karte exportieren..", - 1711312434: "Öffentlicher Schlüssel", - 383371114: "Entschlüsselung fehlgeschlagen", - 3048830188: "PSBT konnte nicht geladen werden", - 4192663412: "Adresse konnte nicht geladen werden", - 1996021743: "Schlüssel konnte nicht geladen werden", - 1108715658: "Nachricht konnte nicht geladen werden", - 1081425878: "Mnemonic konnte nicht geladen werden", - 928667220: "Ausgabedeskriptor konnte nicht geladen werden", - 1620572516: "Passphrase konnte nicht geladen werden", - 2946146830: "Mnemonic konnte nicht gespeichert werden", - 1303554751: "Gebühr: ", - 104500973: "Vorschubgeschwindigkeit", - 3313339187: "Dateiname", - 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", - 3737729752: "Fingerabdruck: %s", - 2542772894: "Die Firmware übersteigt die maximale Größe: %d", - 1406590538: "Flötendurchmesser", - 3086093110: "Frei: ", - 1893243331: "Vom Speicher", + 3838465623: "Explorer des fichiers?", + 4170881190: "Exportation vers la carte SD..", + 1711312434: "Clé publique", + 383371114: "Échec de décrypter", + 3048830188: "Erreur de chargement PSBT", + 4192663412: "Erreur de chargement d'adresse", + 1996021743: "Échec du chargement de la clé", + 1108715658: "Échec du chargement du message", + 1081425878: "Erreur de chargement mnémonique", + 928667220: "Échec du chargement du descripteur de sortie", + 1620572516: "Échec du chargement de la phrase secrète", + 2946146830: "Échec de stocker mnémonique", + 1303554751: "Frais: ", + 104500973: "Taux d'alimentation", + 3313339187: "Nom de fichier", + 1982637349: "Le nom de fichier %s existe sur la carte SD, écraser ?", + 3737729752: "Empreinte Digitale: %s", + 2542772894: "Le micrologiciel dépasse la taille maximale: %d", + 1406590538: "Diamètre de flûte", + 3086093110: "Libre: ", + 1893243331: "Du stockage", 4120536442: "GRBL", - 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 299338213: "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", 602716148: "Go", - 831562513: "Wärmeintervall", - 2300171403: "Hitzezeit", - 3580020863: "Hex öffentlicher Schlüssel", - 2691246967: "Hexadezimal", - 2736309107: "ID existiert bereits\n", - 631342955: "Input (%d): ", - 2585599782: "Ungültige Adresse", - 2874529150: "Ungültiger Bootloader", - 4093416954: "Ungültige mnemonische Lange", - 1422874211: "Ungültiger öffentlicher Schlüssel", - 2443867979: "Ungültige Wallet:\n%s", - 4122897393: "Umkehren", - 3000888649: "Schlüssel", - 2686333978: "Schlüssel:", + 831562513: "Intervalle de chauffe", + 2300171403: "Temps de chauffe", + 3580020863: "Clé public hexadécimal", + 2691246967: "Hexadécimal", + 2736309107: "Id existe déjà\n", + 631342955: "Entrées (%d) : ", + 2585599782: "Adresse invalide", + 2874529150: "Chargeur de démarrage invalide", + 4093416954: "Longueur mnémonique invalide", + 1422874211: "Clé publique non valide", + 2443867979: "Portefeuille invalide:\n%s", + 4122897393: "Inverser", + 3000888649: "Clé", + 2686333978: "Clé:", 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Krux Drucker Test-QR", - 766317539: "Sprache", - 972436696: "Leitungsverzögerung", - 3596093890: "Linie: ", - 2820726296: "Mnemonic laden", - 879727077: "Von SD-Karte laden?", - 669106195: "Eine laden?", - 3330705289: "Laden?", - 2596531078: "Lade Kamera..", - 596389387: "Lade Change Adresse %d..", - 336702608: "Drucker wird geladen..", - 2538883522: "Lade Empfangsadresse %d..", - 3159494909: "Wird geladen..", - 1177338798: "Spracheinstellung", - 2817059741: "Speicherort", - 63976957: "Log Level", - 86530918: "Logging", - 2917810189: "Maximale Länge überschritten (%s)", - 2030045667: "Nachricht", - 3928301843: "Fehlende Signaturdatei", - 1948316555: "Mnemonic", - 2123991188: "Mnemonische ID", - 3911073154: "Mnemonische Speicher-ID", - 570639842: "Mnemonic wurde nicht entschlüsselt", - 1746030071: "Mnemonic wurde nicht verschlüsselt", - 1458925155: "Geändert:", - 1845376098: "Multisig", - 2939797024: "Netzwerk", - 73574491: "Neue Mnemonic", - 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", - 4063104189: "Nein", - 3927838899: "Keine BIP39 Passphrase", - 4092516657: "Nicht genug Würfe!", - 1577637745: "Oktal", - 3312581301: "PBKDF2-Iter.", + 3835918229: "Test de l'imprimante Krux QR", + 766317539: "Langue", + 972436696: "Délai de Ligne", + 3596093890: "Ligne: ", + 2820726296: "Charger mnémonique", + 879727077: "Charger depuis la carte SD ?", + 669106195: "En charger qu'un?", + 3330705289: "Charger?", + 2596531078: "Caméra de Chargement..", + 596389387: "Chargement de l'adresse de changement %d..", + 336702608: "Chargement de l'imprimante..", + 2538883522: "Chargement de l'adresse de réception %d..", + 3159494909: "Chargement..", + 1177338798: "Paramètres régionaux", + 2817059741: "Emplacement", + 63976957: "Niveau de journalisation", + 86530918: "Enregistrement", + 2917810189: "Longueur maximale dépassée (% s)", + 2030045667: "Message", + 3928301843: "Fichier de signature manquant", + 1948316555: "Mnémonique", + 2123991188: "ID mnémonique", + 3911073154: "ID de stockage mnémonique", + 570639842: "Mnémonique n'a pas été décryptée", + 1746030071: "Mnémonique n'était pas cryptée", + 1458925155: "Modifié:", + 1845376098: "Multi\nsignature", + 2939797024: "Réseau", + 73574491: "Nouveau mnémonique", + 2792272353: "Nouveau micrologiciel détecté.\n\nSHA256:\n%s\n\n\n\nInstaller?", + 4063104189: "Non", + 3927838899: "Pas de phrase passante bip39", + 4092516657: "Pas assez de rouleaux !", + 1577637745: "Octale", + 3312581301: "Itér. PBKDF2", 721090621: "PSBT", - 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", - 2987800462: "Papierbreite", - 3050763890: "Teil\n%d / %d", - 3559456868: "Teilegröße", - 4249903283: "Passphrase", - 3712257341: "Passphrase:", - 140802882: "Speicher", - 1703779997: "Klartext-QR", - 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", - 784609464: "Tauchrate", - 3037062877: "Drucke Test-QR", - 4278257699: "Als QR-Code drucken?\n\n%s\n\n", - 516488026: "Drucken?\n\n%s\n\n", - 1123106929: "Drucker", - 3903571079: "Druckertreiber nicht gesetzt!", - 2609799302: "Drucken\n%d / %d", - 844861889: "Wird gedruckt ...", - 2580599003: "Weiter?", - 556126964: "Wird bearbeitet ...", - 1848310591: "QR-Code", - 710709610: "RX Pin", - 2697857197: "Empfangen", - 1746677167: "Empfangsadresse", - 364354944: "Region: ", - 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", - 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", - 856795528: "Würfe:\n\n%s", - 255086803: "Würfe: %d\n", - 3976793317: "SD-Karte", - 2827687530: "SD-Karte nicht erkannt", - 2736513298: "SD-Karte nicht erkannt.", - 3593785196: "SHA256 der Würfe:\n\n%s", - 1143278725: "SHA256 des Snapshots:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Auf SD-Karte speichern?", - 810036588: "Auf SD-Karte gespeichert:\n%s", - 763824768: "Skala", - 4117455079: "Adresse\nscannen", - 3219991109: "Scan BIP39 Passphrase", - 2537207336: "Schlüssel QR-Code scannen", - 4006316572: "Wörter 1-12 erneut scannen", - 2736506158: "Wörter 13-24 scannen", - 266935239: "SeedQR", - 1698829144: "Selbstübertragung oder Change (%d): ", - 473154195: "Einstellungen", - 1825881236: "Ausschalten", - 2120776272: "Herunterfahren..", - 1061961408: "Signieren", - 4282338366: "Signieren?", - 746161122: "Signatur", - 1988416729: "Signierte Nachricht", - 3672006076: "Signierte PSBT", - 2281377987: "Single-Sig", - 4221794628: "Größe: ", - 2309020186: "Ausgabe (%d): ", + 995862913: "Peignez les points perforés en noir afin qu'ils puissent être détectés.", + 2987800462: "Largeur du papier", + 3050763890: "Partie\n%d / %d", + 3559456868: "Taille de la pièce", + 4249903283: "Phrase de passe", + 3712257341: "Phrass de passe:", + 140802882: "Persister", + 1703779997: "QR en Texte Brut", + 3561756278: "Veuillez charger un descripteur de sortie de portefeuille", + 784609464: "Taux de plongée", + 3037062877: "Test d'impression QR", + 4278257699: "Imprimer en QR?\n\n%s\n\n", + 516488026: "Imprimer?\n\n%s\n\n", + 1123106929: "Imprimante", + 3903571079: "Le conducteur d'imprimante n'est pas défini!", + 2609799302: "Impression\n%d / %d", + 844861889: "Impression ...", + 2580599003: "Procéder?", + 556126964: "Traitement ...", + 1848310591: "QR Code", + 710709610: "RX Fiche", + 2697857197: "Recevoir", + 1746677167: "Adresses de Réception", + 364354944: "Région: ", + 1662254634: "Examinez les données numérisées, modifiez-les si nécessaire", + 770350922: "Lancez le dé au moins %d fois pour générer un mnémonique.", + 856795528: "Rouleaux:\n\n%s", + 255086803: "Rouleaux: %d\n", + 3976793317: "Carte SD", + 2827687530: "Carte SD non détectée", + 2736513298: "Carte SD non détectée.", + 3593785196: "SHA256 de rouleaux:\n\n%s", + 1143278725: "Sha256 de Snapshot:\n\n% s", + 3338679392: "SHA256:\n%s", + 3531742595: "Enregistrer sur la carte SD ?", + 810036588: "Enregistré sur la carte SD :\n%s", + 763824768: "L'échelle", + 4117455079: "Scannez l'adresse", + 3219991109: "Scan bip39 en phrase secrète", + 2537207336: "Scanner le code QR de la clé", + 4006316572: "Analyser à nouveau les mots 1 à 12", + 2736506158: "Analyser les mots 13 à 24", + 3593497655: "Économiseur d'écran", + 266935239: "Seedqr", + 1698829144: "Auto-transfert ou changement (%d): ", + 473154195: "Paramètres", + 1825881236: "Fermer", + 2120776272: "Éteindre..", + 1061961408: "Signature", + 4282338366: "Signature?", + 746161122: "Signature", + 1988416729: "Message signé", + 3672006076: "PSBT signé", + 2281377987: "Clé unique", + 4221794628: "Capacité: ", + 2309020186: "Dépense (%d) : ", 3355862324: "Stackbit 1248", - 3303592908: "Auf Flash speichern", - 720041451: "Auf der SD-Karte speichern", - 3514476519: "Wischen um den Modus zu ändern", - 1898550184: "TOUCH oder ENTER zum Erfassen", - 4228215415: "TX Pin", - 2612594937: "Text", - 1454688268: "Thema", - 1180180513: "Thermisch", + 3303592908: "Stocker sur flash", + 720041451: "Stocker sur la carte SD", + 3514476519: "Faites glisser pour changer de mode", + 1898550184: "TOUCHEZ ou ENTER pour capturer", + 4228215415: "TX Fiche", + 2612594937: "Texte", + 1454688268: "Thème", + 1180180513: "Thermique", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Werkzeuge", - 3684696112: "Berühre Schwellenwert", - 2978718564: "Touchscreen", - 2732611775: "Weiter versuchen?", - 1487826746: "BIP39 Passphrase eingeben", - 2061556020: "Schlüssel eingeben", - 2089395053: "Einheit", - 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", - 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", - 2736001501: "Firmware wird aktualisiert..\n\n%d%%", - 2674953168: "Verwende eine schwarze Hintergrundfläche.", - 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", - 236075140: "Belegt: ", - 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", - 4191058607: "Via Kamera", + 1732872974: "Tiny Seed (bits)", + 725348723: "Outils", + 3684696112: "Seuil Tactile", + 2978718564: "Écran Tactile", + 2732611775: "Réessayer?", + 1487826746: "Type Bip39 Plasque", + 2061556020: "Clé de type", + 2089395053: "Unité", + 2845607430: "Mise à jour du chargeur de démarrage..\n\n%d%%", + 4164597446: "Mise à niveau complète.\n\nÉteindre..", + 2736001501: "Mise à niveau du micrologiciel..\n\n%d%%", + 2674953168: "Utilisez une surface de fond noire.", + 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", + 236075140: "Utilisé: ", + 4003084591: "Valeur% s hors de portée: [% s,% s]", + 4191058607: "Par caméra", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Via manueller Eingabe", - 2504354847: "Warte auf die Erfassung", - 2297028319: "Wallet-Deskriptor", - 4232654916: "Wallet Ausgabedeskriptor", - 2587172867: "Wallet Ausgabedeskriptor geladen!", - 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", - 1831109430: "Warnung:\nUnvollständiger Ausgabedeskriptor", - 797660533: "Wort %d", - 3742424146: "Wortnummern", - 2965123464: "Wörter", - 1303016265: "Ja", - 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", - 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", + 590330112: "Par saisie manuelle", + 2504354847: "Attendez la capture", + 3992434312: "Temps d'attente", + 2297028319: "Descripteur de Portefeuille", + 4232654916: "Descripteur de sortie du portefeuille", + 2587172867: "Descripteur de sortie du portefeuille chargé!", + 2499782468: "Descripteur de sortie du portefeuille introuvable.", + 1831109430: "Attention:\nDescripteur de sortie incomplet", + 797660533: "Mot %d", + 3742424146: "Numéros de mots", + 2965123464: "Mots", + 1303016265: "Oui", + 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", + 2569054451: "Vos modifications seront conservées sur la carte SD.", }, - "vi-VN": { - 1185266064: "%d của %d đa chữ kí", - 2004520398: "%d. Thay đổi: \n\n%s\n\n", - 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", - 3264377309: "%d. Chi tiêu: \n\n%s\n\n", - 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", - 3921290840: "%s\n\nlà một địa chỉ khả dụng!", - 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 3348584292: "(Thực nghiệm)", - 2739590230: "12 từ", - 1310058127: "24 từ", + "nl-NL": { + 1185266064: "%d van %d multisig", + 2004520398: "%d. Wisselgeld: \n\n%s\n\n", + 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", + 3264377309: "%d. Uitgaven: \n\n%s\n\n", + 2399232215: "%s\n\nis een valide wisselgeld adres!", + 3921290840: "%s\n\nis een valide ontvangst adres!", + 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", + 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", + 3348584292: "(Experimenteel)", + 2739590230: "12 woorden", + 1310058127: "24 woorden", 2743272264: "ABC", - 1949634023: "Về chúng tôi", + 1949634023: "Over", 1517128857: "Adafruit", - 3270727197: "Địa chỉ", - 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", - 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", - 88746165: "Chống lóa bị vô hiệu hóa", - 1521033296: "Đã bật chống lóa", - 1056821534: "Bạn có chắc không?", - 3247612282: "Mã mnemonic dạng chuẩn BIP39", - 3455872521: "Trở lại", - 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", - 2256777600: "Chữ ký xấu", - 3937333362: "Tốc độ baud", + 3270727197: "Adres", + 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", + 283202181: "Richt de camera en Tiny Seed op de juiste manier.", + 88746165: "Anti reflecterend uitgeschakeld", + 1521033296: "Anti reflecterend ingeschakeld", + 1056821534: "Weet je het zeker?", + 3247612282: "BIP-39 geheugensteun", + 3455872521: "Terug", + 2541860807: "Backup van de bootloader...\n\n%d%%", + 2256777600: "Ongeldige handtekening", + 3937333362: "Baudratio", 427617266: "Bitcoin", - 928727036: "Đệm viền", + 928727036: "Rand opvulling", 213030954: "CNC", - 1207696150: "Thay đổi", - 3126552510: "Thay địa chỉ", - 1583186953: "Thay đổi chủ đề và khởi động lại?", - 2697733395: "Thay đổi được lưu trên thẻ SD!", - 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", - 3442025874: "Kiểm tra thẻ SD", - 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", - 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", - 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", - 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", - 2470115694: "Kiểm tra thẻ SD..", - 3655273987: "Đang kiểm tra %d địa chỉ..", - 2407028014: "SeedQR nhỏ gọn", - 4041895036: "Tiếp tục?", - 4094072796: "Tạo mã QR", - 167798282: "Tạo mã QR từ văn bản?", - 2767642191: "Tạo:", - 3513215254: "Mã QR tùy chỉnh", - 124617190: "Chiều sâu cắt", - 597912140: "Phương pháp cắt", - 2504034831: "Số thập phân", - 2751113454: "Phản đối?", - 1016609898: "Xóa tài liệu?", - 1364509700: "Xóa ghi nhớ", - 4102535566: "Độ sâu mỗi lần vượt qua", - 2791699253: "Nguồn gốc: %s", - 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", - 3836852788: "Hoàn tất?", - 382368239: "Người cầm lái", - 3978947916: "Mã hoá", - 4090746898: "Gỡ lỗi bộ mã hóa", - 374684711: "Mã hóa Mnemonic", - 1244124409: "Mã QR được mã hóa", - 2968548114: "MNemon được mã hóa không được lưu trữ", - 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", - 350279787: "Mã hóa", - 2601598799: "Chế độ mã hóa", - 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", - 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", - 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", - 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", - 784361051: "Lỗi:\n%s", - 1505332462: "Esc", - 3838465623: "Khám phá các tập tin?", - 4170881190: "Xuất vào thẻ SD ..", - 1711312434: "Khóa công cộng", - 383371114: "Không giải mã được", - 3048830188: "Tải PSBT thất bại", - 4192663412: "Tải địa chỉ thất bại", - 1996021743: "Không tải khóa", - 1108715658: "Không tải được tin nhắn", - 1081425878: "Tải mã mnemonic thất bại", - 928667220: "Không thể tải bộ mô tả đầu ra", - 1620572516: "Không tải được cụm mật khẩu", - 2946146830: "Không lưu trữ MNemonic", - 1303554751: "Phí: ", - 104500973: "Tỷ lệ thức ăn", - 3313339187: "Tên tệp", - 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", - 3737729752: "Dấu vân tay: %s", - 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", - 1406590538: "Đường kính ống sáo", - 3086093110: "Khả dụng: ", - 1893243331: "Từ lưu trữ", - 4120536442: "GRBL", - 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", - 602716148: "Đến", - 831562513: "Khoảng thời gian nhiệt", - 2300171403: "Thời gian nhiệt", - 3580020863: "Khóa công khai Hex", - 2691246967: "Thập lục phân", - 2736309107: "Id đã tồn tại\n", - 631342955: "Đầu vào (%d): ", - 2585599782: "Địa chỉ không hợp lệ", - 2874529150: "Bộ tải khởi động không hợp lệ", - 4093416954: "Độ dài mã mnemonic không hợp lệ", - 1422874211: "Khóa công khai không hợp lệ", - 2443867979: "Ví không hợp lệ:\n%s", - 4122897393: "Đảo ngược", - 3000888649: "Chìa khóa", - 2686333978: "Chìa khóa:", - 4123798664: "Krux\n\n\nPhiên Bản\n%s", - 3835918229: "QR kiểm tra máy in Krux", - 766317539: "Ngôn ngữ", - 972436696: "Độ trễ Dòng", - 3596093890: "Đường kẻ: ", - 2820726296: "Tải mã mnemonic", - 879727077: "Tải từ thẻ SD?", - 669106195: "Tải một?", - 3330705289: "Tải?", - 2596531078: "Đang tải máy ảnh..", - 596389387: "Đang tải thay đổi địa chỉ %d..", - 336702608: "Tải máy in ..", - 2538883522: "Đang tải địa chỉ nhận %d..", - 3159494909: "Đang tải..", - 1177338798: "Ngôn ngữ", - 2817059741: "Vị trí cửa hàng", - 63976957: "Log Level", - 86530918: "Khai thác gỗ", - 2917810189: "Chiều dài tối đa vượt quá (%s)", - 2030045667: "Tin nhắn", - 3928301843: "Thiếu tập tin chữ ký", - 1948316555: "Mã mnemonic", - 2123991188: "ID ghi nhớ", - 3911073154: "ID lưu trữ ghi nhớ", - 570639842: "Ghi nhớ không được giải mã", - 1746030071: "Ghi nhớ không được mã hóa", - 1458925155: "Đã sửa đổi:", - 1845376098: "Đa chữ kí", - 2939797024: "Mạng lưới", - 73574491: "Mnemonic mới", - 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", - 4063104189: "Không", - 3927838899: "Không có cụm mật khẩu BIP39", - 4092516657: "Không đủ cuộn!", - 1577637745: "Bát phân", - 3312581301: "Lặp lại PBKDF2", + 1207696150: "Change", + 3126552510: "Wisselgeldadres", + 1583186953: "Thema veranderen en opnieuw opstarten?", + 2697733395: "Wijzigingen aanhouden op SD kaart!", + 388908871: "Wijzigingen blijven van kracht tot afsluiten.", + 3442025874: "Controleer SD kaart", + 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", + 2856261511: "Na %d geen wisselgeld adressen gevonden.", + 2788541416: "Na %d geen ontvangst adressen gevonden.", + 2446472910: "Wisselgeldadres %d controleren...", + 2470115694: "SD kaart controleren...", + 3655273987: "Ontvangstadres %d controleren...", + 2407028014: "Compact SeedQR", + 4041895036: "Doorgaan?", + 4094072796: "QR code maken", + 167798282: "QR code maken van tekst?", + 2767642191: "Aangemaakt: ", + 3513215254: "Aangepaste QR code", + 124617190: "Snijdiepte", + 597912140: "Snijmethode", + 2504034831: "Decimaal", + 2751113454: "Ontsleutelen?", + 1016609898: "Bestand verwijderen?", + 1364509700: "Geheugensteun verwijderen", + 4102535566: "Diepte per pas", + 2791699253: "Afgeleide: %s", + 1230133196: "Opslag op apparaat is niet gedetecteerd.", + 3836852788: "Klaar?", + 382368239: "Driver", + 3978947916: "Encoder", + 4090746898: "Encoder-debounce", + 374684711: "Geheugensteun versleutelen", + 1244124409: "Versleutelde QR code", + 2968548114: "Versleutelde geheugensteun was niet opgeslagen", + 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", + 350279787: "Versleutelen", + 2601598799: "Versleutel modus", + 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", + 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", + 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", + 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", + 784361051: "Fout:\n%s", + 1505332462: "Esc", + 3838465623: "Bestanden verkennen?", + 4170881190: "Exporteren naar SD-kaart..", + 1711312434: "Uitgebreide publieke sleutel", + 383371114: "Ontsleutelen is niet gelukt", + 3048830188: "PSBT laden is niet gelukt", + 4192663412: "Adres laden is niet gelukt", + 1996021743: "Sleutel laden is niet gelukt", + 1108715658: "Bericht laden is niet gelukt", + 1081425878: "Geheugensteun laden is niet gelukt", + 928667220: "Descriptor laden is niet gelukt", + 1620572516: "Wachtwoord laden is niet gelukt", + 2946146830: "Geheugensteun opslaan is niet gelukt", + 1303554751: "Tarief: ", + 104500973: "Voedingssnelheid", + 3313339187: "Bestandsnaam", + 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", + 3737729752: "Vingerafdruk: %s", + 2542772894: "Firmware overschrijdt de maximale grootte: %d", + 1406590538: "Fluit diameter", + 3086093110: "Vrij: ", + 1893243331: "Uit data-opslag", + 4120536442: "GRBL", + 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", + 602716148: "Ga", + 831562513: "Warmte interval", + 2300171403: "Warmte tijd", + 3580020863: "Hex publieke sleutel", + 2691246967: "Hexadecimaal", + 2736309107: "ID bestaat al\n", + 631342955: "Invoer (%d): ", + 2585599782: "Ongeldig adres", + 2874529150: "Ongeldige bootloader", + 4093416954: "Ongeldige geheugensteun lengte", + 1422874211: "Ongeldige publieke sleutel", + 2443867979: "Ongeldige portemonnee:\n%s", + 4122897393: "Omkeren", + 3000888649: "Sleutel", + 2686333978: "Sleutel: ", + 4123798664: "Krux\n\n\nVersie\n%s", + 3835918229: "Krux printer test QR", + 766317539: "Taal", + 972436696: "Lijn vertraging", + 3596093890: "Lijn: ", + 2820726296: "Geheugensteun laden", + 879727077: "Laden vanaf SD-kaart?", + 669106195: "Laden?", + 3330705289: "Laden?", + 2596531078: "Camera laden...", + 596389387: "Wisselgeldadres %d laden...", + 336702608: "Laadprinter..", + 2538883522: "Ontvangstadres %d laden...", + 3159494909: "Laden...", + 1177338798: "Taal", + 2817059741: "Opslaglocatie", + 63976957: "Log niveau", + 86530918: "Debug logs", + 2917810189: "Maximale lengte overschreden (%s)", + 2030045667: "Bericht", + 3928301843: "Handtekening bestand mist", + 1948316555: "Geheugensteun", + 2123991188: "Geheugensteun ID", + 3911073154: "Geheugensteun opslag ID", + 570639842: "Geheugensteun is niet ontsleuteld", + 1746030071: "Geheugensteun is niet versleuteld", + 1458925155: "Aangepast: ", + 1845376098: "Multisig", + 2939797024: "Netwerk", + 73574491: "Geheugensteun aanmaken", + 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", + 4063104189: "Nee", + 3927838899: "Geen BIP-39 wachtwoord", + 4092516657: "Niet genoeg gedobbeld!", + 1577637745: "Octaal", + 3312581301: "PBKDF2 iter.", 721090621: "PSBT", - 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", - 2987800462: "Chiều rộng giấy", - 3050763890: "Phần\n%d / %d", - 3559456868: "Kích thước một phần", - 4249903283: "Cụm mật khẩu", - 3712257341: "Cụm cụm:", - 140802882: "Vị trí lưu", - 1703779997: "Văn bản rõ QR", - 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", - 784609464: "Tỷ lệ sụt giảm", - 3037062877: "In kiểm tra QR", - 4278257699: "In ra mã QR?\n\n%s\n\n", - 516488026: "In?\n\n%s\n\n", - 1123106929: "Máy in", - 3903571079: "Trình điều khiển máy in không đặt!", - 2609799302: "Đang in\n%d / %d", - 844861889: "In ấn ...", - 2580599003: "Thực hiện?", - 556126964: "Xử lý ...", - 1848310591: "Mã QR", - 710709610: "RX Ghim", - 2697857197: "Nhận được", - 1746677167: "Nhận địa chỉ", - 364354944: "Vùng: ", - 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", - 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", - 856795528: "Súc sắc cuộn:\n\n%s", - 255086803: "Súc sắc cuộn: %d\n", - 3976793317: "Thẻ SD", - 2827687530: "Thẻ SD không được phát hiện", - 2736513298: "Thẻ SD không được phát hiện.", - 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", - 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", + 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", + 2987800462: "Papier breedte", + 3050763890: "Deel\n%d / %d", + 3559456868: "Deel grootte", + 4249903283: "Wachtwoord", + 3712257341: "Wachtwoord: ", + 140802882: "Opslag", + 1703779997: "Platte tekst QR", + 3561756278: "Laadt een portemonnee descriptor in", + 784609464: "Duik tarief", + 3037062877: "Test QR afdrukken", + 4278257699: "Afdrukken naar QR?\n\n%s\n\n", + 516488026: "Afdrukken?\n\n%s\n\n", + 1123106929: "Printer", + 3903571079: "Printer driver niet ingesteld!", + 2609799302: "Afdruk\n%d / %d", + 844861889: "Afdrukken...", + 2580599003: "Doorgaan?", + 556126964: "Verwerken...", + 1848310591: "QR code", + 710709610: "RX pin", + 2697857197: "Ontvangen", + 1746677167: "Ontvangstadres", + 364354944: "Regio: ", + 1662254634: "Controleer gescande gegevens en bewerk indien nodig", + 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", + 856795528: "Gedobbeld:\n\n%s", + 255086803: "Gedobbeld: %d\n", + 3976793317: "SD kaart", + 2827687530: "SD kaart niet gedetecteerd", + 2736513298: "SD kaart niet gedetecteerd.", + 3593785196: "Gedobbelde SHA256:\n\n%s", + 1143278725: "Momentopname van SHA256:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Lưu vào thẻ SD?", - 810036588: "Đã lưu vào thẻ SD:\n%s", - 763824768: "Cái cân", - 4117455079: "Quét địa chỉ", - 3219991109: "Quét BIP39 Cụm cụm", - 2537207336: "Quét mã QR khóa", - 4006316572: "Quét lại từ 1-12", - 2736506158: "Quét từ 13-24", - 266935239: "SEEDQR", - 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", - 473154195: "Cài đặt", - 1825881236: "Tắt", - 2120776272: "Đang tắt..", - 1061961408: "Chữ kí", - 4282338366: "Kí?", - 746161122: "Chữ ký", - 1988416729: "Tin nhắn đã ký", - 3672006076: "Đã ký PSBT", - 2281377987: "Khóa đơn", - 4221794628: "Dung lượng: ", - 2309020186: "Chi tiêu (%d): ", + 3531742595: "Opslaan op SD-kaart?", + 810036588: "Opgeslagen op SD-kaart:\n%s", + 763824768: "Schaal", + 4117455079: "Adres scannen", + 3219991109: "BIP-39 wachtwoord scannen", + 2537207336: "QR code sleutel scannen", + 4006316572: "Woorden 1 t/m 12 opnieuw scannen", + 2736506158: "Woorden 13 t/m 24 scannen", + 3593497655: "Screensaver", + 266935239: "SeedQR", + 1698829144: "Zelf overschrijving of wisselgeld (%d): ", + 473154195: "Instellingen", + 1825881236: "Afsluiten", + 2120776272: "Bezig met afsluiten...", + 1061961408: "Ondertekenen", + 4282338366: "Ondertekenen?", + 746161122: "Handtekening", + 1988416729: "Bericht ondertekend", + 3672006076: "PSBT ondertekend", + 2281377987: "Enkele sleutel", + 4221794628: "Grootte: ", + 2309020186: "Uitgaven (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Lưu trữ trên flash", - 720041451: "Lưu trữ trên thẻ SD", - 3514476519: "Vuốt để thay đổi chế độ", - 1898550184: "TOUCH hoặc ENTER để chụp", - 4228215415: "TX Ghim", - 2612594937: "Chữ", - 1454688268: "Chủ đề", - 1180180513: "Nhiệt", + 3303592908: "Opslaan op apparaat", + 720041451: "Opslaan op SD kaart", + 3514476519: "Verander modus", + 1898550184: "TIK of ENTER voor opname", + 4228215415: "TX pin", + 2612594937: "Tekst", + 1454688268: "Thema", + 1180180513: "Thermisch", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bit)", - 725348723: "Công cụ", - 3684696112: "Ngưỡng cảm ứng", - 2978718564: "Màn hình cảm ứng", - 2732611775: "Thử thêm nữa?", - 1487826746: "Nhập cụm BIP39", - 2061556020: "Nhập khóa", - 2089395053: "Đơn vị", - 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", - 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", - 2736001501: "Nâng cấp firmware..\n\n%d%%", - 2674953168: "Sử dụng bề mặt nền đen.", - 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", - 236075140: "Đã sử dụng: ", - 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", - 4191058607: "Qua máy ảnh", - 1254681955: "Qua D20", - 525309547: "Qua D6", - 590330112: "Thông qua đầu vào thủ công", - 2504354847: "Chờ bắt", - 2297028319: "Trình mô tả ví", - 4232654916: "Ví đầu ra mô tả", - 2587172867: "Đã tải bộ mô tả đầu ra của ví!", - 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", - 1831109430: "Cảnh báo:\nBộ mô tả đầu ra chưa hoàn chỉnh", - 797660533: "Kí tự %d", - 3742424146: "Từ số", - 2965123464: "Từ ngữ", - 1303016265: "Đúng", - 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", - 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Hulpmiddelen", + 3684696112: "Aanraak gevoeligheid", + 2978718564: "Aanraakscherm", + 2732611775: "Meer proberen?", + 1487826746: "Voer BIP-39 wachtwoord in", + 2061556020: "Voer sleutel in", + 2089395053: "Eenheid", + 2845607430: "Bootloader updaten...\n\n%d%%", + 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", + 2736001501: "Firmware upgraden...\n\n%d%%", + 2674953168: "Gebruik een donker achergrond.", + 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", + 236075140: "Gebruikt: ", + 4003084591: "Waarde %s is buiten bereik: [%s, %s]", + 4191058607: "Via camera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Via handmatige invoer", + 2504354847: "Wacht op opname", + 3992434312: "Wacht tijd", + 2297028319: "Descriptor", + 4232654916: "Portemonnee descriptor", + 2587172867: "Portemonnee descriptor geladen!", + 2499782468: "Portemonnee descriptor niet gevonden.", + 1831109430: "Waarschuwing:\nIncomplete portemonnee descriptor", + 797660533: "Woord %d", + 3742424146: "Woord nummers", + 2965123464: "Woorden", + 1303016265: "Yes", + 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", + 2569054451: "Veranderingen worden opgeslagen op SD kaart.", }, - "fr-FR": { - 1185266064: "%d de %d multisignature", - 2004520398: "%d. Changement : \n\n%s\n\n", - 3862364126: "%d. Auto-transfert : \n\n%s\n\n", - 3264377309: "%d. Dépense : \n\n%s\n\n", - 2399232215: "%s\n\nest une adresse changement valide!", - 3921290840: "%s\n\nest une adresse reçue valide!", - 1808355833: "INTROUVABLE dans les premières %d adresses de changement", - 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", - 3348584292: "(Expérimental)", - 2739590230: "12 mots", - 1310058127: "24 mots", + "pt-BR": { + 1185266064: "%d da %d multisig", + 2004520398: "%d. Troco: \n\n%s\n\n", + 3862364126: "%d. Autotransferência: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n é um endereço de troco válido!", + 3921290840: "%s\n\né um endereço de recepção válido!", + 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", + 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", + 3348584292: "(Experimental)", + 2739590230: "12 palavras", + 1310058127: "24 palavras", 2743272264: "ABC", - 1949634023: "À propos", + 1949634023: "Sobre", 1517128857: "Adafruit", - 3270727197: "Adresse", - 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", - 283202181: "Alignez correctement la caméra et Tiny Seed.", - 88746165: "Anti-éblouissement désactivé", - 1521033296: "Anti-éblouissement activé", - 1056821534: "Es-tu sûr?", - 3247612282: "BIP39 Mnémonique", - 3455872521: "Retour", - 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", - 2256777600: "Mauvaise signature", - 3937333362: "Débit en bauds", + 3270727197: "Endereço", + 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", + 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", + 88746165: "Antirreflexo desativado", + 1521033296: "Antirreflexo ativado", + 1056821534: "Tem certeza?", + 3247612282: "Mnemônico BIP39", + 3455872521: "Voltar", + 2541860807: "Backing up bootloader..\n\n%d%%", + 2256777600: "Assinatura Inválida", + 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Rembourrage de bordure", + 928727036: "Borda", 213030954: "CNC", - 1207696150: "Changement", - 3126552510: "Adresses de Changement", - 1583186953: "Changer de thème et redémarrer?", - 2697733395: "Modifications enregistrées sur la carte SD!", - 388908871: "Les modifications dureront jusqu'à l'arrêt.", - 3442025874: "Vérifiez la carte SD", - 3119547911: "Vérifiez que l'adresse appartient à cette portefeuille?", - 2856261511: "Adresses %d changement vérifiées sans correspondance.", - 2788541416: "Adresses %d reçues vérifiées sans correspondance.", - 2446472910: "Vérification de l'adresse changement %d pour correspondance..", - 2470115694: "Vérification de la carte SD..", - 3655273987: "Vérification de l'adresse reçue %d pour correspondance..", - 2407028014: "SeedQR Compact", - 4041895036: "Continuer?", - 4094072796: "Créer du code QR", - 167798282: "Créer du code QR à partir du texte?", - 2767642191: "Créé:", - 3513215254: "Code QR personnalisé", - 124617190: "Profondeur de coupe", - 597912140: "Méthode de coupe", - 2504034831: "Décimal", - 2751113454: "Décrypter?", - 1016609898: "Supprimer le fichier?", - 1364509700: "Supprimer mnémonique", - 4102535566: "Profondeur par passage", - 2791699253: "Dérivation: %s", - 1230133196: "Stockage flash de l'appareil non détecté.", - 3836852788: "Terminé?", - 382368239: "Conducteur", - 3978947916: "Encodeur", - 4090746898: "Anti-rebond de l'encodeur", - 374684711: "Crypter mnémonique", - 1244124409: "Code QR crypté", - 2968548114: "Le mnémonique crypté n'a pas été stocké", - 3315319371: "Mnémonique cryptée a été stockée avec ID:", - 350279787: "Chiffrement", - 2601598799: "Mode de chiffrement", - 3504179008: "Entrez chaque mot de votre BIP-39 mnémonique sous la forme d'un nombre 1 jusqu'à 2048.", - 1100685007: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en hexadécimal de 1 à 800.", - 4090266642: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en octal de 1 à 4000.", - 2780625730: "Entrez chaque mot de votre BIP-39 mnémonique.", - 784361051: "Erreur:\n%s", + 1207696150: "Troco", + 3126552510: "Endereços de Troco", + 1583186953: "Mudar o tema e reiniciar?", + 2697733395: "Mudanças salvas no cartão SD!", + 388908871: "Alterações só durarão até o desligamento.", + 3442025874: "Verifique o cartão SD", + 3119547911: "Verificar se este endereço pertence a carteira?", + 2856261511: "Endereço de troco %d não corresponde.", + 2788541416: "Endereço de recebimento %d não corresponde.", + 2446472910: "Verificando correspondência do endereço de troco %d ..", + 2470115694: "Verificando o cartão SD..", + 3655273987: "Verificando correspondência do endereço de recebimento %d ..", + 2407028014: "SeedQR Compacto", + 4041895036: "Continuar?", + 4094072796: "Gerar Código QR", + 167798282: "Gerar código QR do texto?", + 2767642191: "Criado: ", + 3513215254: "Código QR Customizado", + 124617190: "Profundidade de Corte", + 597912140: "Método de Corte", + 2504034831: "Decimal", + 2751113454: "Descriptografar?", + 1016609898: "Excluir Arquivo?", + 1364509700: "Excluir Mnemônico", + 4102535566: "Profundidade da Passagem", + 2791699253: "Derivação: %s", + 1230133196: "Armazenamento flash do dispositivo não detectado.", + 3836852788: "Feito?", + 382368239: "Driver", + 3978947916: "Codificador", + 4090746898: "Debounce do Encoder", + 374684711: "Criptografar Mnemônico", + 1244124409: "Código QR Criptografado", + 2968548114: "Mnemonic criptografado não foi armazenado", + 3315319371: "Mnemônico criptografado foi armazenado com ID:", + 350279787: "Criptografia", + 2601598799: "Modo de Criptografia", + 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", + 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", + 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", + 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", + 784361051: "Erro:\n%s", 1505332462: "Esc", - 3838465623: "Explorer des fichiers?", - 4170881190: "Exportation vers la carte SD..", - 1711312434: "Clé publique", - 383371114: "Échec de décrypter", - 3048830188: "Erreur de chargement PSBT", - 4192663412: "Erreur de chargement d'adresse", - 1996021743: "Échec du chargement de la clé", - 1108715658: "Échec du chargement du message", - 1081425878: "Erreur de chargement mnémonique", - 928667220: "Échec du chargement du descripteur de sortie", - 1620572516: "Échec du chargement de la phrase secrète", - 2946146830: "Échec de stocker mnémonique", - 1303554751: "Frais: ", - 104500973: "Taux d'alimentation", - 3313339187: "Nom de fichier", - 1982637349: "Le nom de fichier %s existe sur la carte SD, écraser ?", - 3737729752: "Empreinte Digitale: %s", - 2542772894: "Le micrologiciel dépasse la taille maximale: %d", - 1406590538: "Diamètre de flûte", - 3086093110: "Libre: ", - 1893243331: "Du stockage", + 3838465623: "Explorar arquivos?", + 4170881190: "Exportando para o cartão SD..", + 1711312434: "Chave Pública Estendida", + 383371114: "Falhou em descriptografar", + 3048830188: "Falhou ao carregar PSBT", + 4192663412: "Falhou ao carregar endereço", + 1996021743: "Falha ao carregar a chave", + 1108715658: "Falhou ao carregar mensagem", + 1081425878: "Falhou ao carregar mnemônico", + 928667220: "Falha ao carregar o descritor de saída", + 1620572516: "Falha ao carregar a senha", + 2946146830: "Falhou ao armazenar mnemônico", + 1303554751: "Taxa: ", + 104500973: "Taxa de Alimentação", + 3313339187: "Nome do arquivo", + 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", + 3737729752: "Impressão digital: %s", + 2542772894: "Firmware excede o tamanho máximo: %d", + 1406590538: "Diâmetro da Fresa", + 3086093110: "Livre: ", + 1893243331: "Do Armazenamento", 4120536442: "GRBL", - 299338213: "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", - 602716148: "Go", - 831562513: "Intervalle de chauffe", - 2300171403: "Temps de chauffe", - 3580020863: "Clé public hexadécimal", - 2691246967: "Hexadécimal", - 2736309107: "Id existe déjà\n", - 631342955: "Entrées (%d) : ", - 2585599782: "Adresse invalide", - 2874529150: "Chargeur de démarrage invalide", - 4093416954: "Longueur mnémonique invalide", - 1422874211: "Clé publique non valide", - 2443867979: "Portefeuille invalide:\n%s", - 4122897393: "Inverser", - 3000888649: "Clé", - 2686333978: "Clé:", - 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Test de l'imprimante Krux QR", - 766317539: "Langue", - 972436696: "Délai de Ligne", - 3596093890: "Ligne: ", - 2820726296: "Charger mnémonique", - 879727077: "Charger depuis la carte SD ?", - 669106195: "En charger qu'un?", - 3330705289: "Charger?", - 2596531078: "Caméra de Chargement..", - 596389387: "Chargement de l'adresse de changement %d..", - 336702608: "Chargement de l'imprimante..", - 2538883522: "Chargement de l'adresse de réception %d..", - 3159494909: "Chargement..", - 1177338798: "Paramètres régionaux", - 2817059741: "Emplacement", - 63976957: "Niveau de journalisation", - 86530918: "Enregistrement", - 2917810189: "Longueur maximale dépassée (% s)", - 2030045667: "Message", - 3928301843: "Fichier de signature manquant", - 1948316555: "Mnémonique", - 2123991188: "ID mnémonique", - 3911073154: "ID de stockage mnémonique", - 570639842: "Mnémonique n'a pas été décryptée", - 1746030071: "Mnémonique n'était pas cryptée", - 1458925155: "Modifié:", - 1845376098: "Multi\nsignature", - 2939797024: "Réseau", - 73574491: "Nouveau mnémonique", - 2792272353: "Nouveau micrologiciel détecté.\n\nSHA256:\n%s\n\n\n\nInstaller?", - 4063104189: "Non", - 3927838899: "Pas de phrase passante bip39", - 4092516657: "Pas assez de rouleaux !", - 1577637745: "Octale", - 3312581301: "Itér. PBKDF2", + 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", + 602716148: "Ir", + 831562513: "Intervalo de Aquecimento", + 2300171403: "Tempo de Aquecimento", + 3580020863: "Chave pública hexadecimal", + 2691246967: "Hexadecimal", + 2736309107: "Id já existe\n", + 631342955: "Entradas (%d): ", + 2585599782: "Endereço inválido", + 2874529150: "Bootloader inválido", + 4093416954: "Comprimento de mnemônico inválido", + 1422874211: "Chave pública inválida", + 2443867979: "Carteira inválida:\n%s", + 4122897393: "Invertido", + 3000888649: "Chave", + 2686333978: "Chave:", + 4123798664: "Krux\n\n\nVersão\n%s", + 3835918229: "Teste de impressão de QR krux", + 766317539: "Língua", + 972436696: "Atraso de Linha", + 3596093890: "Linha: ", + 2820726296: "Carregar Mnemônico", + 879727077: "Carregar do cartão SD?", + 669106195: "Carregar um?", + 3330705289: "Carregar?", + 2596531078: "Carregando Câmera..", + 596389387: "Carregando endereço de troco %d..", + 336702608: "Carregando impressora..", + 2538883522: "Carregando endereço de recebimento %d..", + 3159494909: "Carregando..", + 1177338798: "Idioma", + 2817059741: "Local", + 63976957: "Nível de log", + 86530918: "Logging", + 2917810189: "Comprimento máximo excedido (%s)", + 2030045667: "Mensagem", + 3928301843: "Arquivo de assinatura faltando", + 1948316555: "Mnemônico", + 2123991188: "ID do mnemônico", + 3911073154: "ID de armazenamento", + 570639842: "Mnemônico não foi descriptografado", + 1746030071: "Mnemônico não foi criptografado", + 1458925155: "Modificado:", + 1845376098: "Multisig", + 2939797024: "Rede", + 73574491: "Novo Mnemônico", + 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", + 4063104189: "Não", + 3927838899: "Sem senha BIP39", + 4092516657: "Jogadas insuficientes!", + 1577637745: "Octal", + 3312581301: "Iter. PBKDF2", 721090621: "PSBT", - 995862913: "Peignez les points perforés en noir afin qu'ils puissent être détectés.", - 2987800462: "Largeur du papier", - 3050763890: "Partie\n%d / %d", - 3559456868: "Taille de la pièce", - 4249903283: "Phrase de passe", - 3712257341: "Phrass de passe:", - 140802882: "Persister", - 1703779997: "QR en Texte Brut", - 3561756278: "Veuillez charger un descripteur de sortie de portefeuille", - 784609464: "Taux de plongée", - 3037062877: "Test d'impression QR", - 4278257699: "Imprimer en QR?\n\n%s\n\n", - 516488026: "Imprimer?\n\n%s\n\n", - 1123106929: "Imprimante", - 3903571079: "Le conducteur d'imprimante n'est pas défini!", - 2609799302: "Impression\n%d / %d", - 844861889: "Impression ...", - 2580599003: "Procéder?", - 556126964: "Traitement ...", - 1848310591: "QR Code", - 710709610: "RX Fiche", - 2697857197: "Recevoir", - 1746677167: "Adresses de Réception", - 364354944: "Région: ", - 1662254634: "Examinez les données numérisées, modifiez-les si nécessaire", - 770350922: "Lancez le dé au moins %d fois pour générer un mnémonique.", - 856795528: "Rouleaux:\n\n%s", - 255086803: "Rouleaux: %d\n", - 3976793317: "Carte SD", - 2827687530: "Carte SD non détectée", - 2736513298: "Carte SD non détectée.", - 3593785196: "SHA256 de rouleaux:\n\n%s", - 1143278725: "Sha256 de Snapshot:\n\n% s", + 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", + 2987800462: "Largura do papel", + 3050763890: "Parte\n%d / %d", + 3559456868: "Tamanho da peça", + 4249903283: "Senha", + 3712257341: "Senha:", + 140802882: "Salvar", + 1703779997: "QR em Texto", + 3561756278: "Carregue um descritor da carteira", + 784609464: "Taxa de Mergulho", + 3037062877: "Imprimir QR de teste", + 4278257699: "Imprimir QR?\n\n%s\n\n", + 516488026: "Imprimir?\n\n%s\n\n", + 1123106929: "Impressora", + 3903571079: "Driver de impressora não está definido!", + 2609799302: "Imprimindo\n%d / %d", + 844861889: "Imprimindo ...", + 2580599003: "Seguir?", + 556126964: "Processando ...", + 1848310591: "Código QR", + 710709610: "Pino RX", + 2697857197: "Recebimento", + 1746677167: "Endereços de Recebimento", + 364354944: "Região: ", + 1662254634: "Revise os dados, edite se necessário", + 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", + 856795528: "Jogadas:\n\n%s", + 255086803: "Jogadas: %d\n", + 3976793317: "Cartão SD", + 2827687530: "Cartão SD não detectado", + 2736513298: "Cartão SD não detectado.", + 3593785196: "SHA256 de jogadas:\n\n%s", + 1143278725: "Sha256 da imagem:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Enregistrer sur la carte SD ?", - 810036588: "Enregistré sur la carte SD :\n%s", - 763824768: "L'échelle", - 4117455079: "Scannez l'adresse", - 3219991109: "Scan bip39 en phrase secrète", - 2537207336: "Scanner le code QR de la clé", - 4006316572: "Analyser à nouveau les mots 1 à 12", - 2736506158: "Analyser les mots 13 à 24", - 266935239: "Seedqr", - 1698829144: "Auto-transfert ou changement (%d): ", - 473154195: "Paramètres", - 1825881236: "Fermer", - 2120776272: "Éteindre..", - 1061961408: "Signature", - 4282338366: "Signature?", - 746161122: "Signature", - 1988416729: "Message signé", - 3672006076: "PSBT signé", - 2281377987: "Clé unique", - 4221794628: "Capacité: ", - 2309020186: "Dépense (%d) : ", + 3531742595: "Salvar no cartão SD?", + 810036588: "Salvo no cartão SD:\n%s", + 763824768: "Escala", + 4117455079: "Escanear Endereço", + 3219991109: "Escanear a senha BIP39", + 2537207336: "Escanear código QR da chave", + 4006316572: "Escaneando as palavras 1-12 novamente", + 2736506158: "Escaneando as palavras 13-24", + 3593497655: "Protetor de tela", + 266935239: "SeedQR", + 1698829144: "Autotransferência ou Troco (%d): ", + 473154195: "Configurações", + 1825881236: "Desligar", + 2120776272: "Desligando..", + 1061961408: "Assinar", + 4282338366: "Assinar?", + 746161122: "Assinatura", + 1988416729: "Mensagem Assinada", + 3672006076: "PSBT Assinada", + 2281377987: "Single-sig", + 4221794628: "Total: ", + 2309020186: "Gastos (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Stocker sur flash", - 720041451: "Stocker sur la carte SD", - 3514476519: "Faites glisser pour changer de mode", - 1898550184: "TOUCHEZ ou ENTER pour capturer", - 4228215415: "TX Fiche", - 2612594937: "Texte", - 1454688268: "Thème", - 1180180513: "Thermique", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Outils", - 3684696112: "Seuil Tactile", - 2978718564: "Écran Tactile", - 2732611775: "Réessayer?", - 1487826746: "Type Bip39 Plasque", - 2061556020: "Clé de type", - 2089395053: "Unité", - 2845607430: "Mise à jour du chargeur de démarrage..\n\n%d%%", - 4164597446: "Mise à niveau complète.\n\nÉteindre..", - 2736001501: "Mise à niveau du micrologiciel..\n\n%d%%", - 2674953168: "Utilisez une surface de fond noire.", - 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", - 236075140: "Utilisé: ", - 4003084591: "Valeur% s hors de portée: [% s,% s]", - 4191058607: "Par caméra", + 3303592908: "Armazene na Flash", + 720041451: "Armazene no Cartão SD", + 3514476519: "Deslize para mudar de modo", + 1898550184: "TOQUE ou ENTER para capturar", + 4228215415: "Pino TX", + 2612594937: "Texto", + 1454688268: "Tema", + 1180180513: "Térmica", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (bits)", + 725348723: "Ferramentas", + 3684696112: "Limiar de Toque", + 2978718564: "Touchscreen", + 2732611775: "Tentar mais?", + 1487826746: "Digitar a senha BIP39", + 2061556020: "Digite a Chave", + 2089395053: "Unidade", + 2845607430: "Atualizando bootloader..\n\n%d%%", + 4164597446: "Atualização completa.\n\nDesligando..", + 2736001501: "Atualizando firmware..\n\n%d%%", + 2674953168: "Use uma superfície de fundo preta.", + 2402455261: "Use a entropia da câmera para criar um novo mnemônico", + 236075140: "Usado: ", + 4003084591: "Valor %s fora do alcance: [ %s, %s]", + 4191058607: "Pela Câmera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Par saisie manuelle", - 2504354847: "Attendez la capture", - 2297028319: "Descripteur de Portefeuille", - 4232654916: "Descripteur de sortie du portefeuille", - 2587172867: "Descripteur de sortie du portefeuille chargé!", - 2499782468: "Descripteur de sortie du portefeuille introuvable.", - 1831109430: "Attention:\nDescripteur de sortie incomplet", - 797660533: "Mot %d", - 3742424146: "Numéros de mots", - 2965123464: "Mots", - 1303016265: "Oui", - 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", - 2569054451: "Vos modifications seront conservées sur la carte SD.", + 590330112: "Por entrada manual", + 2504354847: "Aguarde a captura", + 3992434312: "Tempo de espera", + 2297028319: "Descritor de Carteira", + 4232654916: "Descritor da carteira", + 2587172867: "Descritor de saída da carteira carregado!", + 2499782468: "O descritor de saída da carteira não foi encontrado.", + 1831109430: "Atenção:\nDescritor de saída incompleto", + 797660533: "Palavra %d", + 3742424146: "Números das Palavras", + 2965123464: "Palavras", + 1303016265: "Sim", + 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", + 2569054451: "Suas alterações serão mantidas no cartão SD.", }, - "nl-NL": { - 1185266064: "%d van %d multisig", - 2004520398: "%d. Wisselgeld: \n\n%s\n\n", - 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", - 3264377309: "%d. Uitgaven: \n\n%s\n\n", - 2399232215: "%s\n\nis een valide wisselgeld adres!", - 3921290840: "%s\n\nis een valide ontvangst adres!", - 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", - 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", - 3348584292: "(Experimenteel)", - 2739590230: "12 woorden", - 1310058127: "24 woorden", + "vi-VN": { + 1185266064: "%d của %d đa chữ kí", + 2004520398: "%d. Thay đổi: \n\n%s\n\n", + 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", + 3264377309: "%d. Chi tiêu: \n\n%s\n\n", + 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", + 3921290840: "%s\n\nlà một địa chỉ khả dụng!", + 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 3348584292: "(Thực nghiệm)", + 2739590230: "12 từ", + 1310058127: "24 từ", 2743272264: "ABC", - 1949634023: "Over", + 1949634023: "Về chúng tôi", 1517128857: "Adafruit", - 3270727197: "Adres", - 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", - 283202181: "Richt de camera en Tiny Seed op de juiste manier.", - 88746165: "Anti reflecterend uitgeschakeld", - 1521033296: "Anti reflecterend ingeschakeld", - 1056821534: "Weet je het zeker?", - 3247612282: "BIP-39 geheugensteun", - 3455872521: "Terug", - 2541860807: "Backup van de bootloader...\n\n%d%%", - 2256777600: "Ongeldige handtekening", - 3937333362: "Baudratio", + 3270727197: "Địa chỉ", + 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", + 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", + 88746165: "Chống lóa bị vô hiệu hóa", + 1521033296: "Đã bật chống lóa", + 1056821534: "Bạn có chắc không?", + 3247612282: "Mã mnemonic dạng chuẩn BIP39", + 3455872521: "Trở lại", + 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", + 2256777600: "Chữ ký xấu", + 3937333362: "Tốc độ baud", 427617266: "Bitcoin", - 928727036: "Rand opvulling", + 928727036: "Đệm viền", 213030954: "CNC", - 1207696150: "Change", - 3126552510: "Wisselgeldadres", - 1583186953: "Thema veranderen en opnieuw opstarten?", - 2697733395: "Wijzigingen aanhouden op SD kaart!", - 388908871: "Wijzigingen blijven van kracht tot afsluiten.", - 3442025874: "Controleer SD kaart", - 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", - 2856261511: "Na %d geen wisselgeld adressen gevonden.", - 2788541416: "Na %d geen ontvangst adressen gevonden.", - 2446472910: "Wisselgeldadres %d controleren...", - 2470115694: "SD kaart controleren...", - 3655273987: "Ontvangstadres %d controleren...", - 2407028014: "Compact SeedQR", - 4041895036: "Doorgaan?", - 4094072796: "QR code maken", - 167798282: "QR code maken van tekst?", - 2767642191: "Aangemaakt: ", - 3513215254: "Aangepaste QR code", - 124617190: "Snijdiepte", - 597912140: "Snijmethode", - 2504034831: "Decimaal", - 2751113454: "Ontsleutelen?", - 1016609898: "Bestand verwijderen?", - 1364509700: "Geheugensteun verwijderen", - 4102535566: "Diepte per pas", - 2791699253: "Afgeleide: %s", - 1230133196: "Opslag op apparaat is niet gedetecteerd.", - 3836852788: "Klaar?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-debounce", - 374684711: "Geheugensteun versleutelen", - 1244124409: "Versleutelde QR code", - 2968548114: "Versleutelde geheugensteun was niet opgeslagen", - 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", - 350279787: "Versleutelen", - 2601598799: "Versleutel modus", - 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", - 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", - 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", - 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", - 784361051: "Fout:\n%s", + 1207696150: "Thay đổi", + 3126552510: "Thay địa chỉ", + 1583186953: "Thay đổi chủ đề và khởi động lại?", + 2697733395: "Thay đổi được lưu trên thẻ SD!", + 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", + 3442025874: "Kiểm tra thẻ SD", + 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", + 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", + 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", + 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", + 2470115694: "Kiểm tra thẻ SD..", + 3655273987: "Đang kiểm tra %d địa chỉ..", + 2407028014: "SeedQR nhỏ gọn", + 4041895036: "Tiếp tục?", + 4094072796: "Tạo mã QR", + 167798282: "Tạo mã QR từ văn bản?", + 2767642191: "Tạo:", + 3513215254: "Mã QR tùy chỉnh", + 124617190: "Chiều sâu cắt", + 597912140: "Phương pháp cắt", + 2504034831: "Số thập phân", + 2751113454: "Phản đối?", + 1016609898: "Xóa tài liệu?", + 1364509700: "Xóa ghi nhớ", + 4102535566: "Độ sâu mỗi lần vượt qua", + 2791699253: "Nguồn gốc: %s", + 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", + 3836852788: "Hoàn tất?", + 382368239: "Người cầm lái", + 3978947916: "Mã hoá", + 4090746898: "Gỡ lỗi bộ mã hóa", + 374684711: "Mã hóa Mnemonic", + 1244124409: "Mã QR được mã hóa", + 2968548114: "MNemon được mã hóa không được lưu trữ", + 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", + 350279787: "Mã hóa", + 2601598799: "Chế độ mã hóa", + 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", + 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", + 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", + 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", + 784361051: "Lỗi:\n%s", 1505332462: "Esc", - 3838465623: "Bestanden verkennen?", - 4170881190: "Exporteren naar SD-kaart..", - 1711312434: "Uitgebreide publieke sleutel", - 383371114: "Ontsleutelen is niet gelukt", - 3048830188: "PSBT laden is niet gelukt", - 4192663412: "Adres laden is niet gelukt", - 1996021743: "Sleutel laden is niet gelukt", - 1108715658: "Bericht laden is niet gelukt", - 1081425878: "Geheugensteun laden is niet gelukt", - 928667220: "Descriptor laden is niet gelukt", - 1620572516: "Wachtwoord laden is niet gelukt", - 2946146830: "Geheugensteun opslaan is niet gelukt", - 1303554751: "Tarief: ", - 104500973: "Voedingssnelheid", - 3313339187: "Bestandsnaam", - 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", - 3737729752: "Vingerafdruk: %s", - 2542772894: "Firmware overschrijdt de maximale grootte: %d", - 1406590538: "Fluit diameter", - 3086093110: "Vrij: ", - 1893243331: "Uit data-opslag", - 4120536442: "GRBL", - 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", - 602716148: "Ga", - 831562513: "Warmte interval", - 2300171403: "Warmte tijd", - 3580020863: "Hex publieke sleutel", - 2691246967: "Hexadecimaal", - 2736309107: "ID bestaat al\n", - 631342955: "Invoer (%d): ", - 2585599782: "Ongeldig adres", - 2874529150: "Ongeldige bootloader", - 4093416954: "Ongeldige geheugensteun lengte", - 1422874211: "Ongeldige publieke sleutel", - 2443867979: "Ongeldige portemonnee:\n%s", - 4122897393: "Omkeren", - 3000888649: "Sleutel", - 2686333978: "Sleutel: ", - 4123798664: "Krux\n\n\nVersie\n%s", - 3835918229: "Krux printer test QR", - 766317539: "Taal", - 972436696: "Lijn vertraging", - 3596093890: "Lijn: ", - 2820726296: "Geheugensteun laden", - 879727077: "Laden vanaf SD-kaart?", - 669106195: "Laden?", - 3330705289: "Laden?", - 2596531078: "Camera laden...", - 596389387: "Wisselgeldadres %d laden...", - 336702608: "Laadprinter..", - 2538883522: "Ontvangstadres %d laden...", - 3159494909: "Laden...", - 1177338798: "Taal", - 2817059741: "Opslaglocatie", - 63976957: "Log niveau", - 86530918: "Debug logs", - 2917810189: "Maximale lengte overschreden (%s)", - 2030045667: "Bericht", - 3928301843: "Handtekening bestand mist", - 1948316555: "Geheugensteun", - 2123991188: "Geheugensteun ID", - 3911073154: "Geheugensteun opslag ID", - 570639842: "Geheugensteun is niet ontsleuteld", - 1746030071: "Geheugensteun is niet versleuteld", - 1458925155: "Aangepast: ", - 1845376098: "Multisig", - 2939797024: "Netwerk", - 73574491: "Geheugensteun aanmaken", - 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", - 4063104189: "Nee", - 3927838899: "Geen BIP-39 wachtwoord", - 4092516657: "Niet genoeg gedobbeld!", - 1577637745: "Octaal", - 3312581301: "PBKDF2 iter.", + 3838465623: "Khám phá các tập tin?", + 4170881190: "Xuất vào thẻ SD ..", + 1711312434: "Khóa công cộng", + 383371114: "Không giải mã được", + 3048830188: "Tải PSBT thất bại", + 4192663412: "Tải địa chỉ thất bại", + 1996021743: "Không tải khóa", + 1108715658: "Không tải được tin nhắn", + 1081425878: "Tải mã mnemonic thất bại", + 928667220: "Không thể tải bộ mô tả đầu ra", + 1620572516: "Không tải được cụm mật khẩu", + 2946146830: "Không lưu trữ MNemonic", + 1303554751: "Phí: ", + 104500973: "Tỷ lệ thức ăn", + 3313339187: "Tên tệp", + 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", + 3737729752: "Dấu vân tay: %s", + 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", + 1406590538: "Đường kính ống sáo", + 3086093110: "Khả dụng: ", + 1893243331: "Từ lưu trữ", + 4120536442: "GRBL", + 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", + 602716148: "Đến", + 831562513: "Khoảng thời gian nhiệt", + 2300171403: "Thời gian nhiệt", + 3580020863: "Khóa công khai Hex", + 2691246967: "Thập lục phân", + 2736309107: "Id đã tồn tại\n", + 631342955: "Đầu vào (%d): ", + 2585599782: "Địa chỉ không hợp lệ", + 2874529150: "Bộ tải khởi động không hợp lệ", + 4093416954: "Độ dài mã mnemonic không hợp lệ", + 1422874211: "Khóa công khai không hợp lệ", + 2443867979: "Ví không hợp lệ:\n%s", + 4122897393: "Đảo ngược", + 3000888649: "Chìa khóa", + 2686333978: "Chìa khóa:", + 4123798664: "Krux\n\n\nPhiên Bản\n%s", + 3835918229: "QR kiểm tra máy in Krux", + 766317539: "Ngôn ngữ", + 972436696: "Độ trễ Dòng", + 3596093890: "Đường kẻ: ", + 2820726296: "Tải mã mnemonic", + 879727077: "Tải từ thẻ SD?", + 669106195: "Tải một?", + 3330705289: "Tải?", + 2596531078: "Đang tải máy ảnh..", + 596389387: "Đang tải thay đổi địa chỉ %d..", + 336702608: "Tải máy in ..", + 2538883522: "Đang tải địa chỉ nhận %d..", + 3159494909: "Đang tải..", + 1177338798: "Ngôn ngữ", + 2817059741: "Vị trí cửa hàng", + 63976957: "Log Level", + 86530918: "Khai thác gỗ", + 2917810189: "Chiều dài tối đa vượt quá (%s)", + 2030045667: "Tin nhắn", + 3928301843: "Thiếu tập tin chữ ký", + 1948316555: "Mã mnemonic", + 2123991188: "ID ghi nhớ", + 3911073154: "ID lưu trữ ghi nhớ", + 570639842: "Ghi nhớ không được giải mã", + 1746030071: "Ghi nhớ không được mã hóa", + 1458925155: "Đã sửa đổi:", + 1845376098: "Đa chữ kí", + 2939797024: "Mạng lưới", + 73574491: "Mnemonic mới", + 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", + 4063104189: "Không", + 3927838899: "Không có cụm mật khẩu BIP39", + 4092516657: "Không đủ cuộn!", + 1577637745: "Bát phân", + 3312581301: "Lặp lại PBKDF2", 721090621: "PSBT", - 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", - 2987800462: "Papier breedte", - 3050763890: "Deel\n%d / %d", - 3559456868: "Deel grootte", - 4249903283: "Wachtwoord", - 3712257341: "Wachtwoord: ", - 140802882: "Opslag", - 1703779997: "Platte tekst QR", - 3561756278: "Laadt een portemonnee descriptor in", - 784609464: "Duik tarief", - 3037062877: "Test QR afdrukken", - 4278257699: "Afdrukken naar QR?\n\n%s\n\n", - 516488026: "Afdrukken?\n\n%s\n\n", - 1123106929: "Printer", - 3903571079: "Printer driver niet ingesteld!", - 2609799302: "Afdruk\n%d / %d", - 844861889: "Afdrukken...", - 2580599003: "Doorgaan?", - 556126964: "Verwerken...", - 1848310591: "QR code", - 710709610: "RX pin", - 2697857197: "Ontvangen", - 1746677167: "Ontvangstadres", - 364354944: "Regio: ", - 1662254634: "Controleer gescande gegevens en bewerk indien nodig", - 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", - 856795528: "Gedobbeld:\n\n%s", - 255086803: "Gedobbeld: %d\n", - 3976793317: "SD kaart", - 2827687530: "SD kaart niet gedetecteerd", - 2736513298: "SD kaart niet gedetecteerd.", - 3593785196: "Gedobbelde SHA256:\n\n%s", - 1143278725: "Momentopname van SHA256:\n\n%s", + 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", + 2987800462: "Chiều rộng giấy", + 3050763890: "Phần\n%d / %d", + 3559456868: "Kích thước một phần", + 4249903283: "Cụm mật khẩu", + 3712257341: "Cụm cụm:", + 140802882: "Vị trí lưu", + 1703779997: "Văn bản rõ QR", + 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", + 784609464: "Tỷ lệ sụt giảm", + 3037062877: "In kiểm tra QR", + 4278257699: "In ra mã QR?\n\n%s\n\n", + 516488026: "In?\n\n%s\n\n", + 1123106929: "Máy in", + 3903571079: "Trình điều khiển máy in không đặt!", + 2609799302: "Đang in\n%d / %d", + 844861889: "In ấn ...", + 2580599003: "Thực hiện?", + 556126964: "Xử lý ...", + 1848310591: "Mã QR", + 710709610: "RX Ghim", + 2697857197: "Nhận được", + 1746677167: "Nhận địa chỉ", + 364354944: "Vùng: ", + 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", + 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", + 856795528: "Súc sắc cuộn:\n\n%s", + 255086803: "Súc sắc cuộn: %d\n", + 3976793317: "Thẻ SD", + 2827687530: "Thẻ SD không được phát hiện", + 2736513298: "Thẻ SD không được phát hiện.", + 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", + 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Opslaan op SD-kaart?", - 810036588: "Opgeslagen op SD-kaart:\n%s", - 763824768: "Schaal", - 4117455079: "Adres scannen", - 3219991109: "BIP-39 wachtwoord scannen", - 2537207336: "QR code sleutel scannen", - 4006316572: "Woorden 1 t/m 12 opnieuw scannen", - 2736506158: "Woorden 13 t/m 24 scannen", - 266935239: "SeedQR", - 1698829144: "Zelf overschrijving of wisselgeld (%d): ", - 473154195: "Instellingen", - 1825881236: "Afsluiten", - 2120776272: "Bezig met afsluiten...", - 1061961408: "Ondertekenen", - 4282338366: "Ondertekenen?", - 746161122: "Handtekening", - 1988416729: "Bericht ondertekend", - 3672006076: "PSBT ondertekend", - 2281377987: "Enkele sleutel", - 4221794628: "Grootte: ", - 2309020186: "Uitgaven (%d): ", + 3531742595: "Lưu vào thẻ SD?", + 810036588: "Đã lưu vào thẻ SD:\n%s", + 763824768: "Cái cân", + 4117455079: "Quét địa chỉ", + 3219991109: "Quét BIP39 Cụm cụm", + 2537207336: "Quét mã QR khóa", + 4006316572: "Quét lại từ 1-12", + 2736506158: "Quét từ 13-24", + 3593497655: "Bảo vệ màn hình", + 266935239: "SEEDQR", + 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", + 473154195: "Cài đặt", + 1825881236: "Tắt", + 2120776272: "Đang tắt..", + 1061961408: "Chữ kí", + 4282338366: "Kí?", + 746161122: "Chữ ký", + 1988416729: "Tin nhắn đã ký", + 3672006076: "Đã ký PSBT", + 2281377987: "Khóa đơn", + 4221794628: "Dung lượng: ", + 2309020186: "Chi tiêu (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Opslaan op apparaat", - 720041451: "Opslaan op SD kaart", - 3514476519: "Verander modus", - 1898550184: "TIK of ENTER voor opname", - 4228215415: "TX pin", - 2612594937: "Tekst", - 1454688268: "Thema", - 1180180513: "Thermisch", + 3303592908: "Lưu trữ trên flash", + 720041451: "Lưu trữ trên thẻ SD", + 3514476519: "Vuốt để thay đổi chế độ", + 1898550184: "TOUCH hoặc ENTER để chụp", + 4228215415: "TX Ghim", + 2612594937: "Chữ", + 1454688268: "Chủ đề", + 1180180513: "Nhiệt", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Hulpmiddelen", - 3684696112: "Aanraak gevoeligheid", - 2978718564: "Aanraakscherm", - 2732611775: "Meer proberen?", - 1487826746: "Voer BIP-39 wachtwoord in", - 2061556020: "Voer sleutel in", - 2089395053: "Eenheid", - 2845607430: "Bootloader updaten...\n\n%d%%", - 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", - 2736001501: "Firmware upgraden...\n\n%d%%", - 2674953168: "Gebruik een donker achergrond.", - 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", - 236075140: "Gebruikt: ", - 4003084591: "Waarde %s is buiten bereik: [%s, %s]", - 4191058607: "Via camera", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Via handmatige invoer", - 2504354847: "Wacht op opname", - 2297028319: "Descriptor", - 4232654916: "Portemonnee descriptor", - 2587172867: "Portemonnee descriptor geladen!", - 2499782468: "Portemonnee descriptor niet gevonden.", - 1831109430: "Waarschuwing:\nIncomplete portemonnee descriptor", - 797660533: "Woord %d", - 3742424146: "Woord nummers", - 2965123464: "Woorden", - 1303016265: "Yes", - 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", - 2569054451: "Veranderingen worden opgeslagen op SD kaart.", + 1732872974: "Tiny Seed (bit)", + 725348723: "Công cụ", + 3684696112: "Ngưỡng cảm ứng", + 2978718564: "Màn hình cảm ứng", + 2732611775: "Thử thêm nữa?", + 1487826746: "Nhập cụm BIP39", + 2061556020: "Nhập khóa", + 2089395053: "Đơn vị", + 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", + 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", + 2736001501: "Nâng cấp firmware..\n\n%d%%", + 2674953168: "Sử dụng bề mặt nền đen.", + 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", + 236075140: "Đã sử dụng: ", + 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", + 4191058607: "Qua máy ảnh", + 1254681955: "Qua D20", + 525309547: "Qua D6", + 590330112: "Thông qua đầu vào thủ công", + 2504354847: "Chờ bắt", + 3992434312: "Thời gian chờ đợi", + 2297028319: "Trình mô tả ví", + 4232654916: "Ví đầu ra mô tả", + 2587172867: "Đã tải bộ mô tả đầu ra của ví!", + 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", + 1831109430: "Cảnh báo:\nBộ mô tả đầu ra chưa hoàn chỉnh", + 797660533: "Kí tự %d", + 3742424146: "Từ số", + 2965123464: "Từ ngữ", + 1303016265: "Đúng", + 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", + 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", }, } From f6e5fd65a4f6e1dc6e5eab56fa824b8135f5566d Mon Sep 17 00:00:00 2001 From: tadeubas Date: Fri, 29 Sep 2023 12:06:10 -0300 Subject: [PATCH 033/114] better centralization of the screensaver --- src/krux/context.py | 11 +++++++---- src/krux/display.py | 5 ++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/krux/context.py b/src/krux/context.py index af6fe07d9..df431d8e7 100644 --- a/src/krux/context.py +++ b/src/krux/context.py @@ -38,14 +38,17 @@ class Context: """ def __init__(self, logo=None): + self.display = Display() + if logo is None: logo = [] - self.logo = logo - for _ in range(3): + self.logo = logo + for _ in range((self.display.total_lines - len(logo))//2): self.logo.insert(0, "") self.logo.append("") - self.logo.append("") - self.display = Display() + self.logo.append("") + self.logo.append("") + self.input = Input(screensaver_fallback=self.screensaver) self.camera = Camera() self.light = Light() if "LED_W" in board.config["krux"]["pins"] else None diff --git a/src/krux/display.py b/src/krux/display.py index 170da00f6..eb776e783 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -47,9 +47,8 @@ def __init__(self): self.i2c = None self.font_width = FONT_WIDTH self.font_height = FONT_HEIGHT - self.bottom_line = board.config["lcd"]["width"] // FONT_HEIGHT # total lines - self.bottom_line -= 1 - self.bottom_line *= FONT_HEIGHT + self.total_lines = board.config["lcd"]["width"] // FONT_HEIGHT + self.bottom_line = (self.total_lines - 1) * FONT_HEIGHT if board.config["type"] == "m5stickv": self.bottom_prompt_line = self.bottom_line - DEFAULT_PADDING else: From 2d7f1b796f54d934ec81e9f0d453dfa1d03da1ef Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Fri, 29 Sep 2023 12:56:03 -0300 Subject: [PATCH 034/114] adapt tests to IRQ interface --- src/krux/touch.py | 12 ++- tests/pages/test_login.py | 8 +- tests/pages/test_page.py | 26 +++-- tests/pages/test_tiny_seed.py | 15 ++- tests/pages/test_tools.py | 4 +- tests/shared_mocks.py | 17 ++- tests/test_display.py | 19 ---- tests/test_input.py | 196 ++++++++++++++++------------------ 8 files changed, 149 insertions(+), 148 deletions(-) diff --git a/src/krux/touch.py b/src/krux/touch.py index 144ca2afa..96bbd2c79 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -56,8 +56,9 @@ def __init__(self, width, height, irq_pin=None): self.gesture = None self.state = IDLE self.width, self.height = width, height - touch_control.activate_irq(irq_pin) - touch_control.threshold(Settings().touch.threshold) + self.touch_driver = touch_control + self.touch_driver.activate_irq(irq_pin) + self.touch_driver.threshold(Settings().touch.threshold) def clear_regions(self): """Remove previously stored buttons map""" @@ -127,7 +128,7 @@ def _store_points(self, data): def current_state(self): """Returns the touchscreen state""" self.sample_time = time.ticks_ms() - data = touch_control.current_point() + data = self.touch_driver.current_point() if isinstance(data, tuple): self._store_points(data) elif data is None: # gets release then return to idle. @@ -162,10 +163,11 @@ def event(self): current_time = time.ticks_ms() if current_time > self.sample_time + TOUCH_S_PERIOD: self.current_state() # Update state - if touch_control.event(): + if self.touch_driver.event(): # Resets touch and gets irq point self.state = IDLE - self._store_points(touch_control.irq_point) + if isinstance(self.touch_driver.irq_point, tuple): + self._store_points(self.touch_driver.irq_point) return True return False diff --git a/tests/pages/test_login.py b/tests/pages/test_login.py index 49530d8da..03c80840c 100644 --- a/tests/pages/test_login.py +++ b/tests/pages/test_login.py @@ -1742,8 +1742,6 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): # Paper Width BUTTON_PAGE, BUTTON_PAGE, - BUTTON_PAGE, - BUTTON_PAGE, BUTTON_ENTER, # Change width # Remove digit @@ -1824,6 +1822,7 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): cases = [ ( + # Case 0 ( # Bitcoin 0, @@ -1841,6 +1840,7 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): CategorySetting, ), ( + # Case 1 ( # Printer PRINTER_INDEX, @@ -1851,7 +1851,7 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): NEXT_INDEX, GO_INDEX, # Back to Thermal - 8, + 6, # Back to Printer 3, # Leave Settings @@ -1865,6 +1865,7 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): CategorySetting, ), ( + # Case 2 ( # Language LOCALE_INDEX, @@ -1880,6 +1881,7 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): CategorySetting, ), ( + # Case 3 ( # Logging LOGGING_INDEX, diff --git a/tests/pages/test_page.py b/tests/pages/test_page.py index f9160cace..eb26e6884 100644 --- a/tests/pages/test_page.py +++ b/tests/pages/test_page.py @@ -37,6 +37,19 @@ def test_init(mocker, m5stickv, mock_page_cls): assert isinstance(page, Page) +def test_flash_text(mocker, m5stickv, mock_page_cls): + import krux + + ctx = mock_context(mocker) + mocker.patch("time.ticks_ms", new=lambda: 0) + page = mock_page_cls(ctx) + page.flash_text("Hello world", krux.display.lcd.WHITE, 0, 1000) + + assert ctx.display.clear.call_count == 2 + ctx.display.draw_centered_text.assert_called_once() + krux.pages.time.sleep_ms.assert_called_with(1000) + + def test_capture_qr_code(mocker, m5stickv, mock_page_cls): mocker.patch( "krux.camera.sensor.snapshot", new=snapshot_generator(outcome=SNAP_SUCCESS) @@ -50,6 +63,7 @@ def test_capture_qr_code(mocker, m5stickv, mock_page_cls): mocker.patch("time.ticks_ms", new=lambda: 0) page = mock_page_cls(ctx) + ctx.input.flush_events() qr_code, qr_format = page.capture_qr_code() assert qr_code == "12345678910" @@ -60,7 +74,7 @@ def test_capture_qr_code(mocker, m5stickv, mock_page_cls): ctx.display.draw_centered_text.assert_has_calls([mocker.call("Loading Camera..")]) -def test_camera_antiglare_light(mocker, m5stickv, mock_page_cls): +def test_camera_antiglare(mocker, m5stickv, mock_page_cls): from krux.camera import OV7740_ID from krux.input import PRESSED, RELEASED @@ -75,12 +89,12 @@ def test_camera_antiglare_light(mocker, m5stickv, mock_page_cls): from krux.camera import Camera ctx = mock_context(mocker) - ENTER_SEQ = [RELEASED] + [PRESSED] + [PRESSED] + [RELEASED] - PAGE_PREV_SEQ = [RELEASED] + [RELEASED] + [RELEASED] + [PRESSED] + ENTER_SEQ = [False] + [True] + [True] + [False] + PAGE_PREV_SEQ = [False] + [False] + [False] + [True] mocker.patch("time.ticks_ms", time_mocker.tick) - ctx.input.enter_value = mocker.MagicMock(side_effect=ENTER_SEQ) - ctx.input.page_value = mocker.MagicMock(side_effect=ENTER_SEQ) - ctx.input.page_prev_value = mocker.MagicMock(side_effect=PAGE_PREV_SEQ) + ctx.input.enter_event = mocker.MagicMock(side_effect=ENTER_SEQ) + ctx.input.page_event = mocker.MagicMock(side_effect=ENTER_SEQ) + ctx.input.page_prev_event = mocker.MagicMock(side_effect=PAGE_PREV_SEQ) ctx.camera = Camera() ctx.camera.cam_id = OV7740_ID mocker.spy(ctx.camera, "disable_antiglare") diff --git a/tests/pages/test_tiny_seed.py b/tests/pages/test_tiny_seed.py index 60d9f226a..3a72b01e1 100644 --- a/tests/pages/test_tiny_seed.py +++ b/tests/pages/test_tiny_seed.py @@ -276,10 +276,10 @@ def test_scan_tiny_seed_24w(m5stickv, mocker): # Seed will be returned as its word index import time from krux.pages.tiny_seed import TinyScanner - from krux.input import BUTTON_ENTER, PRESSED, RELEASED + from krux.input import BUTTON_ENTER BTN_SEQUENCE = [BUTTON_ENTER] + [BUTTON_ENTER] # Intro # Check OK - ENTER_SEQ = [RELEASED] + [PRESSED] + [RELEASED] * 3 + ENTER_SEQ = [False] + [True] + [False] * 3 TIME_STAMPS = (0, 1, 1000, 2000, 3000, 4000, 5000) TINYSEED_RECTANGLE = (10, 10, 100, 100) TEST_WORDS_NUMBERS_1_12 = [ @@ -314,7 +314,9 @@ def test_scan_tiny_seed_24w(m5stickv, mocker): TEST_24_WORDS = "market glass laugh warm cream either robot end blood awful escape fan palm waste surge kick display shoe remove achieve shoulder siren loop gate" mocker.patch.object(time, "ticks_ms", mocker.MagicMock(side_effect=TIME_STAMPS)) ctx = create_ctx(mocker, BTN_SEQUENCE) - ctx.input.enter_value = mocker.MagicMock(side_effect=ENTER_SEQ) + mocker.patch.object(ctx.input, "page_event", new=lambda: False) + mocker.patch.object(ctx.input, "page_prev_event", new=lambda: False) + ctx.input.enter_event = mocker.MagicMock(side_effect=ENTER_SEQ) tiny_seed = TinyScanner(ctx) mocker.patch.object( tiny_seed, "_detect_tiny_seed", new=lambda image: TINYSEED_RECTANGLE @@ -335,7 +337,7 @@ def test_scan_tiny_seed_24w_amigo(amigo_tft, mocker): from krux.input import BUTTON_ENTER, PRESSED, RELEASED BTN_SEQUENCE = [BUTTON_ENTER] + [BUTTON_ENTER] # Intro # Check OK - ENTER_SEQ = [RELEASED] + [PRESSED] + [RELEASED] * 3 + ENTER_SEQ = [False] + [True] + [False] * 3 TIME_STAMPS = (0, 1, 1000, 2000, 3000, 4000, 5000) TINYSEED_RECTANGLE = (10, 10, 100, 100) TEST_WORDS_NUMBERS_1_12 = [ @@ -370,7 +372,10 @@ def test_scan_tiny_seed_24w_amigo(amigo_tft, mocker): TEST_24_WORDS = "market glass laugh warm cream either robot end blood awful escape fan palm waste surge kick display shoe remove achieve shoulder siren loop gate" mocker.patch.object(time, "ticks_ms", mocker.MagicMock(side_effect=TIME_STAMPS)) ctx = create_ctx(mocker, BTN_SEQUENCE) - ctx.input.enter_value = mocker.MagicMock(side_effect=ENTER_SEQ) + mocker.patch.object(ctx.input, "page_event", new=lambda: False) + mocker.patch.object(ctx.input, "page_prev_event", new=lambda: False) + mocker.patch.object(ctx.input, "touch_event", new=lambda: False) + ctx.input.enter_event = mocker.MagicMock(side_effect=ENTER_SEQ) tiny_seed = TinyScanner(ctx) mocker.patch.object( tiny_seed, "_detect_tiny_seed", new=lambda image: TINYSEED_RECTANGLE diff --git a/tests/pages/test_tools.py b/tests/pages/test_tools.py index cd187ec34..8b944eba5 100644 --- a/tests/pages/test_tools.py +++ b/tests/pages/test_tools.py @@ -89,9 +89,9 @@ def test_sd_check_no_sd(m5stickv, mocker): ctx = mock_context(mocker) ctx.input.wait_for_button = mocker.MagicMock(side_effect=BTN_SEQUENCE) tool = Tools(ctx) + tool.flash_text = mocker.MagicMock() tool.sd_check() - - ctx.display.flash_text.assert_has_calls([mocker.call("SD card not detected", ANY)]) + tool.flash_text.assert_has_calls([mocker.call("SD card not detected", ANY)]) def test_sd_check(m5stickv, mocker, mock_file_operations): diff --git a/tests/shared_mocks.py b/tests/shared_mocks.py index 60b75fada..4de80b3c3 100644 --- a/tests/shared_mocks.py +++ b/tests/shared_mocks.py @@ -285,6 +285,7 @@ def board_amigo_tft(): "BUTTON_A": 16, "BUTTON_B": 20, "BUTTON_C": 23, + "TOUCH_IRQ": 33, "LED_W": 32, "I2C_SDA": 27, "I2C_SCL": 24, @@ -333,7 +334,13 @@ def mock_context(mocker): if board.config["type"] == "m5stickv": return mocker.MagicMock( - input=mocker.MagicMock(touch=None), + input=mocker.MagicMock( + touch=None, + enter_event=mocker.MagicMock(return_value=False), + page_event=mocker.MagicMock(return_value=False), + page_prev_event=mocker.MagicMock(return_value=False), + touch_event=mocker.MagicMock(return_value=False), + ), display=mocker.MagicMock( font_width=8, font_height=14, @@ -344,7 +351,13 @@ def mock_context(mocker): ) elif board.config["type"] == "dock": return mocker.MagicMock( - input=mocker.MagicMock(touch=None), + input=mocker.MagicMock( + touch=None, + enter_event=mocker.MagicMock(return_value=False), + page_event=mocker.MagicMock(return_value=False), + page_prev_event=mocker.MagicMock(return_value=False), + touch_event=mocker.MagicMock(return_value=False), + ), display=mocker.MagicMock( font_width=8, font_height=16, diff --git a/tests/test_display.py b/tests/test_display.py index e054aace3..eefb9c295 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -420,25 +420,6 @@ def test_draw_centered_text(mocker, m5stickv): ) -def test_flash_text(mocker, m5stickv): - mocker.patch("krux.display.lcd", new=mocker.MagicMock()) - mocker.patch("krux.display.time", new=mocker.MagicMock()) - import krux - from krux.display import Display - - d = Display() - mocker.patch.object(d, "width", new=lambda: 135) - mocker.patch.object(d, "height", new=lambda: 240) - mocker.spy(d, "draw_centered_text") - mocker.spy(d, "clear") - - d.flash_text("Hello world", krux.display.lcd.WHITE, 0, 1000) - - assert d.clear.call_count == 2 - d.draw_centered_text.assert_called_once() - krux.display.time.sleep_ms.assert_called_with(1000) - - def test_draw_qr_code(mocker, m5stickv): mocker.patch("krux.display.lcd", new=mocker.MagicMock()) import krux diff --git a/tests/test_input.py b/tests/test_input.py index e0487d51f..4906b9b4a 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -7,18 +7,22 @@ def reset_input_states(mocker, input): if input.enter: mocker.patch.object(input, "enter_value", new=lambda: RELEASED) + mocker.patch.object(input, "enter_event", new=lambda: False) if input.page: mocker.patch.object(input, "page_value", new=lambda: RELEASED) + mocker.patch.object(input, "page_event", new=lambda: False) if input.page_prev: mocker.patch.object(input, "page_prev_value", new=lambda: RELEASED) + mocker.patch.object(input, "page_prev_event", new=lambda: False) if input.touch: mocker.patch.object(input.touch.touch_driver, "current_point", new=lambda: None) + mocker.patch.object(input.touch.touch_driver, "event", new=lambda: False) return input def test_init(mocker, m5stickv): - mocker.patch("krux.input.fm.register", new=mocker.MagicMock()) - mocker.patch("krux.input.GPIO", new=mocker.MagicMock()) + mocker.patch("krux.buttons.fm.register", new=mocker.MagicMock()) + mocker.patch("krux.buttons.GPIO", new=mocker.MagicMock()) import krux from krux.input import Input import board @@ -26,37 +30,37 @@ def test_init(mocker, m5stickv): input = Input() assert isinstance(input, Input) - krux.input.fm.register.assert_has_calls( + krux.buttons.fm.register.assert_has_calls( [ mocker.call(board.config["krux"]["pins"]["BUTTON_A"], mocker.ANY), mocker.call(board.config["krux"]["pins"]["BUTTON_B"], mocker.ANY), ] ) assert ( - krux.input.fm.register.call_args_list[0].args[1]._extract_mock_name() + krux.buttons.fm.register.call_args_list[0].args[1]._extract_mock_name() == "mock.fm.fpioa.GPIOHS21" ) assert ( - krux.input.fm.register.call_args_list[1].args[1]._extract_mock_name() + krux.buttons.fm.register.call_args_list[1].args[1]._extract_mock_name() == "mock.fm.fpioa.GPIOHS22" ) assert input.enter is not None assert input.page is not None - assert krux.input.GPIO.call_count == 2 + assert krux.buttons.GPIO.call_count == 2 assert ( - krux.input.GPIO.call_args_list[0].args[0]._extract_mock_name() + krux.buttons.GPIO.call_args_list[0].args[0]._extract_mock_name() == "mock.GPIOHS21" ) assert ( - krux.input.GPIO.call_args_list[1].args[0]._extract_mock_name() + krux.buttons.GPIO.call_args_list[1].args[0]._extract_mock_name() == "mock.GPIOHS22" ) def test_init_amigo_tft(mocker, amigo_tft): - mocker.patch("krux.input.fm.register", new=mocker.MagicMock()) - mocker.patch("krux.input.GPIO", new=mocker.MagicMock()) + mocker.patch("krux.buttons.fm.register", new=mocker.MagicMock()) + mocker.patch("krux.buttons.GPIO", new=mocker.MagicMock()) import krux from krux.input import Input import board @@ -64,7 +68,7 @@ def test_init_amigo_tft(mocker, amigo_tft): input = Input() assert isinstance(input, Input) - krux.input.fm.register.assert_has_calls( + krux.buttons.fm.register.assert_has_calls( [ mocker.call(board.config["krux"]["pins"]["BUTTON_A"], mocker.ANY), mocker.call(board.config["krux"]["pins"]["BUTTON_B"], mocker.ANY), @@ -72,38 +76,39 @@ def test_init_amigo_tft(mocker, amigo_tft): ] ) assert ( - krux.input.fm.register.call_args_list[0].args[1]._extract_mock_name() + krux.buttons.fm.register.call_args_list[0].args[1]._extract_mock_name() == "mock.fm.fpioa.GPIOHS21" ) assert ( - krux.input.fm.register.call_args_list[1].args[1]._extract_mock_name() + krux.buttons.fm.register.call_args_list[1].args[1]._extract_mock_name() == "mock.fm.fpioa.GPIOHS22" ) assert ( - krux.input.fm.register.call_args_list[2].args[1]._extract_mock_name() + krux.buttons.fm.register.call_args_list[2].args[1]._extract_mock_name() == "mock.fm.fpioa.GPIOHS0" ) assert input.enter is not None assert input.page is not None assert input.page_prev is not None - assert krux.input.GPIO.call_count == 3 + assert krux.buttons.GPIO.call_count == 3 assert ( - krux.input.GPIO.call_args_list[0].args[0]._extract_mock_name() + krux.buttons.GPIO.call_args_list[0].args[0]._extract_mock_name() == "mock.GPIOHS21" ) assert ( - krux.input.GPIO.call_args_list[1].args[0]._extract_mock_name() + krux.buttons.GPIO.call_args_list[1].args[0]._extract_mock_name() == "mock.GPIOHS22" ) assert ( - krux.input.GPIO.call_args_list[2].args[0]._extract_mock_name() == "mock.GPIOHS0" + krux.buttons.GPIO.call_args_list[2].args[0]._extract_mock_name() + == "mock.GPIOHS0" ) def test_init_dock(mocker, dock): - mocker.patch("krux.input.fm.register", new=mocker.MagicMock()) - mocker.patch("krux.input.GPIO", new=mocker.MagicMock()) + mocker.patch("krux.buttons.fm.register", new=mocker.MagicMock()) + mocker.patch("krux.buttons.GPIO", new=mocker.MagicMock()) import krux from krux.input import Input import board @@ -111,7 +116,7 @@ def test_init_dock(mocker, dock): input = Input() assert isinstance(input, Input) - krux.input.fm.register.assert_has_calls( + krux.buttons.fm.register.assert_has_calls( [ mocker.call(board.config["krux"]["pins"]["BUTTON_A"], mocker.ANY), ] @@ -123,7 +128,7 @@ def test_init_dock(mocker, dock): ] ) assert ( - krux.input.fm.register.call_args_list[0].args[1]._extract_mock_name() + krux.buttons.fm.register.call_args_list[0].args[1]._extract_mock_name() == "mock.fm.fpioa.GPIOHS21" ) assert ( @@ -138,10 +143,10 @@ def test_init_dock(mocker, dock): assert input.page is not None assert input.page_prev is not None - assert krux.input.GPIO.call_count == 1 + assert krux.buttons.GPIO.call_count == 1 assert krux.rotary.GPIO.call_count == 2 assert ( - krux.input.GPIO.call_args_list[0].args[0]._extract_mock_name() + krux.buttons.GPIO.call_args_list[0].args[0]._extract_mock_name() == "mock.GPIOHS21" ) assert ( @@ -225,19 +230,20 @@ def test_wait_for_release(mocker, m5stickv): input = Input() input = reset_input_states(mocker, input) + mocker.patch.object(input, "enter_event", new=lambda: True) mocker.patch.object(input, "enter_value", new=lambda: PRESSED) def release(): - mocker.patch.object(time, "ticks_ms", new=lambda: 0) + mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 100) + mocker.patch.object(time, "ticks_ms", new=lambda: 2000) mocker.patch.object(input, "enter_value", new=lambda: RELEASED) assert input.entropy == 0 t = threading.Thread(target=release) t.start() - input.wait_for_release() + input.wait_for_button() t.join() assert input.entropy > 0 @@ -252,13 +258,13 @@ def test_wait_for_button_blocks_until_enter_released(mocker, m5stickv): input = Input() input = reset_input_states(mocker, input) + mocker.patch.object(input, "enter_event", new=lambda: True) + mocker.patch.object(input, "enter_value", new=lambda: PRESSED) + def release(): - mocker.patch.object(time, "ticks_ms", new=lambda: 0) + mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 100) - mocker.patch.object(input, "enter_value", new=lambda: PRESSED) - time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 200) + mocker.patch.object(time, "ticks_ms", new=lambda: 1100) mocker.patch.object(input, "enter_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -281,13 +287,13 @@ def test_wait_for_button_blocks_until_page_released(mocker, m5stickv): input = Input() input = reset_input_states(mocker, input) + mocker.patch.object(input, "page_event", new=lambda: True) + mocker.patch.object(input, "page_value", new=lambda: PRESSED) + def release(): - mocker.patch.object(time, "ticks_ms", new=lambda: 0) - time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 100) - mocker.patch.object(input, "page_value", new=lambda: PRESSED) + mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 200) + mocker.patch.object(time, "ticks_ms", new=lambda: 1100) mocker.patch.object(input, "page_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -302,7 +308,7 @@ def release(): krux.input.wdt.feed.assert_called() -def test_wait_for_button_blocks_until_page_prev_released(mocker, amigo_tft): +def test_wait_for_button_blocks_until_page_prev_released(mocker, m5stickv): import threading import krux from krux.input import Input, RELEASED, PRESSED, BUTTON_PAGE_PREV @@ -310,27 +316,18 @@ def test_wait_for_button_blocks_until_page_prev_released(mocker, amigo_tft): input = Input() input = reset_input_states(mocker, input) - def click(): - mocker.patch.object(time, "ticks_ms", new=lambda: 0) - time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 100) - # if input.page_prev, "value" is mocked, in what apparently is bug, - # other input buttons get the same "value", invalidating the test - mocker.patch.object(input, "page_prev_value", new=lambda: PRESSED) + mocker.patch.object(input, "page_prev_event", new=lambda: True) + mocker.patch.object(input, "page_prev_value", new=lambda: PRESSED) + + def release(): + mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 200) + mocker.patch.object(time, "ticks_ms", new=lambda: 1100) mocker.patch.object(input, "page_prev_value", new=lambda: RELEASED) assert input.entropy == 0 - # first one click to enable physical buttons - t = threading.Thread(target=click) - t.start() - btn = input.wait_for_button(True) - t.join() - - # than other click to be counted - t = threading.Thread(target=click) + t = threading.Thread(target=release) t.start() btn = input.wait_for_button(True) t.join() @@ -343,51 +340,19 @@ def click(): def test_wait_for_button_blocks_until_touch_released(mocker, amigo_tft): import threading import krux - from krux.input import Input, BUTTON_TOUCH + from krux.input import Input, BUTTON_TOUCH, PRESSED, RELEASED input = Input() input = reset_input_states(mocker, input) - def click(): - mocker.patch.object(time, "ticks_ms", new=lambda: 0) - time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 100) - mocker.patch.object(input.touch, "current_state", new=lambda: 1) - time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 200) - mocker.patch.object(input.touch, "current_state", new=lambda: 0) - - assert input.entropy == 0 - - t = threading.Thread(target=click) - t.start() - btn = input.wait_for_button(True) - t.join() - - assert btn == BUTTON_TOUCH - assert input.entropy > 0 - krux.input.wdt.feed.assert_called() - - -def test_wait_for_button_waits_for_existing_press_to_release(mocker, m5stickv): - import threading - import krux - from krux.input import Input, RELEASED, PRESSED, BUTTON_ENTER - - input = Input() - input = reset_input_states(mocker, input) + mocker.patch.object(input.touch.touch_driver, "event", new=lambda: True) + mocker.patch.object(input, "touch_value", new=lambda: PRESSED) def release(): - mocker.patch.object(time, "ticks_ms", new=lambda: 0) + mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 100) - mocker.patch.object(input, "page_value", new=lambda: RELEASED) - time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 200) - mocker.patch.object(input, "enter_value", new=lambda: PRESSED) - time.sleep(0.1) - mocker.patch.object(time, "ticks_ms", new=lambda: 300) - mocker.patch.object(input, "enter_value", new=lambda: RELEASED) + mocker.patch.object(time, "ticks_ms", new=lambda: 1100) + mocker.patch.object(input, "touch_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -396,7 +361,7 @@ def release(): btn = input.wait_for_button(True) t.join() - assert btn == BUTTON_ENTER + assert btn == BUTTON_TOUCH assert input.entropy > 0 krux.input.wdt.feed.assert_called() @@ -435,8 +400,11 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 0) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 100) + mocker.patch.object(input, "page_event", new=lambda: True) mocker.patch.object(input, "page_value", new=lambda: PRESSED) time.sleep(0.1) + mocker.patch.object(input, "page_event", new=lambda: False) + time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: LONG_PRESS_PERIOD + 500) mocker.patch.object(input, "page_value", new=lambda: RELEASED) @@ -464,8 +432,11 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 0) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 100) + mocker.patch.object(input, "page_prev_event", new=lambda: True) mocker.patch.object(input, "page_prev_value", new=lambda: PRESSED) time.sleep(0.1) + mocker.patch.object(input, "page_prev_event", new=lambda: False) + time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: LONG_PRESS_PERIOD + 500) mocker.patch.object(input, "page_prev_value", new=lambda: RELEASED) @@ -490,31 +461,34 @@ def test_touch_indexing(mocker, amigo_tft): input = reset_input_states(mocker, input) elapsed_time = 0 + mocker.patch.object(input.touch.touch_driver, "event", new=lambda: True) def time_control(point1, point2): nonlocal elapsed_time - mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) time.sleep(0.1) - elapsed_time += 500 + elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) # touch on 3º quadrant + mocker.patch.object(input.touch.touch_driver, "irq_point", new=lambda: point1) mocker.patch.object( input.touch.touch_driver, "current_point", new=lambda: point1 ) time.sleep(0.1) - elapsed_time += 500 + # mocker.patch.object(input.touch.touch_driver, "event", new=lambda: False) + elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) # touch slightly sideways before release mocker.patch.object( input.touch.touch_driver, "current_point", new=lambda: point2 ) time.sleep(0.1) - elapsed_time += 500 + elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) + # release touch mocker.patch.object(input.touch.touch_driver, "current_point", new=lambda: None) time.sleep(0.1) - elapsed_time += 500 + elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) # full screen as single touch button @@ -557,27 +531,31 @@ def test_touch_gestures(mocker, amigo_tft): def time_control(point1, point2): nonlocal elapsed_time + elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) - time.sleep(0.1) - elapsed_time += 500 - mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) - # touch on 3º quadrant + mocker.patch.object(input.touch.touch_driver, "event", new=lambda: True) + mocker.patch.object(input.touch.touch_driver, "irq_point", new=lambda: point1) mocker.patch.object( input.touch.touch_driver, "current_point", new=lambda: point1 ) time.sleep(0.1) - elapsed_time += 500 + # Detect press event + elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) - # swipe + time.sleep(0.1) + mocker.patch.object(input.touch.touch_driver, "event", new=lambda: False) + time.sleep(0.1) + # Swipe mocker.patch.object( input.touch.touch_driver, "current_point", new=lambda: point2 ) time.sleep(0.1) - elapsed_time += 500 + # Release + elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) mocker.patch.object(input.touch.touch_driver, "current_point", new=lambda: None) time.sleep(0.1) - elapsed_time += 500 + elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) # Swipe Right @@ -723,9 +701,11 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 0) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 100) + mocker.patch.object(input, "enter_event", new=lambda: True) mocker.patch.object(input, "enter_value", new=lambda: PRESSED) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 200) + mocker.patch.object(input, "enter_event", new=lambda: False) mocker.patch.object(input, "enter_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -754,9 +734,11 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 0) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 100) + mocker.patch.object(input, "page_event", new=lambda: True) mocker.patch.object(input, "page_value", new=lambda: PRESSED) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 200) + mocker.patch.object(input, "page_event", new=lambda: False) mocker.patch.object(input, "page_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -785,9 +767,11 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 0) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 100) + mocker.patch.object(input, "page_prev_event", new=lambda: True) mocker.patch.object(input, "page_prev_value", new=lambda: PRESSED) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 200) + mocker.patch.object(input, "page_prev_event", new=lambda: False) mocker.patch.object(input, "page_prev_value", new=lambda: RELEASED) assert input.entropy == 0 From 64b766d2fcfde9766b9dc491cc0e5c8943d4eb30 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Fri, 29 Sep 2023 17:29:15 -0300 Subject: [PATCH 035/114] bugfix: discard invalid point touch presses --- src/krux/touch.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/krux/touch.py b/src/krux/touch.py index 96bbd2c79..2c2dc3e00 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -168,6 +168,8 @@ def event(self): self.state = IDLE if isinstance(self.touch_driver.irq_point, tuple): self._store_points(self.touch_driver.irq_point) + if self.state == RELEASED: # Invalid press point detected + return False return True return False From d70cfb4dcb35200940b7758824a0557c70d07258 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Fri, 29 Sep 2023 22:04:40 -0300 Subject: [PATCH 036/114] touch adjustments --- src/krux/touch.py | 52 +++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/krux/touch.py b/src/krux/touch.py index 2c2dc3e00..c31a81281 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -77,6 +77,17 @@ def add_x_delimiter(self, region): raise ValueError("Touch region added outside display area") self.x_regions.append(region) + def valid_position(self, data): + if self.x_regions and data[0] < self.x_regions[0]: + return False + if self.x_regions and data[0] > self.x_regions[-1]: + return False + if self.y_regions and data[1] < self.y_regions[0]: + return False + if self.y_regions and data[1] > self.y_regions[-1]: + return False + return True + def _extract_index(self, data): """Gets an index from touched points, x and y delimiters""" index = 0 @@ -84,26 +95,17 @@ def _extract_index(self, data): for region in self.y_regions: if data[1] > region: index += 1 - if index == 0 or index >= len(self.y_regions): # outside y areas - self.state = RELEASED - else: - index -= 1 - if self.x_regions: # if 2D array - index *= len(self.x_regions) - 1 - x_index = 0 - for x_region in self.x_regions: - if data[0] > x_region: - x_index += 1 - if x_index == 0 or x_index >= len( - self.x_regions - ): # outside x areas - self.state = RELEASED - else: - x_index -= 1 - index += x_index - else: - index = 0 - return index + index -= 1 + if self.x_regions: # if 2D array + index *= len(self.x_regions) - 1 + x_index = 0 + for x_region in self.x_regions: + if data[0] > x_region: + x_index += 1 + x_index -= 1 + index += x_index + return index + return 0 def _store_points(self, data): """Store pressed points and calculare an average pressed point""" @@ -162,20 +164,18 @@ def event(self): """Checks if a touch happened and stores the point""" current_time = time.ticks_ms() if current_time > self.sample_time + TOUCH_S_PERIOD: - self.current_state() # Update state if self.touch_driver.event(): # Resets touch and gets irq point self.state = IDLE if isinstance(self.touch_driver.irq_point, tuple): - self._store_points(self.touch_driver.irq_point) - if self.state == RELEASED: # Invalid press point detected - return False - return True + if self.valid_position(self.touch_driver.irq_point): + self._store_points(self.touch_driver.irq_point) + return True return False def value(self): """Wraps touch states to behave like a regular button""" - return 0 if self.current_state() == PRESSED else 1 + return 1 if self.current_state() == IDLE else 0 def swipe_right_value(self): """Returns detected gestures and clean respective variable""" From 06123e0a83321f1e9219ce5e15aef18e0df133f8 Mon Sep 17 00:00:00 2001 From: aglkm Date: Sun, 1 Oct 2023 13:26:47 +0300 Subject: [PATCH 037/114] fix code typo --- i18n/translations/de-DE.json | 1 + i18n/translations/es-MX.json | 1 + i18n/translations/fr-FR.json | 1 + i18n/translations/nl-NL.json | 1 + i18n/translations/pl-PL.json | 1 + i18n/translations/pt-BR.json | 1 + i18n/translations/ru-RU.json | 9 +- i18n/translations/vi-VN.json | 1 + src/krux/pages/encryption_ui.py | 2 +- src/krux/translations.py | 2808 ++++++++++++++++--------------- 10 files changed, 1421 insertions(+), 1405 deletions(-) diff --git a/i18n/translations/de-DE.json b/i18n/translations/de-DE.json index 6feabc798..88c6ab8a1 100644 --- a/i18n/translations/de-DE.json +++ b/i18n/translations/de-DE.json @@ -49,6 +49,7 @@ "Cut Method": "Cut-Methode", "Decimal": "Dezimal", "Decrypt?": "Entschlüsseln?", + "Delete %s?": "Löschen %s?", "Delete File?": "Datei löschen?", "Delete Mnemonic": "Mnemonic löschen", "Depth Per Pass": "Tiefe pro Durchgang", diff --git a/i18n/translations/es-MX.json b/i18n/translations/es-MX.json index 43d5def8a..6327387cd 100644 --- a/i18n/translations/es-MX.json +++ b/i18n/translations/es-MX.json @@ -49,6 +49,7 @@ "Cut Method": "Método de corte", "Decimal": "Decimal", "Decrypt?": "Descifrar?", + "Delete %s?": "Eliminar %s?", "Delete File?": "¿Borrar archivo?", "Delete Mnemonic": "Eliminar mnemónico", "Depth Per Pass": "Profundidad por pasada", diff --git a/i18n/translations/fr-FR.json b/i18n/translations/fr-FR.json index 00ea8847e..462445929 100644 --- a/i18n/translations/fr-FR.json +++ b/i18n/translations/fr-FR.json @@ -49,6 +49,7 @@ "Cut Method": "Méthode de coupe", "Decimal": "Décimal", "Decrypt?": "Décrypter?", + "Delete %s?": "Supprimer %s?", "Delete File?": "Supprimer le fichier?", "Delete Mnemonic": "Supprimer mnémonique", "Depth Per Pass": "Profondeur par passage", diff --git a/i18n/translations/nl-NL.json b/i18n/translations/nl-NL.json index 28aa1372b..a2bf92501 100644 --- a/i18n/translations/nl-NL.json +++ b/i18n/translations/nl-NL.json @@ -49,6 +49,7 @@ "Cut Method": "Snijmethode", "Decimal": "Decimaal", "Decrypt?": "Ontsleutelen?", + "Delete %s?": "Verwijderen %s?", "Delete File?": "Bestand verwijderen?", "Delete Mnemonic": "Geheugensteun verwijderen", "Depth Per Pass": "Diepte per pas", diff --git a/i18n/translations/pl-PL.json b/i18n/translations/pl-PL.json index 6a075b2db..b85fda1b0 100644 --- a/i18n/translations/pl-PL.json +++ b/i18n/translations/pl-PL.json @@ -49,6 +49,7 @@ "Cut Method": "Metoda cięcia", "Decimal": "Dziesiętny", "Decrypt?": "Odszyfrować?", + "Delete %s?": "Usuń %s?", "Delete File?": "Usunąć plik?", "Delete Mnemonic": "Usuń mnemonic", "Depth Per Pass": "Głębokość na przepustkę", diff --git a/i18n/translations/pt-BR.json b/i18n/translations/pt-BR.json index b26bbf57c..87ed08ab9 100644 --- a/i18n/translations/pt-BR.json +++ b/i18n/translations/pt-BR.json @@ -49,6 +49,7 @@ "Cut Method": "Método de Corte", "Decimal": "Decimal", "Decrypt?": "Descriptografar?", + "Delete %s?": "Excluir %s?", "Delete File?": "Excluir Arquivo?", "Delete Mnemonic": "Excluir Mnemônico", "Depth Per Pass": "Profundidade da Passagem", diff --git a/i18n/translations/ru-RU.json b/i18n/translations/ru-RU.json index 9a76c183c..d7ea4d00c 100644 --- a/i18n/translations/ru-RU.json +++ b/i18n/translations/ru-RU.json @@ -49,6 +49,7 @@ "Cut Method": "Метод Резки", "Decimal": "Десятичный", "Decrypt?": "Расшифровать?", + "Delete %s?": "Удалить %s?", "Delete File?": "Удалить Файл?", "Delete Mnemonic": "Удалить Мнемонику", "Depth Per Pass": "Глубина За Проход", @@ -61,7 +62,7 @@ "Encrypt Mnemonic": "Зашифровать Мнемонику", "Encrypted QR Code": "Зашифрованный QR Код", "Encrypted mnemonic was not stored": "Зашифрованная мнемоника не была сохранена", - "Encrypted mnemonic was stored with ID: ": "Зашифрованная мнемоника была сохранена с ID", + "Encrypted mnemonic was stored with ID: ": "Зашифрованная мнемоника была сохранена с ID: ", "Encryption": "Шифрование", "Encryption Mode": "Метод шифрования", "Enter each word of your BIP-39 mnemonic as a number from 1 to 2048.": "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", @@ -162,7 +163,7 @@ "Printing\n%d / %d": "Идет печать\n%d / %d", "Printing ...": "Идет печать ...", "Proceed?": "Продолжить?", - "Processing ...": "Обрабатываю ...", + "Processing ...": "Обработка ...", "QR Code": "QR Код", "RX Pin": "RX Пин", "Receive": "Получить", @@ -239,6 +240,6 @@ "Word Numbers": "Числа Слов", "Words": "Слова", "Yes": "Да", - "Your changes will be kept on device flash storage.": "Ваши изменения буду храниться на флэш памяти устройства.", - "Your changes will be kept on the SD card.": "Ваши изменения будут храниться на SD карте." + "Your changes will be kept on device flash storage.": "Ваши изменения будут сохранены на флэш памяти устройства.", + "Your changes will be kept on the SD card.": "Ваши изменения будут сохранены на SD карте." } \ No newline at end of file diff --git a/i18n/translations/vi-VN.json b/i18n/translations/vi-VN.json index 5fa912567..22898f571 100644 --- a/i18n/translations/vi-VN.json +++ b/i18n/translations/vi-VN.json @@ -49,6 +49,7 @@ "Cut Method": "Phương pháp cắt", "Decimal": "Số thập phân", "Decrypt?": "Phản đối?", + "Delete %s?": "Xóa %s?", "Delete File?": "Xóa tài liệu?", "Delete Mnemonic": "Xóa ghi nhớ", "Depth Per Pass": "Độ sâu mỗi lần vượt qua", diff --git a/src/krux/pages/encryption_ui.py b/src/krux/pages/encryption_ui.py index 609893542..dbb5fb6dd 100644 --- a/src/krux/pages/encryption_ui.py +++ b/src/krux/pages/encryption_ui.py @@ -304,6 +304,6 @@ def _delete_encrypted_mnemonic(self, mnemonic_id, sd_card=False): mnemonic_storage = MnemonicStorage() self.ctx.display.clear() - if self.prompt(t("Delete %s?" % mnemonic_id), self.ctx.display.height() // 2): + if self.prompt(t("Delete %s?") % mnemonic_id, self.ctx.display.height() // 2): mnemonic_storage.del_mnemonic(mnemonic_id, sd_card) del mnemonic_storage diff --git a/src/krux/translations.py b/src/krux/translations.py index 6d26801c6..39c1ae73c 100644 --- a/src/krux/translations.py +++ b/src/krux/translations.py @@ -21,249 +21,250 @@ # THE SOFTWARE. # pylint: disable=C0301 translation_table = { - "pt-BR": { - 1185266064: "%d da %d multisig", - 2004520398: "%d. Troco: \n\n%s\n\n", - 3862364126: "%d. Autotransferência: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n é um endereço de troco válido!", - 3921290840: "%s\n\né um endereço de recepção válido!", - 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", - 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", - 3348584292: "(Experimental)", - 2739590230: "12 palavras", - 1310058127: "24 palavras", + "ru-RU": { + 1185266064: "%d из %d мультиподпись", + 2004520398: "%d. Сдача: \n\n%s\n\n", + 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", + 3264377309: "%d. Расход: \n\n%s\n\n", + 2399232215: "%s\n\nвалидный адрес сдачи!", + 3921290840: "%s\n\nвалидный адрес получения!", + 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", + 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", + 3348584292: "(Эксперементальный)", + 2739590230: "12 слов", + 1310058127: "24 слова", 2743272264: "ABC", - 1949634023: "Sobre", + 1949634023: "О Программе", 1517128857: "Adafruit", - 3270727197: "Endereço", - 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", - 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", - 88746165: "Antirreflexo desativado", - 1521033296: "Antirreflexo ativado", - 1056821534: "Tem certeza?", - 3247612282: "Mnemônico BIP39", - 3455872521: "Voltar", - 2541860807: "Backing up bootloader..\n\n%d%%", - 2256777600: "Assinatura Inválida", - 3937333362: "Baudrate", - 427617266: "Bitcoin", - 928727036: "Borda", + 3270727197: "Адрес", + 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", + 283202181: "Правильно совместите камеру и Мини Сид-фразу.", + 88746165: "Антиблик отключен", + 1521033296: "Антиблик включен", + 1056821534: "Вы уверены?", + 3247612282: "BIP39 Мнемоника", + 3455872521: "Назад", + 2541860807: "Резервное копирование загрузчика..\n\n%d%%", + 2256777600: "Плохая подпись", + 3937333362: "Скорость Передачи Данных", + 427617266: "Биткоин", + 928727036: "Заполнение границ", 213030954: "CNC", - 1207696150: "Troco", - 3126552510: "Endereços de Troco", - 1583186953: "Mudar o tema e reiniciar?", - 2697733395: "Mudanças salvas no cartão SD!", - 388908871: "Alterações só durarão até o desligamento.", - 3442025874: "Verifique o cartão SD", - 3119547911: "Verificar se este endereço pertence a carteira?", - 2856261511: "Endereço de troco %d não corresponde.", - 2788541416: "Endereço de recebimento %d não corresponde.", - 2446472910: "Verificando correspondência do endereço de troco %d ..", - 2470115694: "Verificando o cartão SD..", - 3655273987: "Verificando correspondência do endereço de recebimento %d ..", - 2407028014: "SeedQR Compacto", - 4041895036: "Continuar?", - 4094072796: "Gerar Código QR", - 167798282: "Gerar código QR do texto?", - 2767642191: "Criado: ", - 3513215254: "Código QR Customizado", - 124617190: "Profundidade de Corte", - 597912140: "Método de Corte", - 2504034831: "Decimal", - 2751113454: "Descriptografar?", - 1016609898: "Excluir Arquivo?", - 1364509700: "Excluir Mnemônico", - 4102535566: "Profundidade da Passagem", - 2791699253: "Derivação: %s", - 1230133196: "Armazenamento flash do dispositivo não detectado.", - 3836852788: "Feito?", - 382368239: "Driver", - 3978947916: "Codificador", - 4090746898: "Debounce do Encoder", - 374684711: "Criptografar Mnemônico", - 1244124409: "Código QR Criptografado", - 2968548114: "Mnemonic criptografado não foi armazenado", - 3315319371: "Mnemônico criptografado foi armazenado com ID:", - 350279787: "Criptografia", - 2601598799: "Modo de Criptografia", - 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", - 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", - 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", - 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", - 784361051: "Erro:\n%s", - 1505332462: "Esc", - 3838465623: "Explorar arquivos?", - 4170881190: "Exportando para o cartão SD..", - 1711312434: "Chave Pública Estendida", - 383371114: "Falhou em descriptografar", - 3048830188: "Falhou ao carregar PSBT", - 4192663412: "Falhou ao carregar endereço", - 1996021743: "Falha ao carregar a chave", - 1108715658: "Falhou ao carregar mensagem", - 1081425878: "Falhou ao carregar mnemônico", - 928667220: "Falha ao carregar o descritor de saída", - 1620572516: "Falha ao carregar a senha", - 2946146830: "Falhou ao armazenar mnemônico", - 1303554751: "Taxa: ", - 104500973: "Taxa de Alimentação", - 3313339187: "Nome do arquivo", - 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", - 3737729752: "Impressão digital: %s", - 2542772894: "Firmware excede o tamanho máximo: %d", - 1406590538: "Diâmetro da Fresa", - 3086093110: "Livre: ", - 1893243331: "Do Armazenamento", + 1207696150: "Сдача", + 3126552510: "Адрес Сдачи", + 1583186953: "Сменить тему и перезагрузить?", + 2697733395: "Изменения сохранены на SD карте!", + 388908871: "Изменения будут храниться до выключения.", + 3442025874: "Проверить SD Карту", + 3119547911: "Проверить, что адрес принадлежит этому кошельку?", + 2856261511: "Проверено %d адресов сдачи без совпадений.", + 2788541416: "Проверено %d адресов получения без совпадений.", + 2446472910: "Проверяем адрес сдачи %d на совпадение..", + 2470115694: "Проверка SD карты..", + 3655273987: "Проверяем адрес получения %d на совпадение..", + 2407028014: "Компактный SeedQR", + 4041895036: "Продолжить?", + 4094072796: "Создать QR Код", + 167798282: "Создать QR код из текста?", + 2767642191: "Создано", + 3513215254: "Пользовательский QR Код", + 124617190: "Глубина Резки", + 597912140: "Метод Резки", + 2504034831: "Десятичный", + 2751113454: "Расшифровать?", + 3510912550: "Удалить %s?", + 1016609898: "Удалить Файл?", + 1364509700: "Удалить Мнемонику", + 4102535566: "Глубина За Проход", + 2791699253: "Производный путь: %s", + 1230133196: "Флэш память устройства не обнаружена.", + 3836852788: "Готово?", + 382368239: "Драйвер", + 3978947916: "Кодер", + 4090746898: "Дебаунс Кодера", + 374684711: "Зашифровать Мнемонику", + 1244124409: "Зашифрованный QR Код", + 2968548114: "Зашифрованная мнемоника не была сохранена", + 3315319371: "Зашифрованная мнемоника была сохранена с ID: ", + 350279787: "Шифрование", + 2601598799: "Метод шифрования", + 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", + 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", + 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", + 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", + 784361051: "Ошибка:\n%s", + 1505332462: "Выйти", + 3838465623: "Исследовать файлы?", + 4170881190: "Экспортирование на SD карту..", + 1711312434: "Расширенный Публичный Ключ", + 383371114: "Не удалось расшифровать", + 3048830188: "Не удалось загрузить PSBT", + 4192663412: "Не удалось загрузить адрес", + 1996021743: "Не удалось загрузить ключ", + 1108715658: "Не удалось загрузить сообщение", + 1081425878: "Не удалось загрузить мнемонику", + 928667220: "Не удалось загрузить выходной дескриптор", + 1620572516: "Не удалось загрузить фразу-пароль", + 2946146830: "Не удалось сохранить мнемонику", + 1303554751: "Комиссия: ", + 104500973: "Скорость подачи", + 3313339187: "Имя файла", + 1982637349: "Файл %s существует на SD карте, перезаписать?", + 3737729752: "Фингерпринт: %s", + 2542772894: "Прошивка превышает максимальный размер: %d", + 1406590538: "Flute Диаметр", + 3086093110: "Бесплатно: ", + 1893243331: "Из Памяти", 4120536442: "GRBL", - 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", - 602716148: "Ir", - 3580020863: "Chave pública hexadecimal", - 2691246967: "Hexadecimal", - 2736309107: "Id já existe\n", - 1706005805: "Descritor incompleto", - 631342955: "Entradas (%d): ", - 2585599782: "Endereço inválido", - 2874529150: "Bootloader inválido", - 4093416954: "Comprimento de mnemônico inválido", - 1422874211: "Chave pública inválida", - 2443867979: "Carteira inválida:\n%s", - 4122897393: "Invertido", - 3000888649: "Chave", - 2686333978: "Chave:", - 4123798664: "Krux\n\n\nVersão\n%s", - 3835918229: "Teste de impressão de QR krux", - 766317539: "Língua", - 972436696: "Atraso de Linha", - 3596093890: "Linha: ", - 2820726296: "Carregar Mnemônico", - 879727077: "Carregar do cartão SD?", - 669106195: "Carregar um?", - 3330705289: "Carregar?", - 2596531078: "Carregando Câmera..", - 596389387: "Carregando endereço de troco %d..", - 336702608: "Carregando impressora..", - 2538883522: "Carregando endereço de recebimento %d..", - 3159494909: "Carregando..", - 1177338798: "Idioma", - 2817059741: "Local", - 63976957: "Nível de log", - 86530918: "Logging", - 2917810189: "Comprimento máximo excedido (%s)", - 2030045667: "Mensagem", - 3928301843: "Arquivo de assinatura faltando", - 1948316555: "Mnemônico", - 2123991188: "ID do mnemônico", - 3911073154: "ID de armazenamento", - 570639842: "Mnemônico não foi descriptografado", - 1746030071: "Mnemônico não foi criptografado", - 1458925155: "Modificado:", - 1845376098: "Multisig", - 2939797024: "Rede", - 73574491: "Novo Mnemônico", - 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", - 4063104189: "Não", - 3927838899: "Sem senha BIP39", - 4092516657: "Jogadas insuficientes!", - 1577637745: "Octal", - 3312581301: "Iter. PBKDF2", - 721090621: "PSBT", - 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", - 2987800462: "Largura do papel", - 3050763890: "Parte\n%d / %d", - 3559456868: "Tamanho da peça", - 4249903283: "Senha", - 3712257341: "Senha:", - 140802882: "Salvar", - 1703779997: "QR em Texto", - 3561756278: "Carregue um descritor da carteira", - 784609464: "Taxa de Mergulho", - 3037062877: "Imprimir QR de teste", - 4278257699: "Imprimir QR?\n\n%s\n\n", - 516488026: "Imprimir?\n\n%s\n\n", - 1123106929: "Impressora", - 3903571079: "Driver de impressora não está definido!", - 2609799302: "Imprimindo\n%d / %d", - 844861889: "Imprimindo ...", - 2580599003: "Seguir?", - 556126964: "Processando ...", - 1848310591: "Código QR", - 710709610: "Pino RX", - 2697857197: "Recebimento", - 1746677167: "Endereços de Recebimento", - 364354944: "Região: ", - 1662254634: "Revise os dados, edite se necessário", - 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", - 856795528: "Jogadas:\n\n%s", - 255086803: "Jogadas: %d\n", - 3976793317: "Cartão SD", - 2827687530: "Cartão SD não detectado", - 2736513298: "Cartão SD não detectado.", - 3593785196: "SHA256 de jogadas:\n\n%s", - 1143278725: "Sha256 da imagem:\n\n%s", + 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", + 602716148: "OK", + 3580020863: "Шестнадцатеричный Публичный Ключ", + 2691246967: "Шестнадцатеричный", + 2736309107: "ID уже существует\n", + 1706005805: "Неполный выходной дескриптор", + 631342955: "Входы (%d): ", + 2585599782: "Неверный адрес", + 2874529150: "Неверный загрузчик", + 4093416954: "Неверная длина мнемоники", + 1422874211: "Неверный публичный ключ", + 2443867979: "Неверный кошелек:\n%s", + 4122897393: "Инвертировать", + 3000888649: "Ключ", + 2686333978: "Ключ: ", + 4123798664: "Krux\n\n\nВерсия\n%s", + 3835918229: "Тестовый QR Принтера Krux", + 766317539: "Язык", + 972436696: "Задержка Линии", + 3596093890: "Линия: ", + 2820726296: "Загрузить Мнемонику", + 879727077: "Загрузить с SD карты?", + 669106195: "Загрузить одну?", + 3330705289: "Загрузить?", + 2596531078: "Загрузка Камеры..", + 596389387: "Загрузка адреса сдачи %d..", + 336702608: "Загрузка принтера..", + 2538883522: "Загрузка адреса получения %d..", + 3159494909: "Загрузка..", + 1177338798: "Локаль", + 2817059741: "Расположение", + 63976957: "Уровень логирования", + 86530918: "Логирование", + 2917810189: "Максимальная длина превышена (%s)", + 2030045667: "Сообщение", + 3928301843: "Отсутствует файл подписи", + 1948316555: "Мнемоника", + 2123991188: "ID мнемоники", + 3911073154: "ID памяти мнемоники", + 570639842: "Мнемоника не была расшифрована", + 1746030071: "Мнемоника не была зашифрована", + 1458925155: "Изменено: ", + 1845376098: "Мультиподпись", + 2939797024: "Сеть", + 73574491: "Новая Мнемоника", + 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", + 4063104189: "Нет", + 3927838899: "Без BIP39 фразы-пароля", + 4092516657: "Недостаточно бросков!", + 1577637745: "Восьмеричный", + 3312581301: "PBKDF2 Итерации", + 721090621: "PSBT", + 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", + 2987800462: "Ширина Бумаги", + 3050763890: "Часть\n%d / %d", + 3559456868: "Размер Части", + 4249903283: "Фраза-пароль", + 3712257341: "Фраза-пароль: ", + 140802882: "Постоянная Память", + 1703779997: "QR открытым текстом", + 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", + 784609464: "Скорость Погружения", + 3037062877: "Напечатать Тестовый QR", + 4278257699: "Напечатать в виде QR?\n\n%s\n\n", + 516488026: "Печатать?\n\n%s\n\n", + 1123106929: "Принтер", + 3903571079: "Драйвер Принтера не установлен!", + 2609799302: "Идет печать\n%d / %d", + 844861889: "Идет печать ...", + 2580599003: "Продолжить?", + 556126964: "Обработка ...", + 1848310591: "QR Код", + 710709610: "RX Пин", + 2697857197: "Получить", + 1746677167: "Адрес Получения", + 364354944: "Регион: ", + 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", + 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", + 856795528: "Броски:\n\n%s", + 255086803: "Броски: %d\n", + 3976793317: "SD карта", + 2827687530: "SD карта не обнаружена", + 2736513298: "SD карта не обнаружена.", + 3593785196: "SHA256 бросков:\n\n%s", + 1143278725: "SHA256 снэпшота:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Salvar no cartão SD?", - 810036588: "Salvo no cartão SD:\n%s", - 763824768: "Escala", - 4117455079: "Escanear Endereço", - 3219991109: "Escanear a senha BIP39", - 2537207336: "Escanear código QR da chave", - 4006316572: "Escaneando as palavras 1-12 novamente", - 2736506158: "Escaneando as palavras 13-24", + 3531742595: "Сохранить на SD карту?", + 810036588: "Сохранено на SD карту:\n%s", + 763824768: "Шкала", + 4117455079: "Отсканировать Адрес", + 3219991109: "Отсканировать BIP39 фразу-пароль", + 2537207336: "Отсканировать Ключ QR код", + 4006316572: "Сканирование слов 1-12 снова", + 2736506158: "Сканирование слов 13-24", 266935239: "SeedQR", - 1698829144: "Autotransferência ou Troco (%d): ", - 473154195: "Configurações", - 1825881236: "Desligar", - 2120776272: "Desligando..", - 1061961408: "Assinar", - 4282338366: "Assinar?", - 746161122: "Assinatura", - 1988416729: "Mensagem Assinada", - 3672006076: "PSBT Assinada", - 2281377987: "Single-sig", - 4221794628: "Total: ", - 2344747135: "Algumas verificações não podem ser realizadas.", - 2309020186: "Gastos (%d): ", - 3355862324: "Stackbit 1248", - 3303592908: "Armazene na Flash", - 720041451: "Armazene no Cartão SD", - 3514476519: "Deslize para mudar de modo", - 1898550184: "TOQUE ou ENTER para capturar", - 4228215415: "Pino TX", - 2612594937: "Texto", - 1454688268: "Tema", - 1180180513: "Térmica", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Ferramentas", - 3684696112: "Limiar de Toque", - 2978718564: "Touchscreen", - 2732611775: "Tentar mais?", - 1487826746: "Digitar a senha BIP39", - 2061556020: "Digite a Chave", - 2089395053: "Unidade", - 2845607430: "Atualizando bootloader..\n\n%d%%", - 4164597446: "Atualização completa.\n\nDesligando..", - 2736001501: "Atualizando firmware..\n\n%d%%", - 2674953168: "Use uma superfície de fundo preta.", - 2402455261: "Use a entropia da câmera para criar um novo mnemônico", - 236075140: "Usado: ", - 4003084591: "Valor %s fora do alcance: [ %s, %s]", - 4191058607: "Pela Câmera", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Por entrada manual", - 2504354847: "Aguarde a captura", - 2297028319: "Descritor de Carteira", - 4232654916: "Descritor da carteira", - 2587172867: "Descritor de saída da carteira carregado!", - 2499782468: "O descritor de saída da carteira não foi encontrado.", - 2671738224: "Aviso:", - 797660533: "Palavra %d", - 3742424146: "Números das Palavras", - 2965123464: "Palavras", - 1303016265: "Sim", - 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", - 2569054451: "Suas alterações serão mantidas no cartão SD.", + 1698829144: "Трансфер самому себе или Сдача (%d): ", + 473154195: "Настройки", + 1825881236: "Выключить", + 2120776272: "Выключение..", + 1061961408: "Подписать", + 4282338366: "Подписать?", + 746161122: "Подпись", + 1988416729: "Подписанное Сообщение", + 3672006076: "Подписанное PSBT", + 2281377987: "Одна подпись", + 4221794628: "Размер: ", + 2344747135: "Некоторые проверки не могут быть выполнены.", + 2309020186: "Расход (%d): ", + 3355862324: "Стэкбит 1248", + 3303592908: "Сохранить на Флэш Память", + 720041451: "Сохранить на SD Карту", + 3514476519: "Свайпните, чтобы сменить режим", + 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", + 4228215415: "TX Пин", + 2612594937: "Текст", + 1454688268: "Тема", + 1180180513: "Термальный", + 4119292117: "Мини Сид-фраза", + 1732872974: "Мини Сид-фраза (Биты)", + 725348723: "Инструменты", + 3684696112: "Прикоснитесь Границы", + 2978718564: "Тачскрин", + 2732611775: "Попробовать ещё?", + 1487826746: "Введите BIP39 фразу-пароль", + 2061556020: "Введите Ключ", + 2089395053: "Юнит", + 2845607430: "Обновление загрузчика..\n\n%d%%", + 4164597446: "Обновление завершено.\n\nВыключение..", + 2736001501: "Обновление прошивки..\n\n%d%%", + 2674953168: "Использовать черную фоновую поверхность.", + 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", + 236075140: "Использовано: ", + 4003084591: "Значение %s вне диапозона: [%s, %s]", + 4191058607: "С Помощью Камеры", + 1254681955: "С Помощью D20", + 525309547: "С Помощью D6", + 590330112: "С Помощью Ручного Ввода", + 2504354847: "Дождитесь Захвата", + 2297028319: "Дескриптор Кошелька", + 4232654916: "Выходной дескриптор кошелька", + 2587172867: "Выходной дескриптор кошелька загружен!", + 2499782468: "Выходной дескриптор кошелька не найден.", + 2671738224: "Предупреждение:", + 797660533: "Слово %d", + 3742424146: "Числа Слов", + 2965123464: "Слова", + 1303016265: "Да", + 771968845: "Ваши изменения будут сохранены на флэш памяти устройства.", + 2569054451: "Ваши изменения будут сохранены на SD карте.", }, "pl-PL": { 1185266064: "%d z %d multisig", @@ -316,6 +317,7 @@ 597912140: "Metoda cięcia", 2504034831: "Dziesiętny", 2751113454: "Odszyfrować?", + 3510912550: "Usuń %s?", 1016609898: "Usunąć plik?", 1364509700: "Usuń mnemonic", 4102535566: "Głębokość na przepustkę", @@ -560,6 +562,7 @@ 597912140: "Método de corte", 2504034831: "Decimal", 2751113454: "Descifrar?", + 3510912550: "Eliminar %s?", 1016609898: "¿Borrar archivo?", 1364509700: "Eliminar mnemónico", 4102535566: "Profundidad por pasada", @@ -753,1224 +756,1229 @@ 771968845: "Sus cambios se guardarán en el almacenamiento flash del dispositivo.", 2569054451: "Sus cambios se guardarán en la tarjeta SD.", }, - "de-DE": { - 1185266064: "%d von %d Multisig", - 2004520398: "%d. Change: \n\n%s\n\n", - 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", - 3264377309: "%d. Ausgaben: \n\n%s\n\n", - 2399232215: "%s\n\nist eine gültige Change Adresse!", - 3921290840: "%s\n\nist eine gültige Empfangsadresse!", - 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", - 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", + "pt-BR": { + 1185266064: "%d da %d multisig", + 2004520398: "%d. Troco: \n\n%s\n\n", + 3862364126: "%d. Autotransferência: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n é um endereço de troco válido!", + 3921290840: "%s\n\né um endereço de recepção válido!", + 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", + 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", 3348584292: "(Experimental)", - 2739590230: "12 Wörter", - 1310058127: "24 Wörter", + 2739590230: "12 palavras", + 1310058127: "24 palavras", 2743272264: "ABC", - 1949634023: "Über", + 1949634023: "Sobre", 1517128857: "Adafruit", - 3270727197: "Adresse", - 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", - 283202181: "Richte Kamera und Tiny Seed korrekt aus.", - 88746165: "Blendschutz deaktiviert", - 1521033296: "Blendschutz aktiviert", - 1056821534: "Bist Du sicher?", - 3247612282: "BIP39 Mnemonic", - 3455872521: "Zurück", - 2541860807: "Bootloader wird gesichert..\n\n%d%%", - 2256777600: "Ungültige Signatur", - 3937333362: "Baudrate", - 427617266: "Bitcoin", - 928727036: "Randpolsterung", - 213030954: "CNC", - 1207696150: "Change Adresse", - 3126552510: "Change Adressen", - 1583186953: "Thema ändern und neu starten?", - 2697733395: "Änderungen auf SD-Karte gespeichert!", - 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", - 3442025874: "Prüfe SD-Karte", - 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", - 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", - 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", - 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", - 2470115694: "Suche nach SD-Karte..", - 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", - 2407028014: "Kompakt SeedQR", - 4041895036: "Weiter?", - 4094072796: "Erstelle QR-Code", - 167798282: "QR-Code aus Text erzeugen?", - 2767642191: "Erstellt:", - 3513215254: "Benutzerdefinierte QR-Code", - 124617190: "Schnitttiefe", - 597912140: "Cut-Methode", - 2504034831: "Dezimal", - 2751113454: "Entschlüsseln?", - 1016609898: "Datei löschen?", - 1364509700: "Mnemonic löschen", - 4102535566: "Tiefe pro Durchgang", - 2791699253: "Ableitung: %s", - 1230133196: "Geräte-Flash-Speicher nicht erkannt.", - 3836852788: "Fertig?", + 3270727197: "Endereço", + 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", + 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", + 88746165: "Antirreflexo desativado", + 1521033296: "Antirreflexo ativado", + 1056821534: "Tem certeza?", + 3247612282: "Mnemônico BIP39", + 3455872521: "Voltar", + 2541860807: "Backing up bootloader..\n\n%d%%", + 2256777600: "Assinatura Inválida", + 3937333362: "Baudrate", + 427617266: "Bitcoin", + 928727036: "Borda", + 213030954: "CNC", + 1207696150: "Troco", + 3126552510: "Endereços de Troco", + 1583186953: "Mudar o tema e reiniciar?", + 2697733395: "Mudanças salvas no cartão SD!", + 388908871: "Alterações só durarão até o desligamento.", + 3442025874: "Verifique o cartão SD", + 3119547911: "Verificar se este endereço pertence a carteira?", + 2856261511: "Endereço de troco %d não corresponde.", + 2788541416: "Endereço de recebimento %d não corresponde.", + 2446472910: "Verificando correspondência do endereço de troco %d ..", + 2470115694: "Verificando o cartão SD..", + 3655273987: "Verificando correspondência do endereço de recebimento %d ..", + 2407028014: "SeedQR Compacto", + 4041895036: "Continuar?", + 4094072796: "Gerar Código QR", + 167798282: "Gerar código QR do texto?", + 2767642191: "Criado: ", + 3513215254: "Código QR Customizado", + 124617190: "Profundidade de Corte", + 597912140: "Método de Corte", + 2504034831: "Decimal", + 2751113454: "Descriptografar?", + 3510912550: "Excluir %s?", + 1016609898: "Excluir Arquivo?", + 1364509700: "Excluir Mnemônico", + 4102535566: "Profundidade da Passagem", + 2791699253: "Derivação: %s", + 1230133196: "Armazenamento flash do dispositivo não detectado.", + 3836852788: "Feito?", 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-Entprellung", - 374684711: "Verschlüssel Mnemonic", - 1244124409: "Verschlüsselter QR-Code", - 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", - 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", - 350279787: "Verschlüsselung", - 2601598799: "Verschlüsselungsmodus", - 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", - 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", - 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", - 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", - 784361051: "Fehler:\n%s", + 3978947916: "Codificador", + 4090746898: "Debounce do Encoder", + 374684711: "Criptografar Mnemônico", + 1244124409: "Código QR Criptografado", + 2968548114: "Mnemonic criptografado não foi armazenado", + 3315319371: "Mnemônico criptografado foi armazenado com ID:", + 350279787: "Criptografia", + 2601598799: "Modo de Criptografia", + 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", + 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", + 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", + 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", + 784361051: "Erro:\n%s", 1505332462: "Esc", - 3838465623: "Dateien durchsuchen?", - 4170881190: "Auf SD-Karte exportieren..", - 1711312434: "Öffentlicher Schlüssel", - 383371114: "Entschlüsselung fehlgeschlagen", - 3048830188: "PSBT konnte nicht geladen werden", - 4192663412: "Adresse konnte nicht geladen werden", - 1996021743: "Schlüssel konnte nicht geladen werden", - 1108715658: "Nachricht konnte nicht geladen werden", - 1081425878: "Mnemonic konnte nicht geladen werden", - 928667220: "Ausgabedeskriptor konnte nicht geladen werden", - 1620572516: "Passphrase konnte nicht geladen werden", - 2946146830: "Mnemonic konnte nicht gespeichert werden", - 1303554751: "Gebühr: ", - 104500973: "Vorschubgeschwindigkeit", - 3313339187: "Dateiname", - 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", - 3737729752: "Fingerabdruck: %s", - 2542772894: "Die Firmware übersteigt die maximale Größe: %d", - 1406590538: "Flötendurchmesser", - 3086093110: "Frei: ", - 1893243331: "Vom Speicher", + 3838465623: "Explorar arquivos?", + 4170881190: "Exportando para o cartão SD..", + 1711312434: "Chave Pública Estendida", + 383371114: "Falhou em descriptografar", + 3048830188: "Falhou ao carregar PSBT", + 4192663412: "Falhou ao carregar endereço", + 1996021743: "Falha ao carregar a chave", + 1108715658: "Falhou ao carregar mensagem", + 1081425878: "Falhou ao carregar mnemônico", + 928667220: "Falha ao carregar o descritor de saída", + 1620572516: "Falha ao carregar a senha", + 2946146830: "Falhou ao armazenar mnemônico", + 1303554751: "Taxa: ", + 104500973: "Taxa de Alimentação", + 3313339187: "Nome do arquivo", + 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", + 3737729752: "Impressão digital: %s", + 2542772894: "Firmware excede o tamanho máximo: %d", + 1406590538: "Diâmetro da Fresa", + 3086093110: "Livre: ", + 1893243331: "Do Armazenamento", 4120536442: "GRBL", - 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", - 602716148: "Go", - 3580020863: "Hex öffentlicher Schlüssel", - 2691246967: "Hexadezimal", - 2736309107: "ID existiert bereits\n", - 1706005805: "Unvollständiger Ausgabedeskriptor", - 631342955: "Input (%d): ", - 2585599782: "Ungültige Adresse", - 2874529150: "Ungültiger Bootloader", - 4093416954: "Ungültige mnemonische Lange", - 1422874211: "Ungültiger öffentlicher Schlüssel", - 2443867979: "Ungültige Wallet:\n%s", - 4122897393: "Umkehren", - 3000888649: "Schlüssel", - 2686333978: "Schlüssel:", - 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Krux Drucker Test-QR", - 766317539: "Sprache", - 972436696: "Leitungsverzögerung", - 3596093890: "Linie: ", - 2820726296: "Mnemonic laden", - 879727077: "Von SD-Karte laden?", - 669106195: "Eine laden?", - 3330705289: "Laden?", - 2596531078: "Lade Kamera..", - 596389387: "Lade Change Adresse %d..", - 336702608: "Drucker wird geladen..", - 2538883522: "Lade Empfangsadresse %d..", - 3159494909: "Wird geladen..", - 1177338798: "Spracheinstellung", - 2817059741: "Speicherort", - 63976957: "Log Level", + 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", + 602716148: "Ir", + 3580020863: "Chave pública hexadecimal", + 2691246967: "Hexadecimal", + 2736309107: "Id já existe\n", + 1706005805: "Descritor incompleto", + 631342955: "Entradas (%d): ", + 2585599782: "Endereço inválido", + 2874529150: "Bootloader inválido", + 4093416954: "Comprimento de mnemônico inválido", + 1422874211: "Chave pública inválida", + 2443867979: "Carteira inválida:\n%s", + 4122897393: "Invertido", + 3000888649: "Chave", + 2686333978: "Chave:", + 4123798664: "Krux\n\n\nVersão\n%s", + 3835918229: "Teste de impressão de QR krux", + 766317539: "Língua", + 972436696: "Atraso de Linha", + 3596093890: "Linha: ", + 2820726296: "Carregar Mnemônico", + 879727077: "Carregar do cartão SD?", + 669106195: "Carregar um?", + 3330705289: "Carregar?", + 2596531078: "Carregando Câmera..", + 596389387: "Carregando endereço de troco %d..", + 336702608: "Carregando impressora..", + 2538883522: "Carregando endereço de recebimento %d..", + 3159494909: "Carregando..", + 1177338798: "Idioma", + 2817059741: "Local", + 63976957: "Nível de log", 86530918: "Logging", - 2917810189: "Maximale Länge überschritten (%s)", - 2030045667: "Nachricht", - 3928301843: "Fehlende Signaturdatei", - 1948316555: "Mnemonic", - 2123991188: "Mnemonische ID", - 3911073154: "Mnemonische Speicher-ID", - 570639842: "Mnemonic wurde nicht entschlüsselt", - 1746030071: "Mnemonic wurde nicht verschlüsselt", - 1458925155: "Geändert:", + 2917810189: "Comprimento máximo excedido (%s)", + 2030045667: "Mensagem", + 3928301843: "Arquivo de assinatura faltando", + 1948316555: "Mnemônico", + 2123991188: "ID do mnemônico", + 3911073154: "ID de armazenamento", + 570639842: "Mnemônico não foi descriptografado", + 1746030071: "Mnemônico não foi criptografado", + 1458925155: "Modificado:", 1845376098: "Multisig", - 2939797024: "Netzwerk", - 73574491: "Neue Mnemonic", - 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", - 4063104189: "Nein", - 3927838899: "Keine BIP39 Passphrase", - 4092516657: "Nicht genug Würfe!", - 1577637745: "Oktal", - 3312581301: "PBKDF2-Iter.", + 2939797024: "Rede", + 73574491: "Novo Mnemônico", + 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", + 4063104189: "Não", + 3927838899: "Sem senha BIP39", + 4092516657: "Jogadas insuficientes!", + 1577637745: "Octal", + 3312581301: "Iter. PBKDF2", 721090621: "PSBT", - 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", - 2987800462: "Papierbreite", - 3050763890: "Teil\n%d / %d", - 3559456868: "Teilegröße", - 4249903283: "Passphrase", - 3712257341: "Passphrase:", - 140802882: "Speicher", - 1703779997: "Klartext-QR", - 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", - 784609464: "Tauchrate", - 3037062877: "Drucke Test-QR", - 4278257699: "Als QR-Code drucken?\n\n%s\n\n", - 516488026: "Drucken?\n\n%s\n\n", - 1123106929: "Drucker", - 3903571079: "Druckertreiber nicht gesetzt!", - 2609799302: "Drucken\n%d / %d", - 844861889: "Wird gedruckt ...", - 2580599003: "Weiter?", - 556126964: "Wird bearbeitet ...", - 1848310591: "QR-Code", - 710709610: "RX Pin", - 2697857197: "Empfangen", - 1746677167: "Empfangsadresse", - 364354944: "Region: ", - 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", - 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", - 856795528: "Würfe:\n\n%s", - 255086803: "Würfe: %d\n", - 3976793317: "SD-Karte", - 2827687530: "SD-Karte nicht erkannt", - 2736513298: "SD-Karte nicht erkannt.", - 3593785196: "SHA256 der Würfe:\n\n%s", - 1143278725: "SHA256 des Snapshots:\n\n%s", + 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", + 2987800462: "Largura do papel", + 3050763890: "Parte\n%d / %d", + 3559456868: "Tamanho da peça", + 4249903283: "Senha", + 3712257341: "Senha:", + 140802882: "Salvar", + 1703779997: "QR em Texto", + 3561756278: "Carregue um descritor da carteira", + 784609464: "Taxa de Mergulho", + 3037062877: "Imprimir QR de teste", + 4278257699: "Imprimir QR?\n\n%s\n\n", + 516488026: "Imprimir?\n\n%s\n\n", + 1123106929: "Impressora", + 3903571079: "Driver de impressora não está definido!", + 2609799302: "Imprimindo\n%d / %d", + 844861889: "Imprimindo ...", + 2580599003: "Seguir?", + 556126964: "Processando ...", + 1848310591: "Código QR", + 710709610: "Pino RX", + 2697857197: "Recebimento", + 1746677167: "Endereços de Recebimento", + 364354944: "Região: ", + 1662254634: "Revise os dados, edite se necessário", + 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", + 856795528: "Jogadas:\n\n%s", + 255086803: "Jogadas: %d\n", + 3976793317: "Cartão SD", + 2827687530: "Cartão SD não detectado", + 2736513298: "Cartão SD não detectado.", + 3593785196: "SHA256 de jogadas:\n\n%s", + 1143278725: "Sha256 da imagem:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Auf SD-Karte speichern?", - 810036588: "Auf SD-Karte gespeichert:\n%s", - 763824768: "Skala", - 4117455079: "Adresse\nscannen", - 3219991109: "Scan BIP39 Passphrase", - 2537207336: "Schlüssel QR-Code scannen", - 4006316572: "Wörter 1-12 erneut scannen", - 2736506158: "Wörter 13-24 scannen", + 3531742595: "Salvar no cartão SD?", + 810036588: "Salvo no cartão SD:\n%s", + 763824768: "Escala", + 4117455079: "Escanear Endereço", + 3219991109: "Escanear a senha BIP39", + 2537207336: "Escanear código QR da chave", + 4006316572: "Escaneando as palavras 1-12 novamente", + 2736506158: "Escaneando as palavras 13-24", 266935239: "SeedQR", - 1698829144: "Selbstübertragung oder Change (%d): ", - 473154195: "Einstellungen", - 1825881236: "Ausschalten", - 2120776272: "Herunterfahren..", - 1061961408: "Signieren", - 4282338366: "Signieren?", - 746161122: "Signatur", - 1988416729: "Signierte Nachricht", - 3672006076: "Signierte PSBT", - 2281377987: "Single-Sig", - 4221794628: "Größe: ", - 2344747135: "Einige Schecks können nicht durchgeführt werden.", - 2309020186: "Ausgabe (%d): ", + 1698829144: "Autotransferência ou Troco (%d): ", + 473154195: "Configurações", + 1825881236: "Desligar", + 2120776272: "Desligando..", + 1061961408: "Assinar", + 4282338366: "Assinar?", + 746161122: "Assinatura", + 1988416729: "Mensagem Assinada", + 3672006076: "PSBT Assinada", + 2281377987: "Single-sig", + 4221794628: "Total: ", + 2344747135: "Algumas verificações não podem ser realizadas.", + 2309020186: "Gastos (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Auf Flash speichern", - 720041451: "Auf der SD-Karte speichern", - 3514476519: "Wischen um den Modus zu ändern", - 1898550184: "TOUCH oder ENTER zum Erfassen", - 4228215415: "TX Pin", - 2612594937: "Text", - 1454688268: "Thema", - 1180180513: "Thermisch", + 3303592908: "Armazene na Flash", + 720041451: "Armazene no Cartão SD", + 3514476519: "Deslize para mudar de modo", + 1898550184: "TOQUE ou ENTER para capturar", + 4228215415: "Pino TX", + 2612594937: "Texto", + 1454688268: "Tema", + 1180180513: "Térmica", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Werkzeuge", - 3684696112: "Berühre Schwellenwert", + 1732872974: "Tiny Seed (bits)", + 725348723: "Ferramentas", + 3684696112: "Limiar de Toque", 2978718564: "Touchscreen", - 2732611775: "Weiter versuchen?", - 1487826746: "BIP39 Passphrase eingeben", - 2061556020: "Schlüssel eingeben", - 2089395053: "Einheit", - 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", - 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", - 2736001501: "Firmware wird aktualisiert..\n\n%d%%", - 2674953168: "Verwende eine schwarze Hintergrundfläche.", - 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", - 236075140: "Belegt: ", - 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", - 4191058607: "Via Kamera", + 2732611775: "Tentar mais?", + 1487826746: "Digitar a senha BIP39", + 2061556020: "Digite a Chave", + 2089395053: "Unidade", + 2845607430: "Atualizando bootloader..\n\n%d%%", + 4164597446: "Atualização completa.\n\nDesligando..", + 2736001501: "Atualizando firmware..\n\n%d%%", + 2674953168: "Use uma superfície de fundo preta.", + 2402455261: "Use a entropia da câmera para criar um novo mnemônico", + 236075140: "Usado: ", + 4003084591: "Valor %s fora do alcance: [ %s, %s]", + 4191058607: "Pela Câmera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Via manueller Eingabe", - 2504354847: "Warte auf die Erfassung", - 2297028319: "Wallet-Deskriptor", - 4232654916: "Wallet Ausgabedeskriptor", - 2587172867: "Wallet Ausgabedeskriptor geladen!", - 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", - 2671738224: "Warnung:", - 797660533: "Wort %d", - 3742424146: "Wortnummern", - 2965123464: "Wörter", - 1303016265: "Ja", - 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", - 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", + 590330112: "Por entrada manual", + 2504354847: "Aguarde a captura", + 2297028319: "Descritor de Carteira", + 4232654916: "Descritor da carteira", + 2587172867: "Descritor de saída da carteira carregado!", + 2499782468: "O descritor de saída da carteira não foi encontrado.", + 2671738224: "Aviso:", + 797660533: "Palavra %d", + 3742424146: "Números das Palavras", + 2965123464: "Palavras", + 1303016265: "Sim", + 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", + 2569054451: "Suas alterações serão mantidas no cartão SD.", }, - "vi-VN": { - 1185266064: "%d của %d đa chữ kí", - 2004520398: "%d. Thay đổi: \n\n%s\n\n", - 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", - 3264377309: "%d. Chi tiêu: \n\n%s\n\n", - 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", - 3921290840: "%s\n\nlà một địa chỉ khả dụng!", - 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 3348584292: "(Thực nghiệm)", - 2739590230: "12 từ", - 1310058127: "24 từ", + "fr-FR": { + 1185266064: "%d de %d multisignature", + 2004520398: "%d. Changement : \n\n%s\n\n", + 3862364126: "%d. Auto-transfert : \n\n%s\n\n", + 3264377309: "%d. Dépense : \n\n%s\n\n", + 2399232215: "%s\n\nest une adresse changement valide!", + 3921290840: "%s\n\nest une adresse reçue valide!", + 1808355833: "INTROUVABLE dans les premières %d adresses de changement", + 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", + 3348584292: "(Expérimental)", + 2739590230: "12 mots", + 1310058127: "24 mots", 2743272264: "ABC", - 1949634023: "Về chúng tôi", + 1949634023: "À propos", 1517128857: "Adafruit", - 3270727197: "Địa chỉ", - 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", - 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", - 88746165: "Chống lóa bị vô hiệu hóa", - 1521033296: "Đã bật chống lóa", - 1056821534: "Bạn có chắc không?", - 3247612282: "Mã mnemonic dạng chuẩn BIP39", - 3455872521: "Trở lại", - 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", - 2256777600: "Chữ ký xấu", - 3937333362: "Tốc độ baud", + 3270727197: "Adresse", + 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", + 283202181: "Alignez correctement la caméra et Tiny Seed.", + 88746165: "Anti-éblouissement désactivé", + 1521033296: "Anti-éblouissement activé", + 1056821534: "Es-tu sûr?", + 3247612282: "BIP39 Mnémonique", + 3455872521: "Retour", + 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", + 2256777600: "Mauvaise signature", + 3937333362: "Débit en bauds", 427617266: "Bitcoin", - 928727036: "Đệm viền", + 928727036: "Rembourrage de bordure", 213030954: "CNC", - 1207696150: "Thay đổi", - 3126552510: "Thay địa chỉ", - 1583186953: "Thay đổi chủ đề và khởi động lại?", - 2697733395: "Thay đổi được lưu trên thẻ SD!", - 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", - 3442025874: "Kiểm tra thẻ SD", - 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", - 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", - 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", - 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", - 2470115694: "Kiểm tra thẻ SD..", - 3655273987: "Đang kiểm tra %d địa chỉ..", - 2407028014: "SeedQR nhỏ gọn", - 4041895036: "Tiếp tục?", - 4094072796: "Tạo mã QR", - 167798282: "Tạo mã QR từ văn bản?", - 2767642191: "Tạo:", - 3513215254: "Mã QR tùy chỉnh", - 124617190: "Chiều sâu cắt", - 597912140: "Phương pháp cắt", - 2504034831: "Số thập phân", - 2751113454: "Phản đối?", - 1016609898: "Xóa tài liệu?", - 1364509700: "Xóa ghi nhớ", - 4102535566: "Độ sâu mỗi lần vượt qua", - 2791699253: "Nguồn gốc: %s", - 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", - 3836852788: "Hoàn tất?", - 382368239: "Người cầm lái", - 3978947916: "Mã hoá", - 4090746898: "Gỡ lỗi bộ mã hóa", - 374684711: "Mã hóa Mnemonic", - 1244124409: "Mã QR được mã hóa", - 2968548114: "MNemon được mã hóa không được lưu trữ", - 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", - 350279787: "Mã hóa", - 2601598799: "Chế độ mã hóa", - 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", - 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", - 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", - 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", - 784361051: "Lỗi:\n%s", - 1505332462: "Esc", - 3838465623: "Khám phá các tập tin?", - 4170881190: "Xuất vào thẻ SD ..", - 1711312434: "Khóa công cộng", - 383371114: "Không giải mã được", - 3048830188: "Tải PSBT thất bại", - 4192663412: "Tải địa chỉ thất bại", - 1996021743: "Không tải khóa", - 1108715658: "Không tải được tin nhắn", - 1081425878: "Tải mã mnemonic thất bại", - 928667220: "Không thể tải bộ mô tả đầu ra", - 1620572516: "Không tải được cụm mật khẩu", - 2946146830: "Không lưu trữ MNemonic", - 1303554751: "Phí: ", - 104500973: "Tỷ lệ thức ăn", - 3313339187: "Tên tệp", - 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", - 3737729752: "Dấu vân tay: %s", - 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", - 1406590538: "Đường kính ống sáo", - 3086093110: "Khả dụng: ", - 1893243331: "Từ lưu trữ", + 1207696150: "Changement", + 3126552510: "Adresses de Changement", + 1583186953: "Changer de thème et redémarrer?", + 2697733395: "Modifications enregistrées sur la carte SD!", + 388908871: "Les modifications dureront jusqu'à l'arrêt.", + 3442025874: "Vérifiez la carte SD", + 3119547911: "Vérifiez que l'adresse appartient à cette portefeuille?", + 2856261511: "Adresses %d changement vérifiées sans correspondance.", + 2788541416: "Adresses %d reçues vérifiées sans correspondance.", + 2446472910: "Vérification de l'adresse changement %d pour correspondance..", + 2470115694: "Vérification de la carte SD..", + 3655273987: "Vérification de l'adresse reçue %d pour correspondance..", + 2407028014: "SeedQR Compact", + 4041895036: "Continuer?", + 4094072796: "Créer du code QR", + 167798282: "Créer du code QR à partir du texte?", + 2767642191: "Créé:", + 3513215254: "Code QR personnalisé", + 124617190: "Profondeur de coupe", + 597912140: "Méthode de coupe", + 2504034831: "Décimal", + 2751113454: "Décrypter?", + 3510912550: "Supprimer %s?", + 1016609898: "Supprimer le fichier?", + 1364509700: "Supprimer mnémonique", + 4102535566: "Profondeur par passage", + 2791699253: "Dérivation: %s", + 1230133196: "Stockage flash de l'appareil non détecté.", + 3836852788: "Terminé?", + 382368239: "Conducteur", + 3978947916: "Encodeur", + 4090746898: "Anti-rebond de l'encodeur", + 374684711: "Crypter mnémonique", + 1244124409: "Code QR crypté", + 2968548114: "Le mnémonique crypté n'a pas été stocké", + 3315319371: "Mnémonique cryptée a été stockée avec ID:", + 350279787: "Chiffrement", + 2601598799: "Mode de chiffrement", + 3504179008: "Entrez chaque mot de votre BIP-39 mnémonique sous la forme d'un nombre 1 jusqu'à 2048.", + 1100685007: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en hexadécimal de 1 à 800.", + 4090266642: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en octal de 1 à 4000.", + 2780625730: "Entrez chaque mot de votre BIP-39 mnémonique.", + 784361051: "Erreur:\n%s", + 1505332462: "Esc", + 3838465623: "Explorer des fichiers?", + 4170881190: "Exportation vers la carte SD..", + 1711312434: "Clé publique", + 383371114: "Échec de décrypter", + 3048830188: "Erreur de chargement PSBT", + 4192663412: "Erreur de chargement d'adresse", + 1996021743: "Échec du chargement de la clé", + 1108715658: "Échec du chargement du message", + 1081425878: "Erreur de chargement mnémonique", + 928667220: "Échec du chargement du descripteur de sortie", + 1620572516: "Échec du chargement de la phrase secrète", + 2946146830: "Échec de stocker mnémonique", + 1303554751: "Frais: ", + 104500973: "Taux d'alimentation", + 3313339187: "Nom de fichier", + 1982637349: "Le nom de fichier %s existe sur la carte SD, écraser ?", + 3737729752: "Empreinte Digitale: %s", + 2542772894: "Le micrologiciel dépasse la taille maximale: %d", + 1406590538: "Diamètre de flûte", + 3086093110: "Libre: ", + 1893243331: "Du stockage", 4120536442: "GRBL", - 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", - 602716148: "Đến", - 3580020863: "Khóa công khai Hex", - 2691246967: "Thập lục phân", - 2736309107: "Id đã tồn tại\n", - 1706005805: "Bộ mô tả đầu ra chưa hoàn chỉnh", - 631342955: "Đầu vào (%d): ", - 2585599782: "Địa chỉ không hợp lệ", - 2874529150: "Bộ tải khởi động không hợp lệ", - 4093416954: "Độ dài mã mnemonic không hợp lệ", - 1422874211: "Khóa công khai không hợp lệ", - 2443867979: "Ví không hợp lệ:\n%s", - 4122897393: "Đảo ngược", - 3000888649: "Chìa khóa", - 2686333978: "Chìa khóa:", - 4123798664: "Krux\n\n\nPhiên Bản\n%s", - 3835918229: "QR kiểm tra máy in Krux", - 766317539: "Ngôn ngữ", - 972436696: "Độ trễ Dòng", - 3596093890: "Đường kẻ: ", - 2820726296: "Tải mã mnemonic", - 879727077: "Tải từ thẻ SD?", - 669106195: "Tải một?", - 3330705289: "Tải?", - 2596531078: "Đang tải máy ảnh..", - 596389387: "Đang tải thay đổi địa chỉ %d..", - 336702608: "Tải máy in ..", - 2538883522: "Đang tải địa chỉ nhận %d..", - 3159494909: "Đang tải..", - 1177338798: "Ngôn ngữ", - 2817059741: "Vị trí cửa hàng", - 63976957: "Log Level", - 86530918: "Khai thác gỗ", - 2917810189: "Chiều dài tối đa vượt quá (%s)", - 2030045667: "Tin nhắn", - 3928301843: "Thiếu tập tin chữ ký", - 1948316555: "Mã mnemonic", - 2123991188: "ID ghi nhớ", - 3911073154: "ID lưu trữ ghi nhớ", - 570639842: "Ghi nhớ không được giải mã", - 1746030071: "Ghi nhớ không được mã hóa", - 1458925155: "Đã sửa đổi:", - 1845376098: "Đa chữ kí", - 2939797024: "Mạng lưới", - 73574491: "Mnemonic mới", - 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", - 4063104189: "Không", - 3927838899: "Không có cụm mật khẩu BIP39", - 4092516657: "Không đủ cuộn!", - 1577637745: "Bát phân", - 3312581301: "Lặp lại PBKDF2", + 299338213: "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", + 602716148: "Go", + 3580020863: "Clé public hexadécimal", + 2691246967: "Hexadécimal", + 2736309107: "Id existe déjà\n", + 1706005805: "Descripteur de sortie incomplet", + 631342955: "Entrées (%d) : ", + 2585599782: "Adresse invalide", + 2874529150: "Chargeur de démarrage invalide", + 4093416954: "Longueur mnémonique invalide", + 1422874211: "Clé publique non valide", + 2443867979: "Portefeuille invalide:\n%s", + 4122897393: "Inverser", + 3000888649: "Clé", + 2686333978: "Clé:", + 4123798664: "Krux\n\n\nVersion\n%s", + 3835918229: "Test de l'imprimante Krux QR", + 766317539: "Langue", + 972436696: "Délai de Ligne", + 3596093890: "Ligne: ", + 2820726296: "Charger mnémonique", + 879727077: "Charger depuis la carte SD ?", + 669106195: "En charger qu'un?", + 3330705289: "Charger?", + 2596531078: "Caméra de Chargement..", + 596389387: "Chargement de l'adresse de changement %d..", + 336702608: "Chargement de l'imprimante..", + 2538883522: "Chargement de l'adresse de réception %d..", + 3159494909: "Chargement..", + 1177338798: "Paramètres régionaux", + 2817059741: "Emplacement", + 63976957: "Niveau de journalisation", + 86530918: "Enregistrement", + 2917810189: "Longueur maximale dépassée (% s)", + 2030045667: "Message", + 3928301843: "Fichier de signature manquant", + 1948316555: "Mnémonique", + 2123991188: "ID mnémonique", + 3911073154: "ID de stockage mnémonique", + 570639842: "Mnémonique n'a pas été décryptée", + 1746030071: "Mnémonique n'était pas cryptée", + 1458925155: "Modifié:", + 1845376098: "Multi\nsignature", + 2939797024: "Réseau", + 73574491: "Nouveau mnémonique", + 2792272353: "Nouveau micrologiciel détecté.\n\nSHA256:\n%s\n\n\n\nInstaller?", + 4063104189: "Non", + 3927838899: "Pas de phrase passante bip39", + 4092516657: "Pas assez de rouleaux !", + 1577637745: "Octale", + 3312581301: "Itér. PBKDF2", 721090621: "PSBT", - 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", - 2987800462: "Chiều rộng giấy", - 3050763890: "Phần\n%d / %d", - 3559456868: "Kích thước một phần", - 4249903283: "Cụm mật khẩu", - 3712257341: "Cụm cụm:", - 140802882: "Vị trí lưu", - 1703779997: "Văn bản rõ QR", - 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", - 784609464: "Tỷ lệ sụt giảm", - 3037062877: "In kiểm tra QR", - 4278257699: "In ra mã QR?\n\n%s\n\n", - 516488026: "In?\n\n%s\n\n", - 1123106929: "Máy in", - 3903571079: "Trình điều khiển máy in không đặt!", - 2609799302: "Đang in\n%d / %d", - 844861889: "In ấn ...", - 2580599003: "Thực hiện?", - 556126964: "Xử lý ...", - 1848310591: "Mã QR", - 710709610: "RX Ghim", - 2697857197: "Nhận được", - 1746677167: "Nhận địa chỉ", - 364354944: "Vùng: ", - 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", - 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", - 856795528: "Súc sắc cuộn:\n\n%s", - 255086803: "Súc sắc cuộn: %d\n", - 3976793317: "Thẻ SD", - 2827687530: "Thẻ SD không được phát hiện", - 2736513298: "Thẻ SD không được phát hiện.", - 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", - 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", + 995862913: "Peignez les points perforés en noir afin qu'ils puissent être détectés.", + 2987800462: "Largeur du papier", + 3050763890: "Partie\n%d / %d", + 3559456868: "Taille de la pièce", + 4249903283: "Phrase de passe", + 3712257341: "Phrass de passe:", + 140802882: "Persister", + 1703779997: "QR en Texte Brut", + 3561756278: "Veuillez charger un descripteur de sortie de portefeuille", + 784609464: "Taux de plongée", + 3037062877: "Test d'impression QR", + 4278257699: "Imprimer en QR?\n\n%s\n\n", + 516488026: "Imprimer?\n\n%s\n\n", + 1123106929: "Imprimante", + 3903571079: "Le conducteur d'imprimante n'est pas défini!", + 2609799302: "Impression\n%d / %d", + 844861889: "Impression ...", + 2580599003: "Procéder?", + 556126964: "Traitement ...", + 1848310591: "QR Code", + 710709610: "RX Fiche", + 2697857197: "Recevoir", + 1746677167: "Adresses de Réception", + 364354944: "Région: ", + 1662254634: "Examinez les données numérisées, modifiez-les si nécessaire", + 770350922: "Lancez le dé au moins %d fois pour générer un mnémonique.", + 856795528: "Rouleaux:\n\n%s", + 255086803: "Rouleaux: %d\n", + 3976793317: "Carte SD", + 2827687530: "Carte SD non détectée", + 2736513298: "Carte SD non détectée.", + 3593785196: "SHA256 de rouleaux:\n\n%s", + 1143278725: "Sha256 de Snapshot:\n\n% s", 3338679392: "SHA256:\n%s", - 3531742595: "Lưu vào thẻ SD?", - 810036588: "Đã lưu vào thẻ SD:\n%s", - 763824768: "Cái cân", - 4117455079: "Quét địa chỉ", - 3219991109: "Quét BIP39 Cụm cụm", - 2537207336: "Quét mã QR khóa", - 4006316572: "Quét lại từ 1-12", - 2736506158: "Quét từ 13-24", - 266935239: "SEEDQR", - 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", - 473154195: "Cài đặt", - 1825881236: "Tắt", - 2120776272: "Đang tắt..", - 1061961408: "Chữ kí", - 4282338366: "Kí?", - 746161122: "Chữ ký", - 1988416729: "Tin nhắn đã ký", - 3672006076: "Đã ký PSBT", - 2281377987: "Khóa đơn", - 4221794628: "Dung lượng: ", - 2344747135: "Một số kiểm tra không thể được thực hiện.", - 2309020186: "Chi tiêu (%d): ", + 3531742595: "Enregistrer sur la carte SD ?", + 810036588: "Enregistré sur la carte SD :\n%s", + 763824768: "L'échelle", + 4117455079: "Scannez l'adresse", + 3219991109: "Scan bip39 en phrase secrète", + 2537207336: "Scanner le code QR de la clé", + 4006316572: "Analyser à nouveau les mots 1 à 12", + 2736506158: "Analyser les mots 13 à 24", + 266935239: "Seedqr", + 1698829144: "Auto-transfert ou changement (%d): ", + 473154195: "Paramètres", + 1825881236: "Fermer", + 2120776272: "Éteindre..", + 1061961408: "Signature", + 4282338366: "Signature?", + 746161122: "Signature", + 1988416729: "Message signé", + 3672006076: "PSBT signé", + 2281377987: "Clé unique", + 4221794628: "Capacité: ", + 2344747135: "Certains chèques ne peuvent pas être effectués.", + 2309020186: "Dépense (%d) : ", 3355862324: "Stackbit 1248", - 3303592908: "Lưu trữ trên flash", - 720041451: "Lưu trữ trên thẻ SD", - 3514476519: "Vuốt để thay đổi chế độ", - 1898550184: "TOUCH hoặc ENTER để chụp", - 4228215415: "TX Ghim", - 2612594937: "Chữ", - 1454688268: "Chủ đề", - 1180180513: "Nhiệt", + 3303592908: "Stocker sur flash", + 720041451: "Stocker sur la carte SD", + 3514476519: "Faites glisser pour changer de mode", + 1898550184: "TOUCHEZ ou ENTER pour capturer", + 4228215415: "TX Fiche", + 2612594937: "Texte", + 1454688268: "Thème", + 1180180513: "Thermique", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bit)", - 725348723: "Công cụ", - 3684696112: "Ngưỡng cảm ứng", - 2978718564: "Màn hình cảm ứng", - 2732611775: "Thử thêm nữa?", - 1487826746: "Nhập cụm BIP39", - 2061556020: "Nhập khóa", - 2089395053: "Đơn vị", - 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", - 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", - 2736001501: "Nâng cấp firmware..\n\n%d%%", - 2674953168: "Sử dụng bề mặt nền đen.", - 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", - 236075140: "Đã sử dụng: ", - 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", - 4191058607: "Qua máy ảnh", - 1254681955: "Qua D20", - 525309547: "Qua D6", - 590330112: "Thông qua đầu vào thủ công", - 2504354847: "Chờ bắt", - 2297028319: "Trình mô tả ví", - 4232654916: "Ví đầu ra mô tả", - 2587172867: "Đã tải bộ mô tả đầu ra của ví!", - 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", - 2671738224: "Cảnh báo:", - 797660533: "Kí tự %d", - 3742424146: "Từ số", - 2965123464: "Từ ngữ", - 1303016265: "Đúng", - 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", - 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", + 1732872974: "Tiny Seed (bits)", + 725348723: "Outils", + 3684696112: "Seuil Tactile", + 2978718564: "Écran Tactile", + 2732611775: "Réessayer?", + 1487826746: "Type Bip39 Plasque", + 2061556020: "Clé de type", + 2089395053: "Unité", + 2845607430: "Mise à jour du chargeur de démarrage..\n\n%d%%", + 4164597446: "Mise à niveau complète.\n\nÉteindre..", + 2736001501: "Mise à niveau du micrologiciel..\n\n%d%%", + 2674953168: "Utilisez une surface de fond noire.", + 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", + 236075140: "Utilisé: ", + 4003084591: "Valeur% s hors de portée: [% s,% s]", + 4191058607: "Par caméra", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Par saisie manuelle", + 2504354847: "Attendez la capture", + 2297028319: "Descripteur de Portefeuille", + 4232654916: "Descripteur de sortie du portefeuille", + 2587172867: "Descripteur de sortie du portefeuille chargé!", + 2499782468: "Descripteur de sortie du portefeuille introuvable.", + 2671738224: "Avertissement:", + 797660533: "Mot %d", + 3742424146: "Numéros de mots", + 2965123464: "Mots", + 1303016265: "Oui", + 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", + 2569054451: "Vos modifications seront conservées sur la carte SD.", }, - "ru-RU": { - 1185266064: "%d из %d мультиподпись", - 2004520398: "%d. Сдача: \n\n%s\n\n", - 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", - 3264377309: "%d. Расход: \n\n%s\n\n", - 2399232215: "%s\n\nвалидный адрес сдачи!", - 3921290840: "%s\n\nвалидный адрес получения!", - 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", - 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", - 3348584292: "(Эксперементальный)", - 2739590230: "12 слов", - 1310058127: "24 слова", + "nl-NL": { + 1185266064: "%d van %d multisig", + 2004520398: "%d. Wisselgeld: \n\n%s\n\n", + 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", + 3264377309: "%d. Uitgaven: \n\n%s\n\n", + 2399232215: "%s\n\nis een valide wisselgeld adres!", + 3921290840: "%s\n\nis een valide ontvangst adres!", + 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", + 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", + 3348584292: "(Experimenteel)", + 2739590230: "12 woorden", + 1310058127: "24 woorden", 2743272264: "ABC", - 1949634023: "О Программе", + 1949634023: "Over", 1517128857: "Adafruit", - 3270727197: "Адрес", - 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", - 283202181: "Правильно совместите камеру и Мини Сид-фразу.", - 88746165: "Антиблик отключен", - 1521033296: "Антиблик включен", - 1056821534: "Вы уверены?", - 3247612282: "BIP39 Мнемоника", - 3455872521: "Назад", - 2541860807: "Резервное копирование загрузчика..\n\n%d%%", - 2256777600: "Плохая подпись", - 3937333362: "Скорость Передачи Данных", - 427617266: "Биткоин", - 928727036: "Заполнение границ", + 3270727197: "Adres", + 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", + 283202181: "Richt de camera en Tiny Seed op de juiste manier.", + 88746165: "Anti reflecterend uitgeschakeld", + 1521033296: "Anti reflecterend ingeschakeld", + 1056821534: "Weet je het zeker?", + 3247612282: "BIP-39 geheugensteun", + 3455872521: "Terug", + 2541860807: "Backup van de bootloader...\n\n%d%%", + 2256777600: "Ongeldige handtekening", + 3937333362: "Baudratio", + 427617266: "Bitcoin", + 928727036: "Rand opvulling", 213030954: "CNC", - 1207696150: "Сдача", - 3126552510: "Адрес Сдачи", - 1583186953: "Сменить тему и перезагрузить?", - 2697733395: "Изменения сохранены на SD карте!", - 388908871: "Изменения будут храниться до выключения.", - 3442025874: "Проверить SD Карту", - 3119547911: "Проверить, что адрес принадлежит этому кошельку?", - 2856261511: "Проверено %d адресов сдачи без совпадений.", - 2788541416: "Проверено %d адресов получения без совпадений.", - 2446472910: "Проверяем адрес сдачи %d на совпадение..", - 2470115694: "Проверка SD карты..", - 3655273987: "Проверяем адрес получения %d на совпадение..", - 2407028014: "Компактный SeedQR", - 4041895036: "Продолжить?", - 4094072796: "Создать QR Код", - 167798282: "Создать QR код из текста?", - 2767642191: "Создано", - 3513215254: "Пользовательский QR Код", - 124617190: "Глубина Резки", - 597912140: "Метод Резки", - 2504034831: "Десятичный", - 2751113454: "Расшифровать?", - 1016609898: "Удалить Файл?", - 1364509700: "Удалить Мнемонику", - 4102535566: "Глубина За Проход", - 2791699253: "Производный путь: %s", - 1230133196: "Флэш память устройства не обнаружена.", - 3836852788: "Готово?", - 382368239: "Драйвер", - 3978947916: "Кодер", - 4090746898: "Дебаунс Кодера", - 374684711: "Зашифровать Мнемонику", - 1244124409: "Зашифрованный QR Код", - 2968548114: "Зашифрованная мнемоника не была сохранена", - 3315319371: "Зашифрованная мнемоника была сохранена с ID", - 350279787: "Шифрование", - 2601598799: "Метод шифрования", - 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", - 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", - 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", - 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", - 784361051: "Ошибка:\n%s", - 1505332462: "Выйти", - 3838465623: "Исследовать файлы?", - 4170881190: "Экспортирование на SD карту..", - 1711312434: "Расширенный Публичный Ключ", - 383371114: "Не удалось расшифровать", - 3048830188: "Не удалось загрузить PSBT", - 4192663412: "Не удалось загрузить адрес", - 1996021743: "Не удалось загрузить ключ", - 1108715658: "Не удалось загрузить сообщение", - 1081425878: "Не удалось загрузить мнемонику", - 928667220: "Не удалось загрузить выходной дескриптор", - 1620572516: "Не удалось загрузить фразу-пароль", - 2946146830: "Не удалось сохранить мнемонику", - 1303554751: "Комиссия: ", - 104500973: "Скорость подачи", - 3313339187: "Имя файла", - 1982637349: "Файл %s существует на SD карте, перезаписать?", - 3737729752: "Фингерпринт: %s", - 2542772894: "Прошивка превышает максимальный размер: %d", - 1406590538: "Flute Диаметр", - 3086093110: "Бесплатно: ", - 1893243331: "Из Памяти", + 1207696150: "Change", + 3126552510: "Wisselgeldadres", + 1583186953: "Thema veranderen en opnieuw opstarten?", + 2697733395: "Wijzigingen aanhouden op SD kaart!", + 388908871: "Wijzigingen blijven van kracht tot afsluiten.", + 3442025874: "Controleer SD kaart", + 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", + 2856261511: "Na %d geen wisselgeld adressen gevonden.", + 2788541416: "Na %d geen ontvangst adressen gevonden.", + 2446472910: "Wisselgeldadres %d controleren...", + 2470115694: "SD kaart controleren...", + 3655273987: "Ontvangstadres %d controleren...", + 2407028014: "Compact SeedQR", + 4041895036: "Doorgaan?", + 4094072796: "QR code maken", + 167798282: "QR code maken van tekst?", + 2767642191: "Aangemaakt: ", + 3513215254: "Aangepaste QR code", + 124617190: "Snijdiepte", + 597912140: "Snijmethode", + 2504034831: "Decimaal", + 2751113454: "Ontsleutelen?", + 3510912550: "Verwijderen %s?", + 1016609898: "Bestand verwijderen?", + 1364509700: "Geheugensteun verwijderen", + 4102535566: "Diepte per pas", + 2791699253: "Afgeleide: %s", + 1230133196: "Opslag op apparaat is niet gedetecteerd.", + 3836852788: "Klaar?", + 382368239: "Driver", + 3978947916: "Encoder", + 4090746898: "Encoder-debounce", + 374684711: "Geheugensteun versleutelen", + 1244124409: "Versleutelde QR code", + 2968548114: "Versleutelde geheugensteun was niet opgeslagen", + 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", + 350279787: "Versleutelen", + 2601598799: "Versleutel modus", + 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", + 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", + 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", + 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", + 784361051: "Fout:\n%s", + 1505332462: "Esc", + 3838465623: "Bestanden verkennen?", + 4170881190: "Exporteren naar SD-kaart..", + 1711312434: "Uitgebreide publieke sleutel", + 383371114: "Ontsleutelen is niet gelukt", + 3048830188: "PSBT laden is niet gelukt", + 4192663412: "Adres laden is niet gelukt", + 1996021743: "Sleutel laden is niet gelukt", + 1108715658: "Bericht laden is niet gelukt", + 1081425878: "Geheugensteun laden is niet gelukt", + 928667220: "Descriptor laden is niet gelukt", + 1620572516: "Wachtwoord laden is niet gelukt", + 2946146830: "Geheugensteun opslaan is niet gelukt", + 1303554751: "Tarief: ", + 104500973: "Voedingssnelheid", + 3313339187: "Bestandsnaam", + 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", + 3737729752: "Vingerafdruk: %s", + 2542772894: "Firmware overschrijdt de maximale grootte: %d", + 1406590538: "Fluit diameter", + 3086093110: "Vrij: ", + 1893243331: "Uit data-opslag", 4120536442: "GRBL", - 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", - 602716148: "OK", - 3580020863: "Шестнадцатеричный Публичный Ключ", - 2691246967: "Шестнадцатеричный", - 2736309107: "ID уже существует\n", - 1706005805: "Неполный выходной дескриптор", - 631342955: "Входы (%d): ", - 2585599782: "Неверный адрес", - 2874529150: "Неверный загрузчик", - 4093416954: "Неверная длина мнемоники", - 1422874211: "Неверный публичный ключ", - 2443867979: "Неверный кошелек:\n%s", - 4122897393: "Инвертировать", - 3000888649: "Ключ", - 2686333978: "Ключ: ", - 4123798664: "Krux\n\n\nВерсия\n%s", - 3835918229: "Тестовый QR Принтера Krux", - 766317539: "Язык", - 972436696: "Задержка Линии", - 3596093890: "Линия: ", - 2820726296: "Загрузить Мнемонику", - 879727077: "Загрузить с SD карты?", - 669106195: "Загрузить одну?", - 3330705289: "Загрузить?", - 2596531078: "Загрузка Камеры..", - 596389387: "Загрузка адреса сдачи %d..", - 336702608: "Загрузка принтера..", - 2538883522: "Загрузка адреса получения %d..", - 3159494909: "Загрузка..", - 1177338798: "Локаль", - 2817059741: "Расположение", - 63976957: "Уровень логирования", - 86530918: "Логирование", - 2917810189: "Максимальная длина превышена (%s)", - 2030045667: "Сообщение", - 3928301843: "Отсутствует файл подписи", - 1948316555: "Мнемоника", - 2123991188: "ID мнемоники", - 3911073154: "ID памяти мнемоники", - 570639842: "Мнемоника не была расшифрована", - 1746030071: "Мнемоника не была зашифрована", - 1458925155: "Изменено: ", - 1845376098: "Мультиподпись", - 2939797024: "Сеть", - 73574491: "Новая Мнемоника", - 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", - 4063104189: "Нет", - 3927838899: "Без BIP39 фразы-пароля", - 4092516657: "Недостаточно бросков!", - 1577637745: "Восьмеричный", - 3312581301: "PBKDF2 Итерации", - 721090621: "PSBT", - 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", - 2987800462: "Ширина Бумаги", - 3050763890: "Часть\n%d / %d", - 3559456868: "Размер Части", - 4249903283: "Фраза-пароль", - 3712257341: "Фраза-пароль: ", - 140802882: "Постоянная Память", - 1703779997: "QR открытым текстом", - 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", - 784609464: "Скорость Погружения", - 3037062877: "Напечатать Тестовый QR", - 4278257699: "Напечатать в виде QR?\n\n%s\n\n", - 516488026: "Печатать?\n\n%s\n\n", - 1123106929: "Принтер", - 3903571079: "Драйвер Принтера не установлен!", - 2609799302: "Идет печать\n%d / %d", - 844861889: "Идет печать ...", - 2580599003: "Продолжить?", - 556126964: "Обрабатываю ...", - 1848310591: "QR Код", - 710709610: "RX Пин", - 2697857197: "Получить", - 1746677167: "Адрес Получения", - 364354944: "Регион: ", - 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", - 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", - 856795528: "Броски:\n\n%s", - 255086803: "Броски: %d\n", - 3976793317: "SD карта", - 2827687530: "SD карта не обнаружена", - 2736513298: "SD карта не обнаружена.", - 3593785196: "SHA256 бросков:\n\n%s", - 1143278725: "SHA256 снэпшота:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Сохранить на SD карту?", - 810036588: "Сохранено на SD карту:\n%s", - 763824768: "Шкала", - 4117455079: "Отсканировать Адрес", - 3219991109: "Отсканировать BIP39 фразу-пароль", - 2537207336: "Отсканировать Ключ QR код", - 4006316572: "Сканирование слов 1-12 снова", - 2736506158: "Сканирование слов 13-24", - 266935239: "SeedQR", - 1698829144: "Трансфер самому себе или Сдача (%d): ", - 473154195: "Настройки", - 1825881236: "Выключить", - 2120776272: "Выключение..", - 1061961408: "Подписать", - 4282338366: "Подписать?", - 746161122: "Подпись", - 1988416729: "Подписанное Сообщение", - 3672006076: "Подписанное PSBT", - 2281377987: "Одна подпись", - 4221794628: "Размер: ", - 2344747135: "Некоторые проверки не могут быть выполнены.", - 2309020186: "Расход (%d): ", - 3355862324: "Стэкбит 1248", - 3303592908: "Сохранить на Флэш Память", - 720041451: "Сохранить на SD Карту", - 3514476519: "Свайпните, чтобы сменить режим", - 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", - 4228215415: "TX Пин", - 2612594937: "Текст", - 1454688268: "Тема", - 1180180513: "Термальный", - 4119292117: "Мини Сид-фраза", - 1732872974: "Мини Сид-фраза (Биты)", - 725348723: "Инструменты", - 3684696112: "Прикоснитесь Границы", - 2978718564: "Тачскрин", - 2732611775: "Попробовать ещё?", - 1487826746: "Введите BIP39 фразу-пароль", - 2061556020: "Введите Ключ", - 2089395053: "Юнит", - 2845607430: "Обновление загрузчика..\n\n%d%%", - 4164597446: "Обновление завершено.\n\nВыключение..", - 2736001501: "Обновление прошивки..\n\n%d%%", - 2674953168: "Использовать черную фоновую поверхность.", - 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", - 236075140: "Использовано: ", - 4003084591: "Значение %s вне диапозона: [%s, %s]", - 4191058607: "С Помощью Камеры", - 1254681955: "С Помощью D20", - 525309547: "С Помощью D6", - 590330112: "С Помощью Ручного Ввода", - 2504354847: "Дождитесь Захвата", - 2297028319: "Дескриптор Кошелька", - 4232654916: "Выходной дескриптор кошелька", - 2587172867: "Выходной дескриптор кошелька загружен!", - 2499782468: "Выходной дескриптор кошелька не найден.", - 2671738224: "Предупреждение:", - 797660533: "Слово %d", - 3742424146: "Числа Слов", - 2965123464: "Слова", - 1303016265: "Да", - 771968845: "Ваши изменения буду храниться на флэш памяти устройства.", - 2569054451: "Ваши изменения будут храниться на SD карте.", + 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", + 602716148: "Ga", + 3580020863: "Hex publieke sleutel", + 2691246967: "Hexadecimaal", + 2736309107: "ID bestaat al\n", + 1706005805: "Incomplete portemonnee descriptor", + 631342955: "Invoer (%d): ", + 2585599782: "Ongeldig adres", + 2874529150: "Ongeldige bootloader", + 4093416954: "Ongeldige geheugensteun lengte", + 1422874211: "Ongeldige publieke sleutel", + 2443867979: "Ongeldige portemonnee:\n%s", + 4122897393: "Omkeren", + 3000888649: "Sleutel", + 2686333978: "Sleutel: ", + 4123798664: "Krux\n\n\nVersie\n%s", + 3835918229: "Krux printer test QR", + 766317539: "Taal", + 972436696: "Lijn vertraging", + 3596093890: "Lijn: ", + 2820726296: "Geheugensteun laden", + 879727077: "Laden vanaf SD-kaart?", + 669106195: "Laden?", + 3330705289: "Laden?", + 2596531078: "Camera laden...", + 596389387: "Wisselgeldadres %d laden...", + 336702608: "Laadprinter..", + 2538883522: "Ontvangstadres %d laden...", + 3159494909: "Laden...", + 1177338798: "Taal", + 2817059741: "Opslaglocatie", + 63976957: "Log niveau", + 86530918: "Debug logs", + 2917810189: "Maximale lengte overschreden (%s)", + 2030045667: "Bericht", + 3928301843: "Handtekening bestand mist", + 1948316555: "Geheugensteun", + 2123991188: "Geheugensteun ID", + 3911073154: "Geheugensteun opslag ID", + 570639842: "Geheugensteun is niet ontsleuteld", + 1746030071: "Geheugensteun is niet versleuteld", + 1458925155: "Aangepast: ", + 1845376098: "Multisig", + 2939797024: "Netwerk", + 73574491: "Geheugensteun aanmaken", + 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", + 4063104189: "Nee", + 3927838899: "Geen BIP-39 wachtwoord", + 4092516657: "Niet genoeg gedobbeld!", + 1577637745: "Octaal", + 3312581301: "PBKDF2 iter.", + 721090621: "PSBT", + 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", + 2987800462: "Papier breedte", + 3050763890: "Deel\n%d / %d", + 3559456868: "Deel grootte", + 4249903283: "Wachtwoord", + 3712257341: "Wachtwoord: ", + 140802882: "Opslag", + 1703779997: "Platte tekst QR", + 3561756278: "Laadt een portemonnee descriptor in", + 784609464: "Duik tarief", + 3037062877: "Test QR afdrukken", + 4278257699: "Afdrukken naar QR?\n\n%s\n\n", + 516488026: "Afdrukken?\n\n%s\n\n", + 1123106929: "Printer", + 3903571079: "Printer driver niet ingesteld!", + 2609799302: "Afdruk\n%d / %d", + 844861889: "Afdrukken...", + 2580599003: "Doorgaan?", + 556126964: "Verwerken...", + 1848310591: "QR code", + 710709610: "RX pin", + 2697857197: "Ontvangen", + 1746677167: "Ontvangstadres", + 364354944: "Regio: ", + 1662254634: "Controleer gescande gegevens en bewerk indien nodig", + 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", + 856795528: "Gedobbeld:\n\n%s", + 255086803: "Gedobbeld: %d\n", + 3976793317: "SD kaart", + 2827687530: "SD kaart niet gedetecteerd", + 2736513298: "SD kaart niet gedetecteerd.", + 3593785196: "Gedobbelde SHA256:\n\n%s", + 1143278725: "Momentopname van SHA256:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Opslaan op SD-kaart?", + 810036588: "Opgeslagen op SD-kaart:\n%s", + 763824768: "Schaal", + 4117455079: "Adres scannen", + 3219991109: "BIP-39 wachtwoord scannen", + 2537207336: "QR code sleutel scannen", + 4006316572: "Woorden 1 t/m 12 opnieuw scannen", + 2736506158: "Woorden 13 t/m 24 scannen", + 266935239: "SeedQR", + 1698829144: "Zelf overschrijving of wisselgeld (%d): ", + 473154195: "Instellingen", + 1825881236: "Afsluiten", + 2120776272: "Bezig met afsluiten...", + 1061961408: "Ondertekenen", + 4282338366: "Ondertekenen?", + 746161122: "Handtekening", + 1988416729: "Bericht ondertekend", + 3672006076: "PSBT ondertekend", + 2281377987: "Enkele sleutel", + 4221794628: "Grootte: ", + 2344747135: "Sommige controles kunnen niet worden uitgevoerd.", + 2309020186: "Uitgaven (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Opslaan op apparaat", + 720041451: "Opslaan op SD kaart", + 3514476519: "Verander modus", + 1898550184: "TIK of ENTER voor opname", + 4228215415: "TX pin", + 2612594937: "Tekst", + 1454688268: "Thema", + 1180180513: "Thermisch", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Hulpmiddelen", + 3684696112: "Aanraak gevoeligheid", + 2978718564: "Aanraakscherm", + 2732611775: "Meer proberen?", + 1487826746: "Voer BIP-39 wachtwoord in", + 2061556020: "Voer sleutel in", + 2089395053: "Eenheid", + 2845607430: "Bootloader updaten...\n\n%d%%", + 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", + 2736001501: "Firmware upgraden...\n\n%d%%", + 2674953168: "Gebruik een donker achergrond.", + 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", + 236075140: "Gebruikt: ", + 4003084591: "Waarde %s is buiten bereik: [%s, %s]", + 4191058607: "Via camera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Via handmatige invoer", + 2504354847: "Wacht op opname", + 2297028319: "Descriptor", + 4232654916: "Portemonnee descriptor", + 2587172867: "Portemonnee descriptor geladen!", + 2499782468: "Portemonnee descriptor niet gevonden.", + 2671738224: "Waarschuwing:", + 797660533: "Woord %d", + 3742424146: "Woord nummers", + 2965123464: "Woorden", + 1303016265: "Yes", + 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", + 2569054451: "Veranderingen worden opgeslagen op SD kaart.", }, - "fr-FR": { - 1185266064: "%d de %d multisignature", - 2004520398: "%d. Changement : \n\n%s\n\n", - 3862364126: "%d. Auto-transfert : \n\n%s\n\n", - 3264377309: "%d. Dépense : \n\n%s\n\n", - 2399232215: "%s\n\nest une adresse changement valide!", - 3921290840: "%s\n\nest une adresse reçue valide!", - 1808355833: "INTROUVABLE dans les premières %d adresses de changement", - 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", - 3348584292: "(Expérimental)", - 2739590230: "12 mots", - 1310058127: "24 mots", + "de-DE": { + 1185266064: "%d von %d Multisig", + 2004520398: "%d. Change: \n\n%s\n\n", + 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", + 3264377309: "%d. Ausgaben: \n\n%s\n\n", + 2399232215: "%s\n\nist eine gültige Change Adresse!", + 3921290840: "%s\n\nist eine gültige Empfangsadresse!", + 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", + 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", + 3348584292: "(Experimental)", + 2739590230: "12 Wörter", + 1310058127: "24 Wörter", 2743272264: "ABC", - 1949634023: "À propos", + 1949634023: "Über", 1517128857: "Adafruit", 3270727197: "Adresse", - 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", - 283202181: "Alignez correctement la caméra et Tiny Seed.", - 88746165: "Anti-éblouissement désactivé", - 1521033296: "Anti-éblouissement activé", - 1056821534: "Es-tu sûr?", - 3247612282: "BIP39 Mnémonique", - 3455872521: "Retour", - 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", - 2256777600: "Mauvaise signature", - 3937333362: "Débit en bauds", + 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", + 283202181: "Richte Kamera und Tiny Seed korrekt aus.", + 88746165: "Blendschutz deaktiviert", + 1521033296: "Blendschutz aktiviert", + 1056821534: "Bist Du sicher?", + 3247612282: "BIP39 Mnemonic", + 3455872521: "Zurück", + 2541860807: "Bootloader wird gesichert..\n\n%d%%", + 2256777600: "Ungültige Signatur", + 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Rembourrage de bordure", + 928727036: "Randpolsterung", 213030954: "CNC", - 1207696150: "Changement", - 3126552510: "Adresses de Changement", - 1583186953: "Changer de thème et redémarrer?", - 2697733395: "Modifications enregistrées sur la carte SD!", - 388908871: "Les modifications dureront jusqu'à l'arrêt.", - 3442025874: "Vérifiez la carte SD", - 3119547911: "Vérifiez que l'adresse appartient à cette portefeuille?", - 2856261511: "Adresses %d changement vérifiées sans correspondance.", - 2788541416: "Adresses %d reçues vérifiées sans correspondance.", - 2446472910: "Vérification de l'adresse changement %d pour correspondance..", - 2470115694: "Vérification de la carte SD..", - 3655273987: "Vérification de l'adresse reçue %d pour correspondance..", - 2407028014: "SeedQR Compact", - 4041895036: "Continuer?", - 4094072796: "Créer du code QR", - 167798282: "Créer du code QR à partir du texte?", - 2767642191: "Créé:", - 3513215254: "Code QR personnalisé", - 124617190: "Profondeur de coupe", - 597912140: "Méthode de coupe", - 2504034831: "Décimal", - 2751113454: "Décrypter?", - 1016609898: "Supprimer le fichier?", - 1364509700: "Supprimer mnémonique", - 4102535566: "Profondeur par passage", - 2791699253: "Dérivation: %s", - 1230133196: "Stockage flash de l'appareil non détecté.", - 3836852788: "Terminé?", - 382368239: "Conducteur", - 3978947916: "Encodeur", - 4090746898: "Anti-rebond de l'encodeur", - 374684711: "Crypter mnémonique", - 1244124409: "Code QR crypté", - 2968548114: "Le mnémonique crypté n'a pas été stocké", - 3315319371: "Mnémonique cryptée a été stockée avec ID:", - 350279787: "Chiffrement", - 2601598799: "Mode de chiffrement", - 3504179008: "Entrez chaque mot de votre BIP-39 mnémonique sous la forme d'un nombre 1 jusqu'à 2048.", - 1100685007: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en hexadécimal de 1 à 800.", - 4090266642: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en octal de 1 à 4000.", - 2780625730: "Entrez chaque mot de votre BIP-39 mnémonique.", - 784361051: "Erreur:\n%s", + 1207696150: "Change Adresse", + 3126552510: "Change Adressen", + 1583186953: "Thema ändern und neu starten?", + 2697733395: "Änderungen auf SD-Karte gespeichert!", + 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", + 3442025874: "Prüfe SD-Karte", + 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", + 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", + 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", + 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", + 2470115694: "Suche nach SD-Karte..", + 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", + 2407028014: "Kompakt SeedQR", + 4041895036: "Weiter?", + 4094072796: "Erstelle QR-Code", + 167798282: "QR-Code aus Text erzeugen?", + 2767642191: "Erstellt:", + 3513215254: "Benutzerdefinierte QR-Code", + 124617190: "Schnitttiefe", + 597912140: "Cut-Methode", + 2504034831: "Dezimal", + 2751113454: "Entschlüsseln?", + 3510912550: "Löschen %s?", + 1016609898: "Datei löschen?", + 1364509700: "Mnemonic löschen", + 4102535566: "Tiefe pro Durchgang", + 2791699253: "Ableitung: %s", + 1230133196: "Geräte-Flash-Speicher nicht erkannt.", + 3836852788: "Fertig?", + 382368239: "Driver", + 3978947916: "Encoder", + 4090746898: "Encoder-Entprellung", + 374684711: "Verschlüssel Mnemonic", + 1244124409: "Verschlüsselter QR-Code", + 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", + 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", + 350279787: "Verschlüsselung", + 2601598799: "Verschlüsselungsmodus", + 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", + 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", + 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", + 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", + 784361051: "Fehler:\n%s", 1505332462: "Esc", - 3838465623: "Explorer des fichiers?", - 4170881190: "Exportation vers la carte SD..", - 1711312434: "Clé publique", - 383371114: "Échec de décrypter", - 3048830188: "Erreur de chargement PSBT", - 4192663412: "Erreur de chargement d'adresse", - 1996021743: "Échec du chargement de la clé", - 1108715658: "Échec du chargement du message", - 1081425878: "Erreur de chargement mnémonique", - 928667220: "Échec du chargement du descripteur de sortie", - 1620572516: "Échec du chargement de la phrase secrète", - 2946146830: "Échec de stocker mnémonique", - 1303554751: "Frais: ", - 104500973: "Taux d'alimentation", - 3313339187: "Nom de fichier", - 1982637349: "Le nom de fichier %s existe sur la carte SD, écraser ?", - 3737729752: "Empreinte Digitale: %s", - 2542772894: "Le micrologiciel dépasse la taille maximale: %d", - 1406590538: "Diamètre de flûte", - 3086093110: "Libre: ", - 1893243331: "Du stockage", + 3838465623: "Dateien durchsuchen?", + 4170881190: "Auf SD-Karte exportieren..", + 1711312434: "Öffentlicher Schlüssel", + 383371114: "Entschlüsselung fehlgeschlagen", + 3048830188: "PSBT konnte nicht geladen werden", + 4192663412: "Adresse konnte nicht geladen werden", + 1996021743: "Schlüssel konnte nicht geladen werden", + 1108715658: "Nachricht konnte nicht geladen werden", + 1081425878: "Mnemonic konnte nicht geladen werden", + 928667220: "Ausgabedeskriptor konnte nicht geladen werden", + 1620572516: "Passphrase konnte nicht geladen werden", + 2946146830: "Mnemonic konnte nicht gespeichert werden", + 1303554751: "Gebühr: ", + 104500973: "Vorschubgeschwindigkeit", + 3313339187: "Dateiname", + 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", + 3737729752: "Fingerabdruck: %s", + 2542772894: "Die Firmware übersteigt die maximale Größe: %d", + 1406590538: "Flötendurchmesser", + 3086093110: "Frei: ", + 1893243331: "Vom Speicher", 4120536442: "GRBL", - 299338213: "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", + 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", 602716148: "Go", - 3580020863: "Clé public hexadécimal", - 2691246967: "Hexadécimal", - 2736309107: "Id existe déjà\n", - 1706005805: "Descripteur de sortie incomplet", - 631342955: "Entrées (%d) : ", - 2585599782: "Adresse invalide", - 2874529150: "Chargeur de démarrage invalide", - 4093416954: "Longueur mnémonique invalide", - 1422874211: "Clé publique non valide", - 2443867979: "Portefeuille invalide:\n%s", - 4122897393: "Inverser", - 3000888649: "Clé", - 2686333978: "Clé:", + 3580020863: "Hex öffentlicher Schlüssel", + 2691246967: "Hexadezimal", + 2736309107: "ID existiert bereits\n", + 1706005805: "Unvollständiger Ausgabedeskriptor", + 631342955: "Input (%d): ", + 2585599782: "Ungültige Adresse", + 2874529150: "Ungültiger Bootloader", + 4093416954: "Ungültige mnemonische Lange", + 1422874211: "Ungültiger öffentlicher Schlüssel", + 2443867979: "Ungültige Wallet:\n%s", + 4122897393: "Umkehren", + 3000888649: "Schlüssel", + 2686333978: "Schlüssel:", 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Test de l'imprimante Krux QR", - 766317539: "Langue", - 972436696: "Délai de Ligne", - 3596093890: "Ligne: ", - 2820726296: "Charger mnémonique", - 879727077: "Charger depuis la carte SD ?", - 669106195: "En charger qu'un?", - 3330705289: "Charger?", - 2596531078: "Caméra de Chargement..", - 596389387: "Chargement de l'adresse de changement %d..", - 336702608: "Chargement de l'imprimante..", - 2538883522: "Chargement de l'adresse de réception %d..", - 3159494909: "Chargement..", - 1177338798: "Paramètres régionaux", - 2817059741: "Emplacement", - 63976957: "Niveau de journalisation", - 86530918: "Enregistrement", - 2917810189: "Longueur maximale dépassée (% s)", - 2030045667: "Message", - 3928301843: "Fichier de signature manquant", - 1948316555: "Mnémonique", - 2123991188: "ID mnémonique", - 3911073154: "ID de stockage mnémonique", - 570639842: "Mnémonique n'a pas été décryptée", - 1746030071: "Mnémonique n'était pas cryptée", - 1458925155: "Modifié:", - 1845376098: "Multi\nsignature", - 2939797024: "Réseau", - 73574491: "Nouveau mnémonique", - 2792272353: "Nouveau micrologiciel détecté.\n\nSHA256:\n%s\n\n\n\nInstaller?", - 4063104189: "Non", - 3927838899: "Pas de phrase passante bip39", - 4092516657: "Pas assez de rouleaux !", - 1577637745: "Octale", - 3312581301: "Itér. PBKDF2", + 3835918229: "Krux Drucker Test-QR", + 766317539: "Sprache", + 972436696: "Leitungsverzögerung", + 3596093890: "Linie: ", + 2820726296: "Mnemonic laden", + 879727077: "Von SD-Karte laden?", + 669106195: "Eine laden?", + 3330705289: "Laden?", + 2596531078: "Lade Kamera..", + 596389387: "Lade Change Adresse %d..", + 336702608: "Drucker wird geladen..", + 2538883522: "Lade Empfangsadresse %d..", + 3159494909: "Wird geladen..", + 1177338798: "Spracheinstellung", + 2817059741: "Speicherort", + 63976957: "Log Level", + 86530918: "Logging", + 2917810189: "Maximale Länge überschritten (%s)", + 2030045667: "Nachricht", + 3928301843: "Fehlende Signaturdatei", + 1948316555: "Mnemonic", + 2123991188: "Mnemonische ID", + 3911073154: "Mnemonische Speicher-ID", + 570639842: "Mnemonic wurde nicht entschlüsselt", + 1746030071: "Mnemonic wurde nicht verschlüsselt", + 1458925155: "Geändert:", + 1845376098: "Multisig", + 2939797024: "Netzwerk", + 73574491: "Neue Mnemonic", + 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", + 4063104189: "Nein", + 3927838899: "Keine BIP39 Passphrase", + 4092516657: "Nicht genug Würfe!", + 1577637745: "Oktal", + 3312581301: "PBKDF2-Iter.", 721090621: "PSBT", - 995862913: "Peignez les points perforés en noir afin qu'ils puissent être détectés.", - 2987800462: "Largeur du papier", - 3050763890: "Partie\n%d / %d", - 3559456868: "Taille de la pièce", - 4249903283: "Phrase de passe", - 3712257341: "Phrass de passe:", - 140802882: "Persister", - 1703779997: "QR en Texte Brut", - 3561756278: "Veuillez charger un descripteur de sortie de portefeuille", - 784609464: "Taux de plongée", - 3037062877: "Test d'impression QR", - 4278257699: "Imprimer en QR?\n\n%s\n\n", - 516488026: "Imprimer?\n\n%s\n\n", - 1123106929: "Imprimante", - 3903571079: "Le conducteur d'imprimante n'est pas défini!", - 2609799302: "Impression\n%d / %d", - 844861889: "Impression ...", - 2580599003: "Procéder?", - 556126964: "Traitement ...", - 1848310591: "QR Code", - 710709610: "RX Fiche", - 2697857197: "Recevoir", - 1746677167: "Adresses de Réception", - 364354944: "Région: ", - 1662254634: "Examinez les données numérisées, modifiez-les si nécessaire", - 770350922: "Lancez le dé au moins %d fois pour générer un mnémonique.", - 856795528: "Rouleaux:\n\n%s", - 255086803: "Rouleaux: %d\n", - 3976793317: "Carte SD", - 2827687530: "Carte SD non détectée", - 2736513298: "Carte SD non détectée.", - 3593785196: "SHA256 de rouleaux:\n\n%s", - 1143278725: "Sha256 de Snapshot:\n\n% s", + 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", + 2987800462: "Papierbreite", + 3050763890: "Teil\n%d / %d", + 3559456868: "Teilegröße", + 4249903283: "Passphrase", + 3712257341: "Passphrase:", + 140802882: "Speicher", + 1703779997: "Klartext-QR", + 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", + 784609464: "Tauchrate", + 3037062877: "Drucke Test-QR", + 4278257699: "Als QR-Code drucken?\n\n%s\n\n", + 516488026: "Drucken?\n\n%s\n\n", + 1123106929: "Drucker", + 3903571079: "Druckertreiber nicht gesetzt!", + 2609799302: "Drucken\n%d / %d", + 844861889: "Wird gedruckt ...", + 2580599003: "Weiter?", + 556126964: "Wird bearbeitet ...", + 1848310591: "QR-Code", + 710709610: "RX Pin", + 2697857197: "Empfangen", + 1746677167: "Empfangsadresse", + 364354944: "Region: ", + 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", + 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", + 856795528: "Würfe:\n\n%s", + 255086803: "Würfe: %d\n", + 3976793317: "SD-Karte", + 2827687530: "SD-Karte nicht erkannt", + 2736513298: "SD-Karte nicht erkannt.", + 3593785196: "SHA256 der Würfe:\n\n%s", + 1143278725: "SHA256 des Snapshots:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Enregistrer sur la carte SD ?", - 810036588: "Enregistré sur la carte SD :\n%s", - 763824768: "L'échelle", - 4117455079: "Scannez l'adresse", - 3219991109: "Scan bip39 en phrase secrète", - 2537207336: "Scanner le code QR de la clé", - 4006316572: "Analyser à nouveau les mots 1 à 12", - 2736506158: "Analyser les mots 13 à 24", - 266935239: "Seedqr", - 1698829144: "Auto-transfert ou changement (%d): ", - 473154195: "Paramètres", - 1825881236: "Fermer", - 2120776272: "Éteindre..", - 1061961408: "Signature", - 4282338366: "Signature?", - 746161122: "Signature", - 1988416729: "Message signé", - 3672006076: "PSBT signé", - 2281377987: "Clé unique", - 4221794628: "Capacité: ", - 2344747135: "Certains chèques ne peuvent pas être effectués.", - 2309020186: "Dépense (%d) : ", + 3531742595: "Auf SD-Karte speichern?", + 810036588: "Auf SD-Karte gespeichert:\n%s", + 763824768: "Skala", + 4117455079: "Adresse\nscannen", + 3219991109: "Scan BIP39 Passphrase", + 2537207336: "Schlüssel QR-Code scannen", + 4006316572: "Wörter 1-12 erneut scannen", + 2736506158: "Wörter 13-24 scannen", + 266935239: "SeedQR", + 1698829144: "Selbstübertragung oder Change (%d): ", + 473154195: "Einstellungen", + 1825881236: "Ausschalten", + 2120776272: "Herunterfahren..", + 1061961408: "Signieren", + 4282338366: "Signieren?", + 746161122: "Signatur", + 1988416729: "Signierte Nachricht", + 3672006076: "Signierte PSBT", + 2281377987: "Single-Sig", + 4221794628: "Größe: ", + 2344747135: "Einige Schecks können nicht durchgeführt werden.", + 2309020186: "Ausgabe (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Stocker sur flash", - 720041451: "Stocker sur la carte SD", - 3514476519: "Faites glisser pour changer de mode", - 1898550184: "TOUCHEZ ou ENTER pour capturer", - 4228215415: "TX Fiche", - 2612594937: "Texte", - 1454688268: "Thème", - 1180180513: "Thermique", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Outils", - 3684696112: "Seuil Tactile", - 2978718564: "Écran Tactile", - 2732611775: "Réessayer?", - 1487826746: "Type Bip39 Plasque", - 2061556020: "Clé de type", - 2089395053: "Unité", - 2845607430: "Mise à jour du chargeur de démarrage..\n\n%d%%", - 4164597446: "Mise à niveau complète.\n\nÉteindre..", - 2736001501: "Mise à niveau du micrologiciel..\n\n%d%%", - 2674953168: "Utilisez une surface de fond noire.", - 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", - 236075140: "Utilisé: ", - 4003084591: "Valeur% s hors de portée: [% s,% s]", - 4191058607: "Par caméra", + 3303592908: "Auf Flash speichern", + 720041451: "Auf der SD-Karte speichern", + 3514476519: "Wischen um den Modus zu ändern", + 1898550184: "TOUCH oder ENTER zum Erfassen", + 4228215415: "TX Pin", + 2612594937: "Text", + 1454688268: "Thema", + 1180180513: "Thermisch", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Werkzeuge", + 3684696112: "Berühre Schwellenwert", + 2978718564: "Touchscreen", + 2732611775: "Weiter versuchen?", + 1487826746: "BIP39 Passphrase eingeben", + 2061556020: "Schlüssel eingeben", + 2089395053: "Einheit", + 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", + 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", + 2736001501: "Firmware wird aktualisiert..\n\n%d%%", + 2674953168: "Verwende eine schwarze Hintergrundfläche.", + 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", + 236075140: "Belegt: ", + 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", + 4191058607: "Via Kamera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Par saisie manuelle", - 2504354847: "Attendez la capture", - 2297028319: "Descripteur de Portefeuille", - 4232654916: "Descripteur de sortie du portefeuille", - 2587172867: "Descripteur de sortie du portefeuille chargé!", - 2499782468: "Descripteur de sortie du portefeuille introuvable.", - 2671738224: "Avertissement:", - 797660533: "Mot %d", - 3742424146: "Numéros de mots", - 2965123464: "Mots", - 1303016265: "Oui", - 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", - 2569054451: "Vos modifications seront conservées sur la carte SD.", + 590330112: "Via manueller Eingabe", + 2504354847: "Warte auf die Erfassung", + 2297028319: "Wallet-Deskriptor", + 4232654916: "Wallet Ausgabedeskriptor", + 2587172867: "Wallet Ausgabedeskriptor geladen!", + 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", + 2671738224: "Warnung:", + 797660533: "Wort %d", + 3742424146: "Wortnummern", + 2965123464: "Wörter", + 1303016265: "Ja", + 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", + 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", }, - "nl-NL": { - 1185266064: "%d van %d multisig", - 2004520398: "%d. Wisselgeld: \n\n%s\n\n", - 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", - 3264377309: "%d. Uitgaven: \n\n%s\n\n", - 2399232215: "%s\n\nis een valide wisselgeld adres!", - 3921290840: "%s\n\nis een valide ontvangst adres!", - 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", - 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", - 3348584292: "(Experimenteel)", - 2739590230: "12 woorden", - 1310058127: "24 woorden", + "vi-VN": { + 1185266064: "%d của %d đa chữ kí", + 2004520398: "%d. Thay đổi: \n\n%s\n\n", + 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", + 3264377309: "%d. Chi tiêu: \n\n%s\n\n", + 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", + 3921290840: "%s\n\nlà một địa chỉ khả dụng!", + 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 3348584292: "(Thực nghiệm)", + 2739590230: "12 từ", + 1310058127: "24 từ", 2743272264: "ABC", - 1949634023: "Over", + 1949634023: "Về chúng tôi", 1517128857: "Adafruit", - 3270727197: "Adres", - 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", - 283202181: "Richt de camera en Tiny Seed op de juiste manier.", - 88746165: "Anti reflecterend uitgeschakeld", - 1521033296: "Anti reflecterend ingeschakeld", - 1056821534: "Weet je het zeker?", - 3247612282: "BIP-39 geheugensteun", - 3455872521: "Terug", - 2541860807: "Backup van de bootloader...\n\n%d%%", - 2256777600: "Ongeldige handtekening", - 3937333362: "Baudratio", + 3270727197: "Địa chỉ", + 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", + 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", + 88746165: "Chống lóa bị vô hiệu hóa", + 1521033296: "Đã bật chống lóa", + 1056821534: "Bạn có chắc không?", + 3247612282: "Mã mnemonic dạng chuẩn BIP39", + 3455872521: "Trở lại", + 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", + 2256777600: "Chữ ký xấu", + 3937333362: "Tốc độ baud", 427617266: "Bitcoin", - 928727036: "Rand opvulling", + 928727036: "Đệm viền", 213030954: "CNC", - 1207696150: "Change", - 3126552510: "Wisselgeldadres", - 1583186953: "Thema veranderen en opnieuw opstarten?", - 2697733395: "Wijzigingen aanhouden op SD kaart!", - 388908871: "Wijzigingen blijven van kracht tot afsluiten.", - 3442025874: "Controleer SD kaart", - 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", - 2856261511: "Na %d geen wisselgeld adressen gevonden.", - 2788541416: "Na %d geen ontvangst adressen gevonden.", - 2446472910: "Wisselgeldadres %d controleren...", - 2470115694: "SD kaart controleren...", - 3655273987: "Ontvangstadres %d controleren...", - 2407028014: "Compact SeedQR", - 4041895036: "Doorgaan?", - 4094072796: "QR code maken", - 167798282: "QR code maken van tekst?", - 2767642191: "Aangemaakt: ", - 3513215254: "Aangepaste QR code", - 124617190: "Snijdiepte", - 597912140: "Snijmethode", - 2504034831: "Decimaal", - 2751113454: "Ontsleutelen?", - 1016609898: "Bestand verwijderen?", - 1364509700: "Geheugensteun verwijderen", - 4102535566: "Diepte per pas", - 2791699253: "Afgeleide: %s", - 1230133196: "Opslag op apparaat is niet gedetecteerd.", - 3836852788: "Klaar?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-debounce", - 374684711: "Geheugensteun versleutelen", - 1244124409: "Versleutelde QR code", - 2968548114: "Versleutelde geheugensteun was niet opgeslagen", - 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", - 350279787: "Versleutelen", - 2601598799: "Versleutel modus", - 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", - 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", - 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", - 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", - 784361051: "Fout:\n%s", + 1207696150: "Thay đổi", + 3126552510: "Thay địa chỉ", + 1583186953: "Thay đổi chủ đề và khởi động lại?", + 2697733395: "Thay đổi được lưu trên thẻ SD!", + 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", + 3442025874: "Kiểm tra thẻ SD", + 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", + 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", + 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", + 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", + 2470115694: "Kiểm tra thẻ SD..", + 3655273987: "Đang kiểm tra %d địa chỉ..", + 2407028014: "SeedQR nhỏ gọn", + 4041895036: "Tiếp tục?", + 4094072796: "Tạo mã QR", + 167798282: "Tạo mã QR từ văn bản?", + 2767642191: "Tạo:", + 3513215254: "Mã QR tùy chỉnh", + 124617190: "Chiều sâu cắt", + 597912140: "Phương pháp cắt", + 2504034831: "Số thập phân", + 2751113454: "Phản đối?", + 3510912550: "Xóa %s?", + 1016609898: "Xóa tài liệu?", + 1364509700: "Xóa ghi nhớ", + 4102535566: "Độ sâu mỗi lần vượt qua", + 2791699253: "Nguồn gốc: %s", + 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", + 3836852788: "Hoàn tất?", + 382368239: "Người cầm lái", + 3978947916: "Mã hoá", + 4090746898: "Gỡ lỗi bộ mã hóa", + 374684711: "Mã hóa Mnemonic", + 1244124409: "Mã QR được mã hóa", + 2968548114: "MNemon được mã hóa không được lưu trữ", + 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", + 350279787: "Mã hóa", + 2601598799: "Chế độ mã hóa", + 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", + 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", + 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", + 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", + 784361051: "Lỗi:\n%s", 1505332462: "Esc", - 3838465623: "Bestanden verkennen?", - 4170881190: "Exporteren naar SD-kaart..", - 1711312434: "Uitgebreide publieke sleutel", - 383371114: "Ontsleutelen is niet gelukt", - 3048830188: "PSBT laden is niet gelukt", - 4192663412: "Adres laden is niet gelukt", - 1996021743: "Sleutel laden is niet gelukt", - 1108715658: "Bericht laden is niet gelukt", - 1081425878: "Geheugensteun laden is niet gelukt", - 928667220: "Descriptor laden is niet gelukt", - 1620572516: "Wachtwoord laden is niet gelukt", - 2946146830: "Geheugensteun opslaan is niet gelukt", - 1303554751: "Tarief: ", - 104500973: "Voedingssnelheid", - 3313339187: "Bestandsnaam", - 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", - 3737729752: "Vingerafdruk: %s", - 2542772894: "Firmware overschrijdt de maximale grootte: %d", - 1406590538: "Fluit diameter", - 3086093110: "Vrij: ", - 1893243331: "Uit data-opslag", - 4120536442: "GRBL", - 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", - 602716148: "Ga", - 3580020863: "Hex publieke sleutel", - 2691246967: "Hexadecimaal", - 2736309107: "ID bestaat al\n", - 1706005805: "Incomplete portemonnee descriptor", - 631342955: "Invoer (%d): ", - 2585599782: "Ongeldig adres", - 2874529150: "Ongeldige bootloader", - 4093416954: "Ongeldige geheugensteun lengte", - 1422874211: "Ongeldige publieke sleutel", - 2443867979: "Ongeldige portemonnee:\n%s", - 4122897393: "Omkeren", - 3000888649: "Sleutel", - 2686333978: "Sleutel: ", - 4123798664: "Krux\n\n\nVersie\n%s", - 3835918229: "Krux printer test QR", - 766317539: "Taal", - 972436696: "Lijn vertraging", - 3596093890: "Lijn: ", - 2820726296: "Geheugensteun laden", - 879727077: "Laden vanaf SD-kaart?", - 669106195: "Laden?", - 3330705289: "Laden?", - 2596531078: "Camera laden...", - 596389387: "Wisselgeldadres %d laden...", - 336702608: "Laadprinter..", - 2538883522: "Ontvangstadres %d laden...", - 3159494909: "Laden...", - 1177338798: "Taal", - 2817059741: "Opslaglocatie", - 63976957: "Log niveau", - 86530918: "Debug logs", - 2917810189: "Maximale lengte overschreden (%s)", - 2030045667: "Bericht", - 3928301843: "Handtekening bestand mist", - 1948316555: "Geheugensteun", - 2123991188: "Geheugensteun ID", - 3911073154: "Geheugensteun opslag ID", - 570639842: "Geheugensteun is niet ontsleuteld", - 1746030071: "Geheugensteun is niet versleuteld", - 1458925155: "Aangepast: ", - 1845376098: "Multisig", - 2939797024: "Netwerk", - 73574491: "Geheugensteun aanmaken", - 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", - 4063104189: "Nee", - 3927838899: "Geen BIP-39 wachtwoord", - 4092516657: "Niet genoeg gedobbeld!", - 1577637745: "Octaal", - 3312581301: "PBKDF2 iter.", + 3838465623: "Khám phá các tập tin?", + 4170881190: "Xuất vào thẻ SD ..", + 1711312434: "Khóa công cộng", + 383371114: "Không giải mã được", + 3048830188: "Tải PSBT thất bại", + 4192663412: "Tải địa chỉ thất bại", + 1996021743: "Không tải khóa", + 1108715658: "Không tải được tin nhắn", + 1081425878: "Tải mã mnemonic thất bại", + 928667220: "Không thể tải bộ mô tả đầu ra", + 1620572516: "Không tải được cụm mật khẩu", + 2946146830: "Không lưu trữ MNemonic", + 1303554751: "Phí: ", + 104500973: "Tỷ lệ thức ăn", + 3313339187: "Tên tệp", + 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", + 3737729752: "Dấu vân tay: %s", + 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", + 1406590538: "Đường kính ống sáo", + 3086093110: "Khả dụng: ", + 1893243331: "Từ lưu trữ", + 4120536442: "GRBL", + 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", + 602716148: "Đến", + 3580020863: "Khóa công khai Hex", + 2691246967: "Thập lục phân", + 2736309107: "Id đã tồn tại\n", + 1706005805: "Bộ mô tả đầu ra chưa hoàn chỉnh", + 631342955: "Đầu vào (%d): ", + 2585599782: "Địa chỉ không hợp lệ", + 2874529150: "Bộ tải khởi động không hợp lệ", + 4093416954: "Độ dài mã mnemonic không hợp lệ", + 1422874211: "Khóa công khai không hợp lệ", + 2443867979: "Ví không hợp lệ:\n%s", + 4122897393: "Đảo ngược", + 3000888649: "Chìa khóa", + 2686333978: "Chìa khóa:", + 4123798664: "Krux\n\n\nPhiên Bản\n%s", + 3835918229: "QR kiểm tra máy in Krux", + 766317539: "Ngôn ngữ", + 972436696: "Độ trễ Dòng", + 3596093890: "Đường kẻ: ", + 2820726296: "Tải mã mnemonic", + 879727077: "Tải từ thẻ SD?", + 669106195: "Tải một?", + 3330705289: "Tải?", + 2596531078: "Đang tải máy ảnh..", + 596389387: "Đang tải thay đổi địa chỉ %d..", + 336702608: "Tải máy in ..", + 2538883522: "Đang tải địa chỉ nhận %d..", + 3159494909: "Đang tải..", + 1177338798: "Ngôn ngữ", + 2817059741: "Vị trí cửa hàng", + 63976957: "Log Level", + 86530918: "Khai thác gỗ", + 2917810189: "Chiều dài tối đa vượt quá (%s)", + 2030045667: "Tin nhắn", + 3928301843: "Thiếu tập tin chữ ký", + 1948316555: "Mã mnemonic", + 2123991188: "ID ghi nhớ", + 3911073154: "ID lưu trữ ghi nhớ", + 570639842: "Ghi nhớ không được giải mã", + 1746030071: "Ghi nhớ không được mã hóa", + 1458925155: "Đã sửa đổi:", + 1845376098: "Đa chữ kí", + 2939797024: "Mạng lưới", + 73574491: "Mnemonic mới", + 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", + 4063104189: "Không", + 3927838899: "Không có cụm mật khẩu BIP39", + 4092516657: "Không đủ cuộn!", + 1577637745: "Bát phân", + 3312581301: "Lặp lại PBKDF2", 721090621: "PSBT", - 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", - 2987800462: "Papier breedte", - 3050763890: "Deel\n%d / %d", - 3559456868: "Deel grootte", - 4249903283: "Wachtwoord", - 3712257341: "Wachtwoord: ", - 140802882: "Opslag", - 1703779997: "Platte tekst QR", - 3561756278: "Laadt een portemonnee descriptor in", - 784609464: "Duik tarief", - 3037062877: "Test QR afdrukken", - 4278257699: "Afdrukken naar QR?\n\n%s\n\n", - 516488026: "Afdrukken?\n\n%s\n\n", - 1123106929: "Printer", - 3903571079: "Printer driver niet ingesteld!", - 2609799302: "Afdruk\n%d / %d", - 844861889: "Afdrukken...", - 2580599003: "Doorgaan?", - 556126964: "Verwerken...", - 1848310591: "QR code", - 710709610: "RX pin", - 2697857197: "Ontvangen", - 1746677167: "Ontvangstadres", - 364354944: "Regio: ", - 1662254634: "Controleer gescande gegevens en bewerk indien nodig", - 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", - 856795528: "Gedobbeld:\n\n%s", - 255086803: "Gedobbeld: %d\n", - 3976793317: "SD kaart", - 2827687530: "SD kaart niet gedetecteerd", - 2736513298: "SD kaart niet gedetecteerd.", - 3593785196: "Gedobbelde SHA256:\n\n%s", - 1143278725: "Momentopname van SHA256:\n\n%s", + 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", + 2987800462: "Chiều rộng giấy", + 3050763890: "Phần\n%d / %d", + 3559456868: "Kích thước một phần", + 4249903283: "Cụm mật khẩu", + 3712257341: "Cụm cụm:", + 140802882: "Vị trí lưu", + 1703779997: "Văn bản rõ QR", + 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", + 784609464: "Tỷ lệ sụt giảm", + 3037062877: "In kiểm tra QR", + 4278257699: "In ra mã QR?\n\n%s\n\n", + 516488026: "In?\n\n%s\n\n", + 1123106929: "Máy in", + 3903571079: "Trình điều khiển máy in không đặt!", + 2609799302: "Đang in\n%d / %d", + 844861889: "In ấn ...", + 2580599003: "Thực hiện?", + 556126964: "Xử lý ...", + 1848310591: "Mã QR", + 710709610: "RX Ghim", + 2697857197: "Nhận được", + 1746677167: "Nhận địa chỉ", + 364354944: "Vùng: ", + 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", + 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", + 856795528: "Súc sắc cuộn:\n\n%s", + 255086803: "Súc sắc cuộn: %d\n", + 3976793317: "Thẻ SD", + 2827687530: "Thẻ SD không được phát hiện", + 2736513298: "Thẻ SD không được phát hiện.", + 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", + 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Opslaan op SD-kaart?", - 810036588: "Opgeslagen op SD-kaart:\n%s", - 763824768: "Schaal", - 4117455079: "Adres scannen", - 3219991109: "BIP-39 wachtwoord scannen", - 2537207336: "QR code sleutel scannen", - 4006316572: "Woorden 1 t/m 12 opnieuw scannen", - 2736506158: "Woorden 13 t/m 24 scannen", - 266935239: "SeedQR", - 1698829144: "Zelf overschrijving of wisselgeld (%d): ", - 473154195: "Instellingen", - 1825881236: "Afsluiten", - 2120776272: "Bezig met afsluiten...", - 1061961408: "Ondertekenen", - 4282338366: "Ondertekenen?", - 746161122: "Handtekening", - 1988416729: "Bericht ondertekend", - 3672006076: "PSBT ondertekend", - 2281377987: "Enkele sleutel", - 4221794628: "Grootte: ", - 2344747135: "Sommige controles kunnen niet worden uitgevoerd.", - 2309020186: "Uitgaven (%d): ", + 3531742595: "Lưu vào thẻ SD?", + 810036588: "Đã lưu vào thẻ SD:\n%s", + 763824768: "Cái cân", + 4117455079: "Quét địa chỉ", + 3219991109: "Quét BIP39 Cụm cụm", + 2537207336: "Quét mã QR khóa", + 4006316572: "Quét lại từ 1-12", + 2736506158: "Quét từ 13-24", + 266935239: "SEEDQR", + 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", + 473154195: "Cài đặt", + 1825881236: "Tắt", + 2120776272: "Đang tắt..", + 1061961408: "Chữ kí", + 4282338366: "Kí?", + 746161122: "Chữ ký", + 1988416729: "Tin nhắn đã ký", + 3672006076: "Đã ký PSBT", + 2281377987: "Khóa đơn", + 4221794628: "Dung lượng: ", + 2344747135: "Một số kiểm tra không thể được thực hiện.", + 2309020186: "Chi tiêu (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Opslaan op apparaat", - 720041451: "Opslaan op SD kaart", - 3514476519: "Verander modus", - 1898550184: "TIK of ENTER voor opname", - 4228215415: "TX pin", - 2612594937: "Tekst", - 1454688268: "Thema", - 1180180513: "Thermisch", + 3303592908: "Lưu trữ trên flash", + 720041451: "Lưu trữ trên thẻ SD", + 3514476519: "Vuốt để thay đổi chế độ", + 1898550184: "TOUCH hoặc ENTER để chụp", + 4228215415: "TX Ghim", + 2612594937: "Chữ", + 1454688268: "Chủ đề", + 1180180513: "Nhiệt", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Hulpmiddelen", - 3684696112: "Aanraak gevoeligheid", - 2978718564: "Aanraakscherm", - 2732611775: "Meer proberen?", - 1487826746: "Voer BIP-39 wachtwoord in", - 2061556020: "Voer sleutel in", - 2089395053: "Eenheid", - 2845607430: "Bootloader updaten...\n\n%d%%", - 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", - 2736001501: "Firmware upgraden...\n\n%d%%", - 2674953168: "Gebruik een donker achergrond.", - 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", - 236075140: "Gebruikt: ", - 4003084591: "Waarde %s is buiten bereik: [%s, %s]", - 4191058607: "Via camera", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Via handmatige invoer", - 2504354847: "Wacht op opname", - 2297028319: "Descriptor", - 4232654916: "Portemonnee descriptor", - 2587172867: "Portemonnee descriptor geladen!", - 2499782468: "Portemonnee descriptor niet gevonden.", - 2671738224: "Waarschuwing:", - 797660533: "Woord %d", - 3742424146: "Woord nummers", - 2965123464: "Woorden", - 1303016265: "Yes", - 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", - 2569054451: "Veranderingen worden opgeslagen op SD kaart.", + 1732872974: "Tiny Seed (bit)", + 725348723: "Công cụ", + 3684696112: "Ngưỡng cảm ứng", + 2978718564: "Màn hình cảm ứng", + 2732611775: "Thử thêm nữa?", + 1487826746: "Nhập cụm BIP39", + 2061556020: "Nhập khóa", + 2089395053: "Đơn vị", + 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", + 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", + 2736001501: "Nâng cấp firmware..\n\n%d%%", + 2674953168: "Sử dụng bề mặt nền đen.", + 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", + 236075140: "Đã sử dụng: ", + 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", + 4191058607: "Qua máy ảnh", + 1254681955: "Qua D20", + 525309547: "Qua D6", + 590330112: "Thông qua đầu vào thủ công", + 2504354847: "Chờ bắt", + 2297028319: "Trình mô tả ví", + 4232654916: "Ví đầu ra mô tả", + 2587172867: "Đã tải bộ mô tả đầu ra của ví!", + 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", + 2671738224: "Cảnh báo:", + 797660533: "Kí tự %d", + 3742424146: "Từ số", + 2965123464: "Từ ngữ", + 1303016265: "Đúng", + 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", + 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", }, } From 15556e2e7a529aa11a8a7920f1b19f74debe195b Mon Sep 17 00:00:00 2001 From: tadeubas Date: Sun, 1 Oct 2023 20:52:52 -0300 Subject: [PATCH 038/114] added missing translations --- i18n/translations/pl-PL.json | 2 + i18n/translations/ru-RU.json | 2 + src/krux/translations.py | 3338 +++++++++++++++++----------------- 3 files changed, 1681 insertions(+), 1661 deletions(-) diff --git a/i18n/translations/pl-PL.json b/i18n/translations/pl-PL.json index 6a075b2db..d1c93ce91 100644 --- a/i18n/translations/pl-PL.json +++ b/i18n/translations/pl-PL.json @@ -186,6 +186,7 @@ "Scan Key QR code": "Skanuj kod QR", "Scanning words 1-12 again": "Znowu skanowanie słów 1-12", "Scanning words 13-24": "Skanowanie słów 13-24", + "Screensaver": "Wygaszacz ekranu", "SeedQR": "Seedqr", "Self-transfer or Change (%d): ": "Samo-transfer lub zmiana (%d):", "Settings": "Ustawienia", @@ -230,6 +231,7 @@ "Via D6": "Przez D6", "Via Manual Input": "Poprzez ręczne wejście", "Wait for the capture": "Poczekaj na schwytanie", + "Wait time": "Czas oczekiwania", "Wallet Descriptor": "Deskryptor portfela", "Wallet output descriptor": "Deskryptor wyjściowy portfela", "Wallet output descriptor loaded!": "Załadowany deskryptor wyjściowy portfela!", diff --git a/i18n/translations/ru-RU.json b/i18n/translations/ru-RU.json index 9a76c183c..50681123b 100644 --- a/i18n/translations/ru-RU.json +++ b/i18n/translations/ru-RU.json @@ -186,6 +186,7 @@ "Scan Key QR code": "Отсканировать Ключ QR код", "Scanning words 1-12 again": "Сканирование слов 1-12 снова", "Scanning words 13-24": "Сканирование слов 13-24", + "Screensaver": "Заставка", "SeedQR": "SeedQR", "Self-transfer or Change (%d): ": "Трансфер самому себе или Сдача (%d): ", "Settings": "Настройки", @@ -230,6 +231,7 @@ "Via D6": "С Помощью D6", "Via Manual Input": "С Помощью Ручного Ввода", "Wait for the capture": "Дождитесь Захвата", + "Wait time": "Время ожидания", "Wallet Descriptor": "Дескриптор Кошелька", "Wallet output descriptor": "Выходной дескриптор кошелька", "Wallet output descriptor loaded!": "Выходной дескриптор кошелька загружен!", diff --git a/src/krux/translations.py b/src/krux/translations.py index 6d26801c6..c6af3cbed 100644 --- a/src/krux/translations.py +++ b/src/krux/translations.py @@ -21,522 +21,280 @@ # THE SOFTWARE. # pylint: disable=C0301 translation_table = { - "pt-BR": { - 1185266064: "%d da %d multisig", - 2004520398: "%d. Troco: \n\n%s\n\n", - 3862364126: "%d. Autotransferência: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n é um endereço de troco válido!", - 3921290840: "%s\n\né um endereço de recepção válido!", - 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", - 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", + "de-DE": { + 1185266064: "%d von %d Multisig", + 2004520398: "%d. Change: \n\n%s\n\n", + 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", + 3264377309: "%d. Ausgaben: \n\n%s\n\n", + 2399232215: "%s\n\nist eine gültige Change Adresse!", + 3921290840: "%s\n\nist eine gültige Empfangsadresse!", + 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", + 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", 3348584292: "(Experimental)", - 2739590230: "12 palavras", - 1310058127: "24 palavras", + 2739590230: "12 Wörter", + 1310058127: "24 Wörter", 2743272264: "ABC", - 1949634023: "Sobre", + 1949634023: "Über", 1517128857: "Adafruit", - 3270727197: "Endereço", - 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", - 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", - 88746165: "Antirreflexo desativado", - 1521033296: "Antirreflexo ativado", - 1056821534: "Tem certeza?", - 3247612282: "Mnemônico BIP39", - 3455872521: "Voltar", - 2541860807: "Backing up bootloader..\n\n%d%%", - 2256777600: "Assinatura Inválida", + 3270727197: "Adresse", + 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", + 283202181: "Richte Kamera und Tiny Seed korrekt aus.", + 88746165: "Blendschutz deaktiviert", + 1521033296: "Blendschutz aktiviert", + 1056821534: "Bist Du sicher?", + 3247612282: "BIP39 Mnemonic", + 3455872521: "Zurück", + 2541860807: "Bootloader wird gesichert..\n\n%d%%", + 2256777600: "Ungültige Signatur", 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Borda", + 928727036: "Randpolsterung", 213030954: "CNC", - 1207696150: "Troco", - 3126552510: "Endereços de Troco", - 1583186953: "Mudar o tema e reiniciar?", - 2697733395: "Mudanças salvas no cartão SD!", - 388908871: "Alterações só durarão até o desligamento.", - 3442025874: "Verifique o cartão SD", - 3119547911: "Verificar se este endereço pertence a carteira?", - 2856261511: "Endereço de troco %d não corresponde.", - 2788541416: "Endereço de recebimento %d não corresponde.", - 2446472910: "Verificando correspondência do endereço de troco %d ..", - 2470115694: "Verificando o cartão SD..", - 3655273987: "Verificando correspondência do endereço de recebimento %d ..", - 2407028014: "SeedQR Compacto", - 4041895036: "Continuar?", - 4094072796: "Gerar Código QR", - 167798282: "Gerar código QR do texto?", - 2767642191: "Criado: ", - 3513215254: "Código QR Customizado", - 124617190: "Profundidade de Corte", - 597912140: "Método de Corte", - 2504034831: "Decimal", - 2751113454: "Descriptografar?", - 1016609898: "Excluir Arquivo?", - 1364509700: "Excluir Mnemônico", - 4102535566: "Profundidade da Passagem", - 2791699253: "Derivação: %s", - 1230133196: "Armazenamento flash do dispositivo não detectado.", - 3836852788: "Feito?", + 1207696150: "Change Adresse", + 3126552510: "Change Adressen", + 1583186953: "Thema ändern und neu starten?", + 2697733395: "Änderungen auf SD-Karte gespeichert!", + 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", + 3442025874: "Prüfe SD-Karte", + 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", + 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", + 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", + 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", + 2470115694: "Suche nach SD-Karte..", + 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", + 2407028014: "Kompakt SeedQR", + 4041895036: "Weiter?", + 4094072796: "Erstelle QR-Code", + 167798282: "QR-Code aus Text erzeugen?", + 2767642191: "Erstellt:", + 3513215254: "Benutzerdefinierte QR-Code", + 124617190: "Schnitttiefe", + 597912140: "Cut-Methode", + 2504034831: "Dezimal", + 2751113454: "Entschlüsseln?", + 1016609898: "Datei löschen?", + 1364509700: "Mnemonic löschen", + 4102535566: "Tiefe pro Durchgang", + 2791699253: "Ableitung: %s", + 1230133196: "Geräte-Flash-Speicher nicht erkannt.", + 3836852788: "Fertig?", 382368239: "Driver", - 3978947916: "Codificador", - 4090746898: "Debounce do Encoder", - 374684711: "Criptografar Mnemônico", - 1244124409: "Código QR Criptografado", - 2968548114: "Mnemonic criptografado não foi armazenado", - 3315319371: "Mnemônico criptografado foi armazenado com ID:", - 350279787: "Criptografia", - 2601598799: "Modo de Criptografia", - 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", - 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", - 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", - 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", - 784361051: "Erro:\n%s", + 3978947916: "Encoder", + 4090746898: "Encoder-Entprellung", + 374684711: "Verschlüssel Mnemonic", + 1244124409: "Verschlüsselter QR-Code", + 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", + 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", + 350279787: "Verschlüsselung", + 2601598799: "Verschlüsselungsmodus", + 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", + 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", + 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", + 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", + 784361051: "Fehler:\n%s", 1505332462: "Esc", - 3838465623: "Explorar arquivos?", - 4170881190: "Exportando para o cartão SD..", - 1711312434: "Chave Pública Estendida", - 383371114: "Falhou em descriptografar", - 3048830188: "Falhou ao carregar PSBT", - 4192663412: "Falhou ao carregar endereço", - 1996021743: "Falha ao carregar a chave", - 1108715658: "Falhou ao carregar mensagem", - 1081425878: "Falhou ao carregar mnemônico", - 928667220: "Falha ao carregar o descritor de saída", - 1620572516: "Falha ao carregar a senha", - 2946146830: "Falhou ao armazenar mnemônico", - 1303554751: "Taxa: ", - 104500973: "Taxa de Alimentação", - 3313339187: "Nome do arquivo", - 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", - 3737729752: "Impressão digital: %s", - 2542772894: "Firmware excede o tamanho máximo: %d", - 1406590538: "Diâmetro da Fresa", - 3086093110: "Livre: ", - 1893243331: "Do Armazenamento", + 3838465623: "Dateien durchsuchen?", + 4170881190: "Auf SD-Karte exportieren..", + 1711312434: "Öffentlicher Schlüssel", + 383371114: "Entschlüsselung fehlgeschlagen", + 3048830188: "PSBT konnte nicht geladen werden", + 4192663412: "Adresse konnte nicht geladen werden", + 1996021743: "Schlüssel konnte nicht geladen werden", + 1108715658: "Nachricht konnte nicht geladen werden", + 1081425878: "Mnemonic konnte nicht geladen werden", + 928667220: "Ausgabedeskriptor konnte nicht geladen werden", + 1620572516: "Passphrase konnte nicht geladen werden", + 2946146830: "Mnemonic konnte nicht gespeichert werden", + 1303554751: "Gebühr: ", + 104500973: "Vorschubgeschwindigkeit", + 3313339187: "Dateiname", + 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", + 3737729752: "Fingerabdruck: %s", + 2542772894: "Die Firmware übersteigt die maximale Größe: %d", + 1406590538: "Flötendurchmesser", + 3086093110: "Frei: ", + 1893243331: "Vom Speicher", 4120536442: "GRBL", - 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", - 602716148: "Ir", - 3580020863: "Chave pública hexadecimal", - 2691246967: "Hexadecimal", - 2736309107: "Id já existe\n", - 1706005805: "Descritor incompleto", - 631342955: "Entradas (%d): ", - 2585599782: "Endereço inválido", - 2874529150: "Bootloader inválido", - 4093416954: "Comprimento de mnemônico inválido", - 1422874211: "Chave pública inválida", - 2443867979: "Carteira inválida:\n%s", - 4122897393: "Invertido", - 3000888649: "Chave", - 2686333978: "Chave:", - 4123798664: "Krux\n\n\nVersão\n%s", - 3835918229: "Teste de impressão de QR krux", - 766317539: "Língua", - 972436696: "Atraso de Linha", - 3596093890: "Linha: ", - 2820726296: "Carregar Mnemônico", - 879727077: "Carregar do cartão SD?", - 669106195: "Carregar um?", - 3330705289: "Carregar?", - 2596531078: "Carregando Câmera..", - 596389387: "Carregando endereço de troco %d..", - 336702608: "Carregando impressora..", - 2538883522: "Carregando endereço de recebimento %d..", - 3159494909: "Carregando..", - 1177338798: "Idioma", - 2817059741: "Local", - 63976957: "Nível de log", + 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 602716148: "Go", + 3580020863: "Hex öffentlicher Schlüssel", + 2691246967: "Hexadezimal", + 2736309107: "ID existiert bereits\n", + 1706005805: "Unvollständiger Ausgabedeskriptor", + 631342955: "Input (%d): ", + 2585599782: "Ungültige Adresse", + 2874529150: "Ungültiger Bootloader", + 4093416954: "Ungültige mnemonische Lange", + 1422874211: "Ungültiger öffentlicher Schlüssel", + 2443867979: "Ungültige Wallet:\n%s", + 4122897393: "Umkehren", + 3000888649: "Schlüssel", + 2686333978: "Schlüssel:", + 4123798664: "Krux\n\n\nVersion\n%s", + 3835918229: "Krux Drucker Test-QR", + 766317539: "Sprache", + 972436696: "Leitungsverzögerung", + 3596093890: "Linie: ", + 2820726296: "Mnemonic laden", + 879727077: "Von SD-Karte laden?", + 669106195: "Eine laden?", + 3330705289: "Laden?", + 2596531078: "Lade Kamera..", + 596389387: "Lade Change Adresse %d..", + 336702608: "Drucker wird geladen..", + 2538883522: "Lade Empfangsadresse %d..", + 3159494909: "Wird geladen..", + 1177338798: "Spracheinstellung", + 2817059741: "Speicherort", + 63976957: "Log Level", 86530918: "Logging", - 2917810189: "Comprimento máximo excedido (%s)", - 2030045667: "Mensagem", - 3928301843: "Arquivo de assinatura faltando", - 1948316555: "Mnemônico", - 2123991188: "ID do mnemônico", - 3911073154: "ID de armazenamento", - 570639842: "Mnemônico não foi descriptografado", - 1746030071: "Mnemônico não foi criptografado", - 1458925155: "Modificado:", + 2917810189: "Maximale Länge überschritten (%s)", + 2030045667: "Nachricht", + 3928301843: "Fehlende Signaturdatei", + 1948316555: "Mnemonic", + 2123991188: "Mnemonische ID", + 3911073154: "Mnemonische Speicher-ID", + 570639842: "Mnemonic wurde nicht entschlüsselt", + 1746030071: "Mnemonic wurde nicht verschlüsselt", + 1458925155: "Geändert:", 1845376098: "Multisig", - 2939797024: "Rede", - 73574491: "Novo Mnemônico", - 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", - 4063104189: "Não", - 3927838899: "Sem senha BIP39", - 4092516657: "Jogadas insuficientes!", - 1577637745: "Octal", - 3312581301: "Iter. PBKDF2", + 2939797024: "Netzwerk", + 73574491: "Neue Mnemonic", + 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", + 4063104189: "Nein", + 3927838899: "Keine BIP39 Passphrase", + 4092516657: "Nicht genug Würfe!", + 1577637745: "Oktal", + 3312581301: "PBKDF2-Iter.", 721090621: "PSBT", - 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", - 2987800462: "Largura do papel", - 3050763890: "Parte\n%d / %d", - 3559456868: "Tamanho da peça", - 4249903283: "Senha", - 3712257341: "Senha:", - 140802882: "Salvar", - 1703779997: "QR em Texto", - 3561756278: "Carregue um descritor da carteira", - 784609464: "Taxa de Mergulho", - 3037062877: "Imprimir QR de teste", - 4278257699: "Imprimir QR?\n\n%s\n\n", - 516488026: "Imprimir?\n\n%s\n\n", - 1123106929: "Impressora", - 3903571079: "Driver de impressora não está definido!", - 2609799302: "Imprimindo\n%d / %d", - 844861889: "Imprimindo ...", - 2580599003: "Seguir?", - 556126964: "Processando ...", - 1848310591: "Código QR", - 710709610: "Pino RX", - 2697857197: "Recebimento", - 1746677167: "Endereços de Recebimento", - 364354944: "Região: ", - 1662254634: "Revise os dados, edite se necessário", - 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", - 856795528: "Jogadas:\n\n%s", - 255086803: "Jogadas: %d\n", - 3976793317: "Cartão SD", - 2827687530: "Cartão SD não detectado", - 2736513298: "Cartão SD não detectado.", - 3593785196: "SHA256 de jogadas:\n\n%s", - 1143278725: "Sha256 da imagem:\n\n%s", + 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", + 2987800462: "Papierbreite", + 3050763890: "Teil\n%d / %d", + 3559456868: "Teilegröße", + 4249903283: "Passphrase", + 3712257341: "Passphrase:", + 140802882: "Speicher", + 1703779997: "Klartext-QR", + 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", + 784609464: "Tauchrate", + 3037062877: "Drucke Test-QR", + 4278257699: "Als QR-Code drucken?\n\n%s\n\n", + 516488026: "Drucken?\n\n%s\n\n", + 1123106929: "Drucker", + 3903571079: "Druckertreiber nicht gesetzt!", + 2609799302: "Drucken\n%d / %d", + 844861889: "Wird gedruckt ...", + 2580599003: "Weiter?", + 556126964: "Wird bearbeitet ...", + 1848310591: "QR-Code", + 710709610: "RX Pin", + 2697857197: "Empfangen", + 1746677167: "Empfangsadresse", + 364354944: "Region: ", + 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", + 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", + 856795528: "Würfe:\n\n%s", + 255086803: "Würfe: %d\n", + 3976793317: "SD-Karte", + 2827687530: "SD-Karte nicht erkannt", + 2736513298: "SD-Karte nicht erkannt.", + 3593785196: "SHA256 der Würfe:\n\n%s", + 1143278725: "SHA256 des Snapshots:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Salvar no cartão SD?", - 810036588: "Salvo no cartão SD:\n%s", - 763824768: "Escala", - 4117455079: "Escanear Endereço", - 3219991109: "Escanear a senha BIP39", - 2537207336: "Escanear código QR da chave", - 4006316572: "Escaneando as palavras 1-12 novamente", - 2736506158: "Escaneando as palavras 13-24", + 3531742595: "Auf SD-Karte speichern?", + 810036588: "Auf SD-Karte gespeichert:\n%s", + 763824768: "Skala", + 4117455079: "Adresse\nscannen", + 3219991109: "Scan BIP39 Passphrase", + 2537207336: "Schlüssel QR-Code scannen", + 4006316572: "Wörter 1-12 erneut scannen", + 2736506158: "Wörter 13-24 scannen", + 3593497655: "Bildschirmschoner", 266935239: "SeedQR", - 1698829144: "Autotransferência ou Troco (%d): ", - 473154195: "Configurações", - 1825881236: "Desligar", - 2120776272: "Desligando..", - 1061961408: "Assinar", - 4282338366: "Assinar?", - 746161122: "Assinatura", - 1988416729: "Mensagem Assinada", - 3672006076: "PSBT Assinada", - 2281377987: "Single-sig", - 4221794628: "Total: ", - 2344747135: "Algumas verificações não podem ser realizadas.", - 2309020186: "Gastos (%d): ", + 1698829144: "Selbstübertragung oder Change (%d): ", + 473154195: "Einstellungen", + 1825881236: "Ausschalten", + 2120776272: "Herunterfahren..", + 1061961408: "Signieren", + 4282338366: "Signieren?", + 746161122: "Signatur", + 1988416729: "Signierte Nachricht", + 3672006076: "Signierte PSBT", + 2281377987: "Single-Sig", + 4221794628: "Größe: ", + 2344747135: "Einige Schecks können nicht durchgeführt werden.", + 2309020186: "Ausgabe (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Armazene na Flash", - 720041451: "Armazene no Cartão SD", - 3514476519: "Deslize para mudar de modo", - 1898550184: "TOQUE ou ENTER para capturar", - 4228215415: "Pino TX", - 2612594937: "Texto", - 1454688268: "Tema", - 1180180513: "Térmica", + 3303592908: "Auf Flash speichern", + 720041451: "Auf der SD-Karte speichern", + 3514476519: "Wischen um den Modus zu ändern", + 1898550184: "TOUCH oder ENTER zum Erfassen", + 4228215415: "TX Pin", + 2612594937: "Text", + 1454688268: "Thema", + 1180180513: "Thermisch", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Ferramentas", - 3684696112: "Limiar de Toque", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Werkzeuge", + 3684696112: "Berühre Schwellenwert", 2978718564: "Touchscreen", - 2732611775: "Tentar mais?", - 1487826746: "Digitar a senha BIP39", - 2061556020: "Digite a Chave", - 2089395053: "Unidade", - 2845607430: "Atualizando bootloader..\n\n%d%%", - 4164597446: "Atualização completa.\n\nDesligando..", - 2736001501: "Atualizando firmware..\n\n%d%%", - 2674953168: "Use uma superfície de fundo preta.", - 2402455261: "Use a entropia da câmera para criar um novo mnemônico", - 236075140: "Usado: ", - 4003084591: "Valor %s fora do alcance: [ %s, %s]", - 4191058607: "Pela Câmera", + 2732611775: "Weiter versuchen?", + 1487826746: "BIP39 Passphrase eingeben", + 2061556020: "Schlüssel eingeben", + 2089395053: "Einheit", + 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", + 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", + 2736001501: "Firmware wird aktualisiert..\n\n%d%%", + 2674953168: "Verwende eine schwarze Hintergrundfläche.", + 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", + 236075140: "Belegt: ", + 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", + 4191058607: "Via Kamera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Por entrada manual", - 2504354847: "Aguarde a captura", - 2297028319: "Descritor de Carteira", - 4232654916: "Descritor da carteira", - 2587172867: "Descritor de saída da carteira carregado!", - 2499782468: "O descritor de saída da carteira não foi encontrado.", - 2671738224: "Aviso:", - 797660533: "Palavra %d", - 3742424146: "Números das Palavras", - 2965123464: "Palavras", - 1303016265: "Sim", - 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", - 2569054451: "Suas alterações serão mantidas no cartão SD.", + 590330112: "Via manueller Eingabe", + 2504354847: "Warte auf die Erfassung", + 3992434312: "Wartezeit", + 2297028319: "Wallet-Deskriptor", + 4232654916: "Wallet Ausgabedeskriptor", + 2587172867: "Wallet Ausgabedeskriptor geladen!", + 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", + 2671738224: "Warnung:", + 797660533: "Wort %d", + 3742424146: "Wortnummern", + 2965123464: "Wörter", + 1303016265: "Ja", + 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", + 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", }, - "pl-PL": { - 1185266064: "%d z %d multisig", - 2004520398: "%D.Zmiana:\n\n%s\n\n", - 3862364126: "%D.Samo-transfer:\n\n%s\n\n", - 3264377309: "%D.Wydać:\n\n%s\n\n", - 2399232215: "%s\n\nis prawidłowy adres zmiany!", - 3921290840: "%s\n\nis ważny adres odbierania!", - 1808355833: "%s\n\nwas nie znaleziono w pierwszych adresach zmiany", - 1306127065: "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", - 3348584292: "(Eksperymentalny)", - 2739590230: "12 słów", - 1310058127: "24 słowa", + "es-MX": { + 1185266064: "%d de %d multisig", + 2004520398: "%d. Cambio: \n\n%s\n\n", + 3862364126: "%d. Autotransferencia: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n¡es una dirección de cambio válida!", + 3921290840: "%s\n\nes un dirección de depósito válido!", + 1808355833: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de cambio", + 1306127065: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de depósito", + 3348584292: "(Experimental)", + 2739590230: "12 palabras", + 1310058127: "24 palabras", 2743272264: "ABC", - 1949634023: "O", + 1949634023: "Nosotros", 1517128857: "Adafruit", - 3270727197: "Adres", - 2574498267: "Dodatkowa entropia z kamery wymaganej dla trybu AES-CBC", - 283202181: "Właściwie wyrównaj kamerę i maleńkie nasiona.", - 88746165: "Niepełnosprawne przeciwblokowane", - 1521033296: "Włączona anty-zabawa", - 1056821534: "Jesteś pewny?", - 3247612282: "BIP39 Mnemonic", - 3455872521: "Z powrotem", - 2541860807: "Kopie zapasowe bootloader ..\n\n%d %%", - 2256777600: "zły podpis", - 3937333362: "Baudrate", + 3270727197: "Dirección", + 2574498267: "Entropía adicional desde la cámara requerida para el modo AES-CBC", + 283202181: "Alinee la cámara y Tiny Seed correctamente.", + 88746165: "Antideslumbrante desactivado", + 1521033296: "Antideslumbrante habilitado", + 1056821534: "¿Estas seguro?", + 3247612282: "BIP39 Mnemónico", + 3455872521: "Atrás", + 2541860807: "Copia de seguridad del cargador de arranque..\n\n%d%%", + 2256777600: "Mala asignatura", + 3937333362: "Velocidad en baudios", 427617266: "Bitcoin", - 928727036: "Wyściółka graniczna", - 213030954: "CNC", - 1207696150: "Zmiana", - 3126552510: "Zmień adresy", - 1583186953: "Zmienić motyw i ponownie uruchomić?", - 2697733395: "Zmiany utrzymywały się na karcie SD!", - 388908871: "Zmiany będą trwać do zamknięcia.", - 3442025874: "Sprawdź kartę SD", - 3119547911: "Sprawdź, czy adres należy do tego portfela?", - 2856261511: "Sprawdzone %d adresy zmiany bez dopasowań.", - 2788541416: "Sprawdzone %D Otrzymuj adresy bez zapałek.", - 2446472910: "Sprawdzanie Zmieniania Adres %D dla dopasowania.", - 2470115694: "Sprawdzanie karty SD ..", - 3655273987: "Sprawdzanie adresu Otrzymaj %D dla meczu.", - 2407028014: "Kompaktowy seedqr", - 4041895036: "Kontynuować?", - 4094072796: "Utwórz kod QR", - 167798282: "Utwórz kod QR z tekstu?", - 2767642191: "Utworzony:", - 3513215254: "Niestandardowy kod QR", - 124617190: "Wytnij głębokość", - 597912140: "Metoda cięcia", - 2504034831: "Dziesiętny", - 2751113454: "Odszyfrować?", - 1016609898: "Usunąć plik?", - 1364509700: "Usuń mnemonic", - 4102535566: "Głębokość na przepustkę", - 2791699253: "Pochodzenie: %s", - 1230133196: "Nie wykryto pamięci flash urządzenia.", - 3836852788: "Zrobione?", - 382368239: "Kierowca", - 3978947916: "Enkoder", - 4090746898: "Encoder Debunet", - 374684711: "Szyfrowanie mnemoniki", - 1244124409: "Zaszyfrowany kod QR", - 2968548114: "Szyfrowana mnemonika nie była przechowywana", - 3315319371: "Szyfrowana mnemonika była przechowywana z ID:", - 350279787: "Szyfrowanie", - 2601598799: "Tryb szyfrowania", - 3504179008: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę od 1 do 2048 r.", - 1100685007: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w heksadecimal od 1 do 800.", - 4090266642: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w wysokości od 1 do 4000.", - 2780625730: "Wprowadź każde słowo swojego mnemonika BIP-39.", - 784361051: "Błąd:\n%s", - 1505332462: "wyjście", - 3838465623: "Eksplorować pliki?", - 4170881190: "Eksportowanie do karty SD ..", - 1711312434: "Rozszerzony klucz publiczny", - 383371114: "Nie udało się odszyfrować", - 3048830188: "Nie udało się załadować PSBT", - 4192663412: "Nie udało się załadować adresu", - 1996021743: "Nie udało się załadować klucza", - 1108715658: "Nie udało się załadować wiadomości", - 1081425878: "Nie udało się załadować mnemonika", - 928667220: "Nie udało się załadować deskryptora wyjściowego", - 1620572516: "Nie udało się załadować pseudonim", - 2946146830: "Nie udało się przechowywać mnemonika", - 1303554751: "Opłata:", - 104500973: "Szybkość pasz", - 3313339187: "Nazwa pliku", - 1982637349: "Nazwa pliku %s istnieje na karcie SD, zastąp?", - 3737729752: "Odcisk palca: %s", - 2542772894: "Oprogramowanie układowe przekracza maksymalny rozmiar: %D", - 1406590538: "Średnica fletu", - 3086093110: "Bezpłatny:", - 1893243331: "Z przechowywania", - 4120536442: "Grbl", - 299338213: "Podaj temu mnemonicznemu identyfikatorowi?W przeciwnym razie zostanie użyty obecny odcisk palca", - 602716148: "Iść", - 3580020863: "Hex Key Public", - 2691246967: "Szesnastkowy", - 2736309107: "ID już istnieje\n", - 1706005805: "inComplete Descriptor", - 631342955: "Wejścia (%d):", - 2585599782: "Błędny adres", - 2874529150: "Nieprawidłowy bootloader", - 4093416954: "Nieprawidłowa długość mnemoniczna", - 1422874211: "Nieprawidłowy klucz publiczny", - 2443867979: "Nieprawidłowy portfel:\n%s", - 4122897393: "Odwracać", - 3000888649: "Klucz", - 2686333978: "Klucz:", - 4123798664: "Krux\n\n\neversion\n%s", - 3835918229: "Test drukarki Krux QR", - 766317539: "Język", - 972436696: "Opóźnienie linii", - 3596093890: "Linia:", - 2820726296: "Ładuj mnemoniczne", - 879727077: "Załaduj z karty SD?", - 669106195: "Załaduj jeden?", - 3330705289: "Obciążenie?", - 2596531078: "Ładowanie aparatu ..", - 596389387: "Ładowanie ZMIANY Adres %D ..", - 336702608: "Ładowanie drukarki ..", - 2538883522: "Ładowanie adresu odbierania %d ..", - 3159494909: "Ładowanie..", - 1177338798: "Widownia", - 2817059741: "Lokalizacja", - 63976957: "Poziom dziennika", - 86530918: "Logowanie", - 2917810189: "Maksymalna długość przekroczona (%s)", - 2030045667: "Wiadomość", - 3928301843: "Brakujący plik podpisu", - 1948316555: "Mnemoniczny", - 2123991188: "Mnemoniczne id", - 3911073154: "Mnemoniczny identyfikator przechowywania", - 570639842: "Mnemonik nie został odszyfrowany", - 1746030071: "Mnemoniczny nie był szyfrowany", - 1458925155: "Zmodyfikowany:", - 1845376098: "Multisig", - 2939797024: "Sieć", - 73574491: "Nowy Mnemonic", - 2792272353: "Wykryto nowe oprogramowanie.\n\nsha256:\n%s\n\n\n\ninstall?", - 4063104189: "NIE", - 3927838899: "Brak frazy BIP39", - 4092516657: "Za mało rolki!", - 1577637745: "Octal", - 3312581301: "PBKDF2 ITER.", - 721090621: "PSBT", - 995862913: "Parzyj kropki czarne, aby można je było wykryć.", - 2987800462: "Szerokość papieru", - 3050763890: "Część\n %d / %d", - 3559456868: "Rozmiar części", - 4249903283: "Fraza", - 3712257341: "FRASSE:", - 140802882: "Trwać", - 1703779997: "PlainText QR", - 3561756278: "Załaduj deskryptor wyjściowy portfela", - 784609464: "Szybkość spadku", - 3037062877: "Test wydrukuj QR", - 4278257699: "Drukuj do qr?\n\n%s\n\n", - 516488026: "Wydrukować?\n\n%s\n\n", - 1123106929: "Drukarka", - 3903571079: "Sterownik drukarki nie jest ustawiony!", - 2609799302: "Drukowanie\n %d / %d", - 844861889: "Drukowanie ...", - 2580599003: "Przystępować?", - 556126964: "Przetwarzanie ...", - 1848310591: "Kod QR", - 710709610: "Pin Rx", - 2697857197: "Odbierać", - 1746677167: "Odbierać adresy", - 364354944: "Region:", - 1662254634: "Przejrzyj zeskanowane dane, w razie potrzeby edytuj", - 770350922: "Rzuć kostkę co najmniej %d, aby wygenerować mnemoniczny.", - 856795528: "Rolls:\n\n%s", - 255086803: "Rolls: %d\n", - 3976793317: "karta SD", - 2827687530: "Karta SD nie została wykryta", - 2736513298: "Karta SD nie została wykryta.", - 3593785196: "SHA256 Rolls:\n\n%s", - 1143278725: "SHA256 migawki:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Zapisz na karcie SD?", - 810036588: "Zapisano na karcie SD:\n%s", - 763824768: "Skala", - 4117455079: "Adres skanowania", - 3219991109: "Scan BIP39 Passhraz", - 2537207336: "Skanuj kod QR", - 4006316572: "Znowu skanowanie słów 1-12", - 2736506158: "Skanowanie słów 13-24", - 266935239: "Seedqr", - 1698829144: "Samo-transfer lub zmiana (%d):", - 473154195: "Ustawienia", - 1825881236: "Zamknięcie", - 2120776272: "Wyłączanie..", - 1061961408: "Podpisać", - 4282338366: "Podpisać?", - 746161122: "Podpis", - 1988416729: "Podpisana wiadomość", - 3672006076: "Podpisano PSBT", - 2281377987: "Pojedyncze Sig", - 4221794628: "Rozmiar:", - 2344747135: "Nie można wykonać niektórych kontroli.", - 2309020186: "Wydać (%d):", - 3355862324: "Stackbit 1248", - 3303592908: "Przechowuj na Flash", - 720041451: "Przechowuj na karcie SD", - 3514476519: "Przesuń tryb zmiany", - 1898550184: "Dotknij lub wejdź do przechwytywania", - 4228215415: "Pin TX", - 2612594937: "Tekst", - 1454688268: "Temat", - 1180180513: "Termiczny", - 4119292117: "Małe ziarno", - 1732872974: "Małe nasiona (bity)", - 725348723: "Narzędzia", - 3684696112: "Próg dotykowy", - 2978718564: "Ekran dotykowy", - 2732611775: "Próbuj bardziej?", - 1487826746: "Passówka typu BIP39", - 2061556020: "Klucz typu", - 2089395053: "Jednostka", - 2845607430: "Aktualizacja bootloader ..\n\n%d %%", - 4164597446: "Uaktualnienie zakończone.\n\nshutting w dół ..", - 2736001501: "Aktualizacja oprogramowania układowego ..\n\n%d %%", - 2674953168: "Użyj czarnej powierzchni tła.", - 2402455261: "Użyj entropii aparatu, aby stworzyć nowy mnemonik", - 236075140: "Używany:", - 4003084591: "Wartość %s z zakresu: [ %s, %s]", - 4191058607: "Za pośrednictwem aparatu", - 1254681955: "Via D20", - 525309547: "Przez D6", - 590330112: "Poprzez ręczne wejście", - 2504354847: "Poczekaj na schwytanie", - 2297028319: "Deskryptor portfela", - 4232654916: "Deskryptor wyjściowy portfela", - 2587172867: "Załadowany deskryptor wyjściowy portfela!", - 2499782468: "Nie znaleziono deskryptora wyjściowego portfela.", - 2671738224: "Ostrzeżenie:", - 797660533: "Słowo %d", - 3742424146: "Numery słów", - 2965123464: "Słowa", - 1303016265: "Tak", - 771968845: "Twoje zmiany będą przechowywane w pamięci flash urządzenia.", - 2569054451: "Twoje zmiany będą przechowywane na karcie SD.", - }, - "es-MX": { - 1185266064: "%d de %d multisig", - 2004520398: "%d. Cambio: \n\n%s\n\n", - 3862364126: "%d. Autotransferencia: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n¡es una dirección de cambio válida!", - 3921290840: "%s\n\nes un dirección de depósito válido!", - 1808355833: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de cambio", - 1306127065: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de depósito", - 3348584292: "(Experimental)", - 2739590230: "12 palabras", - 1310058127: "24 palabras", - 2743272264: "ABC", - 1949634023: "Nosotros", - 1517128857: "Adafruit", - 3270727197: "Dirección", - 2574498267: "Entropía adicional desde la cámara requerida para el modo AES-CBC", - 283202181: "Alinee la cámara y Tiny Seed correctamente.", - 88746165: "Antideslumbrante desactivado", - 1521033296: "Antideslumbrante habilitado", - 1056821534: "¿Estas seguro?", - 3247612282: "BIP39 Mnemónico", - 3455872521: "Atrás", - 2541860807: "Copia de seguridad del cargador de arranque..\n\n%d%%", - 2256777600: "Mala asignatura", - 3937333362: "Velocidad en baudios", - 427617266: "Bitcoin", - 928727036: "Relleno de borde", + 928727036: "Relleno de borde", 213030954: "CNC", 1207696150: "Cambio", 3126552510: "Direcciones de Cambio", @@ -697,6 +455,7 @@ 2537207336: "Escanear el código QR", 4006316572: "Escaneo de palabras 1-12 de nuevo", 2736506158: "Escaneo de palabras 13-24", + 3593497655: "Protector de pantalla", 266935239: "Seedqr", 1698829144: "Autotransferencia o Cambio (%d): ", 473154195: "Ajustes", @@ -741,6 +500,7 @@ 525309547: "Via D6", 590330112: "Mediante entrada manual", 2504354847: "Espera la captura", + 3992434312: "Tiempo de espera", 2297028319: "Descriptor de Cartera", 4232654916: "Descriptor de salida de billetera", 2587172867: "¡Se ha cargado el descriptor de salida de la cartera!", @@ -753,1224 +513,1480 @@ 771968845: "Sus cambios se guardarán en el almacenamiento flash del dispositivo.", 2569054451: "Sus cambios se guardarán en la tarjeta SD.", }, - "de-DE": { - 1185266064: "%d von %d Multisig", - 2004520398: "%d. Change: \n\n%s\n\n", - 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", - 3264377309: "%d. Ausgaben: \n\n%s\n\n", - 2399232215: "%s\n\nist eine gültige Change Adresse!", - 3921290840: "%s\n\nist eine gültige Empfangsadresse!", - 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", - 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", - 3348584292: "(Experimental)", - 2739590230: "12 Wörter", - 1310058127: "24 Wörter", + "fr-FR": { + 1185266064: "%d de %d multisignature", + 2004520398: "%d. Changement : \n\n%s\n\n", + 3862364126: "%d. Auto-transfert : \n\n%s\n\n", + 3264377309: "%d. Dépense : \n\n%s\n\n", + 2399232215: "%s\n\nest une adresse changement valide!", + 3921290840: "%s\n\nest une adresse reçue valide!", + 1808355833: "INTROUVABLE dans les premières %d adresses de changement", + 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", + 3348584292: "(Expérimental)", + 2739590230: "12 mots", + 1310058127: "24 mots", 2743272264: "ABC", - 1949634023: "Über", + 1949634023: "À propos", 1517128857: "Adafruit", 3270727197: "Adresse", - 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", - 283202181: "Richte Kamera und Tiny Seed korrekt aus.", - 88746165: "Blendschutz deaktiviert", - 1521033296: "Blendschutz aktiviert", - 1056821534: "Bist Du sicher?", - 3247612282: "BIP39 Mnemonic", - 3455872521: "Zurück", - 2541860807: "Bootloader wird gesichert..\n\n%d%%", - 2256777600: "Ungültige Signatur", - 3937333362: "Baudrate", + 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", + 283202181: "Alignez correctement la caméra et Tiny Seed.", + 88746165: "Anti-éblouissement désactivé", + 1521033296: "Anti-éblouissement activé", + 1056821534: "Es-tu sûr?", + 3247612282: "BIP39 Mnémonique", + 3455872521: "Retour", + 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", + 2256777600: "Mauvaise signature", + 3937333362: "Débit en bauds", 427617266: "Bitcoin", - 928727036: "Randpolsterung", + 928727036: "Rembourrage de bordure", 213030954: "CNC", - 1207696150: "Change Adresse", - 3126552510: "Change Adressen", - 1583186953: "Thema ändern und neu starten?", - 2697733395: "Änderungen auf SD-Karte gespeichert!", - 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", - 3442025874: "Prüfe SD-Karte", - 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", - 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", - 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", - 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", - 2470115694: "Suche nach SD-Karte..", - 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", - 2407028014: "Kompakt SeedQR", - 4041895036: "Weiter?", - 4094072796: "Erstelle QR-Code", - 167798282: "QR-Code aus Text erzeugen?", - 2767642191: "Erstellt:", - 3513215254: "Benutzerdefinierte QR-Code", - 124617190: "Schnitttiefe", - 597912140: "Cut-Methode", - 2504034831: "Dezimal", - 2751113454: "Entschlüsseln?", - 1016609898: "Datei löschen?", - 1364509700: "Mnemonic löschen", - 4102535566: "Tiefe pro Durchgang", - 2791699253: "Ableitung: %s", - 1230133196: "Geräte-Flash-Speicher nicht erkannt.", - 3836852788: "Fertig?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-Entprellung", - 374684711: "Verschlüssel Mnemonic", - 1244124409: "Verschlüsselter QR-Code", - 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", - 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", - 350279787: "Verschlüsselung", - 2601598799: "Verschlüsselungsmodus", - 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", - 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", - 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", - 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", - 784361051: "Fehler:\n%s", + 1207696150: "Changement", + 3126552510: "Adresses de Changement", + 1583186953: "Changer de thème et redémarrer?", + 2697733395: "Modifications enregistrées sur la carte SD!", + 388908871: "Les modifications dureront jusqu'à l'arrêt.", + 3442025874: "Vérifiez la carte SD", + 3119547911: "Vérifiez que l'adresse appartient à cette portefeuille?", + 2856261511: "Adresses %d changement vérifiées sans correspondance.", + 2788541416: "Adresses %d reçues vérifiées sans correspondance.", + 2446472910: "Vérification de l'adresse changement %d pour correspondance..", + 2470115694: "Vérification de la carte SD..", + 3655273987: "Vérification de l'adresse reçue %d pour correspondance..", + 2407028014: "SeedQR Compact", + 4041895036: "Continuer?", + 4094072796: "Créer du code QR", + 167798282: "Créer du code QR à partir du texte?", + 2767642191: "Créé:", + 3513215254: "Code QR personnalisé", + 124617190: "Profondeur de coupe", + 597912140: "Méthode de coupe", + 2504034831: "Décimal", + 2751113454: "Décrypter?", + 1016609898: "Supprimer le fichier?", + 1364509700: "Supprimer mnémonique", + 4102535566: "Profondeur par passage", + 2791699253: "Dérivation: %s", + 1230133196: "Stockage flash de l'appareil non détecté.", + 3836852788: "Terminé?", + 382368239: "Conducteur", + 3978947916: "Encodeur", + 4090746898: "Anti-rebond de l'encodeur", + 374684711: "Crypter mnémonique", + 1244124409: "Code QR crypté", + 2968548114: "Le mnémonique crypté n'a pas été stocké", + 3315319371: "Mnémonique cryptée a été stockée avec ID:", + 350279787: "Chiffrement", + 2601598799: "Mode de chiffrement", + 3504179008: "Entrez chaque mot de votre BIP-39 mnémonique sous la forme d'un nombre 1 jusqu'à 2048.", + 1100685007: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en hexadécimal de 1 à 800.", + 4090266642: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en octal de 1 à 4000.", + 2780625730: "Entrez chaque mot de votre BIP-39 mnémonique.", + 784361051: "Erreur:\n%s", 1505332462: "Esc", - 3838465623: "Dateien durchsuchen?", - 4170881190: "Auf SD-Karte exportieren..", - 1711312434: "Öffentlicher Schlüssel", - 383371114: "Entschlüsselung fehlgeschlagen", - 3048830188: "PSBT konnte nicht geladen werden", - 4192663412: "Adresse konnte nicht geladen werden", - 1996021743: "Schlüssel konnte nicht geladen werden", - 1108715658: "Nachricht konnte nicht geladen werden", - 1081425878: "Mnemonic konnte nicht geladen werden", - 928667220: "Ausgabedeskriptor konnte nicht geladen werden", - 1620572516: "Passphrase konnte nicht geladen werden", - 2946146830: "Mnemonic konnte nicht gespeichert werden", - 1303554751: "Gebühr: ", - 104500973: "Vorschubgeschwindigkeit", - 3313339187: "Dateiname", - 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", - 3737729752: "Fingerabdruck: %s", - 2542772894: "Die Firmware übersteigt die maximale Größe: %d", - 1406590538: "Flötendurchmesser", - 3086093110: "Frei: ", - 1893243331: "Vom Speicher", + 3838465623: "Explorer des fichiers?", + 4170881190: "Exportation vers la carte SD..", + 1711312434: "Clé publique", + 383371114: "Échec de décrypter", + 3048830188: "Erreur de chargement PSBT", + 4192663412: "Erreur de chargement d'adresse", + 1996021743: "Échec du chargement de la clé", + 1108715658: "Échec du chargement du message", + 1081425878: "Erreur de chargement mnémonique", + 928667220: "Échec du chargement du descripteur de sortie", + 1620572516: "Échec du chargement de la phrase secrète", + 2946146830: "Échec de stocker mnémonique", + 1303554751: "Frais: ", + 104500973: "Taux d'alimentation", + 3313339187: "Nom de fichier", + 1982637349: "Le nom de fichier %s existe sur la carte SD, écraser ?", + 3737729752: "Empreinte Digitale: %s", + 2542772894: "Le micrologiciel dépasse la taille maximale: %d", + 1406590538: "Diamètre de flûte", + 3086093110: "Libre: ", + 1893243331: "Du stockage", 4120536442: "GRBL", - 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 299338213: "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", 602716148: "Go", - 3580020863: "Hex öffentlicher Schlüssel", - 2691246967: "Hexadezimal", - 2736309107: "ID existiert bereits\n", - 1706005805: "Unvollständiger Ausgabedeskriptor", - 631342955: "Input (%d): ", - 2585599782: "Ungültige Adresse", - 2874529150: "Ungültiger Bootloader", - 4093416954: "Ungültige mnemonische Lange", - 1422874211: "Ungültiger öffentlicher Schlüssel", - 2443867979: "Ungültige Wallet:\n%s", - 4122897393: "Umkehren", - 3000888649: "Schlüssel", - 2686333978: "Schlüssel:", + 3580020863: "Clé public hexadécimal", + 2691246967: "Hexadécimal", + 2736309107: "Id existe déjà\n", + 1706005805: "Descripteur de sortie incomplet", + 631342955: "Entrées (%d) : ", + 2585599782: "Adresse invalide", + 2874529150: "Chargeur de démarrage invalide", + 4093416954: "Longueur mnémonique invalide", + 1422874211: "Clé publique non valide", + 2443867979: "Portefeuille invalide:\n%s", + 4122897393: "Inverser", + 3000888649: "Clé", + 2686333978: "Clé:", 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Krux Drucker Test-QR", - 766317539: "Sprache", - 972436696: "Leitungsverzögerung", - 3596093890: "Linie: ", - 2820726296: "Mnemonic laden", - 879727077: "Von SD-Karte laden?", - 669106195: "Eine laden?", - 3330705289: "Laden?", - 2596531078: "Lade Kamera..", - 596389387: "Lade Change Adresse %d..", - 336702608: "Drucker wird geladen..", - 2538883522: "Lade Empfangsadresse %d..", - 3159494909: "Wird geladen..", - 1177338798: "Spracheinstellung", - 2817059741: "Speicherort", - 63976957: "Log Level", - 86530918: "Logging", - 2917810189: "Maximale Länge überschritten (%s)", - 2030045667: "Nachricht", - 3928301843: "Fehlende Signaturdatei", - 1948316555: "Mnemonic", - 2123991188: "Mnemonische ID", - 3911073154: "Mnemonische Speicher-ID", - 570639842: "Mnemonic wurde nicht entschlüsselt", - 1746030071: "Mnemonic wurde nicht verschlüsselt", - 1458925155: "Geändert:", - 1845376098: "Multisig", - 2939797024: "Netzwerk", - 73574491: "Neue Mnemonic", - 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", - 4063104189: "Nein", - 3927838899: "Keine BIP39 Passphrase", - 4092516657: "Nicht genug Würfe!", - 1577637745: "Oktal", - 3312581301: "PBKDF2-Iter.", + 3835918229: "Test de l'imprimante Krux QR", + 766317539: "Langue", + 972436696: "Délai de Ligne", + 3596093890: "Ligne: ", + 2820726296: "Charger mnémonique", + 879727077: "Charger depuis la carte SD ?", + 669106195: "En charger qu'un?", + 3330705289: "Charger?", + 2596531078: "Caméra de Chargement..", + 596389387: "Chargement de l'adresse de changement %d..", + 336702608: "Chargement de l'imprimante..", + 2538883522: "Chargement de l'adresse de réception %d..", + 3159494909: "Chargement..", + 1177338798: "Paramètres régionaux", + 2817059741: "Emplacement", + 63976957: "Niveau de journalisation", + 86530918: "Enregistrement", + 2917810189: "Longueur maximale dépassée (% s)", + 2030045667: "Message", + 3928301843: "Fichier de signature manquant", + 1948316555: "Mnémonique", + 2123991188: "ID mnémonique", + 3911073154: "ID de stockage mnémonique", + 570639842: "Mnémonique n'a pas été décryptée", + 1746030071: "Mnémonique n'était pas cryptée", + 1458925155: "Modifié:", + 1845376098: "Multi\nsignature", + 2939797024: "Réseau", + 73574491: "Nouveau mnémonique", + 2792272353: "Nouveau micrologiciel détecté.\n\nSHA256:\n%s\n\n\n\nInstaller?", + 4063104189: "Non", + 3927838899: "Pas de phrase passante bip39", + 4092516657: "Pas assez de rouleaux !", + 1577637745: "Octale", + 3312581301: "Itér. PBKDF2", 721090621: "PSBT", - 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", - 2987800462: "Papierbreite", - 3050763890: "Teil\n%d / %d", - 3559456868: "Teilegröße", - 4249903283: "Passphrase", - 3712257341: "Passphrase:", - 140802882: "Speicher", - 1703779997: "Klartext-QR", - 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", - 784609464: "Tauchrate", - 3037062877: "Drucke Test-QR", - 4278257699: "Als QR-Code drucken?\n\n%s\n\n", - 516488026: "Drucken?\n\n%s\n\n", - 1123106929: "Drucker", - 3903571079: "Druckertreiber nicht gesetzt!", - 2609799302: "Drucken\n%d / %d", - 844861889: "Wird gedruckt ...", - 2580599003: "Weiter?", - 556126964: "Wird bearbeitet ...", - 1848310591: "QR-Code", - 710709610: "RX Pin", - 2697857197: "Empfangen", - 1746677167: "Empfangsadresse", - 364354944: "Region: ", - 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", - 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", - 856795528: "Würfe:\n\n%s", - 255086803: "Würfe: %d\n", - 3976793317: "SD-Karte", - 2827687530: "SD-Karte nicht erkannt", - 2736513298: "SD-Karte nicht erkannt.", - 3593785196: "SHA256 der Würfe:\n\n%s", - 1143278725: "SHA256 des Snapshots:\n\n%s", + 995862913: "Peignez les points perforés en noir afin qu'ils puissent être détectés.", + 2987800462: "Largeur du papier", + 3050763890: "Partie\n%d / %d", + 3559456868: "Taille de la pièce", + 4249903283: "Phrase de passe", + 3712257341: "Phrass de passe:", + 140802882: "Persister", + 1703779997: "QR en Texte Brut", + 3561756278: "Veuillez charger un descripteur de sortie de portefeuille", + 784609464: "Taux de plongée", + 3037062877: "Test d'impression QR", + 4278257699: "Imprimer en QR?\n\n%s\n\n", + 516488026: "Imprimer?\n\n%s\n\n", + 1123106929: "Imprimante", + 3903571079: "Le conducteur d'imprimante n'est pas défini!", + 2609799302: "Impression\n%d / %d", + 844861889: "Impression ...", + 2580599003: "Procéder?", + 556126964: "Traitement ...", + 1848310591: "QR Code", + 710709610: "RX Fiche", + 2697857197: "Recevoir", + 1746677167: "Adresses de Réception", + 364354944: "Région: ", + 1662254634: "Examinez les données numérisées, modifiez-les si nécessaire", + 770350922: "Lancez le dé au moins %d fois pour générer un mnémonique.", + 856795528: "Rouleaux:\n\n%s", + 255086803: "Rouleaux: %d\n", + 3976793317: "Carte SD", + 2827687530: "Carte SD non détectée", + 2736513298: "Carte SD non détectée.", + 3593785196: "SHA256 de rouleaux:\n\n%s", + 1143278725: "Sha256 de Snapshot:\n\n% s", 3338679392: "SHA256:\n%s", - 3531742595: "Auf SD-Karte speichern?", - 810036588: "Auf SD-Karte gespeichert:\n%s", - 763824768: "Skala", - 4117455079: "Adresse\nscannen", - 3219991109: "Scan BIP39 Passphrase", - 2537207336: "Schlüssel QR-Code scannen", - 4006316572: "Wörter 1-12 erneut scannen", - 2736506158: "Wörter 13-24 scannen", - 266935239: "SeedQR", - 1698829144: "Selbstübertragung oder Change (%d): ", - 473154195: "Einstellungen", - 1825881236: "Ausschalten", - 2120776272: "Herunterfahren..", - 1061961408: "Signieren", - 4282338366: "Signieren?", - 746161122: "Signatur", - 1988416729: "Signierte Nachricht", - 3672006076: "Signierte PSBT", - 2281377987: "Single-Sig", - 4221794628: "Größe: ", - 2344747135: "Einige Schecks können nicht durchgeführt werden.", - 2309020186: "Ausgabe (%d): ", + 3531742595: "Enregistrer sur la carte SD ?", + 810036588: "Enregistré sur la carte SD :\n%s", + 763824768: "L'échelle", + 4117455079: "Scannez l'adresse", + 3219991109: "Scan bip39 en phrase secrète", + 2537207336: "Scanner le code QR de la clé", + 4006316572: "Analyser à nouveau les mots 1 à 12", + 2736506158: "Analyser les mots 13 à 24", + 3593497655: "Économiseur d'écran", + 266935239: "Seedqr", + 1698829144: "Auto-transfert ou changement (%d): ", + 473154195: "Paramètres", + 1825881236: "Fermer", + 2120776272: "Éteindre..", + 1061961408: "Signature", + 4282338366: "Signature?", + 746161122: "Signature", + 1988416729: "Message signé", + 3672006076: "PSBT signé", + 2281377987: "Clé unique", + 4221794628: "Capacité: ", + 2344747135: "Certains chèques ne peuvent pas être effectués.", + 2309020186: "Dépense (%d) : ", 3355862324: "Stackbit 1248", - 3303592908: "Auf Flash speichern", - 720041451: "Auf der SD-Karte speichern", - 3514476519: "Wischen um den Modus zu ändern", - 1898550184: "TOUCH oder ENTER zum Erfassen", - 4228215415: "TX Pin", - 2612594937: "Text", - 1454688268: "Thema", - 1180180513: "Thermisch", + 3303592908: "Stocker sur flash", + 720041451: "Stocker sur la carte SD", + 3514476519: "Faites glisser pour changer de mode", + 1898550184: "TOUCHEZ ou ENTER pour capturer", + 4228215415: "TX Fiche", + 2612594937: "Texte", + 1454688268: "Thème", + 1180180513: "Thermique", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Werkzeuge", - 3684696112: "Berühre Schwellenwert", - 2978718564: "Touchscreen", - 2732611775: "Weiter versuchen?", - 1487826746: "BIP39 Passphrase eingeben", - 2061556020: "Schlüssel eingeben", - 2089395053: "Einheit", - 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", - 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", - 2736001501: "Firmware wird aktualisiert..\n\n%d%%", - 2674953168: "Verwende eine schwarze Hintergrundfläche.", - 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", - 236075140: "Belegt: ", - 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", - 4191058607: "Via Kamera", + 1732872974: "Tiny Seed (bits)", + 725348723: "Outils", + 3684696112: "Seuil Tactile", + 2978718564: "Écran Tactile", + 2732611775: "Réessayer?", + 1487826746: "Type Bip39 Plasque", + 2061556020: "Clé de type", + 2089395053: "Unité", + 2845607430: "Mise à jour du chargeur de démarrage..\n\n%d%%", + 4164597446: "Mise à niveau complète.\n\nÉteindre..", + 2736001501: "Mise à niveau du micrologiciel..\n\n%d%%", + 2674953168: "Utilisez une surface de fond noire.", + 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", + 236075140: "Utilisé: ", + 4003084591: "Valeur% s hors de portée: [% s,% s]", + 4191058607: "Par caméra", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Via manueller Eingabe", - 2504354847: "Warte auf die Erfassung", - 2297028319: "Wallet-Deskriptor", - 4232654916: "Wallet Ausgabedeskriptor", - 2587172867: "Wallet Ausgabedeskriptor geladen!", - 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", - 2671738224: "Warnung:", - 797660533: "Wort %d", - 3742424146: "Wortnummern", - 2965123464: "Wörter", - 1303016265: "Ja", - 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", - 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", + 590330112: "Par saisie manuelle", + 2504354847: "Attendez la capture", + 3992434312: "Temps d'attente", + 2297028319: "Descripteur de Portefeuille", + 4232654916: "Descripteur de sortie du portefeuille", + 2587172867: "Descripteur de sortie du portefeuille chargé!", + 2499782468: "Descripteur de sortie du portefeuille introuvable.", + 2671738224: "Avertissement:", + 797660533: "Mot %d", + 3742424146: "Numéros de mots", + 2965123464: "Mots", + 1303016265: "Oui", + 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", + 2569054451: "Vos modifications seront conservées sur la carte SD.", }, - "vi-VN": { - 1185266064: "%d của %d đa chữ kí", - 2004520398: "%d. Thay đổi: \n\n%s\n\n", - 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", - 3264377309: "%d. Chi tiêu: \n\n%s\n\n", - 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", - 3921290840: "%s\n\nlà một địa chỉ khả dụng!", - 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 3348584292: "(Thực nghiệm)", - 2739590230: "12 từ", - 1310058127: "24 từ", + "nl-NL": { + 1185266064: "%d van %d multisig", + 2004520398: "%d. Wisselgeld: \n\n%s\n\n", + 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", + 3264377309: "%d. Uitgaven: \n\n%s\n\n", + 2399232215: "%s\n\nis een valide wisselgeld adres!", + 3921290840: "%s\n\nis een valide ontvangst adres!", + 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", + 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", + 3348584292: "(Experimenteel)", + 2739590230: "12 woorden", + 1310058127: "24 woorden", 2743272264: "ABC", - 1949634023: "Về chúng tôi", + 1949634023: "Over", 1517128857: "Adafruit", - 3270727197: "Địa chỉ", - 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", - 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", - 88746165: "Chống lóa bị vô hiệu hóa", - 1521033296: "Đã bật chống lóa", - 1056821534: "Bạn có chắc không?", - 3247612282: "Mã mnemonic dạng chuẩn BIP39", - 3455872521: "Trở lại", - 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", - 2256777600: "Chữ ký xấu", - 3937333362: "Tốc độ baud", + 3270727197: "Adres", + 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", + 283202181: "Richt de camera en Tiny Seed op de juiste manier.", + 88746165: "Anti reflecterend uitgeschakeld", + 1521033296: "Anti reflecterend ingeschakeld", + 1056821534: "Weet je het zeker?", + 3247612282: "BIP-39 geheugensteun", + 3455872521: "Terug", + 2541860807: "Backup van de bootloader...\n\n%d%%", + 2256777600: "Ongeldige handtekening", + 3937333362: "Baudratio", 427617266: "Bitcoin", - 928727036: "Đệm viền", + 928727036: "Rand opvulling", 213030954: "CNC", - 1207696150: "Thay đổi", - 3126552510: "Thay địa chỉ", - 1583186953: "Thay đổi chủ đề và khởi động lại?", - 2697733395: "Thay đổi được lưu trên thẻ SD!", - 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", - 3442025874: "Kiểm tra thẻ SD", - 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", - 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", - 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", - 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", - 2470115694: "Kiểm tra thẻ SD..", - 3655273987: "Đang kiểm tra %d địa chỉ..", - 2407028014: "SeedQR nhỏ gọn", - 4041895036: "Tiếp tục?", - 4094072796: "Tạo mã QR", - 167798282: "Tạo mã QR từ văn bản?", - 2767642191: "Tạo:", - 3513215254: "Mã QR tùy chỉnh", - 124617190: "Chiều sâu cắt", - 597912140: "Phương pháp cắt", - 2504034831: "Số thập phân", - 2751113454: "Phản đối?", - 1016609898: "Xóa tài liệu?", - 1364509700: "Xóa ghi nhớ", - 4102535566: "Độ sâu mỗi lần vượt qua", - 2791699253: "Nguồn gốc: %s", - 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", - 3836852788: "Hoàn tất?", - 382368239: "Người cầm lái", - 3978947916: "Mã hoá", - 4090746898: "Gỡ lỗi bộ mã hóa", - 374684711: "Mã hóa Mnemonic", - 1244124409: "Mã QR được mã hóa", - 2968548114: "MNemon được mã hóa không được lưu trữ", - 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", - 350279787: "Mã hóa", - 2601598799: "Chế độ mã hóa", - 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", - 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", - 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", - 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", - 784361051: "Lỗi:\n%s", + 1207696150: "Change", + 3126552510: "Wisselgeldadres", + 1583186953: "Thema veranderen en opnieuw opstarten?", + 2697733395: "Wijzigingen aanhouden op SD kaart!", + 388908871: "Wijzigingen blijven van kracht tot afsluiten.", + 3442025874: "Controleer SD kaart", + 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", + 2856261511: "Na %d geen wisselgeld adressen gevonden.", + 2788541416: "Na %d geen ontvangst adressen gevonden.", + 2446472910: "Wisselgeldadres %d controleren...", + 2470115694: "SD kaart controleren...", + 3655273987: "Ontvangstadres %d controleren...", + 2407028014: "Compact SeedQR", + 4041895036: "Doorgaan?", + 4094072796: "QR code maken", + 167798282: "QR code maken van tekst?", + 2767642191: "Aangemaakt: ", + 3513215254: "Aangepaste QR code", + 124617190: "Snijdiepte", + 597912140: "Snijmethode", + 2504034831: "Decimaal", + 2751113454: "Ontsleutelen?", + 1016609898: "Bestand verwijderen?", + 1364509700: "Geheugensteun verwijderen", + 4102535566: "Diepte per pas", + 2791699253: "Afgeleide: %s", + 1230133196: "Opslag op apparaat is niet gedetecteerd.", + 3836852788: "Klaar?", + 382368239: "Driver", + 3978947916: "Encoder", + 4090746898: "Encoder-debounce", + 374684711: "Geheugensteun versleutelen", + 1244124409: "Versleutelde QR code", + 2968548114: "Versleutelde geheugensteun was niet opgeslagen", + 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", + 350279787: "Versleutelen", + 2601598799: "Versleutel modus", + 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", + 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", + 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", + 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", + 784361051: "Fout:\n%s", 1505332462: "Esc", - 3838465623: "Khám phá các tập tin?", - 4170881190: "Xuất vào thẻ SD ..", - 1711312434: "Khóa công cộng", - 383371114: "Không giải mã được", - 3048830188: "Tải PSBT thất bại", - 4192663412: "Tải địa chỉ thất bại", - 1996021743: "Không tải khóa", - 1108715658: "Không tải được tin nhắn", - 1081425878: "Tải mã mnemonic thất bại", - 928667220: "Không thể tải bộ mô tả đầu ra", - 1620572516: "Không tải được cụm mật khẩu", - 2946146830: "Không lưu trữ MNemonic", - 1303554751: "Phí: ", - 104500973: "Tỷ lệ thức ăn", - 3313339187: "Tên tệp", - 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", - 3737729752: "Dấu vân tay: %s", - 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", - 1406590538: "Đường kính ống sáo", - 3086093110: "Khả dụng: ", - 1893243331: "Từ lưu trữ", + 3838465623: "Bestanden verkennen?", + 4170881190: "Exporteren naar SD-kaart..", + 1711312434: "Uitgebreide publieke sleutel", + 383371114: "Ontsleutelen is niet gelukt", + 3048830188: "PSBT laden is niet gelukt", + 4192663412: "Adres laden is niet gelukt", + 1996021743: "Sleutel laden is niet gelukt", + 1108715658: "Bericht laden is niet gelukt", + 1081425878: "Geheugensteun laden is niet gelukt", + 928667220: "Descriptor laden is niet gelukt", + 1620572516: "Wachtwoord laden is niet gelukt", + 2946146830: "Geheugensteun opslaan is niet gelukt", + 1303554751: "Tarief: ", + 104500973: "Voedingssnelheid", + 3313339187: "Bestandsnaam", + 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", + 3737729752: "Vingerafdruk: %s", + 2542772894: "Firmware overschrijdt de maximale grootte: %d", + 1406590538: "Fluit diameter", + 3086093110: "Vrij: ", + 1893243331: "Uit data-opslag", 4120536442: "GRBL", - 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", - 602716148: "Đến", - 3580020863: "Khóa công khai Hex", - 2691246967: "Thập lục phân", - 2736309107: "Id đã tồn tại\n", - 1706005805: "Bộ mô tả đầu ra chưa hoàn chỉnh", - 631342955: "Đầu vào (%d): ", - 2585599782: "Địa chỉ không hợp lệ", - 2874529150: "Bộ tải khởi động không hợp lệ", - 4093416954: "Độ dài mã mnemonic không hợp lệ", - 1422874211: "Khóa công khai không hợp lệ", - 2443867979: "Ví không hợp lệ:\n%s", - 4122897393: "Đảo ngược", - 3000888649: "Chìa khóa", - 2686333978: "Chìa khóa:", - 4123798664: "Krux\n\n\nPhiên Bản\n%s", - 3835918229: "QR kiểm tra máy in Krux", - 766317539: "Ngôn ngữ", - 972436696: "Độ trễ Dòng", - 3596093890: "Đường kẻ: ", - 2820726296: "Tải mã mnemonic", - 879727077: "Tải từ thẻ SD?", - 669106195: "Tải một?", - 3330705289: "Tải?", - 2596531078: "Đang tải máy ảnh..", - 596389387: "Đang tải thay đổi địa chỉ %d..", - 336702608: "Tải máy in ..", - 2538883522: "Đang tải địa chỉ nhận %d..", - 3159494909: "Đang tải..", - 1177338798: "Ngôn ngữ", - 2817059741: "Vị trí cửa hàng", - 63976957: "Log Level", - 86530918: "Khai thác gỗ", - 2917810189: "Chiều dài tối đa vượt quá (%s)", - 2030045667: "Tin nhắn", - 3928301843: "Thiếu tập tin chữ ký", - 1948316555: "Mã mnemonic", - 2123991188: "ID ghi nhớ", - 3911073154: "ID lưu trữ ghi nhớ", - 570639842: "Ghi nhớ không được giải mã", - 1746030071: "Ghi nhớ không được mã hóa", - 1458925155: "Đã sửa đổi:", - 1845376098: "Đa chữ kí", - 2939797024: "Mạng lưới", - 73574491: "Mnemonic mới", - 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", - 4063104189: "Không", - 3927838899: "Không có cụm mật khẩu BIP39", - 4092516657: "Không đủ cuộn!", - 1577637745: "Bát phân", - 3312581301: "Lặp lại PBKDF2", + 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", + 602716148: "Ga", + 3580020863: "Hex publieke sleutel", + 2691246967: "Hexadecimaal", + 2736309107: "ID bestaat al\n", + 1706005805: "Incomplete portemonnee descriptor", + 631342955: "Invoer (%d): ", + 2585599782: "Ongeldig adres", + 2874529150: "Ongeldige bootloader", + 4093416954: "Ongeldige geheugensteun lengte", + 1422874211: "Ongeldige publieke sleutel", + 2443867979: "Ongeldige portemonnee:\n%s", + 4122897393: "Omkeren", + 3000888649: "Sleutel", + 2686333978: "Sleutel: ", + 4123798664: "Krux\n\n\nVersie\n%s", + 3835918229: "Krux printer test QR", + 766317539: "Taal", + 972436696: "Lijn vertraging", + 3596093890: "Lijn: ", + 2820726296: "Geheugensteun laden", + 879727077: "Laden vanaf SD-kaart?", + 669106195: "Laden?", + 3330705289: "Laden?", + 2596531078: "Camera laden...", + 596389387: "Wisselgeldadres %d laden...", + 336702608: "Laadprinter..", + 2538883522: "Ontvangstadres %d laden...", + 3159494909: "Laden...", + 1177338798: "Taal", + 2817059741: "Opslaglocatie", + 63976957: "Log niveau", + 86530918: "Debug logs", + 2917810189: "Maximale lengte overschreden (%s)", + 2030045667: "Bericht", + 3928301843: "Handtekening bestand mist", + 1948316555: "Geheugensteun", + 2123991188: "Geheugensteun ID", + 3911073154: "Geheugensteun opslag ID", + 570639842: "Geheugensteun is niet ontsleuteld", + 1746030071: "Geheugensteun is niet versleuteld", + 1458925155: "Aangepast: ", + 1845376098: "Multisig", + 2939797024: "Netwerk", + 73574491: "Geheugensteun aanmaken", + 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", + 4063104189: "Nee", + 3927838899: "Geen BIP-39 wachtwoord", + 4092516657: "Niet genoeg gedobbeld!", + 1577637745: "Octaal", + 3312581301: "PBKDF2 iter.", 721090621: "PSBT", - 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", - 2987800462: "Chiều rộng giấy", - 3050763890: "Phần\n%d / %d", - 3559456868: "Kích thước một phần", - 4249903283: "Cụm mật khẩu", - 3712257341: "Cụm cụm:", - 140802882: "Vị trí lưu", - 1703779997: "Văn bản rõ QR", - 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", - 784609464: "Tỷ lệ sụt giảm", - 3037062877: "In kiểm tra QR", - 4278257699: "In ra mã QR?\n\n%s\n\n", - 516488026: "In?\n\n%s\n\n", - 1123106929: "Máy in", - 3903571079: "Trình điều khiển máy in không đặt!", - 2609799302: "Đang in\n%d / %d", - 844861889: "In ấn ...", - 2580599003: "Thực hiện?", - 556126964: "Xử lý ...", - 1848310591: "Mã QR", - 710709610: "RX Ghim", - 2697857197: "Nhận được", - 1746677167: "Nhận địa chỉ", - 364354944: "Vùng: ", - 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", - 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", - 856795528: "Súc sắc cuộn:\n\n%s", - 255086803: "Súc sắc cuộn: %d\n", - 3976793317: "Thẻ SD", - 2827687530: "Thẻ SD không được phát hiện", - 2736513298: "Thẻ SD không được phát hiện.", - 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", - 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Lưu vào thẻ SD?", - 810036588: "Đã lưu vào thẻ SD:\n%s", - 763824768: "Cái cân", - 4117455079: "Quét địa chỉ", - 3219991109: "Quét BIP39 Cụm cụm", - 2537207336: "Quét mã QR khóa", - 4006316572: "Quét lại từ 1-12", - 2736506158: "Quét từ 13-24", - 266935239: "SEEDQR", - 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", - 473154195: "Cài đặt", - 1825881236: "Tắt", - 2120776272: "Đang tắt..", - 1061961408: "Chữ kí", - 4282338366: "Kí?", - 746161122: "Chữ ký", - 1988416729: "Tin nhắn đã ký", - 3672006076: "Đã ký PSBT", - 2281377987: "Khóa đơn", - 4221794628: "Dung lượng: ", - 2344747135: "Một số kiểm tra không thể được thực hiện.", - 2309020186: "Chi tiêu (%d): ", - 3355862324: "Stackbit 1248", - 3303592908: "Lưu trữ trên flash", - 720041451: "Lưu trữ trên thẻ SD", - 3514476519: "Vuốt để thay đổi chế độ", - 1898550184: "TOUCH hoặc ENTER để chụp", - 4228215415: "TX Ghim", - 2612594937: "Chữ", - 1454688268: "Chủ đề", - 1180180513: "Nhiệt", + 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", + 2987800462: "Papier breedte", + 3050763890: "Deel\n%d / %d", + 3559456868: "Deel grootte", + 4249903283: "Wachtwoord", + 3712257341: "Wachtwoord: ", + 140802882: "Opslag", + 1703779997: "Platte tekst QR", + 3561756278: "Laadt een portemonnee descriptor in", + 784609464: "Duik tarief", + 3037062877: "Test QR afdrukken", + 4278257699: "Afdrukken naar QR?\n\n%s\n\n", + 516488026: "Afdrukken?\n\n%s\n\n", + 1123106929: "Printer", + 3903571079: "Printer driver niet ingesteld!", + 2609799302: "Afdruk\n%d / %d", + 844861889: "Afdrukken...", + 2580599003: "Doorgaan?", + 556126964: "Verwerken...", + 1848310591: "QR code", + 710709610: "RX pin", + 2697857197: "Ontvangen", + 1746677167: "Ontvangstadres", + 364354944: "Regio: ", + 1662254634: "Controleer gescande gegevens en bewerk indien nodig", + 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", + 856795528: "Gedobbeld:\n\n%s", + 255086803: "Gedobbeld: %d\n", + 3976793317: "SD kaart", + 2827687530: "SD kaart niet gedetecteerd", + 2736513298: "SD kaart niet gedetecteerd.", + 3593785196: "Gedobbelde SHA256:\n\n%s", + 1143278725: "Momentopname van SHA256:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Opslaan op SD-kaart?", + 810036588: "Opgeslagen op SD-kaart:\n%s", + 763824768: "Schaal", + 4117455079: "Adres scannen", + 3219991109: "BIP-39 wachtwoord scannen", + 2537207336: "QR code sleutel scannen", + 4006316572: "Woorden 1 t/m 12 opnieuw scannen", + 2736506158: "Woorden 13 t/m 24 scannen", + 3593497655: "Screensaver", + 266935239: "SeedQR", + 1698829144: "Zelf overschrijving of wisselgeld (%d): ", + 473154195: "Instellingen", + 1825881236: "Afsluiten", + 2120776272: "Bezig met afsluiten...", + 1061961408: "Ondertekenen", + 4282338366: "Ondertekenen?", + 746161122: "Handtekening", + 1988416729: "Bericht ondertekend", + 3672006076: "PSBT ondertekend", + 2281377987: "Enkele sleutel", + 4221794628: "Grootte: ", + 2344747135: "Sommige controles kunnen niet worden uitgevoerd.", + 2309020186: "Uitgaven (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Opslaan op apparaat", + 720041451: "Opslaan op SD kaart", + 3514476519: "Verander modus", + 1898550184: "TIK of ENTER voor opname", + 4228215415: "TX pin", + 2612594937: "Tekst", + 1454688268: "Thema", + 1180180513: "Thermisch", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bit)", - 725348723: "Công cụ", - 3684696112: "Ngưỡng cảm ứng", - 2978718564: "Màn hình cảm ứng", - 2732611775: "Thử thêm nữa?", - 1487826746: "Nhập cụm BIP39", - 2061556020: "Nhập khóa", - 2089395053: "Đơn vị", - 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", - 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", - 2736001501: "Nâng cấp firmware..\n\n%d%%", - 2674953168: "Sử dụng bề mặt nền đen.", - 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", - 236075140: "Đã sử dụng: ", - 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", - 4191058607: "Qua máy ảnh", - 1254681955: "Qua D20", - 525309547: "Qua D6", - 590330112: "Thông qua đầu vào thủ công", - 2504354847: "Chờ bắt", - 2297028319: "Trình mô tả ví", - 4232654916: "Ví đầu ra mô tả", - 2587172867: "Đã tải bộ mô tả đầu ra của ví!", - 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", - 2671738224: "Cảnh báo:", - 797660533: "Kí tự %d", - 3742424146: "Từ số", - 2965123464: "Từ ngữ", - 1303016265: "Đúng", - 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", - 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Hulpmiddelen", + 3684696112: "Aanraak gevoeligheid", + 2978718564: "Aanraakscherm", + 2732611775: "Meer proberen?", + 1487826746: "Voer BIP-39 wachtwoord in", + 2061556020: "Voer sleutel in", + 2089395053: "Eenheid", + 2845607430: "Bootloader updaten...\n\n%d%%", + 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", + 2736001501: "Firmware upgraden...\n\n%d%%", + 2674953168: "Gebruik een donker achergrond.", + 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", + 236075140: "Gebruikt: ", + 4003084591: "Waarde %s is buiten bereik: [%s, %s]", + 4191058607: "Via camera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Via handmatige invoer", + 2504354847: "Wacht op opname", + 3992434312: "Wacht tijd", + 2297028319: "Descriptor", + 4232654916: "Portemonnee descriptor", + 2587172867: "Portemonnee descriptor geladen!", + 2499782468: "Portemonnee descriptor niet gevonden.", + 2671738224: "Waarschuwing:", + 797660533: "Woord %d", + 3742424146: "Woord nummers", + 2965123464: "Woorden", + 1303016265: "Yes", + 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", + 2569054451: "Veranderingen worden opgeslagen op SD kaart.", }, - "ru-RU": { - 1185266064: "%d из %d мультиподпись", - 2004520398: "%d. Сдача: \n\n%s\n\n", - 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", - 3264377309: "%d. Расход: \n\n%s\n\n", - 2399232215: "%s\n\nвалидный адрес сдачи!", - 3921290840: "%s\n\nвалидный адрес получения!", - 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", - 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", - 3348584292: "(Эксперементальный)", - 2739590230: "12 слов", - 1310058127: "24 слова", + "pl-PL": { + 1185266064: "%d z %d multisig", + 2004520398: "%D.Zmiana:\n\n%s\n\n", + 3862364126: "%D.Samo-transfer:\n\n%s\n\n", + 3264377309: "%D.Wydać:\n\n%s\n\n", + 2399232215: "%s\n\nis prawidłowy adres zmiany!", + 3921290840: "%s\n\nis ważny adres odbierania!", + 1808355833: "%s\n\nwas nie znaleziono w pierwszych adresach zmiany", + 1306127065: "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", + 3348584292: "(Eksperymentalny)", + 2739590230: "12 słów", + 1310058127: "24 słowa", 2743272264: "ABC", - 1949634023: "О Программе", + 1949634023: "O", 1517128857: "Adafruit", - 3270727197: "Адрес", - 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", - 283202181: "Правильно совместите камеру и Мини Сид-фразу.", - 88746165: "Антиблик отключен", - 1521033296: "Антиблик включен", - 1056821534: "Вы уверены?", - 3247612282: "BIP39 Мнемоника", - 3455872521: "Назад", - 2541860807: "Резервное копирование загрузчика..\n\n%d%%", - 2256777600: "Плохая подпись", - 3937333362: "Скорость Передачи Данных", - 427617266: "Биткоин", - 928727036: "Заполнение границ", + 3270727197: "Adres", + 2574498267: "Dodatkowa entropia z kamery wymaganej dla trybu AES-CBC", + 283202181: "Właściwie wyrównaj kamerę i maleńkie nasiona.", + 88746165: "Niepełnosprawne przeciwblokowane", + 1521033296: "Włączona anty-zabawa", + 1056821534: "Jesteś pewny?", + 3247612282: "BIP39 Mnemonic", + 3455872521: "Z powrotem", + 2541860807: "Kopie zapasowe bootloader ..\n\n%d %%", + 2256777600: "zły podpis", + 3937333362: "Baudrate", + 427617266: "Bitcoin", + 928727036: "Wyściółka graniczna", 213030954: "CNC", - 1207696150: "Сдача", - 3126552510: "Адрес Сдачи", - 1583186953: "Сменить тему и перезагрузить?", - 2697733395: "Изменения сохранены на SD карте!", - 388908871: "Изменения будут храниться до выключения.", - 3442025874: "Проверить SD Карту", - 3119547911: "Проверить, что адрес принадлежит этому кошельку?", - 2856261511: "Проверено %d адресов сдачи без совпадений.", - 2788541416: "Проверено %d адресов получения без совпадений.", - 2446472910: "Проверяем адрес сдачи %d на совпадение..", - 2470115694: "Проверка SD карты..", - 3655273987: "Проверяем адрес получения %d на совпадение..", - 2407028014: "Компактный SeedQR", - 4041895036: "Продолжить?", - 4094072796: "Создать QR Код", - 167798282: "Создать QR код из текста?", - 2767642191: "Создано", - 3513215254: "Пользовательский QR Код", - 124617190: "Глубина Резки", - 597912140: "Метод Резки", - 2504034831: "Десятичный", - 2751113454: "Расшифровать?", - 1016609898: "Удалить Файл?", - 1364509700: "Удалить Мнемонику", - 4102535566: "Глубина За Проход", - 2791699253: "Производный путь: %s", - 1230133196: "Флэш память устройства не обнаружена.", - 3836852788: "Готово?", - 382368239: "Драйвер", - 3978947916: "Кодер", - 4090746898: "Дебаунс Кодера", - 374684711: "Зашифровать Мнемонику", - 1244124409: "Зашифрованный QR Код", - 2968548114: "Зашифрованная мнемоника не была сохранена", - 3315319371: "Зашифрованная мнемоника была сохранена с ID", - 350279787: "Шифрование", - 2601598799: "Метод шифрования", - 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", - 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", - 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", - 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", - 784361051: "Ошибка:\n%s", - 1505332462: "Выйти", - 3838465623: "Исследовать файлы?", - 4170881190: "Экспортирование на SD карту..", - 1711312434: "Расширенный Публичный Ключ", - 383371114: "Не удалось расшифровать", - 3048830188: "Не удалось загрузить PSBT", - 4192663412: "Не удалось загрузить адрес", - 1996021743: "Не удалось загрузить ключ", - 1108715658: "Не удалось загрузить сообщение", - 1081425878: "Не удалось загрузить мнемонику", - 928667220: "Не удалось загрузить выходной дескриптор", - 1620572516: "Не удалось загрузить фразу-пароль", - 2946146830: "Не удалось сохранить мнемонику", - 1303554751: "Комиссия: ", - 104500973: "Скорость подачи", - 3313339187: "Имя файла", - 1982637349: "Файл %s существует на SD карте, перезаписать?", - 3737729752: "Фингерпринт: %s", - 2542772894: "Прошивка превышает максимальный размер: %d", - 1406590538: "Flute Диаметр", - 3086093110: "Бесплатно: ", - 1893243331: "Из Памяти", - 4120536442: "GRBL", - 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", - 602716148: "OK", - 3580020863: "Шестнадцатеричный Публичный Ключ", - 2691246967: "Шестнадцатеричный", - 2736309107: "ID уже существует\n", - 1706005805: "Неполный выходной дескриптор", - 631342955: "Входы (%d): ", - 2585599782: "Неверный адрес", - 2874529150: "Неверный загрузчик", - 4093416954: "Неверная длина мнемоники", - 1422874211: "Неверный публичный ключ", - 2443867979: "Неверный кошелек:\n%s", - 4122897393: "Инвертировать", - 3000888649: "Ключ", - 2686333978: "Ключ: ", - 4123798664: "Krux\n\n\nВерсия\n%s", - 3835918229: "Тестовый QR Принтера Krux", - 766317539: "Язык", - 972436696: "Задержка Линии", - 3596093890: "Линия: ", - 2820726296: "Загрузить Мнемонику", - 879727077: "Загрузить с SD карты?", - 669106195: "Загрузить одну?", - 3330705289: "Загрузить?", - 2596531078: "Загрузка Камеры..", - 596389387: "Загрузка адреса сдачи %d..", - 336702608: "Загрузка принтера..", - 2538883522: "Загрузка адреса получения %d..", - 3159494909: "Загрузка..", - 1177338798: "Локаль", - 2817059741: "Расположение", - 63976957: "Уровень логирования", - 86530918: "Логирование", - 2917810189: "Максимальная длина превышена (%s)", - 2030045667: "Сообщение", - 3928301843: "Отсутствует файл подписи", - 1948316555: "Мнемоника", - 2123991188: "ID мнемоники", - 3911073154: "ID памяти мнемоники", - 570639842: "Мнемоника не была расшифрована", - 1746030071: "Мнемоника не была зашифрована", - 1458925155: "Изменено: ", - 1845376098: "Мультиподпись", - 2939797024: "Сеть", - 73574491: "Новая Мнемоника", - 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", - 4063104189: "Нет", - 3927838899: "Без BIP39 фразы-пароля", - 4092516657: "Недостаточно бросков!", - 1577637745: "Восьмеричный", - 3312581301: "PBKDF2 Итерации", - 721090621: "PSBT", - 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", - 2987800462: "Ширина Бумаги", - 3050763890: "Часть\n%d / %d", - 3559456868: "Размер Части", - 4249903283: "Фраза-пароль", - 3712257341: "Фраза-пароль: ", - 140802882: "Постоянная Память", - 1703779997: "QR открытым текстом", - 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", - 784609464: "Скорость Погружения", - 3037062877: "Напечатать Тестовый QR", - 4278257699: "Напечатать в виде QR?\n\n%s\n\n", - 516488026: "Печатать?\n\n%s\n\n", - 1123106929: "Принтер", - 3903571079: "Драйвер Принтера не установлен!", - 2609799302: "Идет печать\n%d / %d", - 844861889: "Идет печать ...", - 2580599003: "Продолжить?", - 556126964: "Обрабатываю ...", - 1848310591: "QR Код", - 710709610: "RX Пин", - 2697857197: "Получить", - 1746677167: "Адрес Получения", - 364354944: "Регион: ", - 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", - 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", - 856795528: "Броски:\n\n%s", - 255086803: "Броски: %d\n", - 3976793317: "SD карта", - 2827687530: "SD карта не обнаружена", - 2736513298: "SD карта не обнаружена.", - 3593785196: "SHA256 бросков:\n\n%s", - 1143278725: "SHA256 снэпшота:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Сохранить на SD карту?", - 810036588: "Сохранено на SD карту:\n%s", - 763824768: "Шкала", - 4117455079: "Отсканировать Адрес", - 3219991109: "Отсканировать BIP39 фразу-пароль", - 2537207336: "Отсканировать Ключ QR код", - 4006316572: "Сканирование слов 1-12 снова", - 2736506158: "Сканирование слов 13-24", - 266935239: "SeedQR", - 1698829144: "Трансфер самому себе или Сдача (%d): ", - 473154195: "Настройки", - 1825881236: "Выключить", - 2120776272: "Выключение..", - 1061961408: "Подписать", - 4282338366: "Подписать?", - 746161122: "Подпись", - 1988416729: "Подписанное Сообщение", - 3672006076: "Подписанное PSBT", - 2281377987: "Одна подпись", - 4221794628: "Размер: ", - 2344747135: "Некоторые проверки не могут быть выполнены.", - 2309020186: "Расход (%d): ", - 3355862324: "Стэкбит 1248", - 3303592908: "Сохранить на Флэш Память", - 720041451: "Сохранить на SD Карту", - 3514476519: "Свайпните, чтобы сменить режим", - 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", - 4228215415: "TX Пин", - 2612594937: "Текст", - 1454688268: "Тема", - 1180180513: "Термальный", - 4119292117: "Мини Сид-фраза", - 1732872974: "Мини Сид-фраза (Биты)", - 725348723: "Инструменты", - 3684696112: "Прикоснитесь Границы", - 2978718564: "Тачскрин", - 2732611775: "Попробовать ещё?", - 1487826746: "Введите BIP39 фразу-пароль", - 2061556020: "Введите Ключ", - 2089395053: "Юнит", - 2845607430: "Обновление загрузчика..\n\n%d%%", - 4164597446: "Обновление завершено.\n\nВыключение..", - 2736001501: "Обновление прошивки..\n\n%d%%", - 2674953168: "Использовать черную фоновую поверхность.", - 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", - 236075140: "Использовано: ", - 4003084591: "Значение %s вне диапозона: [%s, %s]", - 4191058607: "С Помощью Камеры", - 1254681955: "С Помощью D20", - 525309547: "С Помощью D6", - 590330112: "С Помощью Ручного Ввода", - 2504354847: "Дождитесь Захвата", - 2297028319: "Дескриптор Кошелька", - 4232654916: "Выходной дескриптор кошелька", - 2587172867: "Выходной дескриптор кошелька загружен!", - 2499782468: "Выходной дескриптор кошелька не найден.", - 2671738224: "Предупреждение:", - 797660533: "Слово %d", - 3742424146: "Числа Слов", - 2965123464: "Слова", - 1303016265: "Да", - 771968845: "Ваши изменения буду храниться на флэш памяти устройства.", - 2569054451: "Ваши изменения будут храниться на SD карте.", + 1207696150: "Zmiana", + 3126552510: "Zmień adresy", + 1583186953: "Zmienić motyw i ponownie uruchomić?", + 2697733395: "Zmiany utrzymywały się na karcie SD!", + 388908871: "Zmiany będą trwać do zamknięcia.", + 3442025874: "Sprawdź kartę SD", + 3119547911: "Sprawdź, czy adres należy do tego portfela?", + 2856261511: "Sprawdzone %d adresy zmiany bez dopasowań.", + 2788541416: "Sprawdzone %D Otrzymuj adresy bez zapałek.", + 2446472910: "Sprawdzanie Zmieniania Adres %D dla dopasowania.", + 2470115694: "Sprawdzanie karty SD ..", + 3655273987: "Sprawdzanie adresu Otrzymaj %D dla meczu.", + 2407028014: "Kompaktowy seedqr", + 4041895036: "Kontynuować?", + 4094072796: "Utwórz kod QR", + 167798282: "Utwórz kod QR z tekstu?", + 2767642191: "Utworzony:", + 3513215254: "Niestandardowy kod QR", + 124617190: "Wytnij głębokość", + 597912140: "Metoda cięcia", + 2504034831: "Dziesiętny", + 2751113454: "Odszyfrować?", + 1016609898: "Usunąć plik?", + 1364509700: "Usuń mnemonic", + 4102535566: "Głębokość na przepustkę", + 2791699253: "Pochodzenie: %s", + 1230133196: "Nie wykryto pamięci flash urządzenia.", + 3836852788: "Zrobione?", + 382368239: "Kierowca", + 3978947916: "Enkoder", + 4090746898: "Encoder Debunet", + 374684711: "Szyfrowanie mnemoniki", + 1244124409: "Zaszyfrowany kod QR", + 2968548114: "Szyfrowana mnemonika nie była przechowywana", + 3315319371: "Szyfrowana mnemonika była przechowywana z ID:", + 350279787: "Szyfrowanie", + 2601598799: "Tryb szyfrowania", + 3504179008: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę od 1 do 2048 r.", + 1100685007: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w heksadecimal od 1 do 800.", + 4090266642: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w wysokości od 1 do 4000.", + 2780625730: "Wprowadź każde słowo swojego mnemonika BIP-39.", + 784361051: "Błąd:\n%s", + 1505332462: "wyjście", + 3838465623: "Eksplorować pliki?", + 4170881190: "Eksportowanie do karty SD ..", + 1711312434: "Rozszerzony klucz publiczny", + 383371114: "Nie udało się odszyfrować", + 3048830188: "Nie udało się załadować PSBT", + 4192663412: "Nie udało się załadować adresu", + 1996021743: "Nie udało się załadować klucza", + 1108715658: "Nie udało się załadować wiadomości", + 1081425878: "Nie udało się załadować mnemonika", + 928667220: "Nie udało się załadować deskryptora wyjściowego", + 1620572516: "Nie udało się załadować pseudonim", + 2946146830: "Nie udało się przechowywać mnemonika", + 1303554751: "Opłata:", + 104500973: "Szybkość pasz", + 3313339187: "Nazwa pliku", + 1982637349: "Nazwa pliku %s istnieje na karcie SD, zastąp?", + 3737729752: "Odcisk palca: %s", + 2542772894: "Oprogramowanie układowe przekracza maksymalny rozmiar: %D", + 1406590538: "Średnica fletu", + 3086093110: "Bezpłatny:", + 1893243331: "Z przechowywania", + 4120536442: "Grbl", + 299338213: "Podaj temu mnemonicznemu identyfikatorowi?W przeciwnym razie zostanie użyty obecny odcisk palca", + 602716148: "Iść", + 3580020863: "Hex Key Public", + 2691246967: "Szesnastkowy", + 2736309107: "ID już istnieje\n", + 1706005805: "inComplete Descriptor", + 631342955: "Wejścia (%d):", + 2585599782: "Błędny adres", + 2874529150: "Nieprawidłowy bootloader", + 4093416954: "Nieprawidłowa długość mnemoniczna", + 1422874211: "Nieprawidłowy klucz publiczny", + 2443867979: "Nieprawidłowy portfel:\n%s", + 4122897393: "Odwracać", + 3000888649: "Klucz", + 2686333978: "Klucz:", + 4123798664: "Krux\n\n\neversion\n%s", + 3835918229: "Test drukarki Krux QR", + 766317539: "Język", + 972436696: "Opóźnienie linii", + 3596093890: "Linia:", + 2820726296: "Ładuj mnemoniczne", + 879727077: "Załaduj z karty SD?", + 669106195: "Załaduj jeden?", + 3330705289: "Obciążenie?", + 2596531078: "Ładowanie aparatu ..", + 596389387: "Ładowanie ZMIANY Adres %D ..", + 336702608: "Ładowanie drukarki ..", + 2538883522: "Ładowanie adresu odbierania %d ..", + 3159494909: "Ładowanie..", + 1177338798: "Widownia", + 2817059741: "Lokalizacja", + 63976957: "Poziom dziennika", + 86530918: "Logowanie", + 2917810189: "Maksymalna długość przekroczona (%s)", + 2030045667: "Wiadomość", + 3928301843: "Brakujący plik podpisu", + 1948316555: "Mnemoniczny", + 2123991188: "Mnemoniczne id", + 3911073154: "Mnemoniczny identyfikator przechowywania", + 570639842: "Mnemonik nie został odszyfrowany", + 1746030071: "Mnemoniczny nie był szyfrowany", + 1458925155: "Zmodyfikowany:", + 1845376098: "Multisig", + 2939797024: "Sieć", + 73574491: "Nowy Mnemonic", + 2792272353: "Wykryto nowe oprogramowanie.\n\nsha256:\n%s\n\n\n\ninstall?", + 4063104189: "NIE", + 3927838899: "Brak frazy BIP39", + 4092516657: "Za mało rolki!", + 1577637745: "Octal", + 3312581301: "PBKDF2 ITER.", + 721090621: "PSBT", + 995862913: "Parzyj kropki czarne, aby można je było wykryć.", + 2987800462: "Szerokość papieru", + 3050763890: "Część\n %d / %d", + 3559456868: "Rozmiar części", + 4249903283: "Fraza", + 3712257341: "FRASSE:", + 140802882: "Trwać", + 1703779997: "PlainText QR", + 3561756278: "Załaduj deskryptor wyjściowy portfela", + 784609464: "Szybkość spadku", + 3037062877: "Test wydrukuj QR", + 4278257699: "Drukuj do qr?\n\n%s\n\n", + 516488026: "Wydrukować?\n\n%s\n\n", + 1123106929: "Drukarka", + 3903571079: "Sterownik drukarki nie jest ustawiony!", + 2609799302: "Drukowanie\n %d / %d", + 844861889: "Drukowanie ...", + 2580599003: "Przystępować?", + 556126964: "Przetwarzanie ...", + 1848310591: "Kod QR", + 710709610: "Pin Rx", + 2697857197: "Odbierać", + 1746677167: "Odbierać adresy", + 364354944: "Region:", + 1662254634: "Przejrzyj zeskanowane dane, w razie potrzeby edytuj", + 770350922: "Rzuć kostkę co najmniej %d, aby wygenerować mnemoniczny.", + 856795528: "Rolls:\n\n%s", + 255086803: "Rolls: %d\n", + 3976793317: "karta SD", + 2827687530: "Karta SD nie została wykryta", + 2736513298: "Karta SD nie została wykryta.", + 3593785196: "SHA256 Rolls:\n\n%s", + 1143278725: "SHA256 migawki:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Zapisz na karcie SD?", + 810036588: "Zapisano na karcie SD:\n%s", + 763824768: "Skala", + 4117455079: "Adres skanowania", + 3219991109: "Scan BIP39 Passhraz", + 2537207336: "Skanuj kod QR", + 4006316572: "Znowu skanowanie słów 1-12", + 2736506158: "Skanowanie słów 13-24", + 3593497655: "Wygaszacz ekranu", + 266935239: "Seedqr", + 1698829144: "Samo-transfer lub zmiana (%d):", + 473154195: "Ustawienia", + 1825881236: "Zamknięcie", + 2120776272: "Wyłączanie..", + 1061961408: "Podpisać", + 4282338366: "Podpisać?", + 746161122: "Podpis", + 1988416729: "Podpisana wiadomość", + 3672006076: "Podpisano PSBT", + 2281377987: "Pojedyncze Sig", + 4221794628: "Rozmiar:", + 2344747135: "Nie można wykonać niektórych kontroli.", + 2309020186: "Wydać (%d):", + 3355862324: "Stackbit 1248", + 3303592908: "Przechowuj na Flash", + 720041451: "Przechowuj na karcie SD", + 3514476519: "Przesuń tryb zmiany", + 1898550184: "Dotknij lub wejdź do przechwytywania", + 4228215415: "Pin TX", + 2612594937: "Tekst", + 1454688268: "Temat", + 1180180513: "Termiczny", + 4119292117: "Małe ziarno", + 1732872974: "Małe nasiona (bity)", + 725348723: "Narzędzia", + 3684696112: "Próg dotykowy", + 2978718564: "Ekran dotykowy", + 2732611775: "Próbuj bardziej?", + 1487826746: "Passówka typu BIP39", + 2061556020: "Klucz typu", + 2089395053: "Jednostka", + 2845607430: "Aktualizacja bootloader ..\n\n%d %%", + 4164597446: "Uaktualnienie zakończone.\n\nshutting w dół ..", + 2736001501: "Aktualizacja oprogramowania układowego ..\n\n%d %%", + 2674953168: "Użyj czarnej powierzchni tła.", + 2402455261: "Użyj entropii aparatu, aby stworzyć nowy mnemonik", + 236075140: "Używany:", + 4003084591: "Wartość %s z zakresu: [ %s, %s]", + 4191058607: "Za pośrednictwem aparatu", + 1254681955: "Via D20", + 525309547: "Przez D6", + 590330112: "Poprzez ręczne wejście", + 2504354847: "Poczekaj na schwytanie", + 3992434312: "Czas oczekiwania", + 2297028319: "Deskryptor portfela", + 4232654916: "Deskryptor wyjściowy portfela", + 2587172867: "Załadowany deskryptor wyjściowy portfela!", + 2499782468: "Nie znaleziono deskryptora wyjściowego portfela.", + 2671738224: "Ostrzeżenie:", + 797660533: "Słowo %d", + 3742424146: "Numery słów", + 2965123464: "Słowa", + 1303016265: "Tak", + 771968845: "Twoje zmiany będą przechowywane w pamięci flash urządzenia.", + 2569054451: "Twoje zmiany będą przechowywane na karcie SD.", }, - "fr-FR": { - 1185266064: "%d de %d multisignature", - 2004520398: "%d. Changement : \n\n%s\n\n", - 3862364126: "%d. Auto-transfert : \n\n%s\n\n", - 3264377309: "%d. Dépense : \n\n%s\n\n", - 2399232215: "%s\n\nest une adresse changement valide!", - 3921290840: "%s\n\nest une adresse reçue valide!", - 1808355833: "INTROUVABLE dans les premières %d adresses de changement", - 1306127065: "%s\n\nINTROUVABLE dans les premières %d adresses de reçues", - 3348584292: "(Expérimental)", - 2739590230: "12 mots", - 1310058127: "24 mots", + "pt-BR": { + 1185266064: "%d da %d multisig", + 2004520398: "%d. Troco: \n\n%s\n\n", + 3862364126: "%d. Autotransferência: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n é um endereço de troco válido!", + 3921290840: "%s\n\né um endereço de recepção válido!", + 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", + 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", + 3348584292: "(Experimental)", + 2739590230: "12 palavras", + 1310058127: "24 palavras", 2743272264: "ABC", - 1949634023: "À propos", + 1949634023: "Sobre", 1517128857: "Adafruit", - 3270727197: "Adresse", - 2574498267: "Entropie supplémentaire de la caméra requise pour le mode AES-CBC", - 283202181: "Alignez correctement la caméra et Tiny Seed.", - 88746165: "Anti-éblouissement désactivé", - 1521033296: "Anti-éblouissement activé", - 1056821534: "Es-tu sûr?", - 3247612282: "BIP39 Mnémonique", - 3455872521: "Retour", - 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", - 2256777600: "Mauvaise signature", - 3937333362: "Débit en bauds", + 3270727197: "Endereço", + 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", + 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", + 88746165: "Antirreflexo desativado", + 1521033296: "Antirreflexo ativado", + 1056821534: "Tem certeza?", + 3247612282: "Mnemônico BIP39", + 3455872521: "Voltar", + 2541860807: "Backing up bootloader..\n\n%d%%", + 2256777600: "Assinatura Inválida", + 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Rembourrage de bordure", + 928727036: "Borda", 213030954: "CNC", - 1207696150: "Changement", - 3126552510: "Adresses de Changement", - 1583186953: "Changer de thème et redémarrer?", - 2697733395: "Modifications enregistrées sur la carte SD!", - 388908871: "Les modifications dureront jusqu'à l'arrêt.", - 3442025874: "Vérifiez la carte SD", - 3119547911: "Vérifiez que l'adresse appartient à cette portefeuille?", - 2856261511: "Adresses %d changement vérifiées sans correspondance.", - 2788541416: "Adresses %d reçues vérifiées sans correspondance.", - 2446472910: "Vérification de l'adresse changement %d pour correspondance..", - 2470115694: "Vérification de la carte SD..", - 3655273987: "Vérification de l'adresse reçue %d pour correspondance..", - 2407028014: "SeedQR Compact", - 4041895036: "Continuer?", - 4094072796: "Créer du code QR", - 167798282: "Créer du code QR à partir du texte?", - 2767642191: "Créé:", - 3513215254: "Code QR personnalisé", - 124617190: "Profondeur de coupe", - 597912140: "Méthode de coupe", - 2504034831: "Décimal", - 2751113454: "Décrypter?", - 1016609898: "Supprimer le fichier?", - 1364509700: "Supprimer mnémonique", - 4102535566: "Profondeur par passage", - 2791699253: "Dérivation: %s", - 1230133196: "Stockage flash de l'appareil non détecté.", - 3836852788: "Terminé?", - 382368239: "Conducteur", - 3978947916: "Encodeur", - 4090746898: "Anti-rebond de l'encodeur", - 374684711: "Crypter mnémonique", - 1244124409: "Code QR crypté", - 2968548114: "Le mnémonique crypté n'a pas été stocké", - 3315319371: "Mnémonique cryptée a été stockée avec ID:", - 350279787: "Chiffrement", - 2601598799: "Mode de chiffrement", - 3504179008: "Entrez chaque mot de votre BIP-39 mnémonique sous la forme d'un nombre 1 jusqu'à 2048.", - 1100685007: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en hexadécimal de 1 à 800.", - 4090266642: "Entrez chaque mot de votre mnémonique BIP-39 sous la forme d'un nombre en octal de 1 à 4000.", - 2780625730: "Entrez chaque mot de votre BIP-39 mnémonique.", - 784361051: "Erreur:\n%s", - 1505332462: "Esc", - 3838465623: "Explorer des fichiers?", - 4170881190: "Exportation vers la carte SD..", - 1711312434: "Clé publique", - 383371114: "Échec de décrypter", - 3048830188: "Erreur de chargement PSBT", - 4192663412: "Erreur de chargement d'adresse", - 1996021743: "Échec du chargement de la clé", - 1108715658: "Échec du chargement du message", - 1081425878: "Erreur de chargement mnémonique", - 928667220: "Échec du chargement du descripteur de sortie", - 1620572516: "Échec du chargement de la phrase secrète", - 2946146830: "Échec de stocker mnémonique", - 1303554751: "Frais: ", - 104500973: "Taux d'alimentation", - 3313339187: "Nom de fichier", - 1982637349: "Le nom de fichier %s existe sur la carte SD, écraser ?", - 3737729752: "Empreinte Digitale: %s", - 2542772894: "Le micrologiciel dépasse la taille maximale: %d", - 1406590538: "Diamètre de flûte", - 3086093110: "Libre: ", - 1893243331: "Du stockage", + 1207696150: "Troco", + 3126552510: "Endereços de Troco", + 1583186953: "Mudar o tema e reiniciar?", + 2697733395: "Mudanças salvas no cartão SD!", + 388908871: "Alterações só durarão até o desligamento.", + 3442025874: "Verifique o cartão SD", + 3119547911: "Verificar se este endereço pertence a carteira?", + 2856261511: "Endereço de troco %d não corresponde.", + 2788541416: "Endereço de recebimento %d não corresponde.", + 2446472910: "Verificando correspondência do endereço de troco %d ..", + 2470115694: "Verificando o cartão SD..", + 3655273987: "Verificando correspondência do endereço de recebimento %d ..", + 2407028014: "SeedQR Compacto", + 4041895036: "Continuar?", + 4094072796: "Gerar Código QR", + 167798282: "Gerar código QR do texto?", + 2767642191: "Criado: ", + 3513215254: "Código QR Customizado", + 124617190: "Profundidade de Corte", + 597912140: "Método de Corte", + 2504034831: "Decimal", + 2751113454: "Descriptografar?", + 1016609898: "Excluir Arquivo?", + 1364509700: "Excluir Mnemônico", + 4102535566: "Profundidade da Passagem", + 2791699253: "Derivação: %s", + 1230133196: "Armazenamento flash do dispositivo não detectado.", + 3836852788: "Feito?", + 382368239: "Driver", + 3978947916: "Codificador", + 4090746898: "Debounce do Encoder", + 374684711: "Criptografar Mnemônico", + 1244124409: "Código QR Criptografado", + 2968548114: "Mnemonic criptografado não foi armazenado", + 3315319371: "Mnemônico criptografado foi armazenado com ID:", + 350279787: "Criptografia", + 2601598799: "Modo de Criptografia", + 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", + 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", + 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", + 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", + 784361051: "Erro:\n%s", + 1505332462: "Esc", + 3838465623: "Explorar arquivos?", + 4170881190: "Exportando para o cartão SD..", + 1711312434: "Chave Pública Estendida", + 383371114: "Falhou em descriptografar", + 3048830188: "Falhou ao carregar PSBT", + 4192663412: "Falhou ao carregar endereço", + 1996021743: "Falha ao carregar a chave", + 1108715658: "Falhou ao carregar mensagem", + 1081425878: "Falhou ao carregar mnemônico", + 928667220: "Falha ao carregar o descritor de saída", + 1620572516: "Falha ao carregar a senha", + 2946146830: "Falhou ao armazenar mnemônico", + 1303554751: "Taxa: ", + 104500973: "Taxa de Alimentação", + 3313339187: "Nome do arquivo", + 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", + 3737729752: "Impressão digital: %s", + 2542772894: "Firmware excede o tamanho máximo: %d", + 1406590538: "Diâmetro da Fresa", + 3086093110: "Livre: ", + 1893243331: "Do Armazenamento", 4120536442: "GRBL", - 299338213: "Donnez à ce mnémonique un identifiant personnalisé?Sinon l'empreinte actuelle sera utilisée", - 602716148: "Go", - 3580020863: "Clé public hexadécimal", - 2691246967: "Hexadécimal", - 2736309107: "Id existe déjà\n", - 1706005805: "Descripteur de sortie incomplet", - 631342955: "Entrées (%d) : ", - 2585599782: "Adresse invalide", - 2874529150: "Chargeur de démarrage invalide", - 4093416954: "Longueur mnémonique invalide", - 1422874211: "Clé publique non valide", - 2443867979: "Portefeuille invalide:\n%s", - 4122897393: "Inverser", - 3000888649: "Clé", - 2686333978: "Clé:", - 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Test de l'imprimante Krux QR", - 766317539: "Langue", - 972436696: "Délai de Ligne", - 3596093890: "Ligne: ", - 2820726296: "Charger mnémonique", - 879727077: "Charger depuis la carte SD ?", - 669106195: "En charger qu'un?", - 3330705289: "Charger?", - 2596531078: "Caméra de Chargement..", - 596389387: "Chargement de l'adresse de changement %d..", - 336702608: "Chargement de l'imprimante..", - 2538883522: "Chargement de l'adresse de réception %d..", - 3159494909: "Chargement..", - 1177338798: "Paramètres régionaux", - 2817059741: "Emplacement", - 63976957: "Niveau de journalisation", - 86530918: "Enregistrement", - 2917810189: "Longueur maximale dépassée (% s)", - 2030045667: "Message", - 3928301843: "Fichier de signature manquant", - 1948316555: "Mnémonique", - 2123991188: "ID mnémonique", - 3911073154: "ID de stockage mnémonique", - 570639842: "Mnémonique n'a pas été décryptée", - 1746030071: "Mnémonique n'était pas cryptée", - 1458925155: "Modifié:", - 1845376098: "Multi\nsignature", - 2939797024: "Réseau", - 73574491: "Nouveau mnémonique", - 2792272353: "Nouveau micrologiciel détecté.\n\nSHA256:\n%s\n\n\n\nInstaller?", - 4063104189: "Non", - 3927838899: "Pas de phrase passante bip39", - 4092516657: "Pas assez de rouleaux !", - 1577637745: "Octale", - 3312581301: "Itér. PBKDF2", + 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", + 602716148: "Ir", + 3580020863: "Chave pública hexadecimal", + 2691246967: "Hexadecimal", + 2736309107: "Id já existe\n", + 1706005805: "Descritor incompleto", + 631342955: "Entradas (%d): ", + 2585599782: "Endereço inválido", + 2874529150: "Bootloader inválido", + 4093416954: "Comprimento de mnemônico inválido", + 1422874211: "Chave pública inválida", + 2443867979: "Carteira inválida:\n%s", + 4122897393: "Invertido", + 3000888649: "Chave", + 2686333978: "Chave:", + 4123798664: "Krux\n\n\nVersão\n%s", + 3835918229: "Teste de impressão de QR krux", + 766317539: "Língua", + 972436696: "Atraso de Linha", + 3596093890: "Linha: ", + 2820726296: "Carregar Mnemônico", + 879727077: "Carregar do cartão SD?", + 669106195: "Carregar um?", + 3330705289: "Carregar?", + 2596531078: "Carregando Câmera..", + 596389387: "Carregando endereço de troco %d..", + 336702608: "Carregando impressora..", + 2538883522: "Carregando endereço de recebimento %d..", + 3159494909: "Carregando..", + 1177338798: "Idioma", + 2817059741: "Local", + 63976957: "Nível de log", + 86530918: "Logging", + 2917810189: "Comprimento máximo excedido (%s)", + 2030045667: "Mensagem", + 3928301843: "Arquivo de assinatura faltando", + 1948316555: "Mnemônico", + 2123991188: "ID do mnemônico", + 3911073154: "ID de armazenamento", + 570639842: "Mnemônico não foi descriptografado", + 1746030071: "Mnemônico não foi criptografado", + 1458925155: "Modificado:", + 1845376098: "Multisig", + 2939797024: "Rede", + 73574491: "Novo Mnemônico", + 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", + 4063104189: "Não", + 3927838899: "Sem senha BIP39", + 4092516657: "Jogadas insuficientes!", + 1577637745: "Octal", + 3312581301: "Iter. PBKDF2", 721090621: "PSBT", - 995862913: "Peignez les points perforés en noir afin qu'ils puissent être détectés.", - 2987800462: "Largeur du papier", - 3050763890: "Partie\n%d / %d", - 3559456868: "Taille de la pièce", - 4249903283: "Phrase de passe", - 3712257341: "Phrass de passe:", - 140802882: "Persister", - 1703779997: "QR en Texte Brut", - 3561756278: "Veuillez charger un descripteur de sortie de portefeuille", - 784609464: "Taux de plongée", - 3037062877: "Test d'impression QR", - 4278257699: "Imprimer en QR?\n\n%s\n\n", - 516488026: "Imprimer?\n\n%s\n\n", - 1123106929: "Imprimante", - 3903571079: "Le conducteur d'imprimante n'est pas défini!", - 2609799302: "Impression\n%d / %d", - 844861889: "Impression ...", - 2580599003: "Procéder?", - 556126964: "Traitement ...", - 1848310591: "QR Code", - 710709610: "RX Fiche", - 2697857197: "Recevoir", - 1746677167: "Adresses de Réception", - 364354944: "Région: ", - 1662254634: "Examinez les données numérisées, modifiez-les si nécessaire", - 770350922: "Lancez le dé au moins %d fois pour générer un mnémonique.", - 856795528: "Rouleaux:\n\n%s", - 255086803: "Rouleaux: %d\n", - 3976793317: "Carte SD", - 2827687530: "Carte SD non détectée", - 2736513298: "Carte SD non détectée.", - 3593785196: "SHA256 de rouleaux:\n\n%s", - 1143278725: "Sha256 de Snapshot:\n\n% s", + 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", + 2987800462: "Largura do papel", + 3050763890: "Parte\n%d / %d", + 3559456868: "Tamanho da peça", + 4249903283: "Senha", + 3712257341: "Senha:", + 140802882: "Salvar", + 1703779997: "QR em Texto", + 3561756278: "Carregue um descritor da carteira", + 784609464: "Taxa de Mergulho", + 3037062877: "Imprimir QR de teste", + 4278257699: "Imprimir QR?\n\n%s\n\n", + 516488026: "Imprimir?\n\n%s\n\n", + 1123106929: "Impressora", + 3903571079: "Driver de impressora não está definido!", + 2609799302: "Imprimindo\n%d / %d", + 844861889: "Imprimindo ...", + 2580599003: "Seguir?", + 556126964: "Processando ...", + 1848310591: "Código QR", + 710709610: "Pino RX", + 2697857197: "Recebimento", + 1746677167: "Endereços de Recebimento", + 364354944: "Região: ", + 1662254634: "Revise os dados, edite se necessário", + 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", + 856795528: "Jogadas:\n\n%s", + 255086803: "Jogadas: %d\n", + 3976793317: "Cartão SD", + 2827687530: "Cartão SD não detectado", + 2736513298: "Cartão SD não detectado.", + 3593785196: "SHA256 de jogadas:\n\n%s", + 1143278725: "Sha256 da imagem:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Enregistrer sur la carte SD ?", - 810036588: "Enregistré sur la carte SD :\n%s", - 763824768: "L'échelle", - 4117455079: "Scannez l'adresse", - 3219991109: "Scan bip39 en phrase secrète", - 2537207336: "Scanner le code QR de la clé", - 4006316572: "Analyser à nouveau les mots 1 à 12", - 2736506158: "Analyser les mots 13 à 24", - 266935239: "Seedqr", - 1698829144: "Auto-transfert ou changement (%d): ", - 473154195: "Paramètres", - 1825881236: "Fermer", - 2120776272: "Éteindre..", - 1061961408: "Signature", - 4282338366: "Signature?", - 746161122: "Signature", - 1988416729: "Message signé", - 3672006076: "PSBT signé", - 2281377987: "Clé unique", - 4221794628: "Capacité: ", - 2344747135: "Certains chèques ne peuvent pas être effectués.", - 2309020186: "Dépense (%d) : ", + 3531742595: "Salvar no cartão SD?", + 810036588: "Salvo no cartão SD:\n%s", + 763824768: "Escala", + 4117455079: "Escanear Endereço", + 3219991109: "Escanear a senha BIP39", + 2537207336: "Escanear código QR da chave", + 4006316572: "Escaneando as palavras 1-12 novamente", + 2736506158: "Escaneando as palavras 13-24", + 3593497655: "Protetor de tela", + 266935239: "SeedQR", + 1698829144: "Autotransferência ou Troco (%d): ", + 473154195: "Configurações", + 1825881236: "Desligar", + 2120776272: "Desligando..", + 1061961408: "Assinar", + 4282338366: "Assinar?", + 746161122: "Assinatura", + 1988416729: "Mensagem Assinada", + 3672006076: "PSBT Assinada", + 2281377987: "Single-sig", + 4221794628: "Total: ", + 2344747135: "Algumas verificações não podem ser realizadas.", + 2309020186: "Gastos (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Stocker sur flash", - 720041451: "Stocker sur la carte SD", - 3514476519: "Faites glisser pour changer de mode", - 1898550184: "TOUCHEZ ou ENTER pour capturer", - 4228215415: "TX Fiche", - 2612594937: "Texte", - 1454688268: "Thème", - 1180180513: "Thermique", + 3303592908: "Armazene na Flash", + 720041451: "Armazene no Cartão SD", + 3514476519: "Deslize para mudar de modo", + 1898550184: "TOQUE ou ENTER para capturar", + 4228215415: "Pino TX", + 2612594937: "Texto", + 1454688268: "Tema", + 1180180513: "Térmica", 4119292117: "Tiny Seed", 1732872974: "Tiny Seed (bits)", - 725348723: "Outils", - 3684696112: "Seuil Tactile", - 2978718564: "Écran Tactile", - 2732611775: "Réessayer?", - 1487826746: "Type Bip39 Plasque", - 2061556020: "Clé de type", - 2089395053: "Unité", - 2845607430: "Mise à jour du chargeur de démarrage..\n\n%d%%", - 4164597446: "Mise à niveau complète.\n\nÉteindre..", - 2736001501: "Mise à niveau du micrologiciel..\n\n%d%%", - 2674953168: "Utilisez une surface de fond noire.", - 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", - 236075140: "Utilisé: ", - 4003084591: "Valeur% s hors de portée: [% s,% s]", - 4191058607: "Par caméra", + 725348723: "Ferramentas", + 3684696112: "Limiar de Toque", + 2978718564: "Touchscreen", + 2732611775: "Tentar mais?", + 1487826746: "Digitar a senha BIP39", + 2061556020: "Digite a Chave", + 2089395053: "Unidade", + 2845607430: "Atualizando bootloader..\n\n%d%%", + 4164597446: "Atualização completa.\n\nDesligando..", + 2736001501: "Atualizando firmware..\n\n%d%%", + 2674953168: "Use uma superfície de fundo preta.", + 2402455261: "Use a entropia da câmera para criar um novo mnemônico", + 236075140: "Usado: ", + 4003084591: "Valor %s fora do alcance: [ %s, %s]", + 4191058607: "Pela Câmera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Par saisie manuelle", - 2504354847: "Attendez la capture", - 2297028319: "Descripteur de Portefeuille", - 4232654916: "Descripteur de sortie du portefeuille", - 2587172867: "Descripteur de sortie du portefeuille chargé!", - 2499782468: "Descripteur de sortie du portefeuille introuvable.", - 2671738224: "Avertissement:", - 797660533: "Mot %d", - 3742424146: "Numéros de mots", - 2965123464: "Mots", - 1303016265: "Oui", - 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", - 2569054451: "Vos modifications seront conservées sur la carte SD.", + 590330112: "Por entrada manual", + 2504354847: "Aguarde a captura", + 3992434312: "Tempo de espera", + 2297028319: "Descritor de Carteira", + 4232654916: "Descritor da carteira", + 2587172867: "Descritor de saída da carteira carregado!", + 2499782468: "O descritor de saída da carteira não foi encontrado.", + 2671738224: "Aviso:", + 797660533: "Palavra %d", + 3742424146: "Números das Palavras", + 2965123464: "Palavras", + 1303016265: "Sim", + 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", + 2569054451: "Suas alterações serão mantidas no cartão SD.", + }, + "ru-RU": { + 1185266064: "%d из %d мультиподпись", + 2004520398: "%d. Сдача: \n\n%s\n\n", + 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", + 3264377309: "%d. Расход: \n\n%s\n\n", + 2399232215: "%s\n\nвалидный адрес сдачи!", + 3921290840: "%s\n\nвалидный адрес получения!", + 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", + 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", + 3348584292: "(Эксперементальный)", + 2739590230: "12 слов", + 1310058127: "24 слова", + 2743272264: "ABC", + 1949634023: "О Программе", + 1517128857: "Adafruit", + 3270727197: "Адрес", + 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", + 283202181: "Правильно совместите камеру и Мини Сид-фразу.", + 88746165: "Антиблик отключен", + 1521033296: "Антиблик включен", + 1056821534: "Вы уверены?", + 3247612282: "BIP39 Мнемоника", + 3455872521: "Назад", + 2541860807: "Резервное копирование загрузчика..\n\n%d%%", + 2256777600: "Плохая подпись", + 3937333362: "Скорость Передачи Данных", + 427617266: "Биткоин", + 928727036: "Заполнение границ", + 213030954: "CNC", + 1207696150: "Сдача", + 3126552510: "Адрес Сдачи", + 1583186953: "Сменить тему и перезагрузить?", + 2697733395: "Изменения сохранены на SD карте!", + 388908871: "Изменения будут храниться до выключения.", + 3442025874: "Проверить SD Карту", + 3119547911: "Проверить, что адрес принадлежит этому кошельку?", + 2856261511: "Проверено %d адресов сдачи без совпадений.", + 2788541416: "Проверено %d адресов получения без совпадений.", + 2446472910: "Проверяем адрес сдачи %d на совпадение..", + 2470115694: "Проверка SD карты..", + 3655273987: "Проверяем адрес получения %d на совпадение..", + 2407028014: "Компактный SeedQR", + 4041895036: "Продолжить?", + 4094072796: "Создать QR Код", + 167798282: "Создать QR код из текста?", + 2767642191: "Создано", + 3513215254: "Пользовательский QR Код", + 124617190: "Глубина Резки", + 597912140: "Метод Резки", + 2504034831: "Десятичный", + 2751113454: "Расшифровать?", + 1016609898: "Удалить Файл?", + 1364509700: "Удалить Мнемонику", + 4102535566: "Глубина За Проход", + 2791699253: "Производный путь: %s", + 1230133196: "Флэш память устройства не обнаружена.", + 3836852788: "Готово?", + 382368239: "Драйвер", + 3978947916: "Кодер", + 4090746898: "Дебаунс Кодера", + 374684711: "Зашифровать Мнемонику", + 1244124409: "Зашифрованный QR Код", + 2968548114: "Зашифрованная мнемоника не была сохранена", + 3315319371: "Зашифрованная мнемоника была сохранена с ID", + 350279787: "Шифрование", + 2601598799: "Метод шифрования", + 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", + 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", + 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", + 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", + 784361051: "Ошибка:\n%s", + 1505332462: "Выйти", + 3838465623: "Исследовать файлы?", + 4170881190: "Экспортирование на SD карту..", + 1711312434: "Расширенный Публичный Ключ", + 383371114: "Не удалось расшифровать", + 3048830188: "Не удалось загрузить PSBT", + 4192663412: "Не удалось загрузить адрес", + 1996021743: "Не удалось загрузить ключ", + 1108715658: "Не удалось загрузить сообщение", + 1081425878: "Не удалось загрузить мнемонику", + 928667220: "Не удалось загрузить выходной дескриптор", + 1620572516: "Не удалось загрузить фразу-пароль", + 2946146830: "Не удалось сохранить мнемонику", + 1303554751: "Комиссия: ", + 104500973: "Скорость подачи", + 3313339187: "Имя файла", + 1982637349: "Файл %s существует на SD карте, перезаписать?", + 3737729752: "Фингерпринт: %s", + 2542772894: "Прошивка превышает максимальный размер: %d", + 1406590538: "Flute Диаметр", + 3086093110: "Бесплатно: ", + 1893243331: "Из Памяти", + 4120536442: "GRBL", + 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", + 602716148: "OK", + 3580020863: "Шестнадцатеричный Публичный Ключ", + 2691246967: "Шестнадцатеричный", + 2736309107: "ID уже существует\n", + 1706005805: "Неполный выходной дескриптор", + 631342955: "Входы (%d): ", + 2585599782: "Неверный адрес", + 2874529150: "Неверный загрузчик", + 4093416954: "Неверная длина мнемоники", + 1422874211: "Неверный публичный ключ", + 2443867979: "Неверный кошелек:\n%s", + 4122897393: "Инвертировать", + 3000888649: "Ключ", + 2686333978: "Ключ: ", + 4123798664: "Krux\n\n\nВерсия\n%s", + 3835918229: "Тестовый QR Принтера Krux", + 766317539: "Язык", + 972436696: "Задержка Линии", + 3596093890: "Линия: ", + 2820726296: "Загрузить Мнемонику", + 879727077: "Загрузить с SD карты?", + 669106195: "Загрузить одну?", + 3330705289: "Загрузить?", + 2596531078: "Загрузка Камеры..", + 596389387: "Загрузка адреса сдачи %d..", + 336702608: "Загрузка принтера..", + 2538883522: "Загрузка адреса получения %d..", + 3159494909: "Загрузка..", + 1177338798: "Локаль", + 2817059741: "Расположение", + 63976957: "Уровень логирования", + 86530918: "Логирование", + 2917810189: "Максимальная длина превышена (%s)", + 2030045667: "Сообщение", + 3928301843: "Отсутствует файл подписи", + 1948316555: "Мнемоника", + 2123991188: "ID мнемоники", + 3911073154: "ID памяти мнемоники", + 570639842: "Мнемоника не была расшифрована", + 1746030071: "Мнемоника не была зашифрована", + 1458925155: "Изменено: ", + 1845376098: "Мультиподпись", + 2939797024: "Сеть", + 73574491: "Новая Мнемоника", + 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", + 4063104189: "Нет", + 3927838899: "Без BIP39 фразы-пароля", + 4092516657: "Недостаточно бросков!", + 1577637745: "Восьмеричный", + 3312581301: "PBKDF2 Итерации", + 721090621: "PSBT", + 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", + 2987800462: "Ширина Бумаги", + 3050763890: "Часть\n%d / %d", + 3559456868: "Размер Части", + 4249903283: "Фраза-пароль", + 3712257341: "Фраза-пароль: ", + 140802882: "Постоянная Память", + 1703779997: "QR открытым текстом", + 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", + 784609464: "Скорость Погружения", + 3037062877: "Напечатать Тестовый QR", + 4278257699: "Напечатать в виде QR?\n\n%s\n\n", + 516488026: "Печатать?\n\n%s\n\n", + 1123106929: "Принтер", + 3903571079: "Драйвер Принтера не установлен!", + 2609799302: "Идет печать\n%d / %d", + 844861889: "Идет печать ...", + 2580599003: "Продолжить?", + 556126964: "Обрабатываю ...", + 1848310591: "QR Код", + 710709610: "RX Пин", + 2697857197: "Получить", + 1746677167: "Адрес Получения", + 364354944: "Регион: ", + 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", + 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", + 856795528: "Броски:\n\n%s", + 255086803: "Броски: %d\n", + 3976793317: "SD карта", + 2827687530: "SD карта не обнаружена", + 2736513298: "SD карта не обнаружена.", + 3593785196: "SHA256 бросков:\n\n%s", + 1143278725: "SHA256 снэпшота:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Сохранить на SD карту?", + 810036588: "Сохранено на SD карту:\n%s", + 763824768: "Шкала", + 4117455079: "Отсканировать Адрес", + 3219991109: "Отсканировать BIP39 фразу-пароль", + 2537207336: "Отсканировать Ключ QR код", + 4006316572: "Сканирование слов 1-12 снова", + 2736506158: "Сканирование слов 13-24", + 3593497655: "Заставка", + 266935239: "SeedQR", + 1698829144: "Трансфер самому себе или Сдача (%d): ", + 473154195: "Настройки", + 1825881236: "Выключить", + 2120776272: "Выключение..", + 1061961408: "Подписать", + 4282338366: "Подписать?", + 746161122: "Подпись", + 1988416729: "Подписанное Сообщение", + 3672006076: "Подписанное PSBT", + 2281377987: "Одна подпись", + 4221794628: "Размер: ", + 2344747135: "Некоторые проверки не могут быть выполнены.", + 2309020186: "Расход (%d): ", + 3355862324: "Стэкбит 1248", + 3303592908: "Сохранить на Флэш Память", + 720041451: "Сохранить на SD Карту", + 3514476519: "Свайпните, чтобы сменить режим", + 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", + 4228215415: "TX Пин", + 2612594937: "Текст", + 1454688268: "Тема", + 1180180513: "Термальный", + 4119292117: "Мини Сид-фраза", + 1732872974: "Мини Сид-фраза (Биты)", + 725348723: "Инструменты", + 3684696112: "Прикоснитесь Границы", + 2978718564: "Тачскрин", + 2732611775: "Попробовать ещё?", + 1487826746: "Введите BIP39 фразу-пароль", + 2061556020: "Введите Ключ", + 2089395053: "Юнит", + 2845607430: "Обновление загрузчика..\n\n%d%%", + 4164597446: "Обновление завершено.\n\nВыключение..", + 2736001501: "Обновление прошивки..\n\n%d%%", + 2674953168: "Использовать черную фоновую поверхность.", + 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", + 236075140: "Использовано: ", + 4003084591: "Значение %s вне диапозона: [%s, %s]", + 4191058607: "С Помощью Камеры", + 1254681955: "С Помощью D20", + 525309547: "С Помощью D6", + 590330112: "С Помощью Ручного Ввода", + 2504354847: "Дождитесь Захвата", + 3992434312: "Время ожидания", + 2297028319: "Дескриптор Кошелька", + 4232654916: "Выходной дескриптор кошелька", + 2587172867: "Выходной дескриптор кошелька загружен!", + 2499782468: "Выходной дескриптор кошелька не найден.", + 2671738224: "Предупреждение:", + 797660533: "Слово %d", + 3742424146: "Числа Слов", + 2965123464: "Слова", + 1303016265: "Да", + 771968845: "Ваши изменения буду храниться на флэш памяти устройства.", + 2569054451: "Ваши изменения будут храниться на SD карте.", }, - "nl-NL": { - 1185266064: "%d van %d multisig", - 2004520398: "%d. Wisselgeld: \n\n%s\n\n", - 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", - 3264377309: "%d. Uitgaven: \n\n%s\n\n", - 2399232215: "%s\n\nis een valide wisselgeld adres!", - 3921290840: "%s\n\nis een valide ontvangst adres!", - 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", - 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", - 3348584292: "(Experimenteel)", - 2739590230: "12 woorden", - 1310058127: "24 woorden", + "vi-VN": { + 1185266064: "%d của %d đa chữ kí", + 2004520398: "%d. Thay đổi: \n\n%s\n\n", + 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", + 3264377309: "%d. Chi tiêu: \n\n%s\n\n", + 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", + 3921290840: "%s\n\nlà một địa chỉ khả dụng!", + 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 3348584292: "(Thực nghiệm)", + 2739590230: "12 từ", + 1310058127: "24 từ", 2743272264: "ABC", - 1949634023: "Over", + 1949634023: "Về chúng tôi", 1517128857: "Adafruit", - 3270727197: "Adres", - 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", - 283202181: "Richt de camera en Tiny Seed op de juiste manier.", - 88746165: "Anti reflecterend uitgeschakeld", - 1521033296: "Anti reflecterend ingeschakeld", - 1056821534: "Weet je het zeker?", - 3247612282: "BIP-39 geheugensteun", - 3455872521: "Terug", - 2541860807: "Backup van de bootloader...\n\n%d%%", - 2256777600: "Ongeldige handtekening", - 3937333362: "Baudratio", + 3270727197: "Địa chỉ", + 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", + 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", + 88746165: "Chống lóa bị vô hiệu hóa", + 1521033296: "Đã bật chống lóa", + 1056821534: "Bạn có chắc không?", + 3247612282: "Mã mnemonic dạng chuẩn BIP39", + 3455872521: "Trở lại", + 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", + 2256777600: "Chữ ký xấu", + 3937333362: "Tốc độ baud", 427617266: "Bitcoin", - 928727036: "Rand opvulling", + 928727036: "Đệm viền", 213030954: "CNC", - 1207696150: "Change", - 3126552510: "Wisselgeldadres", - 1583186953: "Thema veranderen en opnieuw opstarten?", - 2697733395: "Wijzigingen aanhouden op SD kaart!", - 388908871: "Wijzigingen blijven van kracht tot afsluiten.", - 3442025874: "Controleer SD kaart", - 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", - 2856261511: "Na %d geen wisselgeld adressen gevonden.", - 2788541416: "Na %d geen ontvangst adressen gevonden.", - 2446472910: "Wisselgeldadres %d controleren...", - 2470115694: "SD kaart controleren...", - 3655273987: "Ontvangstadres %d controleren...", - 2407028014: "Compact SeedQR", - 4041895036: "Doorgaan?", - 4094072796: "QR code maken", - 167798282: "QR code maken van tekst?", - 2767642191: "Aangemaakt: ", - 3513215254: "Aangepaste QR code", - 124617190: "Snijdiepte", - 597912140: "Snijmethode", - 2504034831: "Decimaal", - 2751113454: "Ontsleutelen?", - 1016609898: "Bestand verwijderen?", - 1364509700: "Geheugensteun verwijderen", - 4102535566: "Diepte per pas", - 2791699253: "Afgeleide: %s", - 1230133196: "Opslag op apparaat is niet gedetecteerd.", - 3836852788: "Klaar?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-debounce", - 374684711: "Geheugensteun versleutelen", - 1244124409: "Versleutelde QR code", - 2968548114: "Versleutelde geheugensteun was niet opgeslagen", - 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", - 350279787: "Versleutelen", - 2601598799: "Versleutel modus", - 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", - 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", - 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", - 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", - 784361051: "Fout:\n%s", + 1207696150: "Thay đổi", + 3126552510: "Thay địa chỉ", + 1583186953: "Thay đổi chủ đề và khởi động lại?", + 2697733395: "Thay đổi được lưu trên thẻ SD!", + 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", + 3442025874: "Kiểm tra thẻ SD", + 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", + 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", + 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", + 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", + 2470115694: "Kiểm tra thẻ SD..", + 3655273987: "Đang kiểm tra %d địa chỉ..", + 2407028014: "SeedQR nhỏ gọn", + 4041895036: "Tiếp tục?", + 4094072796: "Tạo mã QR", + 167798282: "Tạo mã QR từ văn bản?", + 2767642191: "Tạo:", + 3513215254: "Mã QR tùy chỉnh", + 124617190: "Chiều sâu cắt", + 597912140: "Phương pháp cắt", + 2504034831: "Số thập phân", + 2751113454: "Phản đối?", + 1016609898: "Xóa tài liệu?", + 1364509700: "Xóa ghi nhớ", + 4102535566: "Độ sâu mỗi lần vượt qua", + 2791699253: "Nguồn gốc: %s", + 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", + 3836852788: "Hoàn tất?", + 382368239: "Người cầm lái", + 3978947916: "Mã hoá", + 4090746898: "Gỡ lỗi bộ mã hóa", + 374684711: "Mã hóa Mnemonic", + 1244124409: "Mã QR được mã hóa", + 2968548114: "MNemon được mã hóa không được lưu trữ", + 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", + 350279787: "Mã hóa", + 2601598799: "Chế độ mã hóa", + 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", + 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", + 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", + 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", + 784361051: "Lỗi:\n%s", 1505332462: "Esc", - 3838465623: "Bestanden verkennen?", - 4170881190: "Exporteren naar SD-kaart..", - 1711312434: "Uitgebreide publieke sleutel", - 383371114: "Ontsleutelen is niet gelukt", - 3048830188: "PSBT laden is niet gelukt", - 4192663412: "Adres laden is niet gelukt", - 1996021743: "Sleutel laden is niet gelukt", - 1108715658: "Bericht laden is niet gelukt", - 1081425878: "Geheugensteun laden is niet gelukt", - 928667220: "Descriptor laden is niet gelukt", - 1620572516: "Wachtwoord laden is niet gelukt", - 2946146830: "Geheugensteun opslaan is niet gelukt", - 1303554751: "Tarief: ", - 104500973: "Voedingssnelheid", - 3313339187: "Bestandsnaam", - 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", - 3737729752: "Vingerafdruk: %s", - 2542772894: "Firmware overschrijdt de maximale grootte: %d", - 1406590538: "Fluit diameter", - 3086093110: "Vrij: ", - 1893243331: "Uit data-opslag", - 4120536442: "GRBL", - 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", - 602716148: "Ga", - 3580020863: "Hex publieke sleutel", - 2691246967: "Hexadecimaal", - 2736309107: "ID bestaat al\n", - 1706005805: "Incomplete portemonnee descriptor", - 631342955: "Invoer (%d): ", - 2585599782: "Ongeldig adres", - 2874529150: "Ongeldige bootloader", - 4093416954: "Ongeldige geheugensteun lengte", - 1422874211: "Ongeldige publieke sleutel", - 2443867979: "Ongeldige portemonnee:\n%s", - 4122897393: "Omkeren", - 3000888649: "Sleutel", - 2686333978: "Sleutel: ", - 4123798664: "Krux\n\n\nVersie\n%s", - 3835918229: "Krux printer test QR", - 766317539: "Taal", - 972436696: "Lijn vertraging", - 3596093890: "Lijn: ", - 2820726296: "Geheugensteun laden", - 879727077: "Laden vanaf SD-kaart?", - 669106195: "Laden?", - 3330705289: "Laden?", - 2596531078: "Camera laden...", - 596389387: "Wisselgeldadres %d laden...", - 336702608: "Laadprinter..", - 2538883522: "Ontvangstadres %d laden...", - 3159494909: "Laden...", - 1177338798: "Taal", - 2817059741: "Opslaglocatie", - 63976957: "Log niveau", - 86530918: "Debug logs", - 2917810189: "Maximale lengte overschreden (%s)", - 2030045667: "Bericht", - 3928301843: "Handtekening bestand mist", - 1948316555: "Geheugensteun", - 2123991188: "Geheugensteun ID", - 3911073154: "Geheugensteun opslag ID", - 570639842: "Geheugensteun is niet ontsleuteld", - 1746030071: "Geheugensteun is niet versleuteld", - 1458925155: "Aangepast: ", - 1845376098: "Multisig", - 2939797024: "Netwerk", - 73574491: "Geheugensteun aanmaken", - 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", - 4063104189: "Nee", - 3927838899: "Geen BIP-39 wachtwoord", - 4092516657: "Niet genoeg gedobbeld!", - 1577637745: "Octaal", - 3312581301: "PBKDF2 iter.", + 3838465623: "Khám phá các tập tin?", + 4170881190: "Xuất vào thẻ SD ..", + 1711312434: "Khóa công cộng", + 383371114: "Không giải mã được", + 3048830188: "Tải PSBT thất bại", + 4192663412: "Tải địa chỉ thất bại", + 1996021743: "Không tải khóa", + 1108715658: "Không tải được tin nhắn", + 1081425878: "Tải mã mnemonic thất bại", + 928667220: "Không thể tải bộ mô tả đầu ra", + 1620572516: "Không tải được cụm mật khẩu", + 2946146830: "Không lưu trữ MNemonic", + 1303554751: "Phí: ", + 104500973: "Tỷ lệ thức ăn", + 3313339187: "Tên tệp", + 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", + 3737729752: "Dấu vân tay: %s", + 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", + 1406590538: "Đường kính ống sáo", + 3086093110: "Khả dụng: ", + 1893243331: "Từ lưu trữ", + 4120536442: "GRBL", + 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", + 602716148: "Đến", + 3580020863: "Khóa công khai Hex", + 2691246967: "Thập lục phân", + 2736309107: "Id đã tồn tại\n", + 1706005805: "Bộ mô tả đầu ra chưa hoàn chỉnh", + 631342955: "Đầu vào (%d): ", + 2585599782: "Địa chỉ không hợp lệ", + 2874529150: "Bộ tải khởi động không hợp lệ", + 4093416954: "Độ dài mã mnemonic không hợp lệ", + 1422874211: "Khóa công khai không hợp lệ", + 2443867979: "Ví không hợp lệ:\n%s", + 4122897393: "Đảo ngược", + 3000888649: "Chìa khóa", + 2686333978: "Chìa khóa:", + 4123798664: "Krux\n\n\nPhiên Bản\n%s", + 3835918229: "QR kiểm tra máy in Krux", + 766317539: "Ngôn ngữ", + 972436696: "Độ trễ Dòng", + 3596093890: "Đường kẻ: ", + 2820726296: "Tải mã mnemonic", + 879727077: "Tải từ thẻ SD?", + 669106195: "Tải một?", + 3330705289: "Tải?", + 2596531078: "Đang tải máy ảnh..", + 596389387: "Đang tải thay đổi địa chỉ %d..", + 336702608: "Tải máy in ..", + 2538883522: "Đang tải địa chỉ nhận %d..", + 3159494909: "Đang tải..", + 1177338798: "Ngôn ngữ", + 2817059741: "Vị trí cửa hàng", + 63976957: "Log Level", + 86530918: "Khai thác gỗ", + 2917810189: "Chiều dài tối đa vượt quá (%s)", + 2030045667: "Tin nhắn", + 3928301843: "Thiếu tập tin chữ ký", + 1948316555: "Mã mnemonic", + 2123991188: "ID ghi nhớ", + 3911073154: "ID lưu trữ ghi nhớ", + 570639842: "Ghi nhớ không được giải mã", + 1746030071: "Ghi nhớ không được mã hóa", + 1458925155: "Đã sửa đổi:", + 1845376098: "Đa chữ kí", + 2939797024: "Mạng lưới", + 73574491: "Mnemonic mới", + 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", + 4063104189: "Không", + 3927838899: "Không có cụm mật khẩu BIP39", + 4092516657: "Không đủ cuộn!", + 1577637745: "Bát phân", + 3312581301: "Lặp lại PBKDF2", 721090621: "PSBT", - 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", - 2987800462: "Papier breedte", - 3050763890: "Deel\n%d / %d", - 3559456868: "Deel grootte", - 4249903283: "Wachtwoord", - 3712257341: "Wachtwoord: ", - 140802882: "Opslag", - 1703779997: "Platte tekst QR", - 3561756278: "Laadt een portemonnee descriptor in", - 784609464: "Duik tarief", - 3037062877: "Test QR afdrukken", - 4278257699: "Afdrukken naar QR?\n\n%s\n\n", - 516488026: "Afdrukken?\n\n%s\n\n", - 1123106929: "Printer", - 3903571079: "Printer driver niet ingesteld!", - 2609799302: "Afdruk\n%d / %d", - 844861889: "Afdrukken...", - 2580599003: "Doorgaan?", - 556126964: "Verwerken...", - 1848310591: "QR code", - 710709610: "RX pin", - 2697857197: "Ontvangen", - 1746677167: "Ontvangstadres", - 364354944: "Regio: ", - 1662254634: "Controleer gescande gegevens en bewerk indien nodig", - 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", - 856795528: "Gedobbeld:\n\n%s", - 255086803: "Gedobbeld: %d\n", - 3976793317: "SD kaart", - 2827687530: "SD kaart niet gedetecteerd", - 2736513298: "SD kaart niet gedetecteerd.", - 3593785196: "Gedobbelde SHA256:\n\n%s", - 1143278725: "Momentopname van SHA256:\n\n%s", + 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", + 2987800462: "Chiều rộng giấy", + 3050763890: "Phần\n%d / %d", + 3559456868: "Kích thước một phần", + 4249903283: "Cụm mật khẩu", + 3712257341: "Cụm cụm:", + 140802882: "Vị trí lưu", + 1703779997: "Văn bản rõ QR", + 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", + 784609464: "Tỷ lệ sụt giảm", + 3037062877: "In kiểm tra QR", + 4278257699: "In ra mã QR?\n\n%s\n\n", + 516488026: "In?\n\n%s\n\n", + 1123106929: "Máy in", + 3903571079: "Trình điều khiển máy in không đặt!", + 2609799302: "Đang in\n%d / %d", + 844861889: "In ấn ...", + 2580599003: "Thực hiện?", + 556126964: "Xử lý ...", + 1848310591: "Mã QR", + 710709610: "RX Ghim", + 2697857197: "Nhận được", + 1746677167: "Nhận địa chỉ", + 364354944: "Vùng: ", + 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", + 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", + 856795528: "Súc sắc cuộn:\n\n%s", + 255086803: "Súc sắc cuộn: %d\n", + 3976793317: "Thẻ SD", + 2827687530: "Thẻ SD không được phát hiện", + 2736513298: "Thẻ SD không được phát hiện.", + 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", + 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Opslaan op SD-kaart?", - 810036588: "Opgeslagen op SD-kaart:\n%s", - 763824768: "Schaal", - 4117455079: "Adres scannen", - 3219991109: "BIP-39 wachtwoord scannen", - 2537207336: "QR code sleutel scannen", - 4006316572: "Woorden 1 t/m 12 opnieuw scannen", - 2736506158: "Woorden 13 t/m 24 scannen", - 266935239: "SeedQR", - 1698829144: "Zelf overschrijving of wisselgeld (%d): ", - 473154195: "Instellingen", - 1825881236: "Afsluiten", - 2120776272: "Bezig met afsluiten...", - 1061961408: "Ondertekenen", - 4282338366: "Ondertekenen?", - 746161122: "Handtekening", - 1988416729: "Bericht ondertekend", - 3672006076: "PSBT ondertekend", - 2281377987: "Enkele sleutel", - 4221794628: "Grootte: ", - 2344747135: "Sommige controles kunnen niet worden uitgevoerd.", - 2309020186: "Uitgaven (%d): ", + 3531742595: "Lưu vào thẻ SD?", + 810036588: "Đã lưu vào thẻ SD:\n%s", + 763824768: "Cái cân", + 4117455079: "Quét địa chỉ", + 3219991109: "Quét BIP39 Cụm cụm", + 2537207336: "Quét mã QR khóa", + 4006316572: "Quét lại từ 1-12", + 2736506158: "Quét từ 13-24", + 3593497655: "Bảo vệ màn hình", + 266935239: "SEEDQR", + 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", + 473154195: "Cài đặt", + 1825881236: "Tắt", + 2120776272: "Đang tắt..", + 1061961408: "Chữ kí", + 4282338366: "Kí?", + 746161122: "Chữ ký", + 1988416729: "Tin nhắn đã ký", + 3672006076: "Đã ký PSBT", + 2281377987: "Khóa đơn", + 4221794628: "Dung lượng: ", + 2344747135: "Một số kiểm tra không thể được thực hiện.", + 2309020186: "Chi tiêu (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Opslaan op apparaat", - 720041451: "Opslaan op SD kaart", - 3514476519: "Verander modus", - 1898550184: "TIK of ENTER voor opname", - 4228215415: "TX pin", - 2612594937: "Tekst", - 1454688268: "Thema", - 1180180513: "Thermisch", + 3303592908: "Lưu trữ trên flash", + 720041451: "Lưu trữ trên thẻ SD", + 3514476519: "Vuốt để thay đổi chế độ", + 1898550184: "TOUCH hoặc ENTER để chụp", + 4228215415: "TX Ghim", + 2612594937: "Chữ", + 1454688268: "Chủ đề", + 1180180513: "Nhiệt", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Hulpmiddelen", - 3684696112: "Aanraak gevoeligheid", - 2978718564: "Aanraakscherm", - 2732611775: "Meer proberen?", - 1487826746: "Voer BIP-39 wachtwoord in", - 2061556020: "Voer sleutel in", - 2089395053: "Eenheid", - 2845607430: "Bootloader updaten...\n\n%d%%", - 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", - 2736001501: "Firmware upgraden...\n\n%d%%", - 2674953168: "Gebruik een donker achergrond.", - 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", - 236075140: "Gebruikt: ", - 4003084591: "Waarde %s is buiten bereik: [%s, %s]", - 4191058607: "Via camera", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Via handmatige invoer", - 2504354847: "Wacht op opname", - 2297028319: "Descriptor", - 4232654916: "Portemonnee descriptor", - 2587172867: "Portemonnee descriptor geladen!", - 2499782468: "Portemonnee descriptor niet gevonden.", - 2671738224: "Waarschuwing:", - 797660533: "Woord %d", - 3742424146: "Woord nummers", - 2965123464: "Woorden", - 1303016265: "Yes", - 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", - 2569054451: "Veranderingen worden opgeslagen op SD kaart.", + 1732872974: "Tiny Seed (bit)", + 725348723: "Công cụ", + 3684696112: "Ngưỡng cảm ứng", + 2978718564: "Màn hình cảm ứng", + 2732611775: "Thử thêm nữa?", + 1487826746: "Nhập cụm BIP39", + 2061556020: "Nhập khóa", + 2089395053: "Đơn vị", + 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", + 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", + 2736001501: "Nâng cấp firmware..\n\n%d%%", + 2674953168: "Sử dụng bề mặt nền đen.", + 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", + 236075140: "Đã sử dụng: ", + 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", + 4191058607: "Qua máy ảnh", + 1254681955: "Qua D20", + 525309547: "Qua D6", + 590330112: "Thông qua đầu vào thủ công", + 2504354847: "Chờ bắt", + 3992434312: "Thời gian chờ đợi", + 2297028319: "Trình mô tả ví", + 4232654916: "Ví đầu ra mô tả", + 2587172867: "Đã tải bộ mô tả đầu ra của ví!", + 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", + 2671738224: "Cảnh báo:", + 797660533: "Kí tự %d", + 3742424146: "Từ số", + 2965123464: "Từ ngữ", + 1303016265: "Đúng", + 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", + 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", }, } From 144cbc758a060a5a0931070a599df62c1a9fbe05 Mon Sep 17 00:00:00 2001 From: Odudex Date: Mon, 2 Oct 2023 14:00:14 -0300 Subject: [PATCH 039/114] pylint on touch changes --- src/krux/touch.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/krux/touch.py b/src/krux/touch.py index c31a81281..e711cb581 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -78,6 +78,7 @@ def add_x_delimiter(self, region): self.x_regions.append(region) def valid_position(self, data): + """Checks if touch position is within buttons area""" if self.x_regions and data[0] < self.x_regions[0]: return False if self.x_regions and data[0] > self.x_regions[-1]: From 3d6a3bb26bbe0d71277f49973f1ccf705a3f0a71 Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 4 Oct 2023 16:16:46 -0300 Subject: [PATCH 040/114] add options to restore settings and wipe device settings refactor --- firmware/MaixPy | 2 +- src/krux/krux_settings.py | 60 +++++++++++++++++++------- src/krux/pages/__init__.py | 4 +- src/krux/pages/addresses.py | 2 +- src/krux/pages/home.py | 6 +-- src/krux/pages/print_page.py | 2 +- src/krux/pages/settings_page.py | 74 +++++++++++++++++++++++++++++++-- src/krux/printers/__init__.py | 2 +- src/krux/printers/cnc.py | 28 ++++++------- src/krux/printers/thermal.py | 18 +++++--- src/krux/rotary.py | 2 +- src/krux/themes.py | 31 ++++++++++++-- src/krux/touch.py | 2 +- 13 files changed, 180 insertions(+), 53 deletions(-) diff --git a/firmware/MaixPy b/firmware/MaixPy index e83a88f4a..349ba9394 160000 --- a/firmware/MaixPy +++ b/firmware/MaixPy @@ -1 +1 @@ -Subproject commit e83a88f4a6ecd2917a3c9dc5d29e2a6965b8aefe +Subproject commit 349ba9394d1578ce316036c53866c4abf1d9ddec diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index a71d42534..e4f6923ee 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -272,6 +272,38 @@ def label(self, attr): }[attr] +class HardwareSettings(SettingsNamespace): + """Hardware Related Settings""" + + namespace = "settings.hardware" + + def __init__(self): + self.printer = PrinterSettings() + if ( + board.config["type"].startswith("amigo") + or board.config["type"] == "yahboom" + ): + self.touch = TouchSettings() + if board.config["type"] == "dock": + self.encoder = EncoderSettings() + + def label(self, attr): + """Returns a label for UI when given a setting name or namespace""" + + hardware_menu = { + "printer": t("Printer"), + } + if ( + board.config["type"].startswith("amigo") + or board.config["type"] == "yahboom" + ): + hardware_menu["touchscreen"] = t("Touchscreen") + if board.config["type"] == "dock": + hardware_menu["encoder"] = t("Encoder") + + return hardware_menu[attr] + + class PersistSettings(SettingsNamespace): """Persistent settings""" @@ -315,10 +347,19 @@ class ThemeSettings(SettingsNamespace): DARK_THEME_NAME = "Dark" LIGHT_THEME_NAME = "Light" ORANGE_THEME_NAME = "Orange" + GREEN_THEME = 4 + PINK_THEME = 5 + DARK_THEME_NAME = "Dark" + LIGHT_THEME_NAME = "Light" + ORANGE_THEME_NAME = "Orange" + GREEN_THEME_NAME = "CypherPunk" + PINK_THEME_NAME = "CypherPink" THEME_NAMES = { DARK_THEME: DARK_THEME_NAME, LIGHT_THEME: LIGHT_THEME_NAME, ORANGE_THEME: ORANGE_THEME_NAME, + GREEN_THEME: GREEN_THEME_NAME, + PINK_THEME: PINK_THEME_NAME, } namespace = "settings.appearance" theme = CategorySetting("theme", DARK_THEME_NAME, list(THEME_NAMES.values())) @@ -337,36 +378,23 @@ class Settings(SettingsNamespace): def __init__(self): self.bitcoin = BitcoinSettings() + self.hardware = HardwareSettings() self.i18n = I18nSettings() self.logging = LoggingSettings() self.encryption = EncryptionSettings() - self.printer = PrinterSettings() self.persist = PersistSettings() self.appearance = ThemeSettings() - if ( - board.config["type"].startswith("amigo") - or board.config["type"] == "yahboom" - ): - self.touch = TouchSettings() - if board.config["type"] == "dock": - self.encoder = EncoderSettings() def label(self, attr): """Returns a label for UI when given a setting name or namespace""" main_menu = { "bitcoin": t("Bitcoin"), + "hardware": t("Hardware"), "i18n": t("Language"), "logging": t("Logging"), "encryption": t("Encryption"), "persist": t("Persist"), - "printer": t("Printer"), "appearance": t("Theme"), } - if ( - board.config["type"].startswith("amigo") - or board.config["type"] == "yahboom" - ): - main_menu["touchscreen"] = t("Touchscreen") - if board.config["type"] == "dock": - main_menu["encoder"] = t("Encoder") + return main_menu[attr] diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index d47042c67..f2644269d 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -367,12 +367,12 @@ def print_qr_prompt(self): """Prompts the user to print a QR code in the specified format if a printer is connected """ - if Settings().printer.driver == "none": + if Settings().hardware.printer.driver == "none": return False self.ctx.display.clear() if self.prompt( - t("Print to QR?\n\n%s\n\n") % Settings().printer.driver, + t("Print to QR?\n\n%s\n\n") % Settings().hardware.printer.driver, self.ctx.display.height() // 2, ): return True diff --git a/src/krux/pages/addresses.py b/src/krux/pages/addresses.py index af3f0ba95..343749a03 100644 --- a/src/krux/pages/addresses.py +++ b/src/krux/pages/addresses.py @@ -58,7 +58,7 @@ def addresses_menu(self): submenu = Menu( self.ctx, [ - ((t("Scan Address"), self.pre_scan_address)), + (t("Scan Address"), self.pre_scan_address), (t("Receive Addresses"), self.list_address_type), (t("Change Addresses"), lambda: self.list_address_type(1)), (t("Back"), lambda: MENU_EXIT), diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 0c949fa23..89c48908d 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -94,10 +94,10 @@ def display_mnemonic_words(self): self.ctx.input.wait_for_button() # Avoid printing text on a cnc - if Settings().printer.driver == THERMAL_ADAFRUIT_TXT: + if Settings().hardware.printer.driver == THERMAL_ADAFRUIT_TXT: self.ctx.display.clear() if self.prompt( - t("Print?\n\n%s\n\n") % Settings().printer.driver, + t("Print?\n\n%s\n\n") % Settings().hardware.printer.driver, self.ctx.display.height() // 2, ): from .print_page import PrintPage @@ -158,7 +158,7 @@ def tiny_seed(self): tiny_seed.export() # Allow to print on thermal printer only - if Settings().printer.driver == THERMAL_ADAFRUIT_TXT: + if Settings().hardware.printer.driver == THERMAL_ADAFRUIT_TXT: if self.print_qr_prompt(): tiny_seed.print_tiny_seed() return MENU_CONTINUE diff --git a/src/krux/pages/print_page.py b/src/krux/pages/print_page.py index 7c4184a65..f83c66dda 100644 --- a/src/krux/pages/print_page.py +++ b/src/krux/pages/print_page.py @@ -40,7 +40,7 @@ def __init__(self, ctx): def _send_qr_to_printer(self, qr_code, i=0, count=1): self.ctx.display.clear() - if Settings().printer.driver == "cnc/file": + if Settings().hardware.printer.driver == "cnc/file": self.ctx.display.draw_centered_text(t("Exporting to SD card..")) else: self.ctx.display.draw_centered_text(t("Printing\n%d / %d") % (i + 1, count)) diff --git a/src/krux/pages/settings_page.py b/src/krux/pages/settings_page.py index c66c77bf5..457166601 100644 --- a/src/krux/pages/settings_page.py +++ b/src/krux/pages/settings_page.py @@ -25,9 +25,10 @@ from ..settings import ( CategorySetting, NumberSetting, + Store, SD_PATH, FLASH_PATH, - Store, + SETTINGS_FILENAME, ) from ..krux_settings import ( Settings, @@ -64,6 +65,11 @@ BitcoinSettings.TEST_TXT: GREEN, } +# SPIFFS erase parameters +FLASH_SIZE = 2**24 +SPIFFS_ADDR = 0xD00000 +BLOCK_SIZE = 0x10000 + class SettingsPage(Page): """Class to manage settings interface""" @@ -161,6 +167,65 @@ def _touch_to_physical(self, index): return BUTTON_ENTER return BUTTON_PAGE + def restore_settings(self): + """Restore default settings by deleting the settings files""" + self.ctx.display.clear() + if self.prompt( + t("Restore factory settings and reboot?"), self.ctx.display.height() // 2 + ): + self.ctx.display.clear() + try: + # Delete settings from SD + with SDHandler() as sd: + sd.delete(SETTINGS_FILENAME) + except: + pass + try: + # Delete settings from flash + os.remove("/%s/%s" % (FLASH_PATH, SETTINGS_FILENAME)) + except: + pass + self.ctx.power_manager.reboot() + + def erase_spiffs(self): + """Erase all SPIFFS, removing all saved configs and mnemonics""" + + import flash + + empty_buf = b"\xff" * BLOCK_SIZE + for address in range(SPIFFS_ADDR, FLASH_SIZE, BLOCK_SIZE): + if flash.read(address, BLOCK_SIZE) == empty_buf: + continue + flash.erase(address, BLOCK_SIZE) + + def wipe_device(self): + """Fullyu formatts SPIFFS memory""" + self.ctx.display.clear() + if self.prompt( + t( + "Permanently remove all stored encrypted mnemonics and settings from flash?" + ), + self.ctx.display.height() // 2, + ): + self.ctx.display.clear() + self.ctx.display.draw_centered_text(t("Wiping Device..")) + self.erase_spiffs() + # Reboot so default settings take place and SPIFFS is formatted. + self.ctx.power_manager.reboot() + + def restore_menu(self): + """Option to restore settings and wipe device""" + submenu = Menu( + self.ctx, + [ + (t("Restore Default Settings"), self.restore_settings), + (t("Wipe Device"), self.wipe_device), + (t("Back"), lambda: MENU_EXIT), + ], + ) + submenu.run_loop() + return MENU_CONTINUE + def _settings_exit_check(self): """Handler for the 'Back' on settings screen""" @@ -217,6 +282,7 @@ def handler(): # Case for "Back" on the main Settings if settings_namespace.namespace == Settings.namespace: + items.append((t("Factory Settings"), self.restore_menu)) items.append((t("Back"), self._settings_exit_check)) else: items.append((t("Back"), lambda: MENU_EXIT)) @@ -252,14 +318,16 @@ def _touch_threshold_exit_check(self): # Update touch detection threshold if self.ctx.input.touch is not None: - self.ctx.input.touch.touch_driver.threshold(Settings().touch.threshold) + self.ctx.input.touch.touch_driver.threshold( + Settings().hardware.touch.threshold + ) def _encoder_threshold_exit_check(self): """Handler for the 'Back' on encoder settings screen""" from ..rotary import encoder # Update rotary encoder debounce time - encoder.debounce = Settings().encoder.debounce + encoder.debounce = Settings().hardware.encoder.debounce def category_setting(self, settings_namespace, setting): """Handler for viewing and editing a CategorySetting""" diff --git a/src/krux/printers/__init__.py b/src/krux/printers/__init__.py index 4d61c9812..5270fbe09 100644 --- a/src/krux/printers/__init__.py +++ b/src/krux/printers/__init__.py @@ -58,7 +58,7 @@ def print_string(self, text): def create_printer(): """Instantiates a new printer dynamically based on the default in Settings""" - module, cls = PrinterSettings.PRINTERS[Settings().printer.driver] + module, cls = PrinterSettings.PRINTERS[Settings().hardware.printer.driver] if not cls: return None return getattr( diff --git a/src/krux/printers/cnc.py b/src/krux/printers/cnc.py index cb460d31a..a584b7546 100644 --- a/src/krux/printers/cnc.py +++ b/src/krux/printers/cnc.py @@ -38,15 +38,15 @@ class GCodeGenerator(Printer): """ def __init__(self): - self.unit = Settings().printer.cnc.unit - self.flute_diameter = Settings().printer.cnc.flute_diameter - self.plunge_rate = Settings().printer.cnc.plunge_rate - self.feed_rate = Settings().printer.cnc.feed_rate - self.cut_depth = Settings().printer.cnc.cut_depth - self.pass_depth = Settings().printer.cnc.depth_per_pass - self.part_size = Settings().printer.cnc.part_size - self.border_padding = Settings().printer.cnc.border_padding - self.invert = Settings().printer.cnc.invert + self.unit = Settings().hardware.printer.cnc.unit + self.flute_diameter = Settings().hardware.printer.cnc.flute_diameter + self.plunge_rate = Settings().hardware.printer.cnc.plunge_rate + self.feed_rate = Settings().hardware.printer.cnc.feed_rate + self.cut_depth = Settings().hardware.printer.cnc.cut_depth + self.pass_depth = Settings().hardware.printer.cnc.depth_per_pass + self.part_size = Settings().hardware.printer.cnc.part_size + self.border_padding = Settings().hardware.printer.cnc.border_padding + self.invert = Settings().hardware.printer.cnc.invert if self.plunge_rate > self.feed_rate / 2: raise ValueError("plunge rate must be less than half of feed rate") @@ -103,7 +103,7 @@ def print_qr_code(self, qr_code): def cut_cell(self, x, y, cell_size, plunge_depth): """Hollows out the specified cell using a cutting method defined in settings""" - if Settings().printer.cnc.cut_method == "spiral": + if Settings().hardware.printer.cnc.cut_method == "spiral": self.spiral_cut_cell(x, y, cell_size, plunge_depth) else: self.row_cut_cell(x, y, cell_size, plunge_depth) @@ -281,10 +281,10 @@ def clear(self): # def __init__(self): # super().__init__() -# fm.register(Settings().printer.cnc.grbl.tx_pin, fm.fpioa.UART2_TX, force=False) -# fm.register(Settings().printer.cnc.grbl.rx_pin, fm.fpioa.UART2_RX, force=False) -# self.uart_conn = UART(UART.UART2, Settings().printer.cnc.grbl.baudrate) -# self.byte_time = 11.0 / float(Settings().printer.cnc.grbl.baudrate) +# fm.register(Settings().hardware.printer.cnc.grbl.tx_pin, fm.fpioa.UART2_TX, force=False) +# fm.register(Settings().hardware.printer.cnc.grbl.rx_pin, fm.fpioa.UART2_RX, force=False) +# self.uart_conn = UART(UART.UART2, Settings().hardware.printer.cnc.grbl.baudrate) +# self.byte_time = 11.0 / float(Settings().hardware.printer.cnc.grbl.baudrate) # res = self.uart_conn.readline() # if res is None or not res.decode().lower().startswith("grbl"): # raise ValueError("not connected") diff --git a/src/krux/printers/thermal.py b/src/krux/printers/thermal.py index f43b5cc2e..3b6b0929e 100644 --- a/src/krux/printers/thermal.py +++ b/src/krux/printers/thermal.py @@ -56,17 +56,23 @@ class AdafruitPrinter(Printer): def __init__(self): fm.register( - Settings().printer.thermal.adafruit.tx_pin, fm.fpioa.UART2_TX, force=False + Settings().hardware.printer.thermal.adafruit.tx_pin, + fm.fpioa.UART2_TX, + force=False, ) fm.register( - Settings().printer.thermal.adafruit.rx_pin, fm.fpioa.UART2_RX, force=False + Settings().hardware.printer.thermal.adafruit.rx_pin, + fm.fpioa.UART2_RX, + force=False, ) - self.uart_conn = UART(UART.UART2, Settings().printer.thermal.adafruit.baudrate) + self.uart_conn = UART( + UART.UART2, Settings().hardware.printer.thermal.adafruit.baudrate + ) self.character_height = 24 self.byte_time = 1 # miliseconds - self.dot_print_time = Settings().printer.thermal.adafruit.line_delay + self.dot_print_time = Settings().hardware.printer.thermal.adafruit.line_delay self.dot_feed_time = 2 # miliseconds if not self.has_paper(): @@ -129,8 +135,8 @@ def print_qr_code(self, qr_code): while qr_code[size] != "\n": size += 1 - scale = Settings().printer.thermal.adafruit.paper_width // size - scale *= Settings().printer.thermal.adafruit.scale + scale = Settings().hardware.printer.thermal.adafruit.paper_width // size + scale *= Settings().hardware.printer.thermal.adafruit.scale scale //= 200 # 100*2 because printer will scale 2X later to save data # Being at full size sometimes makes prints more faded (can't apply too much heat?) diff --git a/src/krux/rotary.py b/src/krux/rotary.py index a83d75276..5bf8b9666 100644 --- a/src/krux/rotary.py +++ b/src/krux/rotary.py @@ -55,7 +55,7 @@ def __init__(self): self.value = 0 self.time_frame = 0 - self.debounce = Settings().encoder.debounce + self.debounce = Settings().hardware.encoder.debounce def process(self, new_state): """Sets new encoder state after position is changed""" diff --git a/src/krux/themes.py b/src/krux/themes.py index b098946d6..2c3e6d6e4 100644 --- a/src/krux/themes.py +++ b/src/krux/themes.py @@ -32,9 +32,13 @@ LIGHTBLACK = 0x0842 DARKGREY = 0xEF7B LIGHTGREY = 0x18C6 +LIGHT_GREEN = 0xEC67 GREEN = 0xE007 DARKGREEN = 0x8005 RED = 0x00F8 +LIGHT_PINK = 0x3FFC +PINK = 0x1FF8 +PURPLE = 0x0F78 ORANGE = 0x20FD DARKORANGE = 0x40C3 YELLOW = 0xE0FF @@ -44,14 +48,11 @@ MAGENTA = 0x1FF8 # define NAVY 0x0F00 -# define DARKGREEN 0xE003 # define DARKCYAN 0xEF03 # define MAROON 0x0078 # define PURPLE 0x0F78 # define OLIVE 0xE07B -# define RED 0x00F8 # define GREENYELLOW 0xE5AF -# define PINK 0x1FF8 THEMES = { ThemeSettings.DARK_THEME_NAME: { @@ -90,6 +91,30 @@ "error": RED, "highlight": ORANGE, }, + ThemeSettings.PINK_THEME_NAME: { + "background": BLACK, + "foreground": LIGHT_PINK, + "frame": PURPLE, + "disabled": DARKGREY, + "go": PINK, + "esc_no": RED, + "del": YELLOW, + "toggle": CYAN, + "error": RED, + "highlight": PINK, + }, + ThemeSettings.GREEN_THEME_NAME: { + "background": BLACK, + "foreground": LIGHT_GREEN, + "frame": DARKGREEN, + "disabled": DARKGREY, + "go": GREEN, + "esc_no": RED, + "del": YELLOW, + "toggle": CYAN, + "error": RED, + "highlight": GREEN, + }, } diff --git a/src/krux/touch.py b/src/krux/touch.py index e711cb581..a594e2177 100644 --- a/src/krux/touch.py +++ b/src/krux/touch.py @@ -58,7 +58,7 @@ def __init__(self, width, height, irq_pin=None): self.width, self.height = width, height self.touch_driver = touch_control self.touch_driver.activate_irq(irq_pin) - self.touch_driver.threshold(Settings().touch.threshold) + self.touch_driver.threshold(Settings().hardware.touch.threshold) def clear_regions(self): """Remove previously stored buttons map""" From feca49f6fcbc4acf63689f5332599f8f7d20cd84 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 5 Oct 2023 10:34:28 -0300 Subject: [PATCH 041/114] creating tests for screensaver --- src/krux/context.py | 6 ++--- src/krux/display.py | 2 +- tests/test_context.py | 53 +++++++++++++++++++++++++++++++++++++++++- tests/test_display.py | 19 +++++++++++++++ tests/test_input.py | 28 ++++++++++++++++++++++ tests/test_settings.py | 50 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 153 insertions(+), 5 deletions(-) diff --git a/src/krux/context.py b/src/krux/context.py index df431d8e7..48bbcf413 100644 --- a/src/krux/context.py +++ b/src/krux/context.py @@ -42,8 +42,8 @@ def __init__(self, logo=None): if logo is None: logo = [] - self.logo = logo - for _ in range((self.display.total_lines - len(logo))//2): + self.logo = logo + for _ in range((self.display.total_lines - len(logo)) // 2): self.logo.insert(0, "") self.logo.append("") self.logo.append("") @@ -84,7 +84,7 @@ def screensaver(self): # show animation on the screeen if anim_frame < len(self.logo): - self.display.draw_hcentered_text_with_bg( + self.display.draw_line_hcentered_with_fullw_bg( self.logo[anim_frame], anim_frame, fg_color, bg_color ) diff --git a/src/krux/display.py b/src/krux/display.py index 06c6d5c9e..6d611a3c7 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -308,7 +308,7 @@ def _obtain_hcentered_offset(self, line_str): """Return the offset_x to the horizontally-centered line_str""" return max(0, (self.width() - self.font_width * len(line_str)) // 2) - def draw_hcentered_text_with_bg( + def draw_line_hcentered_with_fullw_bg( self, line_str, qtd_offset_y, diff --git a/tests/test_context.py b/tests/test_context.py index b58ad19ea..469c07605 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -4,9 +4,9 @@ def mock_modules(mocker): mocker.patch("krux.context.logger", new=mocker.MagicMock()) mocker.patch("krux.context.Display", new=mocker.MagicMock()) - mocker.patch("krux.context.Input", new=mocker.MagicMock()) mocker.patch("krux.context.Camera", new=mocker.MagicMock()) mocker.patch("krux.context.Light", new=mocker.MagicMock()) + mocker.patch("krux.context.Input", new=mocker.MagicMock()) def test_init(mocker, m5stickv): @@ -51,3 +51,54 @@ def test_clear_clears_printer(mocker, m5stickv): assert c.wallet is None c.printer.clear.assert_called() + +def test_screensaver(mocker, m5stickv): + """Test whether the screensaver is animating and changing color over time""" + mock_modules(mocker) + from krux.context import Context, SCREENSAVER_ANIMATION_TIME + from krux.themes import theme + from krux.input import BUTTON_ENTER + import time + + logo = """ + ██ + ██ + ██ + ██████ + ██ + ██ ██ + ██ ██ + ████ + ██ ██ + ██ ██ + ██ ██ + """[ + 1:-1 + ].split( + "\n" + ) + c = Context(logo) + + # a sequence of events to simulate users waiting and after some time press BUTTON_ENTER + btn_seq = [] + time_seq = [] + tmp = SCREENSAVER_ANIMATION_TIME +1 + for _ in range(28): + time_seq.append(tmp) + time_seq.append(tmp) + tmp += SCREENSAVER_ANIMATION_TIME +1 + btn_seq.append(None) + + time_seq.append(tmp) + time_seq.append(tmp) + btn_seq.append(BUTTON_ENTER) + + c.input.wait_for_press = mocker.MagicMock(side_effect=btn_seq) + time.ticks_ms = mocker.MagicMock(side_effect=time_seq) + + + c.screensaver() + + c.display.draw_line_hcentered_with_fullw_bg.assert_any_call(logo[10], 10, theme.fg_color, theme.bg_color) + c.display.draw_line_hcentered_with_fullw_bg.assert_any_call(logo[5], 5, theme.bg_color, theme.fg_color) + c.input.wait_for_press.assert_called() diff --git a/tests/test_display.py b/tests/test_display.py index eefb9c295..5d20e2e7e 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -402,6 +402,25 @@ def test_draw_hcentered_text(mocker, m5stickv): 23, 50, "Hello world", krux.display.lcd.WHITE, krux.display.lcd.BLACK ) +def test_draw_line_hcentered_with_fullw_bg(mocker, m5stickv): + mocker.patch("krux.display.lcd", new=mocker.MagicMock()) + import krux + from krux.display import Display + + d = Display() + mocker.patch.object(d, "width", new=lambda: 135) + mocker.spy(d, "draw_string") + + + d.draw_line_hcentered_with_fullw_bg( + "Hello world", 10, krux.display.lcd.WHITE, krux.display.lcd.BLACK + ) + + d.draw_string.assert_called_with( + 23, d.font_height * 10, "Hello world", krux.display.lcd.WHITE, krux.display.lcd.BLACK + ) + krux.display.lcd.fill_rectangle.assert_called() + def test_draw_centered_text(mocker, m5stickv): mocker.patch("krux.display.lcd", new=mocker.MagicMock()) diff --git a/tests/test_input.py b/tests/test_input.py index 4906b9b4a..37129fbe7 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -785,3 +785,31 @@ def release(): assert btn is None assert input.entropy > 0 krux.input.wdt.feed.assert_called() + +def test_wait_for_press_screensaver(mocker, m5stickv): + from krux.input import Input + from krux.krux_settings import Settings + import krux + + input = Input(screensaver_fallback=mocker.MagicMock()) + input = reset_input_states(mocker, input) + input.buttons_active = False + + # Make test faster + Settings().screensaver.time = 0.0001 + + time_seq = [] + tmp = 100 + for _ in range(10): + time_seq.append(tmp) + tmp += 100 + + time.ticks_ms = mocker.MagicMock(side_effect=time_seq) + + input.wait_for_press(True, enable_screensaver=True) + input.screensaver_fallback.assert_called() + + Settings().screensaver.time = 0 + input.wait_for_button(block=False) + input.screensaver_fallback.assert_called_once() + diff --git a/tests/test_settings.py b/tests/test_settings.py index 2e4f95772..def00f454 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -90,3 +90,53 @@ class TestClass: assert t.some_setting == 1 t.some_setting = 2 assert t.some_setting == 2 + +def test_all_labels(mocker, m5stickv): + from krux.krux_settings import ( + BitcoinSettings, + I18nSettings, + LoggingSettings, + EncryptionSettings, + PrinterSettings, + ThermalSettings, + AdafruitPrinterSettings, + CNCSettings, + GRBLSettings, + PersistSettings, + ThemeSettings, + ScreensaverSettings, + TouchSettings, + EncoderSettings, + ) + + bitcoin = BitcoinSettings() + i18n = I18nSettings() + logging = LoggingSettings() + encryption = EncryptionSettings() + printer = PrinterSettings() + thermal = ThermalSettings() + adafruit = AdafruitPrinterSettings() + cnc = CNCSettings() + gbrl = GRBLSettings() + persist = PersistSettings() + appearance = ThemeSettings() + screensaver = ScreensaverSettings() + touch = TouchSettings() + encoder = EncoderSettings() + + assert bitcoin.label("network") + assert i18n.label("locale") + assert logging.label("level") + assert encryption.label("version") + assert printer.label("thermal") + assert thermal.label("adafruit") + assert adafruit.label("tx_pin") + assert cnc.label("invert") + assert gbrl.label("tx_pin") + assert persist.label("location") + assert appearance.label("theme") + assert screensaver.label("time") + assert touch.label("threshold") + assert encoder.label("debounce") + + From f3f326066f4b39023e6dca2d07e5616ff7bf8f86 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 5 Oct 2023 10:52:47 -0300 Subject: [PATCH 042/114] fix some test in constant loop on test_input --- tests/test_input.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/test_input.py b/tests/test_input.py index 37129fbe7..557e13a90 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -16,7 +16,7 @@ def reset_input_states(mocker, input): mocker.patch.object(input, "page_prev_event", new=lambda: False) if input.touch: mocker.patch.object(input.touch.touch_driver, "current_point", new=lambda: None) - mocker.patch.object(input.touch.touch_driver, "event", new=lambda: False) + mocker.patch.object(input.touch, "event", new=lambda: False) return input @@ -345,7 +345,7 @@ def test_wait_for_button_blocks_until_touch_released(mocker, amigo_tft): input = Input() input = reset_input_states(mocker, input) - mocker.patch.object(input.touch.touch_driver, "event", new=lambda: True) + mocker.patch.object(input.touch, "event", new=lambda: True) mocker.patch.object(input, "touch_value", new=lambda: PRESSED) def release(): @@ -461,7 +461,7 @@ def test_touch_indexing(mocker, amigo_tft): input = reset_input_states(mocker, input) elapsed_time = 0 - mocker.patch.object(input.touch.touch_driver, "event", new=lambda: True) + mocker.patch.object(input.touch, "event", new=lambda: True) def time_control(point1, point2): nonlocal elapsed_time @@ -475,7 +475,7 @@ def time_control(point1, point2): input.touch.touch_driver, "current_point", new=lambda: point1 ) time.sleep(0.1) - # mocker.patch.object(input.touch.touch_driver, "event", new=lambda: False) + # mocker.patch.object(input.touch, "event", new=lambda: False) elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) # touch slightly sideways before release @@ -533,7 +533,7 @@ def time_control(point1, point2): elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) - mocker.patch.object(input.touch.touch_driver, "event", new=lambda: True) + mocker.patch.object(input.touch, "event", new=lambda: True) mocker.patch.object(input.touch.touch_driver, "irq_point", new=lambda: point1) mocker.patch.object( input.touch.touch_driver, "current_point", new=lambda: point1 From 689678b7da1c19c89259cccb0e533b163d4a8c55 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 5 Oct 2023 10:56:09 -0300 Subject: [PATCH 043/114] black and i18n --- src/krux/translations.py | 1962 +++++++++++++++++++------------------- tests/test_context.py | 24 +- tests/test_display.py | 8 +- tests/test_input.py | 6 +- tests/test_settings.py | 15 +- 5 files changed, 1019 insertions(+), 996 deletions(-) diff --git a/src/krux/translations.py b/src/krux/translations.py index 39c1ae73c..aa4d7af9e 100644 --- a/src/krux/translations.py +++ b/src/krux/translations.py @@ -21,510 +21,267 @@ # THE SOFTWARE. # pylint: disable=C0301 translation_table = { - "ru-RU": { - 1185266064: "%d из %d мультиподпись", - 2004520398: "%d. Сдача: \n\n%s\n\n", - 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", - 3264377309: "%d. Расход: \n\n%s\n\n", - 2399232215: "%s\n\nвалидный адрес сдачи!", - 3921290840: "%s\n\nвалидный адрес получения!", - 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", - 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", - 3348584292: "(Эксперементальный)", - 2739590230: "12 слов", - 1310058127: "24 слова", + "de-DE": { + 1185266064: "%d von %d Multisig", + 2004520398: "%d. Change: \n\n%s\n\n", + 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", + 3264377309: "%d. Ausgaben: \n\n%s\n\n", + 2399232215: "%s\n\nist eine gültige Change Adresse!", + 3921290840: "%s\n\nist eine gültige Empfangsadresse!", + 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", + 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", + 3348584292: "(Experimental)", + 2739590230: "12 Wörter", + 1310058127: "24 Wörter", 2743272264: "ABC", - 1949634023: "О Программе", + 1949634023: "Über", 1517128857: "Adafruit", - 3270727197: "Адрес", - 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", - 283202181: "Правильно совместите камеру и Мини Сид-фразу.", - 88746165: "Антиблик отключен", - 1521033296: "Антиблик включен", - 1056821534: "Вы уверены?", - 3247612282: "BIP39 Мнемоника", - 3455872521: "Назад", - 2541860807: "Резервное копирование загрузчика..\n\n%d%%", - 2256777600: "Плохая подпись", - 3937333362: "Скорость Передачи Данных", - 427617266: "Биткоин", - 928727036: "Заполнение границ", + 3270727197: "Adresse", + 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", + 283202181: "Richte Kamera und Tiny Seed korrekt aus.", + 88746165: "Blendschutz deaktiviert", + 1521033296: "Blendschutz aktiviert", + 1056821534: "Bist Du sicher?", + 3247612282: "BIP39 Mnemonic", + 3455872521: "Zurück", + 2541860807: "Bootloader wird gesichert..\n\n%d%%", + 2256777600: "Ungültige Signatur", + 3937333362: "Baudrate", + 427617266: "Bitcoin", + 928727036: "Randpolsterung", 213030954: "CNC", - 1207696150: "Сдача", - 3126552510: "Адрес Сдачи", - 1583186953: "Сменить тему и перезагрузить?", - 2697733395: "Изменения сохранены на SD карте!", - 388908871: "Изменения будут храниться до выключения.", - 3442025874: "Проверить SD Карту", - 3119547911: "Проверить, что адрес принадлежит этому кошельку?", - 2856261511: "Проверено %d адресов сдачи без совпадений.", - 2788541416: "Проверено %d адресов получения без совпадений.", - 2446472910: "Проверяем адрес сдачи %d на совпадение..", - 2470115694: "Проверка SD карты..", - 3655273987: "Проверяем адрес получения %d на совпадение..", - 2407028014: "Компактный SeedQR", - 4041895036: "Продолжить?", - 4094072796: "Создать QR Код", - 167798282: "Создать QR код из текста?", - 2767642191: "Создано", - 3513215254: "Пользовательский QR Код", - 124617190: "Глубина Резки", - 597912140: "Метод Резки", - 2504034831: "Десятичный", - 2751113454: "Расшифровать?", - 3510912550: "Удалить %s?", - 1016609898: "Удалить Файл?", - 1364509700: "Удалить Мнемонику", - 4102535566: "Глубина За Проход", - 2791699253: "Производный путь: %s", - 1230133196: "Флэш память устройства не обнаружена.", - 3836852788: "Готово?", - 382368239: "Драйвер", - 3978947916: "Кодер", - 4090746898: "Дебаунс Кодера", - 374684711: "Зашифровать Мнемонику", - 1244124409: "Зашифрованный QR Код", - 2968548114: "Зашифрованная мнемоника не была сохранена", - 3315319371: "Зашифрованная мнемоника была сохранена с ID: ", - 350279787: "Шифрование", - 2601598799: "Метод шифрования", - 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", - 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", - 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", - 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", - 784361051: "Ошибка:\n%s", - 1505332462: "Выйти", - 3838465623: "Исследовать файлы?", - 4170881190: "Экспортирование на SD карту..", - 1711312434: "Расширенный Публичный Ключ", - 383371114: "Не удалось расшифровать", - 3048830188: "Не удалось загрузить PSBT", - 4192663412: "Не удалось загрузить адрес", - 1996021743: "Не удалось загрузить ключ", - 1108715658: "Не удалось загрузить сообщение", - 1081425878: "Не удалось загрузить мнемонику", - 928667220: "Не удалось загрузить выходной дескриптор", - 1620572516: "Не удалось загрузить фразу-пароль", - 2946146830: "Не удалось сохранить мнемонику", - 1303554751: "Комиссия: ", - 104500973: "Скорость подачи", - 3313339187: "Имя файла", - 1982637349: "Файл %s существует на SD карте, перезаписать?", - 3737729752: "Фингерпринт: %s", - 2542772894: "Прошивка превышает максимальный размер: %d", - 1406590538: "Flute Диаметр", - 3086093110: "Бесплатно: ", - 1893243331: "Из Памяти", + 1207696150: "Change Adresse", + 3126552510: "Change Adressen", + 1583186953: "Thema ändern und neu starten?", + 2697733395: "Änderungen auf SD-Karte gespeichert!", + 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", + 3442025874: "Prüfe SD-Karte", + 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", + 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", + 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", + 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", + 2470115694: "Suche nach SD-Karte..", + 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", + 2407028014: "Kompakt SeedQR", + 4041895036: "Weiter?", + 4094072796: "Erstelle QR-Code", + 167798282: "QR-Code aus Text erzeugen?", + 2767642191: "Erstellt:", + 3513215254: "Benutzerdefinierte QR-Code", + 124617190: "Schnitttiefe", + 597912140: "Cut-Methode", + 2504034831: "Dezimal", + 2751113454: "Entschlüsseln?", + 3510912550: "Löschen %s?", + 1016609898: "Datei löschen?", + 1364509700: "Mnemonic löschen", + 4102535566: "Tiefe pro Durchgang", + 2791699253: "Ableitung: %s", + 1230133196: "Geräte-Flash-Speicher nicht erkannt.", + 3836852788: "Fertig?", + 382368239: "Driver", + 3978947916: "Encoder", + 4090746898: "Encoder-Entprellung", + 374684711: "Verschlüssel Mnemonic", + 1244124409: "Verschlüsselter QR-Code", + 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", + 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", + 350279787: "Verschlüsselung", + 2601598799: "Verschlüsselungsmodus", + 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", + 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", + 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", + 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", + 784361051: "Fehler:\n%s", + 1505332462: "Esc", + 3838465623: "Dateien durchsuchen?", + 4170881190: "Auf SD-Karte exportieren..", + 1711312434: "Öffentlicher Schlüssel", + 383371114: "Entschlüsselung fehlgeschlagen", + 3048830188: "PSBT konnte nicht geladen werden", + 4192663412: "Adresse konnte nicht geladen werden", + 1996021743: "Schlüssel konnte nicht geladen werden", + 1108715658: "Nachricht konnte nicht geladen werden", + 1081425878: "Mnemonic konnte nicht geladen werden", + 928667220: "Ausgabedeskriptor konnte nicht geladen werden", + 1620572516: "Passphrase konnte nicht geladen werden", + 2946146830: "Mnemonic konnte nicht gespeichert werden", + 1303554751: "Gebühr: ", + 104500973: "Vorschubgeschwindigkeit", + 3313339187: "Dateiname", + 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", + 3737729752: "Fingerabdruck: %s", + 2542772894: "Die Firmware übersteigt die maximale Größe: %d", + 1406590538: "Flötendurchmesser", + 3086093110: "Frei: ", + 1893243331: "Vom Speicher", 4120536442: "GRBL", - 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", - 602716148: "OK", - 3580020863: "Шестнадцатеричный Публичный Ключ", - 2691246967: "Шестнадцатеричный", - 2736309107: "ID уже существует\n", - 1706005805: "Неполный выходной дескриптор", - 631342955: "Входы (%d): ", - 2585599782: "Неверный адрес", - 2874529150: "Неверный загрузчик", - 4093416954: "Неверная длина мнемоники", - 1422874211: "Неверный публичный ключ", - 2443867979: "Неверный кошелек:\n%s", - 4122897393: "Инвертировать", - 3000888649: "Ключ", - 2686333978: "Ключ: ", - 4123798664: "Krux\n\n\nВерсия\n%s", - 3835918229: "Тестовый QR Принтера Krux", - 766317539: "Язык", - 972436696: "Задержка Линии", - 3596093890: "Линия: ", - 2820726296: "Загрузить Мнемонику", - 879727077: "Загрузить с SD карты?", - 669106195: "Загрузить одну?", - 3330705289: "Загрузить?", - 2596531078: "Загрузка Камеры..", - 596389387: "Загрузка адреса сдачи %d..", - 336702608: "Загрузка принтера..", - 2538883522: "Загрузка адреса получения %d..", - 3159494909: "Загрузка..", - 1177338798: "Локаль", - 2817059741: "Расположение", - 63976957: "Уровень логирования", - 86530918: "Логирование", - 2917810189: "Максимальная длина превышена (%s)", - 2030045667: "Сообщение", - 3928301843: "Отсутствует файл подписи", - 1948316555: "Мнемоника", - 2123991188: "ID мнемоники", - 3911073154: "ID памяти мнемоники", - 570639842: "Мнемоника не была расшифрована", - 1746030071: "Мнемоника не была зашифрована", - 1458925155: "Изменено: ", - 1845376098: "Мультиподпись", - 2939797024: "Сеть", - 73574491: "Новая Мнемоника", - 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", - 4063104189: "Нет", - 3927838899: "Без BIP39 фразы-пароля", - 4092516657: "Недостаточно бросков!", - 1577637745: "Восьмеричный", - 3312581301: "PBKDF2 Итерации", - 721090621: "PSBT", - 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", - 2987800462: "Ширина Бумаги", - 3050763890: "Часть\n%d / %d", - 3559456868: "Размер Части", - 4249903283: "Фраза-пароль", - 3712257341: "Фраза-пароль: ", - 140802882: "Постоянная Память", - 1703779997: "QR открытым текстом", - 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", - 784609464: "Скорость Погружения", - 3037062877: "Напечатать Тестовый QR", - 4278257699: "Напечатать в виде QR?\n\n%s\n\n", - 516488026: "Печатать?\n\n%s\n\n", - 1123106929: "Принтер", - 3903571079: "Драйвер Принтера не установлен!", - 2609799302: "Идет печать\n%d / %d", - 844861889: "Идет печать ...", - 2580599003: "Продолжить?", - 556126964: "Обработка ...", - 1848310591: "QR Код", - 710709610: "RX Пин", - 2697857197: "Получить", - 1746677167: "Адрес Получения", - 364354944: "Регион: ", - 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", - 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", - 856795528: "Броски:\n\n%s", - 255086803: "Броски: %d\n", - 3976793317: "SD карта", - 2827687530: "SD карта не обнаружена", - 2736513298: "SD карта не обнаружена.", - 3593785196: "SHA256 бросков:\n\n%s", - 1143278725: "SHA256 снэпшота:\n\n%s", + 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 602716148: "Go", + 3580020863: "Hex öffentlicher Schlüssel", + 2691246967: "Hexadezimal", + 2736309107: "ID existiert bereits\n", + 1706005805: "Unvollständiger Ausgabedeskriptor", + 631342955: "Input (%d): ", + 2585599782: "Ungültige Adresse", + 2874529150: "Ungültiger Bootloader", + 4093416954: "Ungültige mnemonische Lange", + 1422874211: "Ungültiger öffentlicher Schlüssel", + 2443867979: "Ungültige Wallet:\n%s", + 4122897393: "Umkehren", + 3000888649: "Schlüssel", + 2686333978: "Schlüssel:", + 4123798664: "Krux\n\n\nVersion\n%s", + 3835918229: "Krux Drucker Test-QR", + 766317539: "Sprache", + 972436696: "Leitungsverzögerung", + 3596093890: "Linie: ", + 2820726296: "Mnemonic laden", + 879727077: "Von SD-Karte laden?", + 669106195: "Eine laden?", + 3330705289: "Laden?", + 2596531078: "Lade Kamera..", + 596389387: "Lade Change Adresse %d..", + 336702608: "Drucker wird geladen..", + 2538883522: "Lade Empfangsadresse %d..", + 3159494909: "Wird geladen..", + 1177338798: "Spracheinstellung", + 2817059741: "Speicherort", + 63976957: "Log Level", + 86530918: "Logging", + 2917810189: "Maximale Länge überschritten (%s)", + 2030045667: "Nachricht", + 3928301843: "Fehlende Signaturdatei", + 1948316555: "Mnemonic", + 2123991188: "Mnemonische ID", + 3911073154: "Mnemonische Speicher-ID", + 570639842: "Mnemonic wurde nicht entschlüsselt", + 1746030071: "Mnemonic wurde nicht verschlüsselt", + 1458925155: "Geändert:", + 1845376098: "Multisig", + 2939797024: "Netzwerk", + 73574491: "Neue Mnemonic", + 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", + 4063104189: "Nein", + 3927838899: "Keine BIP39 Passphrase", + 4092516657: "Nicht genug Würfe!", + 1577637745: "Oktal", + 3312581301: "PBKDF2-Iter.", + 721090621: "PSBT", + 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", + 2987800462: "Papierbreite", + 3050763890: "Teil\n%d / %d", + 3559456868: "Teilegröße", + 4249903283: "Passphrase", + 3712257341: "Passphrase:", + 140802882: "Speicher", + 1703779997: "Klartext-QR", + 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", + 784609464: "Tauchrate", + 3037062877: "Drucke Test-QR", + 4278257699: "Als QR-Code drucken?\n\n%s\n\n", + 516488026: "Drucken?\n\n%s\n\n", + 1123106929: "Drucker", + 3903571079: "Druckertreiber nicht gesetzt!", + 2609799302: "Drucken\n%d / %d", + 844861889: "Wird gedruckt ...", + 2580599003: "Weiter?", + 556126964: "Wird bearbeitet ...", + 1848310591: "QR-Code", + 710709610: "RX Pin", + 2697857197: "Empfangen", + 1746677167: "Empfangsadresse", + 364354944: "Region: ", + 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", + 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", + 856795528: "Würfe:\n\n%s", + 255086803: "Würfe: %d\n", + 3976793317: "SD-Karte", + 2827687530: "SD-Karte nicht erkannt", + 2736513298: "SD-Karte nicht erkannt.", + 3593785196: "SHA256 der Würfe:\n\n%s", + 1143278725: "SHA256 des Snapshots:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Сохранить на SD карту?", - 810036588: "Сохранено на SD карту:\n%s", - 763824768: "Шкала", - 4117455079: "Отсканировать Адрес", - 3219991109: "Отсканировать BIP39 фразу-пароль", - 2537207336: "Отсканировать Ключ QR код", - 4006316572: "Сканирование слов 1-12 снова", - 2736506158: "Сканирование слов 13-24", + 3531742595: "Auf SD-Karte speichern?", + 810036588: "Auf SD-Karte gespeichert:\n%s", + 763824768: "Skala", + 4117455079: "Adresse\nscannen", + 3219991109: "Scan BIP39 Passphrase", + 2537207336: "Schlüssel QR-Code scannen", + 4006316572: "Wörter 1-12 erneut scannen", + 2736506158: "Wörter 13-24 scannen", + 3593497655: "Bildschirmschoner", 266935239: "SeedQR", - 1698829144: "Трансфер самому себе или Сдача (%d): ", - 473154195: "Настройки", - 1825881236: "Выключить", - 2120776272: "Выключение..", - 1061961408: "Подписать", - 4282338366: "Подписать?", - 746161122: "Подпись", - 1988416729: "Подписанное Сообщение", - 3672006076: "Подписанное PSBT", - 2281377987: "Одна подпись", - 4221794628: "Размер: ", - 2344747135: "Некоторые проверки не могут быть выполнены.", - 2309020186: "Расход (%d): ", - 3355862324: "Стэкбит 1248", - 3303592908: "Сохранить на Флэш Память", - 720041451: "Сохранить на SD Карту", - 3514476519: "Свайпните, чтобы сменить режим", - 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", - 4228215415: "TX Пин", - 2612594937: "Текст", - 1454688268: "Тема", - 1180180513: "Термальный", - 4119292117: "Мини Сид-фраза", - 1732872974: "Мини Сид-фраза (Биты)", - 725348723: "Инструменты", - 3684696112: "Прикоснитесь Границы", - 2978718564: "Тачскрин", - 2732611775: "Попробовать ещё?", - 1487826746: "Введите BIP39 фразу-пароль", - 2061556020: "Введите Ключ", - 2089395053: "Юнит", - 2845607430: "Обновление загрузчика..\n\n%d%%", - 4164597446: "Обновление завершено.\n\nВыключение..", - 2736001501: "Обновление прошивки..\n\n%d%%", - 2674953168: "Использовать черную фоновую поверхность.", - 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", - 236075140: "Использовано: ", - 4003084591: "Значение %s вне диапозона: [%s, %s]", - 4191058607: "С Помощью Камеры", - 1254681955: "С Помощью D20", - 525309547: "С Помощью D6", - 590330112: "С Помощью Ручного Ввода", - 2504354847: "Дождитесь Захвата", - 2297028319: "Дескриптор Кошелька", - 4232654916: "Выходной дескриптор кошелька", - 2587172867: "Выходной дескриптор кошелька загружен!", - 2499782468: "Выходной дескриптор кошелька не найден.", - 2671738224: "Предупреждение:", - 797660533: "Слово %d", - 3742424146: "Числа Слов", - 2965123464: "Слова", - 1303016265: "Да", - 771968845: "Ваши изменения будут сохранены на флэш памяти устройства.", - 2569054451: "Ваши изменения будут сохранены на SD карте.", + 1698829144: "Selbstübertragung oder Change (%d): ", + 473154195: "Einstellungen", + 1825881236: "Ausschalten", + 2120776272: "Herunterfahren..", + 1061961408: "Signieren", + 4282338366: "Signieren?", + 746161122: "Signatur", + 1988416729: "Signierte Nachricht", + 3672006076: "Signierte PSBT", + 2281377987: "Single-Sig", + 4221794628: "Größe: ", + 2344747135: "Einige Schecks können nicht durchgeführt werden.", + 2309020186: "Ausgabe (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Auf Flash speichern", + 720041451: "Auf der SD-Karte speichern", + 3514476519: "Wischen um den Modus zu ändern", + 1898550184: "TOUCH oder ENTER zum Erfassen", + 4228215415: "TX Pin", + 2612594937: "Text", + 1454688268: "Thema", + 1180180513: "Thermisch", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Werkzeuge", + 3684696112: "Berühre Schwellenwert", + 2978718564: "Touchscreen", + 2732611775: "Weiter versuchen?", + 1487826746: "BIP39 Passphrase eingeben", + 2061556020: "Schlüssel eingeben", + 2089395053: "Einheit", + 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", + 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", + 2736001501: "Firmware wird aktualisiert..\n\n%d%%", + 2674953168: "Verwende eine schwarze Hintergrundfläche.", + 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", + 236075140: "Belegt: ", + 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", + 4191058607: "Via Kamera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Via manueller Eingabe", + 2504354847: "Warte auf die Erfassung", + 3992434312: "Wartezeit", + 2297028319: "Wallet-Deskriptor", + 4232654916: "Wallet Ausgabedeskriptor", + 2587172867: "Wallet Ausgabedeskriptor geladen!", + 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", + 2671738224: "Warnung:", + 797660533: "Wort %d", + 3742424146: "Wortnummern", + 2965123464: "Wörter", + 1303016265: "Ja", + 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", + 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", }, - "pl-PL": { - 1185266064: "%d z %d multisig", - 2004520398: "%D.Zmiana:\n\n%s\n\n", - 3862364126: "%D.Samo-transfer:\n\n%s\n\n", - 3264377309: "%D.Wydać:\n\n%s\n\n", - 2399232215: "%s\n\nis prawidłowy adres zmiany!", - 3921290840: "%s\n\nis ważny adres odbierania!", - 1808355833: "%s\n\nwas nie znaleziono w pierwszych adresach zmiany", - 1306127065: "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", - 3348584292: "(Eksperymentalny)", - 2739590230: "12 słów", - 1310058127: "24 słowa", + "es-MX": { + 1185266064: "%d de %d multisig", + 2004520398: "%d. Cambio: \n\n%s\n\n", + 3862364126: "%d. Autotransferencia: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n¡es una dirección de cambio válida!", + 3921290840: "%s\n\nes un dirección de depósito válido!", + 1808355833: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de cambio", + 1306127065: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de depósito", + 3348584292: "(Experimental)", + 2739590230: "12 palabras", + 1310058127: "24 palabras", 2743272264: "ABC", - 1949634023: "O", - 1517128857: "Adafruit", - 3270727197: "Adres", - 2574498267: "Dodatkowa entropia z kamery wymaganej dla trybu AES-CBC", - 283202181: "Właściwie wyrównaj kamerę i maleńkie nasiona.", - 88746165: "Niepełnosprawne przeciwblokowane", - 1521033296: "Włączona anty-zabawa", - 1056821534: "Jesteś pewny?", - 3247612282: "BIP39 Mnemonic", - 3455872521: "Z powrotem", - 2541860807: "Kopie zapasowe bootloader ..\n\n%d %%", - 2256777600: "zły podpis", - 3937333362: "Baudrate", - 427617266: "Bitcoin", - 928727036: "Wyściółka graniczna", - 213030954: "CNC", - 1207696150: "Zmiana", - 3126552510: "Zmień adresy", - 1583186953: "Zmienić motyw i ponownie uruchomić?", - 2697733395: "Zmiany utrzymywały się na karcie SD!", - 388908871: "Zmiany będą trwać do zamknięcia.", - 3442025874: "Sprawdź kartę SD", - 3119547911: "Sprawdź, czy adres należy do tego portfela?", - 2856261511: "Sprawdzone %d adresy zmiany bez dopasowań.", - 2788541416: "Sprawdzone %D Otrzymuj adresy bez zapałek.", - 2446472910: "Sprawdzanie Zmieniania Adres %D dla dopasowania.", - 2470115694: "Sprawdzanie karty SD ..", - 3655273987: "Sprawdzanie adresu Otrzymaj %D dla meczu.", - 2407028014: "Kompaktowy seedqr", - 4041895036: "Kontynuować?", - 4094072796: "Utwórz kod QR", - 167798282: "Utwórz kod QR z tekstu?", - 2767642191: "Utworzony:", - 3513215254: "Niestandardowy kod QR", - 124617190: "Wytnij głębokość", - 597912140: "Metoda cięcia", - 2504034831: "Dziesiętny", - 2751113454: "Odszyfrować?", - 3510912550: "Usuń %s?", - 1016609898: "Usunąć plik?", - 1364509700: "Usuń mnemonic", - 4102535566: "Głębokość na przepustkę", - 2791699253: "Pochodzenie: %s", - 1230133196: "Nie wykryto pamięci flash urządzenia.", - 3836852788: "Zrobione?", - 382368239: "Kierowca", - 3978947916: "Enkoder", - 4090746898: "Encoder Debunet", - 374684711: "Szyfrowanie mnemoniki", - 1244124409: "Zaszyfrowany kod QR", - 2968548114: "Szyfrowana mnemonika nie była przechowywana", - 3315319371: "Szyfrowana mnemonika była przechowywana z ID:", - 350279787: "Szyfrowanie", - 2601598799: "Tryb szyfrowania", - 3504179008: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę od 1 do 2048 r.", - 1100685007: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w heksadecimal od 1 do 800.", - 4090266642: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w wysokości od 1 do 4000.", - 2780625730: "Wprowadź każde słowo swojego mnemonika BIP-39.", - 784361051: "Błąd:\n%s", - 1505332462: "wyjście", - 3838465623: "Eksplorować pliki?", - 4170881190: "Eksportowanie do karty SD ..", - 1711312434: "Rozszerzony klucz publiczny", - 383371114: "Nie udało się odszyfrować", - 3048830188: "Nie udało się załadować PSBT", - 4192663412: "Nie udało się załadować adresu", - 1996021743: "Nie udało się załadować klucza", - 1108715658: "Nie udało się załadować wiadomości", - 1081425878: "Nie udało się załadować mnemonika", - 928667220: "Nie udało się załadować deskryptora wyjściowego", - 1620572516: "Nie udało się załadować pseudonim", - 2946146830: "Nie udało się przechowywać mnemonika", - 1303554751: "Opłata:", - 104500973: "Szybkość pasz", - 3313339187: "Nazwa pliku", - 1982637349: "Nazwa pliku %s istnieje na karcie SD, zastąp?", - 3737729752: "Odcisk palca: %s", - 2542772894: "Oprogramowanie układowe przekracza maksymalny rozmiar: %D", - 1406590538: "Średnica fletu", - 3086093110: "Bezpłatny:", - 1893243331: "Z przechowywania", - 4120536442: "Grbl", - 299338213: "Podaj temu mnemonicznemu identyfikatorowi?W przeciwnym razie zostanie użyty obecny odcisk palca", - 602716148: "Iść", - 3580020863: "Hex Key Public", - 2691246967: "Szesnastkowy", - 2736309107: "ID już istnieje\n", - 1706005805: "inComplete Descriptor", - 631342955: "Wejścia (%d):", - 2585599782: "Błędny adres", - 2874529150: "Nieprawidłowy bootloader", - 4093416954: "Nieprawidłowa długość mnemoniczna", - 1422874211: "Nieprawidłowy klucz publiczny", - 2443867979: "Nieprawidłowy portfel:\n%s", - 4122897393: "Odwracać", - 3000888649: "Klucz", - 2686333978: "Klucz:", - 4123798664: "Krux\n\n\neversion\n%s", - 3835918229: "Test drukarki Krux QR", - 766317539: "Język", - 972436696: "Opóźnienie linii", - 3596093890: "Linia:", - 2820726296: "Ładuj mnemoniczne", - 879727077: "Załaduj z karty SD?", - 669106195: "Załaduj jeden?", - 3330705289: "Obciążenie?", - 2596531078: "Ładowanie aparatu ..", - 596389387: "Ładowanie ZMIANY Adres %D ..", - 336702608: "Ładowanie drukarki ..", - 2538883522: "Ładowanie adresu odbierania %d ..", - 3159494909: "Ładowanie..", - 1177338798: "Widownia", - 2817059741: "Lokalizacja", - 63976957: "Poziom dziennika", - 86530918: "Logowanie", - 2917810189: "Maksymalna długość przekroczona (%s)", - 2030045667: "Wiadomość", - 3928301843: "Brakujący plik podpisu", - 1948316555: "Mnemoniczny", - 2123991188: "Mnemoniczne id", - 3911073154: "Mnemoniczny identyfikator przechowywania", - 570639842: "Mnemonik nie został odszyfrowany", - 1746030071: "Mnemoniczny nie był szyfrowany", - 1458925155: "Zmodyfikowany:", - 1845376098: "Multisig", - 2939797024: "Sieć", - 73574491: "Nowy Mnemonic", - 2792272353: "Wykryto nowe oprogramowanie.\n\nsha256:\n%s\n\n\n\ninstall?", - 4063104189: "NIE", - 3927838899: "Brak frazy BIP39", - 4092516657: "Za mało rolki!", - 1577637745: "Octal", - 3312581301: "PBKDF2 ITER.", - 721090621: "PSBT", - 995862913: "Parzyj kropki czarne, aby można je było wykryć.", - 2987800462: "Szerokość papieru", - 3050763890: "Część\n %d / %d", - 3559456868: "Rozmiar części", - 4249903283: "Fraza", - 3712257341: "FRASSE:", - 140802882: "Trwać", - 1703779997: "PlainText QR", - 3561756278: "Załaduj deskryptor wyjściowy portfela", - 784609464: "Szybkość spadku", - 3037062877: "Test wydrukuj QR", - 4278257699: "Drukuj do qr?\n\n%s\n\n", - 516488026: "Wydrukować?\n\n%s\n\n", - 1123106929: "Drukarka", - 3903571079: "Sterownik drukarki nie jest ustawiony!", - 2609799302: "Drukowanie\n %d / %d", - 844861889: "Drukowanie ...", - 2580599003: "Przystępować?", - 556126964: "Przetwarzanie ...", - 1848310591: "Kod QR", - 710709610: "Pin Rx", - 2697857197: "Odbierać", - 1746677167: "Odbierać adresy", - 364354944: "Region:", - 1662254634: "Przejrzyj zeskanowane dane, w razie potrzeby edytuj", - 770350922: "Rzuć kostkę co najmniej %d, aby wygenerować mnemoniczny.", - 856795528: "Rolls:\n\n%s", - 255086803: "Rolls: %d\n", - 3976793317: "karta SD", - 2827687530: "Karta SD nie została wykryta", - 2736513298: "Karta SD nie została wykryta.", - 3593785196: "SHA256 Rolls:\n\n%s", - 1143278725: "SHA256 migawki:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Zapisz na karcie SD?", - 810036588: "Zapisano na karcie SD:\n%s", - 763824768: "Skala", - 4117455079: "Adres skanowania", - 3219991109: "Scan BIP39 Passhraz", - 2537207336: "Skanuj kod QR", - 4006316572: "Znowu skanowanie słów 1-12", - 2736506158: "Skanowanie słów 13-24", - 266935239: "Seedqr", - 1698829144: "Samo-transfer lub zmiana (%d):", - 473154195: "Ustawienia", - 1825881236: "Zamknięcie", - 2120776272: "Wyłączanie..", - 1061961408: "Podpisać", - 4282338366: "Podpisać?", - 746161122: "Podpis", - 1988416729: "Podpisana wiadomość", - 3672006076: "Podpisano PSBT", - 2281377987: "Pojedyncze Sig", - 4221794628: "Rozmiar:", - 2344747135: "Nie można wykonać niektórych kontroli.", - 2309020186: "Wydać (%d):", - 3355862324: "Stackbit 1248", - 3303592908: "Przechowuj na Flash", - 720041451: "Przechowuj na karcie SD", - 3514476519: "Przesuń tryb zmiany", - 1898550184: "Dotknij lub wejdź do przechwytywania", - 4228215415: "Pin TX", - 2612594937: "Tekst", - 1454688268: "Temat", - 1180180513: "Termiczny", - 4119292117: "Małe ziarno", - 1732872974: "Małe nasiona (bity)", - 725348723: "Narzędzia", - 3684696112: "Próg dotykowy", - 2978718564: "Ekran dotykowy", - 2732611775: "Próbuj bardziej?", - 1487826746: "Passówka typu BIP39", - 2061556020: "Klucz typu", - 2089395053: "Jednostka", - 2845607430: "Aktualizacja bootloader ..\n\n%d %%", - 4164597446: "Uaktualnienie zakończone.\n\nshutting w dół ..", - 2736001501: "Aktualizacja oprogramowania układowego ..\n\n%d %%", - 2674953168: "Użyj czarnej powierzchni tła.", - 2402455261: "Użyj entropii aparatu, aby stworzyć nowy mnemonik", - 236075140: "Używany:", - 4003084591: "Wartość %s z zakresu: [ %s, %s]", - 4191058607: "Za pośrednictwem aparatu", - 1254681955: "Via D20", - 525309547: "Przez D6", - 590330112: "Poprzez ręczne wejście", - 2504354847: "Poczekaj na schwytanie", - 2297028319: "Deskryptor portfela", - 4232654916: "Deskryptor wyjściowy portfela", - 2587172867: "Załadowany deskryptor wyjściowy portfela!", - 2499782468: "Nie znaleziono deskryptora wyjściowego portfela.", - 2671738224: "Ostrzeżenie:", - 797660533: "Słowo %d", - 3742424146: "Numery słów", - 2965123464: "Słowa", - 1303016265: "Tak", - 771968845: "Twoje zmiany będą przechowywane w pamięci flash urządzenia.", - 2569054451: "Twoje zmiany będą przechowywane na karcie SD.", - }, - "es-MX": { - 1185266064: "%d de %d multisig", - 2004520398: "%d. Cambio: \n\n%s\n\n", - 3862364126: "%d. Autotransferencia: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n¡es una dirección de cambio válida!", - 3921290840: "%s\n\nes un dirección de depósito válido!", - 1808355833: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de cambio", - 1306127065: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de depósito", - 3348584292: "(Experimental)", - 2739590230: "12 palabras", - 1310058127: "24 palabras", - 2743272264: "ABC", - 1949634023: "Nosotros", + 1949634023: "Nosotros", 1517128857: "Adafruit", 3270727197: "Dirección", 2574498267: "Entropía adicional desde la cámara requerida para el modo AES-CBC", @@ -700,6 +457,7 @@ 2537207336: "Escanear el código QR", 4006316572: "Escaneo de palabras 1-12 de nuevo", 2736506158: "Escaneo de palabras 13-24", + 3593497655: "Protector de pantalla", 266935239: "Seedqr", 1698829144: "Autotransferencia o Cambio (%d): ", 473154195: "Ajustes", @@ -744,6 +502,7 @@ 525309547: "Via D6", 590330112: "Mediante entrada manual", 2504354847: "Espera la captura", + 3992434312: "Tiempo de espera", 2297028319: "Descriptor de Cartera", 4232654916: "Descriptor de salida de billetera", 2587172867: "¡Se ha cargado el descriptor de salida de la cartera!", @@ -756,251 +515,6 @@ 771968845: "Sus cambios se guardarán en el almacenamiento flash del dispositivo.", 2569054451: "Sus cambios se guardarán en la tarjeta SD.", }, - "pt-BR": { - 1185266064: "%d da %d multisig", - 2004520398: "%d. Troco: \n\n%s\n\n", - 3862364126: "%d. Autotransferência: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n é um endereço de troco válido!", - 3921290840: "%s\n\né um endereço de recepção válido!", - 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", - 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", - 3348584292: "(Experimental)", - 2739590230: "12 palavras", - 1310058127: "24 palavras", - 2743272264: "ABC", - 1949634023: "Sobre", - 1517128857: "Adafruit", - 3270727197: "Endereço", - 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", - 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", - 88746165: "Antirreflexo desativado", - 1521033296: "Antirreflexo ativado", - 1056821534: "Tem certeza?", - 3247612282: "Mnemônico BIP39", - 3455872521: "Voltar", - 2541860807: "Backing up bootloader..\n\n%d%%", - 2256777600: "Assinatura Inválida", - 3937333362: "Baudrate", - 427617266: "Bitcoin", - 928727036: "Borda", - 213030954: "CNC", - 1207696150: "Troco", - 3126552510: "Endereços de Troco", - 1583186953: "Mudar o tema e reiniciar?", - 2697733395: "Mudanças salvas no cartão SD!", - 388908871: "Alterações só durarão até o desligamento.", - 3442025874: "Verifique o cartão SD", - 3119547911: "Verificar se este endereço pertence a carteira?", - 2856261511: "Endereço de troco %d não corresponde.", - 2788541416: "Endereço de recebimento %d não corresponde.", - 2446472910: "Verificando correspondência do endereço de troco %d ..", - 2470115694: "Verificando o cartão SD..", - 3655273987: "Verificando correspondência do endereço de recebimento %d ..", - 2407028014: "SeedQR Compacto", - 4041895036: "Continuar?", - 4094072796: "Gerar Código QR", - 167798282: "Gerar código QR do texto?", - 2767642191: "Criado: ", - 3513215254: "Código QR Customizado", - 124617190: "Profundidade de Corte", - 597912140: "Método de Corte", - 2504034831: "Decimal", - 2751113454: "Descriptografar?", - 3510912550: "Excluir %s?", - 1016609898: "Excluir Arquivo?", - 1364509700: "Excluir Mnemônico", - 4102535566: "Profundidade da Passagem", - 2791699253: "Derivação: %s", - 1230133196: "Armazenamento flash do dispositivo não detectado.", - 3836852788: "Feito?", - 382368239: "Driver", - 3978947916: "Codificador", - 4090746898: "Debounce do Encoder", - 374684711: "Criptografar Mnemônico", - 1244124409: "Código QR Criptografado", - 2968548114: "Mnemonic criptografado não foi armazenado", - 3315319371: "Mnemônico criptografado foi armazenado com ID:", - 350279787: "Criptografia", - 2601598799: "Modo de Criptografia", - 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", - 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", - 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", - 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", - 784361051: "Erro:\n%s", - 1505332462: "Esc", - 3838465623: "Explorar arquivos?", - 4170881190: "Exportando para o cartão SD..", - 1711312434: "Chave Pública Estendida", - 383371114: "Falhou em descriptografar", - 3048830188: "Falhou ao carregar PSBT", - 4192663412: "Falhou ao carregar endereço", - 1996021743: "Falha ao carregar a chave", - 1108715658: "Falhou ao carregar mensagem", - 1081425878: "Falhou ao carregar mnemônico", - 928667220: "Falha ao carregar o descritor de saída", - 1620572516: "Falha ao carregar a senha", - 2946146830: "Falhou ao armazenar mnemônico", - 1303554751: "Taxa: ", - 104500973: "Taxa de Alimentação", - 3313339187: "Nome do arquivo", - 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", - 3737729752: "Impressão digital: %s", - 2542772894: "Firmware excede o tamanho máximo: %d", - 1406590538: "Diâmetro da Fresa", - 3086093110: "Livre: ", - 1893243331: "Do Armazenamento", - 4120536442: "GRBL", - 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", - 602716148: "Ir", - 3580020863: "Chave pública hexadecimal", - 2691246967: "Hexadecimal", - 2736309107: "Id já existe\n", - 1706005805: "Descritor incompleto", - 631342955: "Entradas (%d): ", - 2585599782: "Endereço inválido", - 2874529150: "Bootloader inválido", - 4093416954: "Comprimento de mnemônico inválido", - 1422874211: "Chave pública inválida", - 2443867979: "Carteira inválida:\n%s", - 4122897393: "Invertido", - 3000888649: "Chave", - 2686333978: "Chave:", - 4123798664: "Krux\n\n\nVersão\n%s", - 3835918229: "Teste de impressão de QR krux", - 766317539: "Língua", - 972436696: "Atraso de Linha", - 3596093890: "Linha: ", - 2820726296: "Carregar Mnemônico", - 879727077: "Carregar do cartão SD?", - 669106195: "Carregar um?", - 3330705289: "Carregar?", - 2596531078: "Carregando Câmera..", - 596389387: "Carregando endereço de troco %d..", - 336702608: "Carregando impressora..", - 2538883522: "Carregando endereço de recebimento %d..", - 3159494909: "Carregando..", - 1177338798: "Idioma", - 2817059741: "Local", - 63976957: "Nível de log", - 86530918: "Logging", - 2917810189: "Comprimento máximo excedido (%s)", - 2030045667: "Mensagem", - 3928301843: "Arquivo de assinatura faltando", - 1948316555: "Mnemônico", - 2123991188: "ID do mnemônico", - 3911073154: "ID de armazenamento", - 570639842: "Mnemônico não foi descriptografado", - 1746030071: "Mnemônico não foi criptografado", - 1458925155: "Modificado:", - 1845376098: "Multisig", - 2939797024: "Rede", - 73574491: "Novo Mnemônico", - 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", - 4063104189: "Não", - 3927838899: "Sem senha BIP39", - 4092516657: "Jogadas insuficientes!", - 1577637745: "Octal", - 3312581301: "Iter. PBKDF2", - 721090621: "PSBT", - 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", - 2987800462: "Largura do papel", - 3050763890: "Parte\n%d / %d", - 3559456868: "Tamanho da peça", - 4249903283: "Senha", - 3712257341: "Senha:", - 140802882: "Salvar", - 1703779997: "QR em Texto", - 3561756278: "Carregue um descritor da carteira", - 784609464: "Taxa de Mergulho", - 3037062877: "Imprimir QR de teste", - 4278257699: "Imprimir QR?\n\n%s\n\n", - 516488026: "Imprimir?\n\n%s\n\n", - 1123106929: "Impressora", - 3903571079: "Driver de impressora não está definido!", - 2609799302: "Imprimindo\n%d / %d", - 844861889: "Imprimindo ...", - 2580599003: "Seguir?", - 556126964: "Processando ...", - 1848310591: "Código QR", - 710709610: "Pino RX", - 2697857197: "Recebimento", - 1746677167: "Endereços de Recebimento", - 364354944: "Região: ", - 1662254634: "Revise os dados, edite se necessário", - 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", - 856795528: "Jogadas:\n\n%s", - 255086803: "Jogadas: %d\n", - 3976793317: "Cartão SD", - 2827687530: "Cartão SD não detectado", - 2736513298: "Cartão SD não detectado.", - 3593785196: "SHA256 de jogadas:\n\n%s", - 1143278725: "Sha256 da imagem:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Salvar no cartão SD?", - 810036588: "Salvo no cartão SD:\n%s", - 763824768: "Escala", - 4117455079: "Escanear Endereço", - 3219991109: "Escanear a senha BIP39", - 2537207336: "Escanear código QR da chave", - 4006316572: "Escaneando as palavras 1-12 novamente", - 2736506158: "Escaneando as palavras 13-24", - 266935239: "SeedQR", - 1698829144: "Autotransferência ou Troco (%d): ", - 473154195: "Configurações", - 1825881236: "Desligar", - 2120776272: "Desligando..", - 1061961408: "Assinar", - 4282338366: "Assinar?", - 746161122: "Assinatura", - 1988416729: "Mensagem Assinada", - 3672006076: "PSBT Assinada", - 2281377987: "Single-sig", - 4221794628: "Total: ", - 2344747135: "Algumas verificações não podem ser realizadas.", - 2309020186: "Gastos (%d): ", - 3355862324: "Stackbit 1248", - 3303592908: "Armazene na Flash", - 720041451: "Armazene no Cartão SD", - 3514476519: "Deslize para mudar de modo", - 1898550184: "TOQUE ou ENTER para capturar", - 4228215415: "Pino TX", - 2612594937: "Texto", - 1454688268: "Tema", - 1180180513: "Térmica", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Ferramentas", - 3684696112: "Limiar de Toque", - 2978718564: "Touchscreen", - 2732611775: "Tentar mais?", - 1487826746: "Digitar a senha BIP39", - 2061556020: "Digite a Chave", - 2089395053: "Unidade", - 2845607430: "Atualizando bootloader..\n\n%d%%", - 4164597446: "Atualização completa.\n\nDesligando..", - 2736001501: "Atualizando firmware..\n\n%d%%", - 2674953168: "Use uma superfície de fundo preta.", - 2402455261: "Use a entropia da câmera para criar um novo mnemônico", - 236075140: "Usado: ", - 4003084591: "Valor %s fora do alcance: [ %s, %s]", - 4191058607: "Pela Câmera", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Por entrada manual", - 2504354847: "Aguarde a captura", - 2297028319: "Descritor de Carteira", - 4232654916: "Descritor da carteira", - 2587172867: "Descritor de saída da carteira carregado!", - 2499782468: "O descritor de saída da carteira não foi encontrado.", - 2671738224: "Aviso:", - 797660533: "Palavra %d", - 3742424146: "Números das Palavras", - 2965123464: "Palavras", - 1303016265: "Sim", - 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", - 2569054451: "Suas alterações serão mantidas no cartão SD.", - }, "fr-FR": { 1185266064: "%d de %d multisignature", 2004520398: "%d. Changement : \n\n%s\n\n", @@ -1190,6 +704,7 @@ 2537207336: "Scanner le code QR de la clé", 4006316572: "Analyser à nouveau les mots 1 à 12", 2736506158: "Analyser les mots 13 à 24", + 3593497655: "Économiseur d'écran", 266935239: "Seedqr", 1698829144: "Auto-transfert ou changement (%d): ", 473154195: "Paramètres", @@ -1234,6 +749,7 @@ 525309547: "Via D6", 590330112: "Par saisie manuelle", 2504354847: "Attendez la capture", + 3992434312: "Temps d'attente", 2297028319: "Descripteur de Portefeuille", 4232654916: "Descripteur de sortie du portefeuille", 2587172867: "Descripteur de sortie du portefeuille chargé!", @@ -1435,6 +951,7 @@ 2537207336: "QR code sleutel scannen", 4006316572: "Woorden 1 t/m 12 opnieuw scannen", 2736506158: "Woorden 13 t/m 24 scannen", + 3593497655: "Screensaver", 266935239: "SeedQR", 1698829144: "Zelf overschrijving of wisselgeld (%d): ", 473154195: "Instellingen", @@ -1479,6 +996,7 @@ 525309547: "Via D6", 590330112: "Via handmatige invoer", 2504354847: "Wacht op opname", + 3992434312: "Wacht tijd", 2297028319: "Descriptor", 4232654916: "Portemonnee descriptor", 2587172867: "Portemonnee descriptor geladen!", @@ -1491,250 +1009,746 @@ 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", 2569054451: "Veranderingen worden opgeslagen op SD kaart.", }, - "de-DE": { - 1185266064: "%d von %d Multisig", - 2004520398: "%d. Change: \n\n%s\n\n", - 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", - 3264377309: "%d. Ausgaben: \n\n%s\n\n", - 2399232215: "%s\n\nist eine gültige Change Adresse!", - 3921290840: "%s\n\nist eine gültige Empfangsadresse!", - 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", - 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", - 3348584292: "(Experimental)", - 2739590230: "12 Wörter", - 1310058127: "24 Wörter", + "pl-PL": { + 1185266064: "%d z %d multisig", + 2004520398: "%D.Zmiana:\n\n%s\n\n", + 3862364126: "%D.Samo-transfer:\n\n%s\n\n", + 3264377309: "%D.Wydać:\n\n%s\n\n", + 2399232215: "%s\n\nis prawidłowy adres zmiany!", + 3921290840: "%s\n\nis ważny adres odbierania!", + 1808355833: "%s\n\nwas nie znaleziono w pierwszych adresach zmiany", + 1306127065: "%s\n\nwas nie znaleziono w pierwszych %D Otrzymuj adresy", + 3348584292: "(Eksperymentalny)", + 2739590230: "12 słów", + 1310058127: "24 słowa", 2743272264: "ABC", - 1949634023: "Über", + 1949634023: "O", 1517128857: "Adafruit", - 3270727197: "Adresse", - 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", - 283202181: "Richte Kamera und Tiny Seed korrekt aus.", - 88746165: "Blendschutz deaktiviert", - 1521033296: "Blendschutz aktiviert", - 1056821534: "Bist Du sicher?", + 3270727197: "Adres", + 2574498267: "Dodatkowa entropia z kamery wymaganej dla trybu AES-CBC", + 283202181: "Właściwie wyrównaj kamerę i maleńkie nasiona.", + 88746165: "Niepełnosprawne przeciwblokowane", + 1521033296: "Włączona anty-zabawa", + 1056821534: "Jesteś pewny?", 3247612282: "BIP39 Mnemonic", - 3455872521: "Zurück", - 2541860807: "Bootloader wird gesichert..\n\n%d%%", - 2256777600: "Ungültige Signatur", + 3455872521: "Z powrotem", + 2541860807: "Kopie zapasowe bootloader ..\n\n%d %%", + 2256777600: "zły podpis", 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Randpolsterung", + 928727036: "Wyściółka graniczna", 213030954: "CNC", - 1207696150: "Change Adresse", - 3126552510: "Change Adressen", - 1583186953: "Thema ändern und neu starten?", - 2697733395: "Änderungen auf SD-Karte gespeichert!", - 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", - 3442025874: "Prüfe SD-Karte", - 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", - 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", - 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", - 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", - 2470115694: "Suche nach SD-Karte..", - 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", - 2407028014: "Kompakt SeedQR", - 4041895036: "Weiter?", - 4094072796: "Erstelle QR-Code", - 167798282: "QR-Code aus Text erzeugen?", - 2767642191: "Erstellt:", - 3513215254: "Benutzerdefinierte QR-Code", - 124617190: "Schnitttiefe", - 597912140: "Cut-Methode", - 2504034831: "Dezimal", - 2751113454: "Entschlüsseln?", - 3510912550: "Löschen %s?", - 1016609898: "Datei löschen?", - 1364509700: "Mnemonic löschen", - 4102535566: "Tiefe pro Durchgang", - 2791699253: "Ableitung: %s", - 1230133196: "Geräte-Flash-Speicher nicht erkannt.", - 3836852788: "Fertig?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-Entprellung", - 374684711: "Verschlüssel Mnemonic", - 1244124409: "Verschlüsselter QR-Code", - 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", - 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", - 350279787: "Verschlüsselung", - 2601598799: "Verschlüsselungsmodus", - 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", - 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", - 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", - 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", - 784361051: "Fehler:\n%s", - 1505332462: "Esc", - 3838465623: "Dateien durchsuchen?", - 4170881190: "Auf SD-Karte exportieren..", - 1711312434: "Öffentlicher Schlüssel", - 383371114: "Entschlüsselung fehlgeschlagen", - 3048830188: "PSBT konnte nicht geladen werden", - 4192663412: "Adresse konnte nicht geladen werden", - 1996021743: "Schlüssel konnte nicht geladen werden", - 1108715658: "Nachricht konnte nicht geladen werden", - 1081425878: "Mnemonic konnte nicht geladen werden", - 928667220: "Ausgabedeskriptor konnte nicht geladen werden", - 1620572516: "Passphrase konnte nicht geladen werden", - 2946146830: "Mnemonic konnte nicht gespeichert werden", - 1303554751: "Gebühr: ", - 104500973: "Vorschubgeschwindigkeit", - 3313339187: "Dateiname", - 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", - 3737729752: "Fingerabdruck: %s", - 2542772894: "Die Firmware übersteigt die maximale Größe: %d", - 1406590538: "Flötendurchmesser", - 3086093110: "Frei: ", - 1893243331: "Vom Speicher", - 4120536442: "GRBL", - 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", - 602716148: "Go", - 3580020863: "Hex öffentlicher Schlüssel", - 2691246967: "Hexadezimal", - 2736309107: "ID existiert bereits\n", - 1706005805: "Unvollständiger Ausgabedeskriptor", - 631342955: "Input (%d): ", - 2585599782: "Ungültige Adresse", - 2874529150: "Ungültiger Bootloader", - 4093416954: "Ungültige mnemonische Lange", - 1422874211: "Ungültiger öffentlicher Schlüssel", - 2443867979: "Ungültige Wallet:\n%s", - 4122897393: "Umkehren", - 3000888649: "Schlüssel", - 2686333978: "Schlüssel:", - 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Krux Drucker Test-QR", - 766317539: "Sprache", - 972436696: "Leitungsverzögerung", - 3596093890: "Linie: ", - 2820726296: "Mnemonic laden", - 879727077: "Von SD-Karte laden?", - 669106195: "Eine laden?", - 3330705289: "Laden?", - 2596531078: "Lade Kamera..", - 596389387: "Lade Change Adresse %d..", - 336702608: "Drucker wird geladen..", - 2538883522: "Lade Empfangsadresse %d..", - 3159494909: "Wird geladen..", - 1177338798: "Spracheinstellung", - 2817059741: "Speicherort", - 63976957: "Log Level", - 86530918: "Logging", - 2917810189: "Maximale Länge überschritten (%s)", - 2030045667: "Nachricht", - 3928301843: "Fehlende Signaturdatei", - 1948316555: "Mnemonic", - 2123991188: "Mnemonische ID", - 3911073154: "Mnemonische Speicher-ID", - 570639842: "Mnemonic wurde nicht entschlüsselt", - 1746030071: "Mnemonic wurde nicht verschlüsselt", - 1458925155: "Geändert:", + 1207696150: "Zmiana", + 3126552510: "Zmień adresy", + 1583186953: "Zmienić motyw i ponownie uruchomić?", + 2697733395: "Zmiany utrzymywały się na karcie SD!", + 388908871: "Zmiany będą trwać do zamknięcia.", + 3442025874: "Sprawdź kartę SD", + 3119547911: "Sprawdź, czy adres należy do tego portfela?", + 2856261511: "Sprawdzone %d adresy zmiany bez dopasowań.", + 2788541416: "Sprawdzone %D Otrzymuj adresy bez zapałek.", + 2446472910: "Sprawdzanie Zmieniania Adres %D dla dopasowania.", + 2470115694: "Sprawdzanie karty SD ..", + 3655273987: "Sprawdzanie adresu Otrzymaj %D dla meczu.", + 2407028014: "Kompaktowy seedqr", + 4041895036: "Kontynuować?", + 4094072796: "Utwórz kod QR", + 167798282: "Utwórz kod QR z tekstu?", + 2767642191: "Utworzony:", + 3513215254: "Niestandardowy kod QR", + 124617190: "Wytnij głębokość", + 597912140: "Metoda cięcia", + 2504034831: "Dziesiętny", + 2751113454: "Odszyfrować?", + 3510912550: "Usuń %s?", + 1016609898: "Usunąć plik?", + 1364509700: "Usuń mnemonic", + 4102535566: "Głębokość na przepustkę", + 2791699253: "Pochodzenie: %s", + 1230133196: "Nie wykryto pamięci flash urządzenia.", + 3836852788: "Zrobione?", + 382368239: "Kierowca", + 3978947916: "Enkoder", + 4090746898: "Encoder Debunet", + 374684711: "Szyfrowanie mnemoniki", + 1244124409: "Zaszyfrowany kod QR", + 2968548114: "Szyfrowana mnemonika nie była przechowywana", + 3315319371: "Szyfrowana mnemonika była przechowywana z ID:", + 350279787: "Szyfrowanie", + 2601598799: "Tryb szyfrowania", + 3504179008: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę od 1 do 2048 r.", + 1100685007: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w heksadecimal od 1 do 800.", + 4090266642: "Wprowadź każde słowo swojego mnemonika BIP-39 jako liczbę w wysokości od 1 do 4000.", + 2780625730: "Wprowadź każde słowo swojego mnemonika BIP-39.", + 784361051: "Błąd:\n%s", + 1505332462: "wyjście", + 3838465623: "Eksplorować pliki?", + 4170881190: "Eksportowanie do karty SD ..", + 1711312434: "Rozszerzony klucz publiczny", + 383371114: "Nie udało się odszyfrować", + 3048830188: "Nie udało się załadować PSBT", + 4192663412: "Nie udało się załadować adresu", + 1996021743: "Nie udało się załadować klucza", + 1108715658: "Nie udało się załadować wiadomości", + 1081425878: "Nie udało się załadować mnemonika", + 928667220: "Nie udało się załadować deskryptora wyjściowego", + 1620572516: "Nie udało się załadować pseudonim", + 2946146830: "Nie udało się przechowywać mnemonika", + 1303554751: "Opłata:", + 104500973: "Szybkość pasz", + 3313339187: "Nazwa pliku", + 1982637349: "Nazwa pliku %s istnieje na karcie SD, zastąp?", + 3737729752: "Odcisk palca: %s", + 2542772894: "Oprogramowanie układowe przekracza maksymalny rozmiar: %D", + 1406590538: "Średnica fletu", + 3086093110: "Bezpłatny:", + 1893243331: "Z przechowywania", + 4120536442: "Grbl", + 299338213: "Podaj temu mnemonicznemu identyfikatorowi?W przeciwnym razie zostanie użyty obecny odcisk palca", + 602716148: "Iść", + 3580020863: "Hex Key Public", + 2691246967: "Szesnastkowy", + 2736309107: "ID już istnieje\n", + 1706005805: "inComplete Descriptor", + 631342955: "Wejścia (%d):", + 2585599782: "Błędny adres", + 2874529150: "Nieprawidłowy bootloader", + 4093416954: "Nieprawidłowa długość mnemoniczna", + 1422874211: "Nieprawidłowy klucz publiczny", + 2443867979: "Nieprawidłowy portfel:\n%s", + 4122897393: "Odwracać", + 3000888649: "Klucz", + 2686333978: "Klucz:", + 4123798664: "Krux\n\n\neversion\n%s", + 3835918229: "Test drukarki Krux QR", + 766317539: "Język", + 972436696: "Opóźnienie linii", + 3596093890: "Linia:", + 2820726296: "Ładuj mnemoniczne", + 879727077: "Załaduj z karty SD?", + 669106195: "Załaduj jeden?", + 3330705289: "Obciążenie?", + 2596531078: "Ładowanie aparatu ..", + 596389387: "Ładowanie ZMIANY Adres %D ..", + 336702608: "Ładowanie drukarki ..", + 2538883522: "Ładowanie adresu odbierania %d ..", + 3159494909: "Ładowanie..", + 1177338798: "Widownia", + 2817059741: "Lokalizacja", + 63976957: "Poziom dziennika", + 86530918: "Logowanie", + 2917810189: "Maksymalna długość przekroczona (%s)", + 2030045667: "Wiadomość", + 3928301843: "Brakujący plik podpisu", + 1948316555: "Mnemoniczny", + 2123991188: "Mnemoniczne id", + 3911073154: "Mnemoniczny identyfikator przechowywania", + 570639842: "Mnemonik nie został odszyfrowany", + 1746030071: "Mnemoniczny nie był szyfrowany", + 1458925155: "Zmodyfikowany:", 1845376098: "Multisig", - 2939797024: "Netzwerk", - 73574491: "Neue Mnemonic", - 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", - 4063104189: "Nein", - 3927838899: "Keine BIP39 Passphrase", - 4092516657: "Nicht genug Würfe!", - 1577637745: "Oktal", - 3312581301: "PBKDF2-Iter.", + 2939797024: "Sieć", + 73574491: "Nowy Mnemonic", + 2792272353: "Wykryto nowe oprogramowanie.\n\nsha256:\n%s\n\n\n\ninstall?", + 4063104189: "NIE", + 3927838899: "Brak frazy BIP39", + 4092516657: "Za mało rolki!", + 1577637745: "Octal", + 3312581301: "PBKDF2 ITER.", 721090621: "PSBT", - 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", - 2987800462: "Papierbreite", - 3050763890: "Teil\n%d / %d", - 3559456868: "Teilegröße", - 4249903283: "Passphrase", - 3712257341: "Passphrase:", - 140802882: "Speicher", - 1703779997: "Klartext-QR", - 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", - 784609464: "Tauchrate", - 3037062877: "Drucke Test-QR", - 4278257699: "Als QR-Code drucken?\n\n%s\n\n", - 516488026: "Drucken?\n\n%s\n\n", - 1123106929: "Drucker", - 3903571079: "Druckertreiber nicht gesetzt!", - 2609799302: "Drucken\n%d / %d", - 844861889: "Wird gedruckt ...", - 2580599003: "Weiter?", - 556126964: "Wird bearbeitet ...", - 1848310591: "QR-Code", - 710709610: "RX Pin", - 2697857197: "Empfangen", - 1746677167: "Empfangsadresse", - 364354944: "Region: ", - 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", - 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", - 856795528: "Würfe:\n\n%s", - 255086803: "Würfe: %d\n", - 3976793317: "SD-Karte", - 2827687530: "SD-Karte nicht erkannt", - 2736513298: "SD-Karte nicht erkannt.", - 3593785196: "SHA256 der Würfe:\n\n%s", - 1143278725: "SHA256 des Snapshots:\n\n%s", + 995862913: "Parzyj kropki czarne, aby można je było wykryć.", + 2987800462: "Szerokość papieru", + 3050763890: "Część\n %d / %d", + 3559456868: "Rozmiar części", + 4249903283: "Fraza", + 3712257341: "FRASSE:", + 140802882: "Trwać", + 1703779997: "PlainText QR", + 3561756278: "Załaduj deskryptor wyjściowy portfela", + 784609464: "Szybkość spadku", + 3037062877: "Test wydrukuj QR", + 4278257699: "Drukuj do qr?\n\n%s\n\n", + 516488026: "Wydrukować?\n\n%s\n\n", + 1123106929: "Drukarka", + 3903571079: "Sterownik drukarki nie jest ustawiony!", + 2609799302: "Drukowanie\n %d / %d", + 844861889: "Drukowanie ...", + 2580599003: "Przystępować?", + 556126964: "Przetwarzanie ...", + 1848310591: "Kod QR", + 710709610: "Pin Rx", + 2697857197: "Odbierać", + 1746677167: "Odbierać adresy", + 364354944: "Region:", + 1662254634: "Przejrzyj zeskanowane dane, w razie potrzeby edytuj", + 770350922: "Rzuć kostkę co najmniej %d, aby wygenerować mnemoniczny.", + 856795528: "Rolls:\n\n%s", + 255086803: "Rolls: %d\n", + 3976793317: "karta SD", + 2827687530: "Karta SD nie została wykryta", + 2736513298: "Karta SD nie została wykryta.", + 3593785196: "SHA256 Rolls:\n\n%s", + 1143278725: "SHA256 migawki:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Auf SD-Karte speichern?", - 810036588: "Auf SD-Karte gespeichert:\n%s", + 3531742595: "Zapisz na karcie SD?", + 810036588: "Zapisano na karcie SD:\n%s", 763824768: "Skala", - 4117455079: "Adresse\nscannen", - 3219991109: "Scan BIP39 Passphrase", - 2537207336: "Schlüssel QR-Code scannen", - 4006316572: "Wörter 1-12 erneut scannen", - 2736506158: "Wörter 13-24 scannen", - 266935239: "SeedQR", - 1698829144: "Selbstübertragung oder Change (%d): ", - 473154195: "Einstellungen", - 1825881236: "Ausschalten", - 2120776272: "Herunterfahren..", - 1061961408: "Signieren", - 4282338366: "Signieren?", - 746161122: "Signatur", - 1988416729: "Signierte Nachricht", - 3672006076: "Signierte PSBT", - 2281377987: "Single-Sig", - 4221794628: "Größe: ", - 2344747135: "Einige Schecks können nicht durchgeführt werden.", - 2309020186: "Ausgabe (%d): ", + 4117455079: "Adres skanowania", + 3219991109: "Scan BIP39 Passhraz", + 2537207336: "Skanuj kod QR", + 4006316572: "Znowu skanowanie słów 1-12", + 2736506158: "Skanowanie słów 13-24", + 3593497655: "Wygaszacz ekranu", + 266935239: "Seedqr", + 1698829144: "Samo-transfer lub zmiana (%d):", + 473154195: "Ustawienia", + 1825881236: "Zamknięcie", + 2120776272: "Wyłączanie..", + 1061961408: "Podpisać", + 4282338366: "Podpisać?", + 746161122: "Podpis", + 1988416729: "Podpisana wiadomość", + 3672006076: "Podpisano PSBT", + 2281377987: "Pojedyncze Sig", + 4221794628: "Rozmiar:", + 2344747135: "Nie można wykonać niektórych kontroli.", + 2309020186: "Wydać (%d):", 3355862324: "Stackbit 1248", - 3303592908: "Auf Flash speichern", - 720041451: "Auf der SD-Karte speichern", - 3514476519: "Wischen um den Modus zu ändern", - 1898550184: "TOUCH oder ENTER zum Erfassen", - 4228215415: "TX Pin", - 2612594937: "Text", - 1454688268: "Thema", - 1180180513: "Thermisch", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Werkzeuge", - 3684696112: "Berühre Schwellenwert", - 2978718564: "Touchscreen", - 2732611775: "Weiter versuchen?", - 1487826746: "BIP39 Passphrase eingeben", - 2061556020: "Schlüssel eingeben", - 2089395053: "Einheit", - 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", - 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", - 2736001501: "Firmware wird aktualisiert..\n\n%d%%", - 2674953168: "Verwende eine schwarze Hintergrundfläche.", - 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", - 236075140: "Belegt: ", - 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", - 4191058607: "Via Kamera", + 3303592908: "Przechowuj na Flash", + 720041451: "Przechowuj na karcie SD", + 3514476519: "Przesuń tryb zmiany", + 1898550184: "Dotknij lub wejdź do przechwytywania", + 4228215415: "Pin TX", + 2612594937: "Tekst", + 1454688268: "Temat", + 1180180513: "Termiczny", + 4119292117: "Małe ziarno", + 1732872974: "Małe nasiona (bity)", + 725348723: "Narzędzia", + 3684696112: "Próg dotykowy", + 2978718564: "Ekran dotykowy", + 2732611775: "Próbuj bardziej?", + 1487826746: "Passówka typu BIP39", + 2061556020: "Klucz typu", + 2089395053: "Jednostka", + 2845607430: "Aktualizacja bootloader ..\n\n%d %%", + 4164597446: "Uaktualnienie zakończone.\n\nshutting w dół ..", + 2736001501: "Aktualizacja oprogramowania układowego ..\n\n%d %%", + 2674953168: "Użyj czarnej powierzchni tła.", + 2402455261: "Użyj entropii aparatu, aby stworzyć nowy mnemonik", + 236075140: "Używany:", + 4003084591: "Wartość %s z zakresu: [ %s, %s]", + 4191058607: "Za pośrednictwem aparatu", 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Via manueller Eingabe", - 2504354847: "Warte auf die Erfassung", - 2297028319: "Wallet-Deskriptor", - 4232654916: "Wallet Ausgabedeskriptor", - 2587172867: "Wallet Ausgabedeskriptor geladen!", - 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", - 2671738224: "Warnung:", - 797660533: "Wort %d", - 3742424146: "Wortnummern", - 2965123464: "Wörter", - 1303016265: "Ja", - 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", - 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", + 525309547: "Przez D6", + 590330112: "Poprzez ręczne wejście", + 2504354847: "Poczekaj na schwytanie", + 3992434312: "Czas oczekiwania", + 2297028319: "Deskryptor portfela", + 4232654916: "Deskryptor wyjściowy portfela", + 2587172867: "Załadowany deskryptor wyjściowy portfela!", + 2499782468: "Nie znaleziono deskryptora wyjściowego portfela.", + 2671738224: "Ostrzeżenie:", + 797660533: "Słowo %d", + 3742424146: "Numery słów", + 2965123464: "Słowa", + 1303016265: "Tak", + 771968845: "Twoje zmiany będą przechowywane w pamięci flash urządzenia.", + 2569054451: "Twoje zmiany będą przechowywane na karcie SD.", + }, + "pt-BR": { + 1185266064: "%d da %d multisig", + 2004520398: "%d. Troco: \n\n%s\n\n", + 3862364126: "%d. Autotransferência: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n é um endereço de troco válido!", + 3921290840: "%s\n\né um endereço de recepção válido!", + 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", + 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", + 3348584292: "(Experimental)", + 2739590230: "12 palavras", + 1310058127: "24 palavras", + 2743272264: "ABC", + 1949634023: "Sobre", + 1517128857: "Adafruit", + 3270727197: "Endereço", + 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", + 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", + 88746165: "Antirreflexo desativado", + 1521033296: "Antirreflexo ativado", + 1056821534: "Tem certeza?", + 3247612282: "Mnemônico BIP39", + 3455872521: "Voltar", + 2541860807: "Backing up bootloader..\n\n%d%%", + 2256777600: "Assinatura Inválida", + 3937333362: "Baudrate", + 427617266: "Bitcoin", + 928727036: "Borda", + 213030954: "CNC", + 1207696150: "Troco", + 3126552510: "Endereços de Troco", + 1583186953: "Mudar o tema e reiniciar?", + 2697733395: "Mudanças salvas no cartão SD!", + 388908871: "Alterações só durarão até o desligamento.", + 3442025874: "Verifique o cartão SD", + 3119547911: "Verificar se este endereço pertence a carteira?", + 2856261511: "Endereço de troco %d não corresponde.", + 2788541416: "Endereço de recebimento %d não corresponde.", + 2446472910: "Verificando correspondência do endereço de troco %d ..", + 2470115694: "Verificando o cartão SD..", + 3655273987: "Verificando correspondência do endereço de recebimento %d ..", + 2407028014: "SeedQR Compacto", + 4041895036: "Continuar?", + 4094072796: "Gerar Código QR", + 167798282: "Gerar código QR do texto?", + 2767642191: "Criado: ", + 3513215254: "Código QR Customizado", + 124617190: "Profundidade de Corte", + 597912140: "Método de Corte", + 2504034831: "Decimal", + 2751113454: "Descriptografar?", + 3510912550: "Excluir %s?", + 1016609898: "Excluir Arquivo?", + 1364509700: "Excluir Mnemônico", + 4102535566: "Profundidade da Passagem", + 2791699253: "Derivação: %s", + 1230133196: "Armazenamento flash do dispositivo não detectado.", + 3836852788: "Feito?", + 382368239: "Driver", + 3978947916: "Codificador", + 4090746898: "Debounce do Encoder", + 374684711: "Criptografar Mnemônico", + 1244124409: "Código QR Criptografado", + 2968548114: "Mnemonic criptografado não foi armazenado", + 3315319371: "Mnemônico criptografado foi armazenado com ID:", + 350279787: "Criptografia", + 2601598799: "Modo de Criptografia", + 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", + 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", + 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", + 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", + 784361051: "Erro:\n%s", + 1505332462: "Esc", + 3838465623: "Explorar arquivos?", + 4170881190: "Exportando para o cartão SD..", + 1711312434: "Chave Pública Estendida", + 383371114: "Falhou em descriptografar", + 3048830188: "Falhou ao carregar PSBT", + 4192663412: "Falhou ao carregar endereço", + 1996021743: "Falha ao carregar a chave", + 1108715658: "Falhou ao carregar mensagem", + 1081425878: "Falhou ao carregar mnemônico", + 928667220: "Falha ao carregar o descritor de saída", + 1620572516: "Falha ao carregar a senha", + 2946146830: "Falhou ao armazenar mnemônico", + 1303554751: "Taxa: ", + 104500973: "Taxa de Alimentação", + 3313339187: "Nome do arquivo", + 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", + 3737729752: "Impressão digital: %s", + 2542772894: "Firmware excede o tamanho máximo: %d", + 1406590538: "Diâmetro da Fresa", + 3086093110: "Livre: ", + 1893243331: "Do Armazenamento", + 4120536442: "GRBL", + 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", + 602716148: "Ir", + 3580020863: "Chave pública hexadecimal", + 2691246967: "Hexadecimal", + 2736309107: "Id já existe\n", + 1706005805: "Descritor incompleto", + 631342955: "Entradas (%d): ", + 2585599782: "Endereço inválido", + 2874529150: "Bootloader inválido", + 4093416954: "Comprimento de mnemônico inválido", + 1422874211: "Chave pública inválida", + 2443867979: "Carteira inválida:\n%s", + 4122897393: "Invertido", + 3000888649: "Chave", + 2686333978: "Chave:", + 4123798664: "Krux\n\n\nVersão\n%s", + 3835918229: "Teste de impressão de QR krux", + 766317539: "Língua", + 972436696: "Atraso de Linha", + 3596093890: "Linha: ", + 2820726296: "Carregar Mnemônico", + 879727077: "Carregar do cartão SD?", + 669106195: "Carregar um?", + 3330705289: "Carregar?", + 2596531078: "Carregando Câmera..", + 596389387: "Carregando endereço de troco %d..", + 336702608: "Carregando impressora..", + 2538883522: "Carregando endereço de recebimento %d..", + 3159494909: "Carregando..", + 1177338798: "Idioma", + 2817059741: "Local", + 63976957: "Nível de log", + 86530918: "Logging", + 2917810189: "Comprimento máximo excedido (%s)", + 2030045667: "Mensagem", + 3928301843: "Arquivo de assinatura faltando", + 1948316555: "Mnemônico", + 2123991188: "ID do mnemônico", + 3911073154: "ID de armazenamento", + 570639842: "Mnemônico não foi descriptografado", + 1746030071: "Mnemônico não foi criptografado", + 1458925155: "Modificado:", + 1845376098: "Multisig", + 2939797024: "Rede", + 73574491: "Novo Mnemônico", + 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", + 4063104189: "Não", + 3927838899: "Sem senha BIP39", + 4092516657: "Jogadas insuficientes!", + 1577637745: "Octal", + 3312581301: "Iter. PBKDF2", + 721090621: "PSBT", + 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", + 2987800462: "Largura do papel", + 3050763890: "Parte\n%d / %d", + 3559456868: "Tamanho da peça", + 4249903283: "Senha", + 3712257341: "Senha:", + 140802882: "Salvar", + 1703779997: "QR em Texto", + 3561756278: "Carregue um descritor da carteira", + 784609464: "Taxa de Mergulho", + 3037062877: "Imprimir QR de teste", + 4278257699: "Imprimir QR?\n\n%s\n\n", + 516488026: "Imprimir?\n\n%s\n\n", + 1123106929: "Impressora", + 3903571079: "Driver de impressora não está definido!", + 2609799302: "Imprimindo\n%d / %d", + 844861889: "Imprimindo ...", + 2580599003: "Seguir?", + 556126964: "Processando ...", + 1848310591: "Código QR", + 710709610: "Pino RX", + 2697857197: "Recebimento", + 1746677167: "Endereços de Recebimento", + 364354944: "Região: ", + 1662254634: "Revise os dados, edite se necessário", + 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", + 856795528: "Jogadas:\n\n%s", + 255086803: "Jogadas: %d\n", + 3976793317: "Cartão SD", + 2827687530: "Cartão SD não detectado", + 2736513298: "Cartão SD não detectado.", + 3593785196: "SHA256 de jogadas:\n\n%s", + 1143278725: "Sha256 da imagem:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Salvar no cartão SD?", + 810036588: "Salvo no cartão SD:\n%s", + 763824768: "Escala", + 4117455079: "Escanear Endereço", + 3219991109: "Escanear a senha BIP39", + 2537207336: "Escanear código QR da chave", + 4006316572: "Escaneando as palavras 1-12 novamente", + 2736506158: "Escaneando as palavras 13-24", + 3593497655: "Protetor de tela", + 266935239: "SeedQR", + 1698829144: "Autotransferência ou Troco (%d): ", + 473154195: "Configurações", + 1825881236: "Desligar", + 2120776272: "Desligando..", + 1061961408: "Assinar", + 4282338366: "Assinar?", + 746161122: "Assinatura", + 1988416729: "Mensagem Assinada", + 3672006076: "PSBT Assinada", + 2281377987: "Single-sig", + 4221794628: "Total: ", + 2344747135: "Algumas verificações não podem ser realizadas.", + 2309020186: "Gastos (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Armazene na Flash", + 720041451: "Armazene no Cartão SD", + 3514476519: "Deslize para mudar de modo", + 1898550184: "TOQUE ou ENTER para capturar", + 4228215415: "Pino TX", + 2612594937: "Texto", + 1454688268: "Tema", + 1180180513: "Térmica", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (bits)", + 725348723: "Ferramentas", + 3684696112: "Limiar de Toque", + 2978718564: "Touchscreen", + 2732611775: "Tentar mais?", + 1487826746: "Digitar a senha BIP39", + 2061556020: "Digite a Chave", + 2089395053: "Unidade", + 2845607430: "Atualizando bootloader..\n\n%d%%", + 4164597446: "Atualização completa.\n\nDesligando..", + 2736001501: "Atualizando firmware..\n\n%d%%", + 2674953168: "Use uma superfície de fundo preta.", + 2402455261: "Use a entropia da câmera para criar um novo mnemônico", + 236075140: "Usado: ", + 4003084591: "Valor %s fora do alcance: [ %s, %s]", + 4191058607: "Pela Câmera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Por entrada manual", + 2504354847: "Aguarde a captura", + 3992434312: "Tempo de espera", + 2297028319: "Descritor de Carteira", + 4232654916: "Descritor da carteira", + 2587172867: "Descritor de saída da carteira carregado!", + 2499782468: "O descritor de saída da carteira não foi encontrado.", + 2671738224: "Aviso:", + 797660533: "Palavra %d", + 3742424146: "Números das Palavras", + 2965123464: "Palavras", + 1303016265: "Sim", + 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", + 2569054451: "Suas alterações serão mantidas no cartão SD.", + }, + "ru-RU": { + 1185266064: "%d из %d мультиподпись", + 2004520398: "%d. Сдача: \n\n%s\n\n", + 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", + 3264377309: "%d. Расход: \n\n%s\n\n", + 2399232215: "%s\n\nвалидный адрес сдачи!", + 3921290840: "%s\n\nвалидный адрес получения!", + 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", + 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", + 3348584292: "(Эксперементальный)", + 2739590230: "12 слов", + 1310058127: "24 слова", + 2743272264: "ABC", + 1949634023: "О Программе", + 1517128857: "Adafruit", + 3270727197: "Адрес", + 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", + 283202181: "Правильно совместите камеру и Мини Сид-фразу.", + 88746165: "Антиблик отключен", + 1521033296: "Антиблик включен", + 1056821534: "Вы уверены?", + 3247612282: "BIP39 Мнемоника", + 3455872521: "Назад", + 2541860807: "Резервное копирование загрузчика..\n\n%d%%", + 2256777600: "Плохая подпись", + 3937333362: "Скорость Передачи Данных", + 427617266: "Биткоин", + 928727036: "Заполнение границ", + 213030954: "CNC", + 1207696150: "Сдача", + 3126552510: "Адрес Сдачи", + 1583186953: "Сменить тему и перезагрузить?", + 2697733395: "Изменения сохранены на SD карте!", + 388908871: "Изменения будут храниться до выключения.", + 3442025874: "Проверить SD Карту", + 3119547911: "Проверить, что адрес принадлежит этому кошельку?", + 2856261511: "Проверено %d адресов сдачи без совпадений.", + 2788541416: "Проверено %d адресов получения без совпадений.", + 2446472910: "Проверяем адрес сдачи %d на совпадение..", + 2470115694: "Проверка SD карты..", + 3655273987: "Проверяем адрес получения %d на совпадение..", + 2407028014: "Компактный SeedQR", + 4041895036: "Продолжить?", + 4094072796: "Создать QR Код", + 167798282: "Создать QR код из текста?", + 2767642191: "Создано", + 3513215254: "Пользовательский QR Код", + 124617190: "Глубина Резки", + 597912140: "Метод Резки", + 2504034831: "Десятичный", + 2751113454: "Расшифровать?", + 3510912550: "Удалить %s?", + 1016609898: "Удалить Файл?", + 1364509700: "Удалить Мнемонику", + 4102535566: "Глубина За Проход", + 2791699253: "Производный путь: %s", + 1230133196: "Флэш память устройства не обнаружена.", + 3836852788: "Готово?", + 382368239: "Драйвер", + 3978947916: "Кодер", + 4090746898: "Дебаунс Кодера", + 374684711: "Зашифровать Мнемонику", + 1244124409: "Зашифрованный QR Код", + 2968548114: "Зашифрованная мнемоника не была сохранена", + 3315319371: "Зашифрованная мнемоника была сохранена с ID: ", + 350279787: "Шифрование", + 2601598799: "Метод шифрования", + 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", + 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", + 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", + 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", + 784361051: "Ошибка:\n%s", + 1505332462: "Выйти", + 3838465623: "Исследовать файлы?", + 4170881190: "Экспортирование на SD карту..", + 1711312434: "Расширенный Публичный Ключ", + 383371114: "Не удалось расшифровать", + 3048830188: "Не удалось загрузить PSBT", + 4192663412: "Не удалось загрузить адрес", + 1996021743: "Не удалось загрузить ключ", + 1108715658: "Не удалось загрузить сообщение", + 1081425878: "Не удалось загрузить мнемонику", + 928667220: "Не удалось загрузить выходной дескриптор", + 1620572516: "Не удалось загрузить фразу-пароль", + 2946146830: "Не удалось сохранить мнемонику", + 1303554751: "Комиссия: ", + 104500973: "Скорость подачи", + 3313339187: "Имя файла", + 1982637349: "Файл %s существует на SD карте, перезаписать?", + 3737729752: "Фингерпринт: %s", + 2542772894: "Прошивка превышает максимальный размер: %d", + 1406590538: "Flute Диаметр", + 3086093110: "Бесплатно: ", + 1893243331: "Из Памяти", + 4120536442: "GRBL", + 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", + 602716148: "OK", + 3580020863: "Шестнадцатеричный Публичный Ключ", + 2691246967: "Шестнадцатеричный", + 2736309107: "ID уже существует\n", + 1706005805: "Неполный выходной дескриптор", + 631342955: "Входы (%d): ", + 2585599782: "Неверный адрес", + 2874529150: "Неверный загрузчик", + 4093416954: "Неверная длина мнемоники", + 1422874211: "Неверный публичный ключ", + 2443867979: "Неверный кошелек:\n%s", + 4122897393: "Инвертировать", + 3000888649: "Ключ", + 2686333978: "Ключ: ", + 4123798664: "Krux\n\n\nВерсия\n%s", + 3835918229: "Тестовый QR Принтера Krux", + 766317539: "Язык", + 972436696: "Задержка Линии", + 3596093890: "Линия: ", + 2820726296: "Загрузить Мнемонику", + 879727077: "Загрузить с SD карты?", + 669106195: "Загрузить одну?", + 3330705289: "Загрузить?", + 2596531078: "Загрузка Камеры..", + 596389387: "Загрузка адреса сдачи %d..", + 336702608: "Загрузка принтера..", + 2538883522: "Загрузка адреса получения %d..", + 3159494909: "Загрузка..", + 1177338798: "Локаль", + 2817059741: "Расположение", + 63976957: "Уровень логирования", + 86530918: "Логирование", + 2917810189: "Максимальная длина превышена (%s)", + 2030045667: "Сообщение", + 3928301843: "Отсутствует файл подписи", + 1948316555: "Мнемоника", + 2123991188: "ID мнемоники", + 3911073154: "ID памяти мнемоники", + 570639842: "Мнемоника не была расшифрована", + 1746030071: "Мнемоника не была зашифрована", + 1458925155: "Изменено: ", + 1845376098: "Мультиподпись", + 2939797024: "Сеть", + 73574491: "Новая Мнемоника", + 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", + 4063104189: "Нет", + 3927838899: "Без BIP39 фразы-пароля", + 4092516657: "Недостаточно бросков!", + 1577637745: "Восьмеричный", + 3312581301: "PBKDF2 Итерации", + 721090621: "PSBT", + 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", + 2987800462: "Ширина Бумаги", + 3050763890: "Часть\n%d / %d", + 3559456868: "Размер Части", + 4249903283: "Фраза-пароль", + 3712257341: "Фраза-пароль: ", + 140802882: "Постоянная Память", + 1703779997: "QR открытым текстом", + 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", + 784609464: "Скорость Погружения", + 3037062877: "Напечатать Тестовый QR", + 4278257699: "Напечатать в виде QR?\n\n%s\n\n", + 516488026: "Печатать?\n\n%s\n\n", + 1123106929: "Принтер", + 3903571079: "Драйвер Принтера не установлен!", + 2609799302: "Идет печать\n%d / %d", + 844861889: "Идет печать ...", + 2580599003: "Продолжить?", + 556126964: "Обработка ...", + 1848310591: "QR Код", + 710709610: "RX Пин", + 2697857197: "Получить", + 1746677167: "Адрес Получения", + 364354944: "Регион: ", + 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", + 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", + 856795528: "Броски:\n\n%s", + 255086803: "Броски: %d\n", + 3976793317: "SD карта", + 2827687530: "SD карта не обнаружена", + 2736513298: "SD карта не обнаружена.", + 3593785196: "SHA256 бросков:\n\n%s", + 1143278725: "SHA256 снэпшота:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Сохранить на SD карту?", + 810036588: "Сохранено на SD карту:\n%s", + 763824768: "Шкала", + 4117455079: "Отсканировать Адрес", + 3219991109: "Отсканировать BIP39 фразу-пароль", + 2537207336: "Отсканировать Ключ QR код", + 4006316572: "Сканирование слов 1-12 снова", + 2736506158: "Сканирование слов 13-24", + 3593497655: "Заставка", + 266935239: "SeedQR", + 1698829144: "Трансфер самому себе или Сдача (%d): ", + 473154195: "Настройки", + 1825881236: "Выключить", + 2120776272: "Выключение..", + 1061961408: "Подписать", + 4282338366: "Подписать?", + 746161122: "Подпись", + 1988416729: "Подписанное Сообщение", + 3672006076: "Подписанное PSBT", + 2281377987: "Одна подпись", + 4221794628: "Размер: ", + 2344747135: "Некоторые проверки не могут быть выполнены.", + 2309020186: "Расход (%d): ", + 3355862324: "Стэкбит 1248", + 3303592908: "Сохранить на Флэш Память", + 720041451: "Сохранить на SD Карту", + 3514476519: "Свайпните, чтобы сменить режим", + 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", + 4228215415: "TX Пин", + 2612594937: "Текст", + 1454688268: "Тема", + 1180180513: "Термальный", + 4119292117: "Мини Сид-фраза", + 1732872974: "Мини Сид-фраза (Биты)", + 725348723: "Инструменты", + 3684696112: "Прикоснитесь Границы", + 2978718564: "Тачскрин", + 2732611775: "Попробовать ещё?", + 1487826746: "Введите BIP39 фразу-пароль", + 2061556020: "Введите Ключ", + 2089395053: "Юнит", + 2845607430: "Обновление загрузчика..\n\n%d%%", + 4164597446: "Обновление завершено.\n\nВыключение..", + 2736001501: "Обновление прошивки..\n\n%d%%", + 2674953168: "Использовать черную фоновую поверхность.", + 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", + 236075140: "Использовано: ", + 4003084591: "Значение %s вне диапозона: [%s, %s]", + 4191058607: "С Помощью Камеры", + 1254681955: "С Помощью D20", + 525309547: "С Помощью D6", + 590330112: "С Помощью Ручного Ввода", + 2504354847: "Дождитесь Захвата", + 3992434312: "Время ожидания", + 2297028319: "Дескриптор Кошелька", + 4232654916: "Выходной дескриптор кошелька", + 2587172867: "Выходной дескриптор кошелька загружен!", + 2499782468: "Выходной дескриптор кошелька не найден.", + 2671738224: "Предупреждение:", + 797660533: "Слово %d", + 3742424146: "Числа Слов", + 2965123464: "Слова", + 1303016265: "Да", + 771968845: "Ваши изменения будут сохранены на флэш памяти устройства.", + 2569054451: "Ваши изменения будут сохранены на SD карте.", }, "vi-VN": { 1185266064: "%d của %d đa chữ kí", @@ -1925,6 +1939,7 @@ 2537207336: "Quét mã QR khóa", 4006316572: "Quét lại từ 1-12", 2736506158: "Quét từ 13-24", + 3593497655: "Bảo vệ màn hình", 266935239: "SEEDQR", 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", 473154195: "Cài đặt", @@ -1969,6 +1984,7 @@ 525309547: "Qua D6", 590330112: "Thông qua đầu vào thủ công", 2504354847: "Chờ bắt", + 3992434312: "Thời gian chờ đợi", 2297028319: "Trình mô tả ví", 4232654916: "Ví đầu ra mô tả", 2587172867: "Đã tải bộ mô tả đầu ra của ví!", diff --git a/tests/test_context.py b/tests/test_context.py index 469c07605..7cb623f49 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -52,6 +52,7 @@ def test_clear_clears_printer(mocker, m5stickv): assert c.wallet is None c.printer.clear.assert_called() + def test_screensaver(mocker, m5stickv): """Test whether the screensaver is animating and changing color over time""" mock_modules(mocker) @@ -73,22 +74,22 @@ def test_screensaver(mocker, m5stickv): ██ ██ ██ ██ """[ - 1:-1 - ].split( - "\n" - ) + 1:-1 + ].split( + "\n" + ) c = Context(logo) # a sequence of events to simulate users waiting and after some time press BUTTON_ENTER btn_seq = [] time_seq = [] - tmp = SCREENSAVER_ANIMATION_TIME +1 + tmp = SCREENSAVER_ANIMATION_TIME + 1 for _ in range(28): time_seq.append(tmp) time_seq.append(tmp) - tmp += SCREENSAVER_ANIMATION_TIME +1 + tmp += SCREENSAVER_ANIMATION_TIME + 1 btn_seq.append(None) - + time_seq.append(tmp) time_seq.append(tmp) btn_seq.append(BUTTON_ENTER) @@ -96,9 +97,12 @@ def test_screensaver(mocker, m5stickv): c.input.wait_for_press = mocker.MagicMock(side_effect=btn_seq) time.ticks_ms = mocker.MagicMock(side_effect=time_seq) - c.screensaver() - c.display.draw_line_hcentered_with_fullw_bg.assert_any_call(logo[10], 10, theme.fg_color, theme.bg_color) - c.display.draw_line_hcentered_with_fullw_bg.assert_any_call(logo[5], 5, theme.bg_color, theme.fg_color) + c.display.draw_line_hcentered_with_fullw_bg.assert_any_call( + logo[10], 10, theme.fg_color, theme.bg_color + ) + c.display.draw_line_hcentered_with_fullw_bg.assert_any_call( + logo[5], 5, theme.bg_color, theme.fg_color + ) c.input.wait_for_press.assert_called() diff --git a/tests/test_display.py b/tests/test_display.py index 5d20e2e7e..a7cc384da 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -402,6 +402,7 @@ def test_draw_hcentered_text(mocker, m5stickv): 23, 50, "Hello world", krux.display.lcd.WHITE, krux.display.lcd.BLACK ) + def test_draw_line_hcentered_with_fullw_bg(mocker, m5stickv): mocker.patch("krux.display.lcd", new=mocker.MagicMock()) import krux @@ -410,14 +411,17 @@ def test_draw_line_hcentered_with_fullw_bg(mocker, m5stickv): d = Display() mocker.patch.object(d, "width", new=lambda: 135) mocker.spy(d, "draw_string") - d.draw_line_hcentered_with_fullw_bg( "Hello world", 10, krux.display.lcd.WHITE, krux.display.lcd.BLACK ) d.draw_string.assert_called_with( - 23, d.font_height * 10, "Hello world", krux.display.lcd.WHITE, krux.display.lcd.BLACK + 23, + d.font_height * 10, + "Hello world", + krux.display.lcd.WHITE, + krux.display.lcd.BLACK, ) krux.display.lcd.fill_rectangle.assert_called() diff --git a/tests/test_input.py b/tests/test_input.py index 557e13a90..389dcda81 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -786,6 +786,7 @@ def release(): assert input.entropy > 0 krux.input.wdt.feed.assert_called() + def test_wait_for_press_screensaver(mocker, m5stickv): from krux.input import Input from krux.krux_settings import Settings @@ -803,13 +804,12 @@ def test_wait_for_press_screensaver(mocker, m5stickv): for _ in range(10): time_seq.append(tmp) tmp += 100 - + time.ticks_ms = mocker.MagicMock(side_effect=time_seq) input.wait_for_press(True, enable_screensaver=True) input.screensaver_fallback.assert_called() - + Settings().screensaver.time = 0 input.wait_for_button(block=False) input.screensaver_fallback.assert_called_once() - diff --git a/tests/test_settings.py b/tests/test_settings.py index def00f454..6451e04a5 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -91,13 +91,14 @@ class TestClass: t.some_setting = 2 assert t.some_setting == 2 + def test_all_labels(mocker, m5stickv): from krux.krux_settings import ( - BitcoinSettings, - I18nSettings, - LoggingSettings, - EncryptionSettings, - PrinterSettings, + BitcoinSettings, + I18nSettings, + LoggingSettings, + EncryptionSettings, + PrinterSettings, ThermalSettings, AdafruitPrinterSettings, CNCSettings, @@ -107,7 +108,7 @@ def test_all_labels(mocker, m5stickv): ScreensaverSettings, TouchSettings, EncoderSettings, - ) + ) bitcoin = BitcoinSettings() i18n = I18nSettings() @@ -138,5 +139,3 @@ def test_all_labels(mocker, m5stickv): assert screensaver.label("time") assert touch.label("threshold") assert encoder.label("debounce") - - From cfe8c71d9e92abe17f9fcc561bcd041761e9f4b5 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Thu, 5 Oct 2023 14:53:55 -0300 Subject: [PATCH 044/114] fix_input_test --- tests/test_input.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_input.py b/tests/test_input.py index 389dcda81..dd503a57a 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -461,8 +461,7 @@ def test_touch_indexing(mocker, amigo_tft): input = reset_input_states(mocker, input) elapsed_time = 0 - mocker.patch.object(input.touch, "event", new=lambda: True) - + def time_control(point1, point2): nonlocal elapsed_time mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) @@ -470,12 +469,14 @@ def time_control(point1, point2): elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) # touch on 3º quadrant + mocker.patch.object(input.touch, "event", new=lambda: True) mocker.patch.object(input.touch.touch_driver, "irq_point", new=lambda: point1) mocker.patch.object( input.touch.touch_driver, "current_point", new=lambda: point1 ) time.sleep(0.1) - # mocker.patch.object(input.touch, "event", new=lambda: False) + mocker.patch.object(input.touch, "event", new=lambda: False) + time.sleep(0.1) elapsed_time += 200 mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) # touch slightly sideways before release From e901c2ef09ba974acfa37f4b42df571ddd449b3f Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Sat, 7 Oct 2023 16:35:41 -0300 Subject: [PATCH 045/114] add screensaver as a appearance setting --- pyproject.toml | 2 +- src/krux/input.py | 4 ++-- src/krux/krux_settings.py | 19 ++++--------------- src/krux/metadata.py | 2 +- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 445a888ff..755dd2e74 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ [tool.poetry] name = "krux" -version = "24.04.beta1" +version = "24.04.beta3" description = "Open-source signing device firmware for Bitcoin" authors = ["Jeff S "] diff --git a/src/krux/input.py b/src/krux/input.py index 791652c40..035f01312 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -204,7 +204,7 @@ def wait_for_press( and enable_screensaver and not self.screensaver_active and self.screensaver_fallback - and self.screensaver_time + (Settings().screensaver.time * 60000) + and self.screensaver_time + (Settings().appearance.screensaver_time * 60000) < time.ticks_ms() ): self.screensaver_active = True @@ -219,7 +219,7 @@ def wait_for_button(self, block=True, enable_screensaver=False): """Waits for any button to release, optionally blocking if block=True. Returns the button that was released, or None if non blocking. """ - if Settings().screensaver.time == 0: + if Settings().appearance.screensaver_time == 0: enable_screensaver = False btn = self.wait_for_press(block, enable_screensaver=enable_screensaver) diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index 6ad8c32c4..acb3d33f2 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -363,27 +363,18 @@ class ThemeSettings(SettingsNamespace): } namespace = "settings.appearance" theme = CategorySetting("theme", DARK_THEME_NAME, list(THEME_NAMES.values())) + screensaver_time = NumberSetting(int, "screensaver_time", 5, [0, 30]) def label(self, attr): """Returns a label for UI when given a setting name or namespace""" return { "theme": t("Theme"), - }[attr] - - -class ScreensaverSettings(SettingsNamespace): - """Screensaver settings""" - - namespace = "settings.screensaver" - time = NumberSetting(int, "time", 5, [0, 30]) + "screensaver_time": t("Screensaver time"), - def label(self, attr): - """Returns a label for UI when given a setting name or namespace""" - return { - "time": t("Wait time"), }[attr] + class Settings(SettingsNamespace): """The top-level settings namespace under which other namespaces reside""" @@ -397,7 +388,6 @@ def __init__(self): self.encryption = EncryptionSettings() self.persist = PersistSettings() self.appearance = ThemeSettings() - self.screensaver = ScreensaverSettings() def label(self, attr): """Returns a label for UI when given a setting name or namespace""" @@ -408,8 +398,7 @@ def label(self, attr): "logging": t("Logging"), "encryption": t("Encryption"), "persist": t("Persist"), - "appearance": t("Theme"), - "screensaver": t("Screensaver"), + "appearance": t("Appearance"), } return main_menu[attr] diff --git a/src/krux/metadata.py b/src/krux/metadata.py index 9c0aeaebf..7590dad98 100644 --- a/src/krux/metadata.py +++ b/src/krux/metadata.py @@ -19,5 +19,5 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -VERSION = "24.04.beta1" +VERSION = "24.04.beta3" SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b" From 42d1b540da58647692a302f4eaadcbeacf69cf13 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Sat, 7 Oct 2023 22:28:33 -0300 Subject: [PATCH 046/114] move flash parameters to firmware.py --- src/krux/firmware.py | 6 +++++- src/krux/pages/settings_page.py | 16 ++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/krux/firmware.py b/src/krux/firmware.py index 7e65f915a..4adfe7ff3 100644 --- a/src/krux/firmware.py +++ b/src/krux/firmware.py @@ -34,14 +34,18 @@ FLASH_MSG_TIME = 2000 +FLASH_SIZE = 2**24 MAX_FIRMWARE_SIZE = 0x300000 FIRMWARE_SLOT_1 = 0x00080000 -FIRMWARE_SLOT_2 = 0x00280000 +FIRMWARE_SLOT_2 = 0x00280000 # TODO: Move to 0x00390000 - Test all possible cases +SPIFFS_ADDR = 0xD00000 MAIN_BOOT_CONFIG_SECTOR_ADDRESS = 0x00004000 BACKUP_BOOT_CONFIG_SECTOR_ADDRESS = 0x00005000 +ERASE_BLOCK_SIZE = 0x10000 + FLASH_IO_WAIT_TIME = 100 diff --git a/src/krux/pages/settings_page.py b/src/krux/pages/settings_page.py index 457166601..cf6495bc4 100644 --- a/src/krux/pages/settings_page.py +++ b/src/krux/pages/settings_page.py @@ -65,11 +65,6 @@ BitcoinSettings.TEST_TXT: GREEN, } -# SPIFFS erase parameters -FLASH_SIZE = 2**24 -SPIFFS_ADDR = 0xD00000 -BLOCK_SIZE = 0x10000 - class SettingsPage(Page): """Class to manage settings interface""" @@ -191,15 +186,16 @@ def erase_spiffs(self): """Erase all SPIFFS, removing all saved configs and mnemonics""" import flash + from ..firmware import FLASH_SIZE, SPIFFS_ADDR, ERASE_BLOCK_SIZE - empty_buf = b"\xff" * BLOCK_SIZE - for address in range(SPIFFS_ADDR, FLASH_SIZE, BLOCK_SIZE): - if flash.read(address, BLOCK_SIZE) == empty_buf: + empty_buf = b"\xff" * ERASE_BLOCK_SIZE + for address in range(SPIFFS_ADDR, FLASH_SIZE, ERASE_BLOCK_SIZE): + if flash.read(address, ERASE_BLOCK_SIZE) == empty_buf: continue - flash.erase(address, BLOCK_SIZE) + flash.erase(address, ERASE_BLOCK_SIZE) def wipe_device(self): - """Fullyu formatts SPIFFS memory""" + """Fully formats SPIFFS memory""" self.ctx.display.clear() if self.prompt( t( From aacc0783b5a1e2b5fd3ee5a85f9901d3dc850e94 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Sat, 7 Oct 2023 22:29:35 -0300 Subject: [PATCH 047/114] fix animated QR event detection black and pylint --- src/krux/display.py | 3 ++- src/krux/input.py | 6 ++++-- src/krux/krux_settings.py | 2 -- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/krux/display.py b/src/krux/display.py index 6d611a3c7..cdae02730 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -315,7 +315,8 @@ def draw_line_hcentered_with_fullw_bg( color=theme.fg_color, bg_color=theme.bg_color, ): - """Draw a line_str horizontally-centered on the display, at qtd_offset_y times font_height, useful for screensaver""" + """Draw a line_str horizontally-centered on the display, at qtd_offset_y times font_height, + useful for screensaver""" lcd.fill_rectangle( 0, qtd_offset_y * self.font_height, self.width(), self.font_height, bg_color ) diff --git a/src/krux/input.py b/src/krux/input.py index 035f01312..8e9f51564 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -180,7 +180,8 @@ def wait_for_press( start_time = time.ticks_ms() while time.ticks_ms() < self.debounce_time + DEBOUNCE: pass - self.flush_events() + if block: + self.flush_events() self.screensaver_time = start_time while True: if self.enter_event(): @@ -204,7 +205,8 @@ def wait_for_press( and enable_screensaver and not self.screensaver_active and self.screensaver_fallback - and self.screensaver_time + (Settings().appearance.screensaver_time * 60000) + and self.screensaver_time + + (Settings().appearance.screensaver_time * 60000) < time.ticks_ms() ): self.screensaver_active = True diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index acb3d33f2..44b0ae363 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -370,11 +370,9 @@ def label(self, attr): return { "theme": t("Theme"), "screensaver_time": t("Screensaver time"), - }[attr] - class Settings(SettingsNamespace): """The top-level settings namespace under which other namespaces reside""" From 972b4a2531d2e6f360c6d6cb7acb13ebe5388b45 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Mon, 9 Oct 2023 14:46:54 -0300 Subject: [PATCH 048/114] tests and simulator printer settings in hardware tests with screensaver settings in appearance --- simulator/kruxsim/mocks/machine.py | 6 ++--- tests/pages/test_home.py | 4 +-- tests/pages/test_login.py | 41 +++++++++++++++++------------- tests/printers/test_cnc.py | 12 ++++----- tests/test_input.py | 4 +-- tests/test_settings.py | 12 +-------- 6 files changed, 38 insertions(+), 41 deletions(-) diff --git a/simulator/kruxsim/mocks/machine.py b/simulator/kruxsim/mocks/machine.py index f5197128f..21f1a2683 100644 --- a/simulator/kruxsim/mocks/machine.py +++ b/simulator/kruxsim/mocks/machine.py @@ -30,7 +30,7 @@ def simulate_printer(): global simulating_printer simulating_printer = True - Settings().printer.driver = "thermal/adafruit" + Settings().hardware.printer.driver = "thermal/adafruit" def reset(): @@ -49,14 +49,14 @@ def __init__(self, pin, baudrate): def read(self, num_bytes): if simulating_printer: - module, cls = PrinterSettings.PRINTERS[Settings().printer.driver] + module, cls = PrinterSettings.PRINTERS[Settings().hardware.printer.driver] if module == "thermal" and cls == "AdafruitPrinter": return chr(0b00000000) return None def readline(self): if simulating_printer: - module, cls = PrinterSettings.PRINTERS[Settings().printer.driver] + module, cls = PrinterSettings.PRINTERS[Settings().hardware.printer.driver] if module == "cnc" and cls == "FilePrinter": return "ok\n".encode() return None diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 4ba34ae9d..342209836 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -91,10 +91,10 @@ def create_ctx(mocker, btn_seq, wallet=None, printer=None, touch_seq=None): ctx.wallet = wallet ctx.printer = printer if printer is None: - Settings().printer.driver = "none" + Settings().hardware.printer.driver = "none" else: mocker.patch("krux.printers.create_printer", new=mocker.MagicMock()) - Settings().printer.driver = THERMAL_ADAFRUIT_TXT + Settings().hardware.printer.driver = THERMAL_ADAFRUIT_TXT if touch_seq: ctx.input.touch = mocker.MagicMock( diff --git a/tests/pages/test_login.py b/tests/pages/test_login.py index 81bd2fe53..9b8107b19 100644 --- a/tests/pages/test_login.py +++ b/tests/pages/test_login.py @@ -1647,13 +1647,11 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): ), ( # 1 ( - # Printer - BUTTON_PAGE, - BUTTON_PAGE, - BUTTON_PAGE, + # Hardware BUTTON_PAGE, BUTTON_PAGE, BUTTON_ENTER, + # TODO: Identify it's printer settings # Thermal BUTTON_PAGE, BUTTON_ENTER, @@ -1672,13 +1670,16 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): BUTTON_PAGE, BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, + BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, ), [ mocker.call("Baudrate\n9600", WHITE), mocker.call("Baudrate\n19200", WHITE), ], - lambda: Settings().printer.thermal.adafruit.baudrate == 19200, + lambda: Settings().hardware.printer.thermal.adafruit.baudrate == 19200, CategorySetting, ), ( # 2 @@ -1686,6 +1687,7 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): # Language BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, # Change Locale BUTTON_PAGE, @@ -1704,6 +1706,7 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): BUTTON_PAGE, BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, # Change log level BUTTON_PAGE, @@ -1716,7 +1719,6 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): BUTTON_PAGE, BUTTON_PAGE, BUTTON_PAGE, - BUTTON_PAGE, BUTTON_ENTER, ), [ @@ -1734,9 +1736,6 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): # Printer BUTTON_PAGE, BUTTON_PAGE, - BUTTON_PAGE, - BUTTON_PAGE, - BUTTON_PAGE, BUTTON_ENTER, # Thermal BUTTON_PAGE, @@ -1773,12 +1772,15 @@ def test_settings_m5stickv(m5stickv, mocker, mocker_printer): BUTTON_PAGE, BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, + BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, ), [ mocker.call("Paper Width", 10), ], - lambda: Settings().printer.thermal.adafruit.paper_width == 389, + lambda: Settings().hardware.printer.thermal.adafruit.paper_width == 389, NumberSetting, ), ] @@ -1818,10 +1820,11 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): GO_INDEX = 1 NEXT_INDEX = 2 - LOCALE_INDEX = 2 - LOGGING_INDEX = 3 - PRINTER_INDEX = 5 - LEAVE_INDEX = 9 + HARDWARE_INDEX = 2 + LOCALE_INDEX = 3 + LOGGING_INDEX = 4 + PRINTER_INDEX = 0 + LEAVE_INDEX = 8 cases = [ ( @@ -1845,6 +1848,8 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): ( # Case 1 ( + # Hardware + HARDWARE_INDEX, # Printer PRINTER_INDEX, # Thermal @@ -1853,10 +1858,12 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): 0, NEXT_INDEX, GO_INDEX, - # Back to Thermal + # Back from Thermal 6, - # Back to Printer + # Back from Printer 3, + # Back from Hardware + 2, # Leave Settings LEAVE_INDEX, ), @@ -1864,7 +1871,7 @@ def test_settings_on_amigo_tft(amigo_tft, mocker, mocker_printer): mocker.call("Baudrate\n9600", WHITE), mocker.call("Baudrate\n19200", WHITE), ], - lambda: Settings().printer.thermal.adafruit.baudrate == 19200, + lambda: Settings().hardware.printer.thermal.adafruit.baudrate == 19200, CategorySetting, ), ( diff --git a/tests/printers/test_cnc.py b/tests/printers/test_cnc.py index 4d4f73e2e..eb48dc49e 100644 --- a/tests/printers/test_cnc.py +++ b/tests/printers/test_cnc.py @@ -81,8 +81,8 @@ def test_print_qr_code_with_row_cutmethod(mocker, m5stickv, mocker_sd_card): ) ) - Settings().printer.cnc.cut_method = "row" - Settings().printer.cnc.invert = False + Settings().hardware.printer.cnc.cut_method = "row" + Settings().hardware.printer.cnc.invert = False p = FilePrinter() @@ -112,8 +112,8 @@ def test_print_qr_code_with_spiral_cutmethod(mocker, m5stickv, mocker_sd_card): ) ) - Settings().printer.cnc.cut_method = "spiral" - Settings().printer.cnc.invert = False + Settings().hardware.printer.cnc.cut_method = "spiral" + Settings().hardware.printer.cnc.invert = False p = FilePrinter() @@ -143,8 +143,8 @@ def test_print_qr_code_inverted(mocker, m5stickv, mocker_sd_card): ) ) - Settings().printer.cnc.cut_method = "spiral" - Settings().printer.cnc.invert = True + Settings().hardware.printer.cnc.cut_method = "spiral" + Settings().hardware.printer.cnc.invert = True p = FilePrinter() diff --git a/tests/test_input.py b/tests/test_input.py index dd503a57a..e95563e50 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -798,7 +798,7 @@ def test_wait_for_press_screensaver(mocker, m5stickv): input.buttons_active = False # Make test faster - Settings().screensaver.time = 0.0001 + Settings().appearance.screensaver_time = 0.0001 time_seq = [] tmp = 100 @@ -811,6 +811,6 @@ def test_wait_for_press_screensaver(mocker, m5stickv): input.wait_for_press(True, enable_screensaver=True) input.screensaver_fallback.assert_called() - Settings().screensaver.time = 0 + Settings().appearance.screensaver_time = 0 input.wait_for_button(block=False) input.screensaver_fallback.assert_called_once() diff --git a/tests/test_settings.py b/tests/test_settings.py index 6451e04a5..da48e7cdb 100644 --- a/tests/test_settings.py +++ b/tests/test_settings.py @@ -9,14 +9,6 @@ def test_init(mocker, m5stickv): assert isinstance(s, Settings) -# @pytest.fixture -# def mocker_sd_card(mocker): -# mocker.patch( -# "os.listdir", -# new=mocker.MagicMock(return_value=["somefile", "otherfile"]), -# ) - - def test_store_init(mocker, m5stickv): from krux.settings import Store, SETTINGS_FILENAME, SD_PATH @@ -105,7 +97,6 @@ def test_all_labels(mocker, m5stickv): GRBLSettings, PersistSettings, ThemeSettings, - ScreensaverSettings, TouchSettings, EncoderSettings, ) @@ -121,7 +112,6 @@ def test_all_labels(mocker, m5stickv): gbrl = GRBLSettings() persist = PersistSettings() appearance = ThemeSettings() - screensaver = ScreensaverSettings() touch = TouchSettings() encoder = EncoderSettings() @@ -136,6 +126,6 @@ def test_all_labels(mocker, m5stickv): assert gbrl.label("tx_pin") assert persist.label("location") assert appearance.label("theme") - assert screensaver.label("time") + assert appearance.label("screensaver_time") assert touch.label("threshold") assert encoder.label("debounce") From 151af69f52a40c0d83f6c4a3d96a0648e2634377 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Mon, 9 Oct 2023 15:05:58 -0300 Subject: [PATCH 049/114] Update to Embit 0.7 keep track of changes with changelog --- CHANGELOG.md | 20 ++ poetry.lock | 715 ++++++++++++++++++++----------------------- src/krux/wallet.py | 4 +- tests/test_wallet.py | 14 +- vendor/embit | 2 +- vendor/urtypes | 2 +- 6 files changed, 365 insertions(+), 392 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56da45efe..d5d6d8f41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,23 @@ +# Changelog 24.04.beta3 - October 9, 2023 + +## Changes + +### IRQ Interfaces +Button and touch presses will be detected by the application through IO interrupts. Meaning inputs events will be registered even if other tasks are being executed by the processor, resulting in a better UX. + +### Restore default settings +Option to restore the device's settings to its factory state. + +### Wipe device +Option on settings to wipe the device, permanently removing settings and stored encrypted mnemonics by erasing every single bit of user's flash space. + +### Screensaver +Optional screensaver to reduce pixels' burn-in and grab attention of the user when the device is left powered on. + +### Update Embit to version 0.7 +Use latest Embit release + + # Version 23.09.0 - September 12, 2023 After a long year, new features are finally coming out of beta and making their way into a stable release. Also @jreesun appointed @odudex as the new lead maintainer of the project. diff --git a/poetry.lock b/poetry.lock index ea20943c4..404727ff7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,15 +1,14 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "astroid" -version = "2.15.6" +version = "2.15.8" description = "An abstract syntax tree for Python with inference support." -category = "dev" optional = false python-versions = ">=3.7.2" files = [ - {file = "astroid-2.15.6-py3-none-any.whl", hash = "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c"}, - {file = "astroid-2.15.6.tar.gz", hash = "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"}, + {file = "astroid-2.15.8-py3-none-any.whl", hash = "sha256:1aa149fc5c6589e3d0ece885b4491acd80af4f087baafa3fb5203b113e68cd3c"}, + {file = "astroid-2.15.8.tar.gz", hash = "sha256:6c107453dffee9055899705de3c9ead36e74119cee151e5a9aaf7f0b0e020a6a"}, ] [package.dependencies] @@ -24,7 +23,6 @@ wrapt = [ name = "atomicwrites" version = "1.4.1" description = "Atomic file writes." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -35,7 +33,6 @@ files = [ name = "attrs" version = "23.1.0" description = "Classes Without Boilerplate" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -52,34 +49,33 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte [[package]] name = "black" -version = "23.7.0" +version = "23.9.1" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, - {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, - {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, - {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, - {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, - {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, - {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, - {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, - {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, - {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, - {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:d6bc09188020c9ac2555a498949401ab35bb6bf76d4e0f8ee251694664df6301"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:13ef033794029b85dfea8032c9d3b92b42b526f1ff4bf13b2182ce4e917f5100"}, + {file = "black-23.9.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:75a2dc41b183d4872d3a500d2b9c9016e67ed95738a3624f4751a0cb4818fe71"}, + {file = "black-23.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13a2e4a93bb8ca74a749b6974925c27219bb3df4d42fc45e948a5d9feb5122b7"}, + {file = "black-23.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:adc3e4442eef57f99b5590b245a328aad19c99552e0bdc7f0b04db6656debd80"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:8431445bf62d2a914b541da7ab3e2b4f3bc052d2ccbf157ebad18ea126efb91f"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:8fc1ddcf83f996247505db6b715294eba56ea9372e107fd54963c7553f2b6dfe"}, + {file = "black-23.9.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:7d30ec46de88091e4316b17ae58bbbfc12b2de05e069030f6b747dfc649ad186"}, + {file = "black-23.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:031e8c69f3d3b09e1aa471a926a1eeb0b9071f80b17689a655f7885ac9325a6f"}, + {file = "black-23.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:538efb451cd50f43aba394e9ec7ad55a37598faae3348d723b59ea8e91616300"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:638619a559280de0c2aa4d76f504891c9860bb8fa214267358f0a20f27c12948"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:a732b82747235e0542c03bf352c126052c0fbc458d8a239a94701175b17d4855"}, + {file = "black-23.9.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:cf3a4d00e4cdb6734b64bf23cd4341421e8953615cba6b3670453737a72ec204"}, + {file = "black-23.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf99f3de8b3273a8317681d8194ea222f10e0133a24a7548c73ce44ea1679377"}, + {file = "black-23.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:14f04c990259576acd093871e7e9b14918eb28f1866f91968ff5524293f9c573"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:c619f063c2d68f19b2d7270f4cf3192cb81c9ec5bc5ba02df91471d0b88c4c5c"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:6a3b50e4b93f43b34a9d3ef00d9b6728b4a722c997c99ab09102fd5efdb88325"}, + {file = "black-23.9.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:c46767e8df1b7beefb0899c4a95fb43058fa8500b6db144f4ff3ca38eb2f6393"}, + {file = "black-23.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50254ebfa56aa46a9fdd5d651f9637485068a1adf42270148cd101cdf56e0ad9"}, + {file = "black-23.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:403397c033adbc45c2bd41747da1f7fc7eaa44efbee256b53842470d4ac5a70f"}, + {file = "black-23.9.1-py3-none-any.whl", hash = "sha256:6ccd59584cc834b6d127628713e4b6b968e5f79572da66284532525a042549f9"}, + {file = "black-23.9.1.tar.gz", hash = "sha256:24b6b3ff5c6d9ea08a8888f6977eae858e1f340d7260cf56d70a49823236b62d"}, ] [package.dependencies] @@ -89,7 +85,7 @@ packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -101,7 +97,6 @@ uvloop = ["uvloop (>=0.15.2)"] name = "certifi" version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -113,7 +108,6 @@ files = [ name = "chardet" version = "3.0.4" description = "Universal encoding detector for Python 2 and 3" -category = "main" optional = false python-versions = "*" files = [ @@ -123,99 +117,112 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.3.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = true python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, - {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, + {file = "charset-normalizer-3.3.0.tar.gz", hash = "sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-win32.whl", hash = "sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d"}, + {file = "charset_normalizer-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-win32.whl", hash = "sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786"}, + {file = "charset_normalizer-3.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-win32.whl", hash = "sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df"}, + {file = "charset_normalizer-3.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dc45229747b67ffc441b3de2f3ae5e62877a282ea828a5bdb67883c4ee4a8810"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f4a0033ce9a76e391542c182f0d48d084855b5fcba5010f707c8e8c34663d77"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ada214c6fa40f8d800e575de6b91a40d0548139e5dc457d2ebb61470abf50186"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1121de0e9d6e6ca08289583d7491e7fcb18a439305b34a30b20d8215922d43c"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1063da2c85b95f2d1a430f1c33b55c9c17ffaf5e612e10aeaad641c55a9e2b9d"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70f1d09c0d7748b73290b29219e854b3207aea922f839437870d8cc2168e31cc"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:250c9eb0f4600361dd80d46112213dff2286231d92d3e52af1e5a6083d10cad9"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:750b446b2ffce1739e8578576092179160f6d26bd5e23eb1789c4d64d5af7dc7"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fc52b79d83a3fe3a360902d3f5d79073a993597d48114c29485e9431092905d8"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:588245972aca710b5b68802c8cad9edaa98589b1b42ad2b53accd6910dad3545"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e39c7eb31e3f5b1f88caff88bcff1b7f8334975b46f6ac6e9fc725d829bc35d4"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-win32.whl", hash = "sha256:abecce40dfebbfa6abf8e324e1860092eeca6f7375c8c4e655a8afb61af58f2c"}, + {file = "charset_normalizer-3.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:24a91a981f185721542a0b7c92e9054b7ab4fea0508a795846bc5b0abf8118d4"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:67b8cc9574bb518ec76dc8e705d4c39ae78bb96237cb533edac149352c1f39fe"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac71b2977fb90c35d41c9453116e283fac47bb9096ad917b8819ca8b943abecd"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3ae38d325b512f63f8da31f826e6cb6c367336f95e418137286ba362925c877e"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:542da1178c1c6af8873e143910e2269add130a299c9106eef2594e15dae5e482"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30a85aed0b864ac88309b7d94be09f6046c834ef60762a8833b660139cfbad13"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aae32c93e0f64469f74ccc730a7cb21c7610af3a775157e50bbd38f816536b38"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15b26ddf78d57f1d143bdf32e820fd8935d36abe8a25eb9ec0b5a71c82eb3895"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f5d10bae5d78e4551b7be7a9b29643a95aded9d0f602aa2ba584f0388e7a557"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:249c6470a2b60935bafd1d1d13cd613f8cd8388d53461c67397ee6a0f5dce741"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c5a74c359b2d47d26cdbbc7845e9662d6b08a1e915eb015d044729e92e7050b7"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:b5bcf60a228acae568e9911f410f9d9e0d43197d030ae5799e20dca8df588287"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:187d18082694a29005ba2944c882344b6748d5be69e3a89bf3cc9d878e548d5a"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:81bf654678e575403736b85ba3a7867e31c2c30a69bc57fe88e3ace52fb17b89"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-win32.whl", hash = "sha256:85a32721ddde63c9df9ebb0d2045b9691d9750cb139c161c80e500d210f5e26e"}, + {file = "charset_normalizer-3.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:468d2a840567b13a590e67dd276c570f8de00ed767ecc611994c301d0f8c014f"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e0fc42822278451bc13a2e8626cf2218ba570f27856b536e00cfa53099724828"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:09c77f964f351a7369cc343911e0df63e762e42bac24cd7d18525961c81754f4"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12ebea541c44fdc88ccb794a13fe861cc5e35d64ed689513a5c03d05b53b7c82"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:805dfea4ca10411a5296bcc75638017215a93ffb584c9e344731eef0dcfb026a"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96c2b49eb6a72c0e4991d62406e365d87067ca14c1a729a870d22354e6f68115"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aaf7b34c5bc56b38c931a54f7952f1ff0ae77a2e82496583b247f7c969eb1479"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:619d1c96099be5823db34fe89e2582b336b5b074a7f47f819d6b3a57ff7bdb86"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0ac5e7015a5920cfce654c06618ec40c33e12801711da6b4258af59a8eff00a"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93aa7eef6ee71c629b51ef873991d6911b906d7312c6e8e99790c0f33c576f89"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7966951325782121e67c81299a031f4c115615e68046f79b85856b86ebffc4cd"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:02673e456dc5ab13659f85196c534dc596d4ef260e4d86e856c3b2773ce09843"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:c2af80fb58f0f24b3f3adcb9148e6203fa67dd3f61c4af146ecad033024dde43"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:153e7b6e724761741e0974fc4dcd406d35ba70b92bfe3fedcb497226c93b9da7"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-win32.whl", hash = "sha256:d47ecf253780c90ee181d4d871cd655a789da937454045b17b5798da9393901a"}, + {file = "charset_normalizer-3.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:d97d85fa63f315a8bdaba2af9a6a686e0eceab77b3089af45133252618e70884"}, + {file = "charset_normalizer-3.3.0-py3-none-any.whl", hash = "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2"}, ] [[package]] name = "click" -version = "8.1.6" +version = "8.1.7" description = "Composable command line interface toolkit" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.6-py3-none-any.whl", hash = "sha256:fa244bb30b3b5ee2cae3da8f55c9e5e0c0e86093306301fb418eb9dc40fbded5"}, - {file = "click-8.1.6.tar.gz", hash = "sha256:48ee849951919527a045bfe3bf7baa8a959c423134e1a5b98c05c20ba75a1cbd"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -225,7 +232,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -235,72 +241,63 @@ files = [ [[package]] name = "coverage" -version = "7.2.7" +version = "7.3.2" description = "Code coverage measurement for Python" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, - {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, - {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, - {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, - {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, - {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, - {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, - {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, - {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, - {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, - {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, - {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, - {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, - {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, - {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, - {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, - {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, - {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, + {file = "coverage-7.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d872145f3a3231a5f20fd48500274d7df222e291d90baa2026cc5152b7ce86bf"}, + {file = "coverage-7.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:310b3bb9c91ea66d59c53fa4989f57d2436e08f18fb2f421a1b0b6b8cc7fffda"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f47d39359e2c3779c5331fc740cf4bce6d9d680a7b4b4ead97056a0ae07cb49a"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa72dbaf2c2068404b9870d93436e6d23addd8bbe9295f49cbca83f6e278179c"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beaa5c1b4777f03fc63dfd2a6bd820f73f036bfb10e925fce067b00a340d0f3f"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dbc1b46b92186cc8074fee9d9fbb97a9dd06c6cbbef391c2f59d80eabdf0faa6"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:315a989e861031334d7bee1f9113c8770472db2ac484e5b8c3173428360a9148"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d1bc430677773397f64a5c88cb522ea43175ff16f8bfcc89d467d974cb2274f9"}, + {file = "coverage-7.3.2-cp310-cp310-win32.whl", hash = "sha256:a889ae02f43aa45032afe364c8ae84ad3c54828c2faa44f3bfcafecb5c96b02f"}, + {file = "coverage-7.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c0ba320de3fb8c6ec16e0be17ee1d3d69adcda99406c43c0409cb5c41788a611"}, + {file = "coverage-7.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ac8c802fa29843a72d32ec56d0ca792ad15a302b28ca6203389afe21f8fa062c"}, + {file = "coverage-7.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89a937174104339e3a3ffcf9f446c00e3a806c28b1841c63edb2b369310fd074"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e267e9e2b574a176ddb983399dec325a80dbe161f1a32715c780b5d14b5f583a"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2443cbda35df0d35dcfb9bf8f3c02c57c1d6111169e3c85fc1fcc05e0c9f39a3"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4175e10cc8dda0265653e8714b3174430b07c1dca8957f4966cbd6c2b1b8065a"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c913b556a116b8d5f6ef834038ba983834d887d82187c8f73dec21049abd65c"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1981f785239e4e39e6444c63a98da3a1db8e971cb9ceb50a945ba6296b43f312"}, + {file = "coverage-7.3.2-cp311-cp311-win32.whl", hash = "sha256:43668cabd5ca8258f5954f27a3aaf78757e6acf13c17604d89648ecc0cc66640"}, + {file = "coverage-7.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10c39c0452bf6e694511c901426d6b5ac005acc0f78ff265dbe36bf81f808a2"}, + {file = "coverage-7.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4cbae1051ab791debecc4a5dcc4a1ff45fc27b91b9aee165c8a27514dd160836"}, + {file = "coverage-7.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7bba973ebee5e56fe9251300c00f1579652587a9f4a5ed8404b15a0471f216"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6e9589bd04d0461a417562649522575d8752904d35c12907d8c9dfeba588faf"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d51ac2a26f71da1b57f2dc81d0e108b6ab177e7d30e774db90675467c847bbdf"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:99b89d9f76070237975b315b3d5f4d6956ae354a4c92ac2388a5695516e47c84"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a"}, + {file = "coverage-7.3.2-cp312-cp312-win32.whl", hash = "sha256:289fe43bf45a575e3ab10b26d7b6f2ddb9ee2dba447499f5401cfb5ecb8196bb"}, + {file = "coverage-7.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dbc3ed60e8659bc59b6b304b43ff9c3ed858da2839c78b804973f613d3e92ed"}, + {file = "coverage-7.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738"}, + {file = "coverage-7.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af3d828d2c1cbae52d34bdbb22fcd94d1ce715d95f1a012354a75e5913f1bda2"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630b13e3036e13c7adc480ca42fa7afc2a5d938081d28e20903cf7fd687872e2"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9eacf273e885b02a0273bb3a2170f30e2d53a6d53b72dbe02d6701b5296101c"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f17966e861ff97305e0801134e69db33b143bbfb36436efb9cfff6ec7b2fd9"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4275802d16882cf9c8b3d057a0839acb07ee9379fa2749eca54efbce1535b82"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72c0cfa5250f483181e677ebc97133ea1ab3eb68645e494775deb6a7f6f83901"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb536f0dcd14149425996821a168f6e269d7dcd2c273a8bff8201e79f5104e76"}, + {file = "coverage-7.3.2-cp38-cp38-win32.whl", hash = "sha256:307adb8bd3abe389a471e649038a71b4eb13bfd6b7dd9a129fa856f5c695cf92"}, + {file = "coverage-7.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:88ed2c30a49ea81ea3b7f172e0269c182a44c236eb394718f976239892c0a27a"}, + {file = "coverage-7.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b631c92dfe601adf8f5ebc7fc13ced6bb6e9609b19d9a8cd59fa47c4186ad1ce"}, + {file = "coverage-7.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d3d9df4051c4a7d13036524b66ecf7a7537d14c18a384043f30a303b146164e9"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7363d3b6a1119ef05015959ca24a9afc0ea8a02c687fe7e2d557705375c01f"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f11cc3c967a09d3695d2a6f03fb3e6236622b93be7a4b5dc09166a861be6d25"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3a4006916aa6fee7cd38db3bfc95aa9c54ebb4ffbfc47c677c8bba949ceba0a6"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9028a3871280110d6e1aa2df1afd5ef003bab5fb1ef421d6dc748ae1c8ef2ebc"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f805d62aec8eb92bab5b61c0f07329275b6f41c97d80e847b03eb894f38d083"}, + {file = "coverage-7.3.2-cp39-cp39-win32.whl", hash = "sha256:d1c88ec1a7ff4ebca0219f5b1ef863451d828cccf889c173e1253aa84b1e07ce"}, + {file = "coverage-7.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4767da59464bb593c07afceaddea61b154136300881844768037fd5e859353f"}, + {file = "coverage-7.3.2-pp38.pp39.pp310-none-any.whl", hash = "sha256:ae97af89f0fbf373400970c0a21eef5aa941ffeed90aee43650b81f7d7f47637"}, + {file = "coverage-7.3.2.tar.gz", hash = "sha256:be32ad29341b0170e795ca590e1c07e81fc061cb5b10c74ce7203491484404ef"}, ] [package.dependencies] @@ -313,7 +310,6 @@ toml = ["tomli"] name = "dill" version = "0.3.7" description = "serialize all of Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -326,14 +322,16 @@ graph = ["objgraph (>=1.7.2)"] [[package]] name = "embit" -version = "0.5.0" -description = "yet another bitcoin library" -category = "main" +version = "0.7.0" +description = "A minimal bitcoin library for MicroPython and Python3 with a focus on embedded systems." optional = false python-versions = "*" files = [] develop = true +[package.extras] +dev = ["black", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mypy", "pre-commit", "pytest", "pytest-cov", "requests"] + [package.source] type = "directory" url = "vendor/embit" @@ -342,7 +340,6 @@ url = "vendor/embit" name = "ghp-import" version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." -category = "main" optional = true python-versions = "*" files = [ @@ -360,7 +357,6 @@ dev = ["flake8", "markdown", "twine", "wheel"] name = "googletrans" version = "4.0.0rc1" description = "Free Google Translate API for Python. Translates totally free of charge." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -374,7 +370,6 @@ httpx = "0.13.3" name = "h11" version = "0.9.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" -category = "main" optional = false python-versions = "*" files = [ @@ -386,7 +381,6 @@ files = [ name = "h2" version = "3.2.0" description = "HTTP/2 State-Machine based protocol implementation" -category = "main" optional = false python-versions = "*" files = [ @@ -402,7 +396,6 @@ hyperframe = ">=5.2.0,<6" name = "hpack" version = "3.0.0" description = "Pure-Python HPACK header compression" -category = "main" optional = false python-versions = "*" files = [ @@ -414,7 +407,6 @@ files = [ name = "hstspreload" version = "2023.1.1" description = "Chromium HSTS Preload list as a Python package" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -426,7 +418,6 @@ files = [ name = "httpcore" version = "0.9.1" description = "A minimal low-level HTTP client." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -436,14 +427,13 @@ files = [ [package.dependencies] h11 = ">=0.8,<0.10" -h2 = ">=3.0.0,<4.0.0" -sniffio = ">=1.0.0,<2.0.0" +h2 = "==3.*" +sniffio = "==1.*" [[package]] name = "httpx" version = "0.13.3" description = "The next generation HTTP client." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -453,10 +443,10 @@ files = [ [package.dependencies] certifi = "*" -chardet = ">=3.0.0,<4.0.0" +chardet = "==3.*" hstspreload = "*" -httpcore = ">=0.9.0,<0.10.0" -idna = ">=2.0.0,<3.0.0" +httpcore = "==0.9.*" +idna = "==2.*" rfc3986 = ">=1.3,<2" sniffio = "*" @@ -464,7 +454,6 @@ sniffio = "*" name = "hyperframe" version = "5.2.0" description = "HTTP/2 framing layer for Python" -category = "main" optional = false python-versions = "*" files = [ @@ -476,7 +465,6 @@ files = [ name = "idna" version = "2.10" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -488,7 +476,6 @@ files = [ name = "importlib-metadata" version = "6.8.0" description = "Read metadata from Python packages" -category = "main" optional = true python-versions = ">=3.8" files = [ @@ -508,7 +495,6 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -520,7 +506,6 @@ files = [ name = "isort" version = "5.12.0" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false python-versions = ">=3.8.0" files = [ @@ -538,7 +523,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -556,7 +540,6 @@ i18n = ["Babel (>=2.7)"] name = "lazy-object-proxy" version = "1.9.0" description = "A fast and thorough lazy object proxy." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -600,28 +583,26 @@ files = [ [[package]] name = "markdown" -version = "3.4.4" +version = "3.5" description = "Python implementation of John Gruber's Markdown." -category = "main" optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Markdown-3.4.4-py3-none-any.whl", hash = "sha256:a4c1b65c0957b4bd9e7d86ddc7b3c9868fb9670660f6f99f6d1bca8954d5a941"}, - {file = "Markdown-3.4.4.tar.gz", hash = "sha256:225c6123522495d4119a90b3a3ba31a1e87a70369e03f14799ea9c0d7183a3d6"}, + {file = "Markdown-3.5-py3-none-any.whl", hash = "sha256:4afb124395ce5fc34e6d9886dab977fd9ae987fc6e85689f08278cf0c69d4bf3"}, + {file = "Markdown-3.5.tar.gz", hash = "sha256:a807eb2e4778d9156c8f07876c6e4d50b5494c5665c4834f67b06459dfd877b3"}, ] [package.dependencies] importlib-metadata = {version = ">=4.4", markers = "python_version < \"3.10\""} [package.extras] -docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.0)", "mkdocs-nature (>=0.4)"] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -681,7 +662,6 @@ files = [ name = "mccabe" version = "0.7.0" description = "McCabe checker, plugin for flake8" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -693,7 +673,6 @@ files = [ name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -703,14 +682,13 @@ files = [ [[package]] name = "mkdocs" -version = "1.5.2" +version = "1.5.3" description = "Project documentation with Markdown." -category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "mkdocs-1.5.2-py3-none-any.whl", hash = "sha256:60a62538519c2e96fe8426654a67ee177350451616118a41596ae7c876bb7eac"}, - {file = "mkdocs-1.5.2.tar.gz", hash = "sha256:70d0da09c26cff288852471be03c23f0f521fc15cf16ac89c7a3bfb9ae8d24f9"}, + {file = "mkdocs-1.5.3-py3-none-any.whl", hash = "sha256:3b3a78e736b31158d64dbb2f8ba29bd46a379d0c6e324c2246c3bc3d2189cfc1"}, + {file = "mkdocs-1.5.3.tar.gz", hash = "sha256:eb7c99214dcb945313ba30426c2451b735992c73c2e10838f76d09e39ff4d0e2"}, ] [package.dependencies] @@ -737,7 +715,6 @@ min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-imp name = "mkdocs-material" version = "8.5.11" description = "Documentation that simply works" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -756,21 +733,19 @@ requests = ">=2.26" [[package]] name = "mkdocs-material-extensions" -version = "1.1.1" +version = "1.2" description = "Extension pack for Python Markdown and MkDocs Material." -category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "mkdocs_material_extensions-1.1.1-py3-none-any.whl", hash = "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945"}, - {file = "mkdocs_material_extensions-1.1.1.tar.gz", hash = "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93"}, + {file = "mkdocs_material_extensions-1.2-py3-none-any.whl", hash = "sha256:c767bd6d6305f6420a50f0b541b0c9966d52068839af97029be14443849fb8a1"}, + {file = "mkdocs_material_extensions-1.2.tar.gz", hash = "sha256:27e2d1ed2d031426a6e10d5ea06989d67e90bb02acd588bc5673106b5ee5eedf"}, ] [[package]] name = "mkdocs-static-i18n" version = "0.46" description = "MkDocs i18n plugin using static translation markdown files" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -784,7 +759,6 @@ mkdocs = ">=1.2.3" name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -796,7 +770,6 @@ files = [ name = "numpy" version = "1.25.2" description = "Fundamental package for array computing in Python" -category = "main" optional = true python-versions = ">=3.9" files = [ @@ -829,19 +802,18 @@ files = [ [[package]] name = "opencv-python" -version = "4.8.0.74" +version = "4.8.1.78" description = "Wrapper package for OpenCV python bindings." -category = "main" optional = true python-versions = ">=3.6" files = [ - {file = "opencv-python-4.8.0.74.tar.gz", hash = "sha256:009e3ce356a0cd2d7423723e00a32fd3d3cc5bb5970ed27a9a1f8a8f221d1db5"}, - {file = "opencv_python-4.8.0.74-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:31d0d59fc8fdf703de4cec46c79b9f8d026fdde9d23d6e2e6a66809feeebbda9"}, - {file = "opencv_python-4.8.0.74-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:66eadb5882ee56848b67f9fb57aadcaca2f4c9d9d00a0ef11043041925b51291"}, - {file = "opencv_python-4.8.0.74-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:038ba7075e55cb8e2846663ae970f0fb776a45b48ee69a887bf4ee15e2570083"}, - {file = "opencv_python-4.8.0.74-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43dd0dfe331fb95767af581bf3b2781d7a72cf6560ddf2f55949fe547f3e5c9f"}, - {file = "opencv_python-4.8.0.74-cp37-abi3-win32.whl", hash = "sha256:458e5dc377f15fcf769d80314f3d885bd95457b1a2891bee67df2eb24a1d3a52"}, - {file = "opencv_python-4.8.0.74-cp37-abi3-win_amd64.whl", hash = "sha256:8fe0018d0056a5187c57120b6b3f6c3e706c13b45c48e54e86d245a9a16fac84"}, + {file = "opencv-python-4.8.1.78.tar.gz", hash = "sha256:cc7adbbcd1112877a39274106cb2752e04984bc01a031162952e97450d6117f6"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:91d5f6f5209dc2635d496f6b8ca6573ecdad051a09e6b5de4c399b8e673c60da"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31f47e05447da8b3089faa0a07ffe80e114c91ce0b171e6424f9badbd1c5cd"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9814beca408d3a0eca1bae7e3e5be68b07c17ecceb392b94170881216e09b319"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c406bdb41eb21ea51b4e90dfbc989c002786c3f601c236a99c59a54670a394"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-win32.whl", hash = "sha256:a7aac3900fbacf55b551e7b53626c3dad4c71ce85643645c43e91fcb19045e47"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-win_amd64.whl", hash = "sha256:b983197f97cfa6fcb74e1da1802c7497a6f94ed561aba6980f1f33123f904956"}, ] [package.dependencies] @@ -849,29 +821,27 @@ numpy = [ {version = ">=1.21.0", markers = "python_version <= \"3.9\" and platform_system == \"Darwin\" and platform_machine == \"arm64\""}, {version = ">=1.21.2", markers = "python_version >= \"3.10\""}, {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\""}, + {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, {version = ">=1.19.3", markers = "python_version >= \"3.6\" and platform_system == \"Linux\" and platform_machine == \"aarch64\" or python_version >= \"3.9\""}, {version = ">=1.17.0", markers = "python_version >= \"3.7\""}, {version = ">=1.17.3", markers = "python_version >= \"3.8\""}, - {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, ] [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] name = "pathspec" version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -883,7 +853,6 @@ files = [ name = "pillow" version = "9.5.0" description = "Python Imaging Library (Fork)" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -961,14 +930,13 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "3.10.0" +version = "3.11.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, ] [package.extras] @@ -977,14 +945,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co [[package]] name = "pluggy" -version = "1.2.0" +version = "1.3.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, ] [package.extras] @@ -995,7 +962,6 @@ testing = ["pytest", "pytest-benchmark"] name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -1005,116 +971,115 @@ files = [ [[package]] name = "pycryptodome" -version = "3.18.0" +version = "3.19.0" description = "Cryptographic library for Python" -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycryptodome-3.18.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:d1497a8cd4728db0e0da3c304856cb37c0c4e3d0b36fcbabcc1600f18504fc54"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:928078c530da78ff08e10eb6cada6e0dff386bf3d9fa9871b4bbc9fbc1efe024"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:157c9b5ba5e21b375f052ca78152dd309a09ed04703fd3721dce3ff8ecced148"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:d20082bdac9218649f6abe0b885927be25a917e29ae0502eaf2b53f1233ce0c2"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:e8ad74044e5f5d2456c11ed4cfd3e34b8d4898c0cb201c4038fe41458a82ea27"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-win32.whl", hash = "sha256:62a1e8847fabb5213ccde38915563140a5b338f0d0a0d363f996b51e4a6165cf"}, - {file = "pycryptodome-3.18.0-cp27-cp27m-win_amd64.whl", hash = "sha256:16bfd98dbe472c263ed2821284118d899c76968db1a6665ade0c46805e6b29a4"}, - {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7a3d22c8ee63de22336679e021c7f2386f7fc465477d59675caa0e5706387944"}, - {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:78d863476e6bad2a592645072cc489bb90320972115d8995bcfbee2f8b209918"}, - {file = "pycryptodome-3.18.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:b6a610f8bfe67eab980d6236fdc73bfcdae23c9ed5548192bb2d530e8a92780e"}, - {file = "pycryptodome-3.18.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:422c89fd8df8a3bee09fb8d52aaa1e996120eafa565437392b781abec2a56e14"}, - {file = "pycryptodome-3.18.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:9ad6f09f670c466aac94a40798e0e8d1ef2aa04589c29faa5b9b97566611d1d1"}, - {file = "pycryptodome-3.18.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:53aee6be8b9b6da25ccd9028caf17dcdce3604f2c7862f5167777b707fbfb6cb"}, - {file = "pycryptodome-3.18.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:10da29526a2a927c7d64b8f34592f461d92ae55fc97981aab5bbcde8cb465bb6"}, - {file = "pycryptodome-3.18.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f21efb8438971aa16924790e1c3dba3a33164eb4000106a55baaed522c261acf"}, - {file = "pycryptodome-3.18.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4944defabe2ace4803f99543445c27dd1edbe86d7d4edb87b256476a91e9ffa4"}, - {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:51eae079ddb9c5f10376b4131be9589a6554f6fd84f7f655180937f611cd99a2"}, - {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:83c75952dcf4a4cebaa850fa257d7a860644c70a7cd54262c237c9f2be26f76e"}, - {file = "pycryptodome-3.18.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:957b221d062d5752716923d14e0926f47670e95fead9d240fa4d4862214b9b2f"}, - {file = "pycryptodome-3.18.0-cp35-abi3-win32.whl", hash = "sha256:795bd1e4258a2c689c0b1f13ce9684fa0dd4c0e08680dcf597cf9516ed6bc0f3"}, - {file = "pycryptodome-3.18.0-cp35-abi3-win_amd64.whl", hash = "sha256:b1d9701d10303eec8d0bd33fa54d44e67b8be74ab449052a8372f12a66f93fb9"}, - {file = "pycryptodome-3.18.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:cb1be4d5af7f355e7d41d36d8eec156ef1382a88638e8032215c215b82a4b8ec"}, - {file = "pycryptodome-3.18.0-pp27-pypy_73-win32.whl", hash = "sha256:fc0a73f4db1e31d4a6d71b672a48f3af458f548059aa05e83022d5f61aac9c08"}, - {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f022a4fd2a5263a5c483a2bb165f9cb27f2be06f2f477113783efe3fe2ad887b"}, - {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:363dd6f21f848301c2dcdeb3c8ae5f0dee2286a5e952a0f04954b82076f23825"}, - {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12600268763e6fec3cefe4c2dcdf79bde08d0b6dc1813887e789e495cb9f3403"}, - {file = "pycryptodome-3.18.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4604816adebd4faf8810782f137f8426bf45fee97d8427fa8e1e49ea78a52e2c"}, - {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:01489bbdf709d993f3058e2996f8f40fee3f0ea4d995002e5968965fa2fe89fb"}, - {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3811e31e1ac3069988f7a1c9ee7331b942e605dfc0f27330a9ea5997e965efb2"}, - {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4b967bb11baea9128ec88c3d02f55a3e338361f5e4934f5240afcb667fdaec"}, - {file = "pycryptodome-3.18.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9c8eda4f260072f7dbe42f473906c659dcbadd5ae6159dfb49af4da1293ae380"}, - {file = "pycryptodome-3.18.0.tar.gz", hash = "sha256:c9adee653fc882d98956e33ca2c1fb582e23a8af7ac82fee75bd6113c55a0413"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3006c44c4946583b6de24fe0632091c2653d6256b99a02a3db71ca06472ea1e4"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:7c760c8a0479a4042111a8dd2f067d3ae4573da286c53f13cf6f5c53a5c1f631"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:08ce3558af5106c632baf6d331d261f02367a6bc3733086ae43c0f988fe042db"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45430dfaf1f421cf462c0dd824984378bef32b22669f2635cb809357dbaab405"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:a9bcd5f3794879e91970f2bbd7d899780541d3ff439d8f2112441769c9f2ccea"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-win32.whl", hash = "sha256:190c53f51e988dceb60472baddce3f289fa52b0ec38fbe5fd20dd1d0f795c551"}, + {file = "pycryptodome-3.19.0-cp27-cp27m-win_amd64.whl", hash = "sha256:22e0ae7c3a7f87dcdcf302db06ab76f20e83f09a6993c160b248d58274473bfa"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7822f36d683f9ad7bc2145b2c2045014afdbbd1d9922a6d4ce1cbd6add79a01e"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:05e33267394aad6db6595c0ce9d427fe21552f5425e116a925455e099fdf759a"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:829b813b8ee00d9c8aba417621b94bc0b5efd18c928923802ad5ba4cf1ec709c"}, + {file = "pycryptodome-3.19.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:fc7a79590e2b5d08530175823a242de6790abc73638cc6dc9d2684e7be2f5e49"}, + {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:542f99d5026ac5f0ef391ba0602f3d11beef8e65aae135fa5b762f5ebd9d3bfb"}, + {file = "pycryptodome-3.19.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:61bb3ccbf4bf32ad9af32da8badc24e888ae5231c617947e0f5401077f8b091f"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d49a6c715d8cceffedabb6adb7e0cbf41ae1a2ff4adaeec9432074a80627dea1"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e249a784cc98a29c77cea9df54284a44b40cafbfae57636dd2f8775b48af2434"}, + {file = "pycryptodome-3.19.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d033947e7fd3e2ba9a031cb2d267251620964705a013c5a461fa5233cc025270"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:84c3e4fffad0c4988aef0d5591be3cad4e10aa7db264c65fadbc633318d20bde"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:139ae2c6161b9dd5d829c9645d781509a810ef50ea8b657e2257c25ca20efe33"}, + {file = "pycryptodome-3.19.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5b1986c761258a5b4332a7f94a83f631c1ffca8747d75ab8395bf2e1b93283d9"}, + {file = "pycryptodome-3.19.0-cp35-abi3-win32.whl", hash = "sha256:536f676963662603f1f2e6ab01080c54d8cd20f34ec333dcb195306fa7826997"}, + {file = "pycryptodome-3.19.0-cp35-abi3-win_amd64.whl", hash = "sha256:04dd31d3b33a6b22ac4d432b3274588917dcf850cc0c51c84eca1d8ed6933810"}, + {file = "pycryptodome-3.19.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:8999316e57abcbd8085c91bc0ef75292c8618f41ca6d2b6132250a863a77d1e7"}, + {file = "pycryptodome-3.19.0-pp27-pypy_73-win32.whl", hash = "sha256:a0ab84755f4539db086db9ba9e9f3868d2e3610a3948cbd2a55e332ad83b01b0"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0101f647d11a1aae5a8ce4f5fad6644ae1b22bb65d05accc7d322943c69a74a6"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c1601e04d32087591d78e0b81e1e520e57a92796089864b20e5f18c9564b3fa"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:506c686a1eee6c00df70010be3b8e9e78f406af4f21b23162bbb6e9bdf5427bc"}, + {file = "pycryptodome-3.19.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7919ccd096584b911f2a303c593280869ce1af9bf5d36214511f5e5a1bed8c34"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560591c0777f74a5da86718f70dfc8d781734cf559773b64072bbdda44b3fc3e"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cc2f2ae451a676def1a73c1ae9120cd31af25db3f381893d45f75e77be2400"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17940dcf274fcae4a54ec6117a9ecfe52907ed5e2e438fe712fe7ca502672ed5"}, + {file = "pycryptodome-3.19.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d04f5f623a280fbd0ab1c1d8ecbd753193ab7154f09b6161b0f857a1a676c15f"}, + {file = "pycryptodome-3.19.0.tar.gz", hash = "sha256:bc35d463222cdb4dbebd35e0784155c81e161b9284e567e7e933d722e533331e"}, ] [[package]] name = "pygame" -version = "2.5.0" +version = "2.5.2" description = "Python Game Development" -category = "main" optional = true python-versions = ">=3.6" files = [ - {file = "pygame-2.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e34a2b5660acc298d0a66ce16f13a7ca1c56c2a685e40afef3a0cf6eaf3f44b3"}, - {file = "pygame-2.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:875dbde88b899fb7f48d6f0e87f70c3dcc8ee87a947c3df817d949a9741dbcf5"}, - {file = "pygame-2.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:854dc9106210d1a3a83914af53fc234c0bed65a39f5e6098a8eb489da354ad0c"}, - {file = "pygame-2.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e1898db0fd7b868a31c29204813f447c59390350fd806904d80bebde094f3f8"}, - {file = "pygame-2.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22d5eac9b9936c7dc2813a750bc8efd53234ad1afc32eb99d6f64bb403c2b9aa"}, - {file = "pygame-2.5.0-cp310-cp310-win32.whl", hash = "sha256:e9eed550b8921080a3c7524202822fc2cf7226e0ffd3c4e4d16510ba44b24e6f"}, - {file = "pygame-2.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:93128beb1154c443f05a66bfbf3f1d4eb8659157ab3b45e4a0454e5905440431"}, - {file = "pygame-2.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c71d5b3ec232113cbd2e23a19eb01eef1818db41892d0d5efbac3901f940da66"}, - {file = "pygame-2.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b763062b1996de26a28600e7a8f138d5b36ba0ddd63c65ccbd06124cd95bab70"}, - {file = "pygame-2.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b6a42109f922352c524565fceb22bf8f8b6e4b00d38306e6f5b4c673048f4a"}, - {file = "pygame-2.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bcb19c8ee3fc794ab3a7cb5b5fb1ad38da6866dfbba4af3699a84a828c8a4b9"}, - {file = "pygame-2.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c66b7abc38511c7ca08c5bb58a3bfc14fa51b4e5f85a1786777afc9e584a14dd"}, - {file = "pygame-2.5.0-cp311-cp311-win32.whl", hash = "sha256:46cf1c9b20fb11c7d836c02dd5fc2ca843b699c0e2bc4130cf4ad2f855db5f7f"}, - {file = "pygame-2.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:f7b77b5019a9a6342535f53c75cef912b218cd24e98505828418f135aacc0a1b"}, - {file = "pygame-2.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ddec0c823fd0869fe4a75ba906dcb7889db0e0c289ce8c03d4ce0a67351ab66"}, - {file = "pygame-2.5.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bae93ce29b8337a5e02507603094c51740c9f496272ef070e2624e9647776568"}, - {file = "pygame-2.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c80a1ad38d11102b4dfa0519aa2a26fea534503b259872609acc9adb1860884e"}, - {file = "pygame-2.5.0-cp312-cp312-win32.whl", hash = "sha256:8ffebcafda0add8072f82999498113be37494694fa36e02155cfaf1a0ba56fe2"}, - {file = "pygame-2.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:574e310ba708da0c34b71c4158aa7cdca3cf3e16c4100dcd1d3c931a9c6705b4"}, - {file = "pygame-2.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:275e4fab379620c3b262cd58c457eea80001e91bc2e04d306ddb0ba548c969bf"}, - {file = "pygame-2.5.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c116a96a2784bd1724476dbf9c48bfea466ee493a736bdfa04ecbc3f193de0bc"}, - {file = "pygame-2.5.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4a0787ade8723323a3ba874bb725010bb08990a77327fc85f42474f3a840447"}, - {file = "pygame-2.5.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1cb39b660da1b56a1704ec4aa72bac538030786e23607fb25b8a66f357ffe3a"}, - {file = "pygame-2.5.0-cp36-cp36m-win32.whl", hash = "sha256:d051420667dd9fc8103b3cf994c03e46ee90b1c4a72c174737b8c14729ddf68e"}, - {file = "pygame-2.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6b58356510b7c38836eb81cf08983b58f280da99580d4f17e89ed0ddb707c29c"}, - {file = "pygame-2.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:80f167d8fcec7cd3107f829784ad721b1b7532c19fdf42b3aabbb51f7347850f"}, - {file = "pygame-2.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef96e9a2d8fd9526b89657d192c42dd7c551bfa381fa98ec52d45443e9713818"}, - {file = "pygame-2.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e21d53279fb504b267ae06b565b72d9f95ecbf1f2dd8c705329b287f38295d98"}, - {file = "pygame-2.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147cc0256a5df1316590f351febf6205ef2907564fb0d902935834b91e183486"}, - {file = "pygame-2.5.0-cp37-cp37m-win32.whl", hash = "sha256:e47696154d689180e4eea8c1d6f2bac923986119219db6ad0d2e60ab1f525e8c"}, - {file = "pygame-2.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4c87fa8fa1f3ea94069119accd6d4b5fbf869c2b2954a19b45162dfb3b7c885e"}, - {file = "pygame-2.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:143550078ab10f290cd7c8715a46853e0dc598fd6cdd1561ecb4d6e3116a6b26"}, - {file = "pygame-2.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:969de806bed49b28972862acba652f05ece9420bbdf5f925c970c6a18a9fd1f9"}, - {file = "pygame-2.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5d3b0da31ea341b86ef96d6b13c0ddcb25f5320186b7215bc870f08119d2f80"}, - {file = "pygame-2.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b23effd50121468f1dc41022230485bff515154191a9d343224850aa3ed3b7f0"}, - {file = "pygame-2.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bce4116db6924b544ff8ff03f7ef681c8baf9c6e039a1ec21e26b4ebdaa0e994"}, - {file = "pygame-2.5.0-cp38-cp38-win32.whl", hash = "sha256:50a89c15412506d95e98792435f49a73101788db30ad9c562f611c7aa7b437fa"}, - {file = "pygame-2.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:df1d8affdbe9f417cc7141581e3d08e4b09f708060d3127d2016fd591b2e4f68"}, - {file = "pygame-2.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:99965da24d0bf138d9ac6b7494b9a12781c1510cf936616d1d0c46a736777f6a"}, - {file = "pygame-2.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:daa81057c1beb71a9fb96253457197ad03ee988ba546a166f253bd92a98a9a11"}, - {file = "pygame-2.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ca85da605f6621c99c05f272a5dcf85bf0badcdca45f16ff2bee9a9d41ae042"}, - {file = "pygame-2.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:603d403997d46b07022097861c8b0ff76c6192f8a2f5f89f1a6a978d4411b715"}, - {file = "pygame-2.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7babaeac11544f3e4d7a15756a27f943dc5fff276481fdc9d90415a903ad31a9"}, - {file = "pygame-2.5.0-cp39-cp39-win32.whl", hash = "sha256:9d2126f91699223f0c36845d1c7b2cdfe2f1753ef85b8410ea613e8bd212ca33"}, - {file = "pygame-2.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:8062adc409f0b2742d7996b9b470494025c5e3b73d0d03e3798708dcf5d195cd"}, - {file = "pygame-2.5.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:1bd14adf6151b6ac2f617a8fd71621f1c125209c41a359d3c1cf4bf3904dba5f"}, - {file = "pygame-2.5.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b11708f1c7b1671db15246275adcb18cf384f5f7e73532e26999968876c5099"}, - {file = "pygame-2.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6830e431575697f7a11f7731798445242e37eb07ae9007f7be33083f700e9b1e"}, - {file = "pygame-2.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7dd80addfdf7dc1f0e04f81c98acb96580726783172256f2ebc955a967e84124"}, - {file = "pygame-2.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c2cbd9d1a0a3969d6e1c6b0741279c843b4a36ef3804d324874d0a2f0e49816"}, - {file = "pygame-2.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef373b9865c740f18236f2324e17e7f2111e27c6a4a5b67c490c72a8a8b8de77"}, - {file = "pygame-2.5.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3959038a3e2034cee3f15471786a3bac35baeaa1f7503dc7402bb49d25b5ddbc"}, - {file = "pygame-2.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:583d9c8ad033ad51da8485427139d047afb649f49e42d4fa88477f73734ad4b0"}, - {file = "pygame-2.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b650e925d2e8c82c16bdeae6e7fc5d6ca4ac659a1412da4ecd923ef9d688cb"}, - {file = "pygame-2.5.0.tar.gz", hash = "sha256:edd5745b79435976d92c0a7318aedcafcb7ac4567125ac6ba88aa473559ef9ab"}, + {file = "pygame-2.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a0769eb628c818761755eb0a0ca8216b95270ea8cbcbc82227e39ac9644643da"}, + {file = "pygame-2.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ed9a3d98adafa0805ccbaaff5d2996a2b5795381285d8437a4a5d248dbd12b4a"}, + {file = "pygame-2.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30d1618672a55e8c6669281ba264464b3ab563158e40d89e8c8b3faa0febebd"}, + {file = "pygame-2.5.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39690e9be9baf58b7359d1f3b2336e1fd6f92fedbbce42987be5df27f8d30718"}, + {file = "pygame-2.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03879ec299c9f4ba23901b2649a96b2143f0a5d787f0b6c39469989e2320caf1"}, + {file = "pygame-2.5.2-cp310-cp310-win32.whl", hash = "sha256:74e1d6284100e294f445832e6f6343be4fe4748decc4f8a51131ae197dae8584"}, + {file = "pygame-2.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:485239c7d32265fd35b76ae8f64f34b0637ae11e69d76de15710c4b9edcc7c8d"}, + {file = "pygame-2.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34646ca20e163dc6f6cf8170f1e12a2e41726780112594ac061fa448cf7ccd75"}, + {file = "pygame-2.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3b8a6e351665ed26ea791f0e1fd649d3f483e8681892caef9d471f488f9ea5ee"}, + {file = "pygame-2.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc346965847aef00013fa2364f41a64f068cd096dcc7778fc306ca3735f0eedf"}, + {file = "pygame-2.5.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35632035fd81261f2d797fa810ea8c46111bd78ceb6089d52b61ed7dc3c5d05f"}, + {file = "pygame-2.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e24d05184e4195fe5ebcdce8b18ecb086f00182b9ae460a86682d312ce8d31f"}, + {file = "pygame-2.5.2-cp311-cp311-win32.whl", hash = "sha256:f02c1c7505af18d426d355ac9872bd5c916b27f7b0fe224749930662bea47a50"}, + {file = "pygame-2.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:6d58c8cf937815d3b7cdc0fa9590c5129cb2c9658b72d00e8a4568dea2ff1d42"}, + {file = "pygame-2.5.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1a2a43802bb5e89ce2b3b775744e78db4f9a201bf8d059b946c61722840ceea8"}, + {file = "pygame-2.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1c289f2613c44fe70a1e40769de4a49c5ab5a29b9376f1692bb1a15c9c1c9bfa"}, + {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:074aa6c6e110c925f7f27f00c7733c6303407edc61d738882985091d1eb2ef17"}, + {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe0228501ec616779a0b9c4299e837877783e18df294dd690b9ab0eed3d8aaab"}, + {file = "pygame-2.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31648d38ecdc2335ffc0e38fb18a84b3339730521505dac68514f83a1092e3f4"}, + {file = "pygame-2.5.2-cp312-cp312-win32.whl", hash = "sha256:224c308856334bc792f696e9278e50d099a87c116f7fc314cd6aa3ff99d21592"}, + {file = "pygame-2.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:dd2d2650faf54f9a0f5bd0db8409f79609319725f8f08af6507a0609deadcad4"}, + {file = "pygame-2.5.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:9b30bc1220c457169571aac998e54b013aaeb732d2fd8744966cb1cfab1f61d1"}, + {file = "pygame-2.5.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78fcd7643358b886a44127ff7dec9041c056c212b3a98977674f83f99e9b12d3"}, + {file = "pygame-2.5.2-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35cf093a51cb294ede56c29d4acf41538c00f297fcf78a9b186fb7d23c0577b6"}, + {file = "pygame-2.5.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fe323acbf53a0195c8c98b1b941eba7ac24e3e2b28ae48e8cda566f15fc4945"}, + {file = "pygame-2.5.2-cp36-cp36m-win32.whl", hash = "sha256:5697528266b4716d9cdd44a5a1d210f4d86ef801d0f64ca5da5d0816704009d9"}, + {file = "pygame-2.5.2-cp36-cp36m-win_amd64.whl", hash = "sha256:edda1f7cff4806a4fa39e0e8ccd75f38d1d340fa5fc52d8582ade87aca247d92"}, + {file = "pygame-2.5.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9bd738fd4ecc224769d0b4a719f96900a86578e26e0105193658a32966df2aae"}, + {file = "pygame-2.5.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30a8d7cf12363b4140bf2f93b5eec4028376ca1d0fe4b550588f836279485308"}, + {file = "pygame-2.5.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc12e4dea3e88ea8a553de6d56a37b704dbe2aed95105889f6afeb4b96e62097"}, + {file = "pygame-2.5.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b34c73cb328024f8db3cb6487a37e54000148988275d8d6e5adf99d9323c937"}, + {file = "pygame-2.5.2-cp37-cp37m-win32.whl", hash = "sha256:7d0a2794649defa57ef50b096a99f7113d3d0c2e32d1426cafa7d618eadce4c7"}, + {file = "pygame-2.5.2-cp37-cp37m-win_amd64.whl", hash = "sha256:41f8779f52e0f6e6e6ccb8f0b5536e432bf386ee29c721a1c22cada7767b0cef"}, + {file = "pygame-2.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:677e37bc0ea7afd89dde5a88ced4458aa8656159c70a576eea68b5622ee1997b"}, + {file = "pygame-2.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:47a8415d2bd60e6909823b5643a1d4ef5cc29417d817f2a214b255f6fa3a1e4c"}, + {file = "pygame-2.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ff21201df6278b8ca2e948fb148ffe88f5481fd03760f381dd61e45954c7dff"}, + {file = "pygame-2.5.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d29a84b2e02814b9ba925357fd2e1df78efe5e1aa64dc3051eaed95d2b96eafd"}, + {file = "pygame-2.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d78485c4d21133d6b2fbb504cd544ca655e50b6eb551d2995b3aa6035928adda"}, + {file = "pygame-2.5.2-cp38-cp38-win32.whl", hash = "sha256:d851247239548aa357c4a6840fb67adc2d570ce7cb56988d036a723d26b48bff"}, + {file = "pygame-2.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:88d1cdacc2d3471eceab98bf0c93c14d3a8461f93e58e3d926f20d4de3a75554"}, + {file = "pygame-2.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4f1559e7efe4efb9dc19d2d811d702f325d9605f9f6f9ececa39ee6890c798f5"}, + {file = "pygame-2.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cf2191b756ceb0e8458a761d0c665b0c70b538570449e0d39b75a5ba94ac5cf0"}, + {file = "pygame-2.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cf2257447ce7f2d6de37e5fb019d2bbe32ed05a5721ace8bc78c2d9beaf3aee"}, + {file = "pygame-2.5.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75cbbfaba2b81434d62631d0b08b85fab16cf4a36e40b80298d3868927e1299"}, + {file = "pygame-2.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:daca456d5b9f52e088e06a127dec182b3638a775684fb2260f25d664351cf1ae"}, + {file = "pygame-2.5.2-cp39-cp39-win32.whl", hash = "sha256:3b3e619e33d11c297d7a57a82db40681f9c2c3ae1d5bf06003520b4fe30c435d"}, + {file = "pygame-2.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:1822d534bb7fe756804647b6da2c9ea5d7a62d8796b2e15d172d3be085de28c6"}, + {file = "pygame-2.5.2-pp36-pypy36_pp73-win32.whl", hash = "sha256:e708fc8f709a0fe1d1876489345f2e443d47f3976d33455e2e1e937f972f8677"}, + {file = "pygame-2.5.2-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c13edebc43c240fb0532969e914f0ccefff5ae7e50b0b788d08ad2c15ef793e4"}, + {file = "pygame-2.5.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:263b4a7cbfc9fe2055abc21b0251cc17dea6dff750f0e1c598919ff350cdbffe"}, + {file = "pygame-2.5.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e58e2b0c791041e4bccafa5bd7650623ba1592b8fe62ae0a276b7d0ecb314b6c"}, + {file = "pygame-2.5.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0bd67426c02ffe6c9827fc4bcbda9442fbc451d29b17c83a3c088c56fef2c90"}, + {file = "pygame-2.5.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dcff6cbba1584cf7732ce1dbdd044406cd4f6e296d13bcb7fba963fb4aeefc9"}, + {file = "pygame-2.5.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ce4b6c0bfe44d00bb0998a6517bd0cf9455f642f30f91bc671ad41c05bf6f6ae"}, + {file = "pygame-2.5.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68c4e8e60b725ffc7a6c6ecd9bb5fcc5ed2d6e0e2a2c4a29a8454856ef16ad63"}, + {file = "pygame-2.5.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f3849f97372a3381c66955f99a0d58485ccd513c3d00c030b869094ce6997a6"}, + {file = "pygame-2.5.2.tar.gz", hash = "sha256:c1b89eb5d539e7ac5cf75513125fb5f2f0a2d918b1fd6e981f23bf0ac1b1c24a"}, ] [[package]] name = "pygments" version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1127,18 +1092,17 @@ plugins = ["importlib-metadata"] [[package]] name = "pylint" -version = "2.17.5" +version = "2.17.7" description = "python code static checker" -category = "dev" optional = false python-versions = ">=3.7.2" files = [ - {file = "pylint-2.17.5-py3-none-any.whl", hash = "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413"}, - {file = "pylint-2.17.5.tar.gz", hash = "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"}, + {file = "pylint-2.17.7-py3-none-any.whl", hash = "sha256:27a8d4c7ddc8c2f8c18aa0050148f89ffc09838142193fdbe98f172781a3ff87"}, + {file = "pylint-2.17.7.tar.gz", hash = "sha256:f4fcac7ae74cfe36bc8451e931d8438e4a476c20314b1101c458ad0f05191fad"}, ] [package.dependencies] -astroid = ">=2.15.6,<=2.17.0-dev0" +astroid = ">=2.15.8,<=2.17.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, @@ -1159,7 +1123,6 @@ testutils = ["gitpython (>3)"] name = "pymdown-extensions" version = "9.11" description = "Extension pack for Python Markdown." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1175,7 +1138,6 @@ pyyaml = "*" name = "pyqrcode" version = "1.2.1" description = "A QR code generator written purely in Python with SVG, EPS, PNG and terminal output." -category = "dev" optional = false python-versions = "*" files = [ @@ -1190,7 +1152,6 @@ png = ["pypng (>=0.0.13)"] name = "pytest" version = "6.2.5" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1215,7 +1176,6 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm name = "pytest-cov" version = "3.0.0" description = "Pytest plugin for measuring coverage." -category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1234,7 +1194,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-mock" version = "3.11.1" description = "Thin-wrapper around the mock package for easier use with pytest" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1252,7 +1211,6 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1267,7 +1225,6 @@ six = ">=1.5" name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -1276,6 +1233,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1283,8 +1241,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1301,6 +1266,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1308,6 +1274,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1317,7 +1284,6 @@ files = [ name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " -category = "main" optional = true python-versions = ">=3.6" files = [ @@ -1332,7 +1298,6 @@ pyyaml = "*" name = "pyzbar" version = "0.1.9" description = "Read one-dimensional barcodes and QR codes from Python 2 and 3." -category = "main" optional = true python-versions = "*" files = [ @@ -1348,7 +1313,6 @@ scripts = ["Pillow (>=3.2.0)"] name = "requests" version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1370,7 +1334,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "rfc3986" version = "1.5.0" description = "Validating URI References per RFC 3986" -category = "main" optional = false python-versions = "*" files = [ @@ -1385,7 +1348,6 @@ idna2008 = ["idna"] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = true python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1397,7 +1359,6 @@ files = [ name = "sniffio" version = "1.3.0" description = "Sniff out which async library your code is running under" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1409,7 +1370,6 @@ files = [ name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1421,7 +1381,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1433,7 +1392,6 @@ files = [ name = "tomlkit" version = "0.12.1" description = "Style preserving TOML library" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1443,21 +1401,19 @@ files = [ [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "dev" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] [[package]] name = "ur" version = "0.1.0" description = "UR Implementation in Python -- ported from the C++ Reference Implementation by Blockchain Commons" -category = "main" optional = false python-versions = "*" files = [] @@ -1469,14 +1425,13 @@ url = "vendor/foundation-ur-py" [[package]] name = "urllib3" -version = "2.0.4" +version = "2.0.6" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = true python-versions = ">=3.7" files = [ - {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, - {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, + {file = "urllib3-2.0.6-py3-none-any.whl", hash = "sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2"}, + {file = "urllib3-2.0.6.tar.gz", hash = "sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564"}, ] [package.extras] @@ -1489,7 +1444,6 @@ zstd = ["zstandard (>=0.18.0)"] name = "urtypes" version = "0.1.0" description = "Python implementation of the Blockchain Commons UR Types specification" -category = "main" optional = false python-versions = "^3.9.1" files = [] @@ -1503,7 +1457,6 @@ url = "vendor/urtypes" name = "watchdog" version = "3.0.0" description = "Filesystem events monitoring" -category = "main" optional = true python-versions = ">=3.7" files = [ @@ -1543,7 +1496,6 @@ watchmedo = ["PyYAML (>=3.10)"] name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." -category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -1626,18 +1578,17 @@ files = [ [[package]] name = "zipp" -version = "3.16.2" +version = "3.17.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = true python-versions = ">=3.8" files = [ - {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, - {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [extras] diff --git a/src/krux/wallet.py b/src/krux/wallet.py index 1d9e71c2e..9dfe310de 100644 --- a/src/krux/wallet.py +++ b/src/krux/wallet.py @@ -43,7 +43,7 @@ def __init__(self, key): self.policy = None if not self.key.multisig: self.descriptor = Descriptor.from_string( - "wpkh(%s/{0,1}/*)" % self.key.key_expression() + "wpkh(%s/<0;1>/*)" % self.key.key_expression() ) self.label = t("Single-sig") self.policy = {"type": self.descriptor.scriptpubkey_type()} @@ -206,7 +206,7 @@ def parse_wallet(wallet_data, network): ) else: # Single-sig - descriptor = Descriptor.from_string("wpkh(%s/{0,1}/*)" % keys[0]) + descriptor = Descriptor.from_string("wpkh(%s/<0;1>/*)" % keys[0]) label = ( key_vals[key_vals.index("Name") + 1] if key_vals.index("Name") >= 0 diff --git a/tests/test_wallet.py b/tests/test_wallet.py index a97d3e589..2cd42d059 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -118,16 +118,16 @@ def tdata(mocker): ), ) - UNAMBIGUOUS_SINGLESIG_DESCRIPTOR = "wpkh([55f8fc5d/84h/0h/0h]xpub6DPMTPxGMqdtzMwpqT1dDQaVdyaEppEm2qYSaJ7ANsuES7HkNzrXJst1Ed8D7NAnijUdgSDUFgph1oj5LKKAD5gyxWNhNP2AuDqaKYqzphA/{0,1}/*)" + UNAMBIGUOUS_SINGLESIG_DESCRIPTOR = "wpkh([55f8fc5d/84h/0h/0h]xpub6DPMTPxGMqdtzMwpqT1dDQaVdyaEppEm2qYSaJ7ANsuES7HkNzrXJst1Ed8D7NAnijUdgSDUFgph1oj5LKKAD5gyxWNhNP2AuDqaKYqzphA/<0;1>/*)" AMBIGUOUS_SINGLESIG_DESCRIPTOR = "wpkh([55f8fc5d/84h/0h/0h]xpub6DPMTPxGMqdtzMwpqT1dDQaVdyaEppEm2qYSaJ7ANsuES7HkNzrXJst1Ed8D7NAnijUdgSDUFgph1oj5LKKAD5gyxWNhNP2AuDqaKYqzphA)" - UNAMBIGUOUS_MULTISIG_DESCRIPTOR = "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/{0,1}/*,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/{0,1}/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/{0,1}/*))" + UNAMBIGUOUS_MULTISIG_DESCRIPTOR = "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<0;1>/*,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<0;1>/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/<0;1>/*))" AMBIGUOUS_MULTISIG_DESCRIPTOR = "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv))" UNRELATED_SINGLESIG_DESCRIPTOR = "wpkh([55f8fc5d/84h/0h/0h]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB)" UNRELATED_MULTISIG_DESCRIPTOR = "wsh(sortedmulti(2,[55f8fc5d/48h/0h/0h/2h]xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv))" - UNSORTED_MULTISIG_DESCRIPTOR = "wsh(multi(2,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/{0,1}/*,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/{0,1}/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/{0,1}/*))" + UNSORTED_MULTISIG_DESCRIPTOR = "wsh(multi(2,[3e15470d/48h/0h/0h/2h]xpub6F2P6Pz5KLPgCc6pTBd2xxCunaSYWc8CdkL28W5z15pJrN3aCYY7mCUAkCMtqrgT2wdhAGgRnJxAkCCUpGKoXKxQ57yffEGmPwtYA3DEXwu/<0;1>/*,[55f8fc5d/48h/0h/0h/2h]xpub6EKmKYGYc1WY6t9d3d9SksR8keSaPZbFa6tqsGiH4xVxx8d2YyxSX7WG6yXEX3CmG54dPCxaapDw1XsjwCmfoqP7tbsAeqMVfKvqSAu4ndy/<0;1>/*,[d3a80c8b/48h/0h/0h/2h]xpub6FKYY6y3oVi7ihSCszFKRSeZj5SzrfSsUFXhKqjMV4iigrLhxwMX3mrjioNyLTZ5iD3u4wU9S3tyzpJGxhd5geaXoQ68jGz2M6dfh2zJrUv/<0;1>/*))" return namedtuple( "TestData", @@ -346,7 +346,7 @@ def test_load_multisig(mocker, m5stickv, tdata): ], }, ), - # TODO: Fix + # TODO: Fix - ValueError: xpub not a cosigner # (tdata.UR_OUTPUT_MULTISIG_WALLET_DATA, FORMAT_UR, tdata.UR_OUTPUT_MULTISIG_DESCRIPTOR, '2 of 3', { # 'type': 'p2wsh', 'm': 2, 'n': 3, 'cosigners': [ # tdata.MULTISIG_KEY1.xpub(), @@ -436,8 +436,7 @@ def test_load_singlesig_fails_with_multisig_descriptor(mocker, m5stickv, tdata): cases = [ (tdata.SPECTER_MULTISIG_WALLET_DATA, FORMAT_PMOFN), (tdata.BLUEWALLET_MULTISIG_WALLET_DATA, FORMAT_NONE), - # TODO: Fix - # (tdata.UR_OUTPUT_MULTISIG_WALLET_DATA, FORMAT_UR), + (tdata.UR_OUTPUT_MULTISIG_WALLET_DATA, FORMAT_UR), (tdata.UR_BYTES_MULTISIG_WALLET_DATA, FORMAT_UR), ] for case in cases: @@ -537,7 +536,10 @@ def test_parse_wallet(mocker, m5stickv, tdata): ), ] + case_n = 1 for case in cases: + print(case_n) + case_n += 1 descriptor, label = parse_wallet(case[0], NETWORKS["main"]) assert descriptor.to_string() == case[1] assert label == case[2] diff --git a/vendor/embit b/vendor/embit index be13c6c97..605ca51e9 160000 --- a/vendor/embit +++ b/vendor/embit @@ -1 +1 @@ -Subproject commit be13c6c9789055f39f515389ab3fbf2e1c6beaf3 +Subproject commit 605ca51e96d28b1deed96f790a6ef67c15262adc diff --git a/vendor/urtypes b/vendor/urtypes index 8ff8e6ebe..9b84f87c2 160000 --- a/vendor/urtypes +++ b/vendor/urtypes @@ -1 +1 @@ -Subproject commit 8ff8e6ebe484d7a0f98ad73f4441708704998b43 +Subproject commit 9b84f87c2b127baea0d665ddcbe4f677ee4f45be From f18f14f59ec891477910460e35a6b145fd4ec8fa Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Wed, 11 Oct 2023 16:48:20 -0300 Subject: [PATCH 050/114] better handling of bytes data from QR for simulator and Android --- simulator/kruxsim/mocks/sensor.py | 8 +++++++- src/krux/qr.py | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/simulator/kruxsim/mocks/sensor.py b/simulator/kruxsim/mocks/sensor.py index a427c9357..3904698f9 100644 --- a/simulator/kruxsim/mocks/sensor.py +++ b/simulator/kruxsim/mocks/sensor.py @@ -75,7 +75,13 @@ def find_qrcodes(img): codes = [] data = pyzbar.pyzbar.decode(img) if data: - codes.append(Mockqrcode(data[0].data.decode())) + try: + test_encoding = data[0].data.decode().encode('shift-jis').decode() + # Send data as string + codes.append(Mockqrcode(data[0].data.decode())) + except: + # If fails re-decode test send re-encoded bytes + codes.append(Mockqrcode(data[0].data.decode().encode('shift-jis'))) return codes diff --git a/src/krux/qr.py b/src/krux/qr.py index 9ad82e515..b4e4deba5 100644 --- a/src/krux/qr.py +++ b/src/krux/qr.py @@ -93,6 +93,9 @@ def result(self): return UR(self.decoder.result.type, bytearray(self.decoder.result.cbor)) code_buffer = io.StringIO("") for _, part in sorted(self.parts.items()): + if isinstance(part, bytes): + # Encoded data won't write on StringIO + return part code_buffer.write(part) code = code_buffer.getvalue() code_buffer.close() From 56e7753c0f8080798fcebeb21e60c1b54413b1e0 Mon Sep 17 00:00:00 2001 From: Eduardo Schoenknecht Date: Wed, 11 Oct 2023 18:18:01 -0300 Subject: [PATCH 051/114] sign messages at derived addresses --- src/krux/key.py | 17 +++++++++++ src/krux/pages/home.py | 67 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/src/krux/key.py b/src/krux/key.py index bb986fd02..b6bf00dde 100644 --- a/src/krux/key.py +++ b/src/krux/key.py @@ -88,6 +88,23 @@ def sign(self, message_hash): """Signs a message with the extended master private key""" return self.root.derive(self.derivation).sign(message_hash) + def sign_at(self, derivation, message_hash): + """Signs a message at an adress derived from master key (code adapted from specterDIY)""" + from embit import ec + from embit.util import secp256k1 + + prv = self.root.derive(derivation).key + sig = secp256k1.ecdsa_sign_recoverable( + message_hash, prv._secret # pylint: disable=W0212 + ) + flag = sig[64] + flag = bytes([27 + flag + 4]) + ec_signature = ec.Signature(sig[:64]) + ser = flag + secp256k1.ecdsa_signature_serialize_compact( + ec_signature._sig # pylint: disable=W0212 + ) + return ser + @staticmethod def pick_final_word(entropy, words): """Returns a random final word with a valid checksum for the given list of diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 89c48908d..c40e2d405 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -408,6 +408,70 @@ def _load_file(self, file_ext=""): return filename, sd.read_binary(filename) return "", None + def sign_at_address(self, data, qr_format): + """Message signed at a derived Bitcoin address - Sparrow/Specter""" + if data.startswith(b"signmessage"): + from embit import bip32, compact + import hashlib + from ..baseconv import base_encode + + data_blocks = data.split(b" ") + if len(data_blocks) >= 3: + derivation = data_blocks[1].decode() + message = b" ".join(data_blocks[2:]) + message = message.split(b":") + if len(message) >= 2 and message[0] == b"ascii": + message = b" ".join(message[1:]) + derivation = bip32.parse_path(derivation) + self.ctx.display.clear() + address = self.ctx.wallet.descriptor.derive( + derivation[4], branch_index=0 + ).address(network=self.ctx.wallet.key.network) + add_chars_amount = ( + self.ctx.display.width() // self.ctx.display.font_width + ) + add_chars_amount -= 10 + add_chars_amount //= 2 + short_address = ( + str(derivation[4]) + + ". " + + address[: add_chars_amount + 3] + + ".." + + address[-add_chars_amount:] + ) + self.ctx.display.draw_centered_text( + t("Message:") + + "\n" + + message.decode() + + "\n\n" + + "Address:" + + "\n" + + short_address + ) + if not self.prompt(t("Sign?"), self.ctx.display.bottom_prompt_line): + return MENU_CONTINUE + message_hash = hashlib.sha256( + hashlib.sha256( + b"\x18Bitcoin Signed Message:\n" + + compact.to_bytes(len(message)) + + message + ).digest() + ).digest() + sig = self.ctx.wallet.key.sign_at(derivation, message_hash) + + # Encode sig as base64 string + encoded_sig = base_encode(sig, 64).strip().decode() + self.ctx.display.clear() + self.ctx.display.draw_centered_text( + t("Signature") + ":\n\n%s" % encoded_sig + ) + self.ctx.input.wait_for_button() + title = t("Signed Message") + self.display_qr_codes(encoded_sig, qr_format, title) + self.print_standard_qr(encoded_sig, qr_format, title) + return True + return False + def sign_message(self): """Handler for the 'sign message' menu item""" @@ -434,6 +498,9 @@ def sign_message(self): # message read OK! data = data.encode() if isinstance(data, str) else data + if self.sign_at_address(data, qr_format): + return MENU_CONTINUE + message_hash = None if len(data) == 32: # It's a sha256 hash already From 452545d14f64b1e6f536866964faa909426191a2 Mon Sep 17 00:00:00 2001 From: odudex Date: Fri, 13 Oct 2023 17:11:53 -0300 Subject: [PATCH 052/114] encoding adjustments for simulator and Android --- simulator/kruxsim/mocks/sensor.py | 8 +------- src/krux/pages/login.py | 27 +++++++++++++++++---------- tests/test_input.py | 2 +- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/simulator/kruxsim/mocks/sensor.py b/simulator/kruxsim/mocks/sensor.py index 3904698f9..a427c9357 100644 --- a/simulator/kruxsim/mocks/sensor.py +++ b/simulator/kruxsim/mocks/sensor.py @@ -75,13 +75,7 @@ def find_qrcodes(img): codes = [] data = pyzbar.pyzbar.decode(img) if data: - try: - test_encoding = data[0].data.decode().encode('shift-jis').decode() - # Send data as string - codes.append(Mockqrcode(data[0].data.decode())) - except: - # If fails re-decode test send re-encoded bytes - codes.append(Mockqrcode(data[0].data.decode().encode('shift-jis'))) + codes.append(Mockqrcode(data[0].data.decode())) return codes diff --git a/src/krux/pages/login.py b/src/krux/pages/login.py index 69ae2783b..936082ae2 100644 --- a/src/krux/pages/login.py +++ b/src/krux/pages/login.py @@ -447,21 +447,28 @@ def load_key_from_qr_code(self): pass if not words: + data_bytes = "" try: data_bytes = ( data.encode("latin-1") if isinstance(data, str) else data ) - # CompactSeedQR format - if len(data_bytes) in (16, 32): - words = bip39.mnemonic_from_bytes(data_bytes).split() - # SeedQR format - elif len(data_bytes) in (48, 96): - words = [ - WORDLIST[int(data_bytes[i : i + 4])] - for i in range(0, len(data_bytes), 4) - ] except: - pass + try: + data_bytes = ( + data.encode("shift-jis") if isinstance(data, str) else data + ) + except: + pass + + if len(data_bytes) in (16, 32): + # CompactSeedQR format + words = bip39.mnemonic_from_bytes(data_bytes).split() + # SeedQR format + elif len(data_bytes) in (48, 96): + words = [ + WORDLIST[int(data_bytes[i : i + 4])] + for i in range(0, len(data_bytes), 4) + ] if not words: words = self._encrypted_qr_code(data) if not words or (len(words) != 12 and len(words) != 24): diff --git a/tests/test_input.py b/tests/test_input.py index e95563e50..1f1008f94 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -461,7 +461,7 @@ def test_touch_indexing(mocker, amigo_tft): input = reset_input_states(mocker, input) elapsed_time = 0 - + def time_control(point1, point2): nonlocal elapsed_time mocker.patch.object(time, "ticks_ms", new=lambda: elapsed_time) From f189a29ff80b44e41b9c1d9ac1a37c79df706bd4 Mon Sep 17 00:00:00 2001 From: odudex Date: Tue, 17 Oct 2023 16:16:03 -0300 Subject: [PATCH 053/114] polish message signing - cut big messages --- src/krux/pages/home.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index c40e2d405..a37337b4c 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -410,6 +410,7 @@ def _load_file(self, file_ext=""): def sign_at_address(self, data, qr_format): """Message signed at a derived Bitcoin address - Sparrow/Specter""" + if data.startswith(b"signmessage"): from embit import bip32, compact import hashlib @@ -439,17 +440,28 @@ def sign_at_address(self, data, qr_format): + ".." + address[-add_chars_amount:] ) - self.ctx.display.draw_centered_text( + message_to_display = self.ctx.display.to_lines(message.decode()) + if len(message_to_display) > self.ctx.display.total_lines - 10: + # 5 lines are used for prompt and constant texts + message_cut = (self.ctx.display.total_lines - 10) // 2 + message_to_display = ( + message_to_display[:message_cut] + + ["..."] + + message_to_display[-message_cut:] + ) + message_to_display = "\n".join(message_to_display) + + self.ctx.display.draw_hcentered_text( t("Message:") + "\n" - + message.decode() + + message_to_display + "\n\n" + "Address:" + "\n" + short_address ) if not self.prompt(t("Sign?"), self.ctx.display.bottom_prompt_line): - return MENU_CONTINUE + return True message_hash = hashlib.sha256( hashlib.sha256( b"\x18Bitcoin Signed Message:\n" From 978148202cc3596f5429150d6c187ad05a0e2b32 Mon Sep 17 00:00:00 2001 From: Jean Do Date: Thu, 19 Oct 2023 16:59:39 -0400 Subject: [PATCH 054/114] erase_spiffs() to do so in 4k chunks --- src/krux/firmware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/krux/firmware.py b/src/krux/firmware.py index 4adfe7ff3..83bef0303 100644 --- a/src/krux/firmware.py +++ b/src/krux/firmware.py @@ -44,7 +44,7 @@ MAIN_BOOT_CONFIG_SECTOR_ADDRESS = 0x00004000 BACKUP_BOOT_CONFIG_SECTOR_ADDRESS = 0x00005000 -ERASE_BLOCK_SIZE = 0x10000 +ERASE_BLOCK_SIZE = 0x1000 FLASH_IO_WAIT_TIME = 100 From 952c25fe17c3f3b1632a79ed9ed8c365b61aabc7 Mon Sep 17 00:00:00 2001 From: odudex Date: Sat, 21 Oct 2023 15:07:37 -0300 Subject: [PATCH 055/114] isolate file saving operations on dedicated page loaded only if SD available --- src/krux/pages/__init__.py | 12 +++ src/krux/pages/files_operations.py | 139 ++++++++++++++++++++++++ src/krux/pages/home.py | 167 ++++++----------------------- src/krux/pages/print_page.py | 1 - src/krux/pages/settings_page.py | 16 ++- 5 files changed, 187 insertions(+), 148 deletions(-) create mode 100644 src/krux/pages/files_operations.py diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 9a7a1b3ff..991d60879 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -38,6 +38,7 @@ from ..display import DEFAULT_PADDING from ..qr import to_qr_codes from ..krux_settings import t, Settings, LoggingSettings, BitcoinSettings +from ..sd_card import SDHandler MENU_CONTINUE = 0 MENU_EXIT = 1 @@ -466,6 +467,17 @@ def prompt(self, text, offset_y=0): # BUTTON_ENTER return answer + def has_sd_card(self): + """Checks if the device has a SD card inserted""" + self.ctx.display.clear() + self.ctx.display.draw_centered_text(t("Checking for SD card..")) + try: + # Check for SD hot-plug + with SDHandler(): + return True + except: + return False + def shutdown(self): """Handler for the 'shutdown' menu item""" if self.prompt(t("Are you sure?"), self.ctx.display.height() // 2): diff --git a/src/krux/pages/files_operations.py b/src/krux/pages/files_operations.py new file mode 100644 index 000000000..122a0341d --- /dev/null +++ b/src/krux/pages/files_operations.py @@ -0,0 +1,139 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2023 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from . import ( + Page, + ESC_KEY, + LETTERS, + UPPERCASE_LETTERS, +) +from ..krux_settings import t +from ..sd_card import SDHandler + +FILE_SPECIAL = "0123456789()-.[]_~" + +class SaveFile(Page): + """File saver user interface""" + + def __init__(self, ctx): + super().__init__(ctx, None) + + def save_file( + self, + data, + empty_name, + filename="", + file_description="", + file_extension="", + file_suffix="", + save_as_binary=True, + ): + """File saver handler page""" + try: + with SDHandler() as sd: + # Wait until user defines a filename or select NO on the prompt + filename_undefined = True + while filename_undefined: + self.ctx.display.clear() + if self.prompt( + file_description + "\n" + t("Save to SD card?") + "\n\n", + self.ctx.display.height() // 2, + ): + filename, filename_undefined = self._set_filename( + filename, + empty_name, + file_suffix, + file_extension, + ) + + # if user defined a filename and it is ok, save! + if not filename_undefined: + if save_as_binary: + sd.write_binary(filename, data) + else: + sd.write(filename, data) + self.ctx.display.clear() + self.flash_text(t("Saved to SD card:\n%s") % filename) + else: + filename_undefined = False + except: + self.ctx.display.clear() + self.flash_text(t("SD card not detected.")) + + def _set_filename( + self, curr_filename="", empty_filename="some_file", suffix="", file_extension="" + ): + """Helper to set the filename based on a suggestion and the user input""" + started_filename = curr_filename + filename_undefined = True + + # remove the file_extension if exists + curr_filename = ( + curr_filename[: len(curr_filename) - len(file_extension)] + if curr_filename.endswith(file_extension) + else curr_filename + ) + + # remove the suffix if exists (because we will add it later) + curr_filename = ( + curr_filename[: len(curr_filename) - len(suffix)] + if curr_filename.endswith(suffix) + else curr_filename + ) + + curr_filename = self.capture_from_keypad( + t("Filename"), + [LETTERS, UPPERCASE_LETTERS, FILE_SPECIAL], + starting_buffer=("%s" + suffix) % curr_filename + if curr_filename + else empty_filename + suffix, + ) + + # Verify if user defined a filename and it is not just dots + if ( + curr_filename + and curr_filename != ESC_KEY + and not all(c in "." for c in curr_filename) + ): + # add the extension ".psbt" + curr_filename = ( + curr_filename + if curr_filename.endswith(file_extension) + else curr_filename + file_extension + ) + # check and warn for overwrite filename + # add the "/sd/" prefix + if SDHandler.file_exists("/sd/" + curr_filename): + self.ctx.display.clear() + if self.prompt( + t("Filename %s exists on SD card, overwrite?") % curr_filename + + "\n\n", + self.ctx.display.height() // 2, + ): + filename_undefined = False + else: + filename_undefined = False + + if curr_filename == ESC_KEY: + curr_filename = started_filename + + return (curr_filename, filename_undefined) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index a37337b4c..9d9e263cf 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -31,9 +31,6 @@ Menu, MENU_CONTINUE, MENU_EXIT, - ESC_KEY, - LETTERS, - UPPERCASE_LETTERS, ) from ..sd_card import SDHandler @@ -42,8 +39,6 @@ # len of the xpub to show WALLET_XPUB_DIGITS = 4 -FILE_SPECIAL = "0123456789()-.[]_~" - PSBT_FILE_SUFFIX = "-signed" PSBT_FILE_EXTENSION = ".psbt" PUBKEY_FILE_EXTENSION = ".pub" @@ -193,8 +188,11 @@ def public_key(self): self.print_standard_qr(xpub, FORMAT_NONE, title) # Try to save the XPUB file on the SD card - try: - self._save_file( + if self.has_sd_card(): + from .files_operations import SaveFile + + save_page = SaveFile(self.ctx) + save_page.save_file( xpub, title, title, @@ -202,8 +200,6 @@ def public_key(self): PUBKEY_FILE_EXTENSION, save_as_binary=False, ) - except OSError: - pass return MENU_CONTINUE @@ -372,10 +368,11 @@ def sign_psbt(self): gc.collect() # Try to save the signed PSBT file on the SD card - self.ctx.display.clear() - self.ctx.display.draw_centered_text(t("Checking for SD card..")) - try: - self._save_file( + if self.has_sd_card(): + from .files_operations import SaveFile + + save_page = SaveFile(self.ctx) + save_page.save_file( serialized_signed_psbt, "QRCode", psbt_filename, @@ -383,29 +380,25 @@ def sign_psbt(self): PSBT_FILE_EXTENSION, PSBT_FILE_SUFFIX, ) - except OSError: - pass - return MENU_CONTINUE def _load_file(self, file_ext=""): - self.ctx.display.clear() - self.ctx.display.draw_centered_text(t("Checking for SD card..")) - with SDHandler() as sd: - self.ctx.display.clear() - if self.prompt( - t("Load from SD card?") + "\n\n", self.ctx.display.height() // 2 - ): - from .files_manager import FileManager + if self.has_sd_card(): + with SDHandler() as sd: + self.ctx.display.clear() + if self.prompt( + t("Load from SD card?") + "\n\n", self.ctx.display.height() // 2 + ): + from .files_manager import FileManager - file_manager = FileManager(self.ctx) - filename = file_manager.select_file(file_extension=file_ext) + file_manager = FileManager(self.ctx) + filename = file_manager.select_file(file_extension=file_ext) - if filename: - filename = file_manager.display_file(filename) + if filename: + filename = file_manager.display_file(filename) - if self.prompt(t("Load?"), self.ctx.display.bottom_prompt_line): - return filename, sd.read_binary(filename) + if self.prompt(t("Load?"), self.ctx.display.bottom_prompt_line): + return filename, sd.read_binary(filename) return "", None def sign_at_address(self, data, qr_format): @@ -573,8 +566,11 @@ def sign_message(self): gc.collect() # Try to save the signature file on the SD card - try: - self._save_file( + if self.has_sd_card(): + from .files_operations import SaveFile + + save_page = SaveFile(self.ctx) + save_page.save_file( sig, "message", message_filename, @@ -582,117 +578,14 @@ def sign_message(self): SIGNATURE_FILE_EXTENSION, SIGNATURE_FILE_SUFFIX, ) - except OSError: - pass - # Try to save the public key on the SD card - try: - self._save_file( + # Try to save the public key on the SD card + save_page.save_file( pubkey, "pubkey", "", title + ":", PUBKEY_FILE_EXTENSION, "", False ) - except OSError: - pass return MENU_CONTINUE - def _save_file( - self, - data, - empty_name, - filename="", - file_description="", - file_extension="", - file_suffix="", - save_as_binary=True, - ): - self.ctx.display.clear() - self.ctx.display.draw_centered_text(t("Checking for SD card..")) - with SDHandler() as sd: - # Wait until user defines a filename or select NO on the prompt - filename_undefined = True - while filename_undefined: - self.ctx.display.clear() - if self.prompt( - file_description + "\n" + t("Save to SD card?") + "\n\n", - self.ctx.display.height() // 2, - ): - filename, filename_undefined = self._set_filename( - filename, - empty_name, - file_suffix, - file_extension, - ) - - # if user defined a filename and it is ok, save! - if not filename_undefined: - if save_as_binary: - sd.write_binary(filename, data) - else: - sd.write(filename, data) - self.ctx.display.clear() - self.flash_text(t("Saved to SD card:\n%s") % filename) - else: - filename_undefined = False - - def _set_filename( - self, curr_filename="", empty_filename="some_file", suffix="", file_extension="" - ): - """Helper to set the filename based on a suggestion and the user input""" - started_filename = curr_filename - filename_undefined = True - - # remove the file_extension if exists - curr_filename = ( - curr_filename[: len(curr_filename) - len(file_extension)] - if curr_filename.endswith(file_extension) - else curr_filename - ) - - # remove the suffix if exists (because we will add it later) - curr_filename = ( - curr_filename[: len(curr_filename) - len(suffix)] - if curr_filename.endswith(suffix) - else curr_filename - ) - - curr_filename = self.capture_from_keypad( - t("Filename"), - [LETTERS, UPPERCASE_LETTERS, FILE_SPECIAL], - starting_buffer=("%s" + suffix) % curr_filename - if curr_filename - else empty_filename + suffix, - ) - - # Verify if user defined a filename and it is not just dots - if ( - curr_filename - and curr_filename != ESC_KEY - and not all(c in "." for c in curr_filename) - ): - # add the extension ".psbt" - curr_filename = ( - curr_filename - if curr_filename.endswith(file_extension) - else curr_filename + file_extension - ) - # check and warn for overwrite filename - # add the "/sd/" prefix - if SDHandler.file_exists("/sd/" + curr_filename): - self.ctx.display.clear() - if self.prompt( - t("Filename %s exists on SD card, overwrite?") % curr_filename - + "\n\n", - self.ctx.display.height() // 2, - ): - filename_undefined = False - else: - filename_undefined = False - - if curr_filename == ESC_KEY: - curr_filename = started_filename - - return (curr_filename, filename_undefined) - def display_wallet(self, wallet, include_qr=True): """Displays a wallet, including its label and abbreviated xpubs. If include_qr is True, a QR code of the wallet will be shown diff --git a/src/krux/pages/print_page.py b/src/krux/pages/print_page.py index f83c66dda..eb4f825e8 100644 --- a/src/krux/pages/print_page.py +++ b/src/krux/pages/print_page.py @@ -31,7 +31,6 @@ class PrintPage(Page): """Printing user interface""" def __init__(self, ctx): - # Returns True if printer successfully created super().__init__(ctx, None) self.ctx = ctx self.ctx.display.clear() diff --git a/src/krux/pages/settings_page.py b/src/krux/pages/settings_page.py index cf6495bc4..0a38f1736 100644 --- a/src/krux/pages/settings_page.py +++ b/src/krux/pages/settings_page.py @@ -77,16 +77,12 @@ def settings(self): """Handler for the settings""" location = Settings().persist.location if location == SD_PATH: - self.ctx.display.clear() - self.ctx.display.draw_centered_text(t("Checking for SD card..")) - try: - # Check for SD hot-plug - with SDHandler(): - self._display_centered_text( - t("Your changes will be kept on the SD card."), - duration=SD_MSG_TIME, - ) - except OSError: + if self.has_sd_card(): + self._display_centered_text( + t("Your changes will be kept on the SD card."), + duration=SD_MSG_TIME, + ) + else: self._display_centered_text( t("SD card not detected.") + "\n\n" From 227d94a44185d7aff31763fd15085b7aa791ef9e Mon Sep 17 00:00:00 2001 From: odudex Date: Sat, 21 Oct 2023 16:18:39 -0300 Subject: [PATCH 056/114] isolate message signing ui --- src/krux/pages/files_operations.py | 1 + src/krux/pages/home.py | 199 ++--------------------- src/krux/pages/sign_message_ui.py | 252 +++++++++++++++++++++++++++++ src/krux/sd_card.py | 5 + 4 files changed, 268 insertions(+), 189 deletions(-) create mode 100644 src/krux/pages/sign_message_ui.py diff --git a/src/krux/pages/files_operations.py b/src/krux/pages/files_operations.py index 122a0341d..f1020a2ee 100644 --- a/src/krux/pages/files_operations.py +++ b/src/krux/pages/files_operations.py @@ -31,6 +31,7 @@ FILE_SPECIAL = "0123456789()-.[]_~" + class SaveFile(Page): """File saver user interface""" diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 9d9e263cf..eaaceead3 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -32,19 +32,18 @@ MENU_CONTINUE, MENU_EXIT, ) -from ..sd_card import SDHandler +from ..sd_card import ( + SDHandler, + PUBKEY_FILE_EXTENSION, + PSBT_FILE_EXTENSION, + SIGNED_FILE_SUFFIX, +) # to start xpub value without the xpub/zpub/ypub prefix WALLET_XPUB_START = 4 # len of the xpub to show WALLET_XPUB_DIGITS = 4 -PSBT_FILE_SUFFIX = "-signed" -PSBT_FILE_EXTENSION = ".psbt" -PUBKEY_FILE_EXTENSION = ".pub" -SIGNATURE_FILE_EXTENSION = ".sig" -SIGNATURE_FILE_SUFFIX = PSBT_FILE_SUFFIX - class Home(Page): """Home is the main menu page of the app""" @@ -378,7 +377,7 @@ def sign_psbt(self): psbt_filename, title + ":", PSBT_FILE_EXTENSION, - PSBT_FILE_SUFFIX, + SIGNED_FILE_SUFFIX, ) return MENU_CONTINUE @@ -401,190 +400,12 @@ def _load_file(self, file_ext=""): return filename, sd.read_binary(filename) return "", None - def sign_at_address(self, data, qr_format): - """Message signed at a derived Bitcoin address - Sparrow/Specter""" - - if data.startswith(b"signmessage"): - from embit import bip32, compact - import hashlib - from ..baseconv import base_encode - - data_blocks = data.split(b" ") - if len(data_blocks) >= 3: - derivation = data_blocks[1].decode() - message = b" ".join(data_blocks[2:]) - message = message.split(b":") - if len(message) >= 2 and message[0] == b"ascii": - message = b" ".join(message[1:]) - derivation = bip32.parse_path(derivation) - self.ctx.display.clear() - address = self.ctx.wallet.descriptor.derive( - derivation[4], branch_index=0 - ).address(network=self.ctx.wallet.key.network) - add_chars_amount = ( - self.ctx.display.width() // self.ctx.display.font_width - ) - add_chars_amount -= 10 - add_chars_amount //= 2 - short_address = ( - str(derivation[4]) - + ". " - + address[: add_chars_amount + 3] - + ".." - + address[-add_chars_amount:] - ) - message_to_display = self.ctx.display.to_lines(message.decode()) - if len(message_to_display) > self.ctx.display.total_lines - 10: - # 5 lines are used for prompt and constant texts - message_cut = (self.ctx.display.total_lines - 10) // 2 - message_to_display = ( - message_to_display[:message_cut] - + ["..."] - + message_to_display[-message_cut:] - ) - message_to_display = "\n".join(message_to_display) - - self.ctx.display.draw_hcentered_text( - t("Message:") - + "\n" - + message_to_display - + "\n\n" - + "Address:" - + "\n" - + short_address - ) - if not self.prompt(t("Sign?"), self.ctx.display.bottom_prompt_line): - return True - message_hash = hashlib.sha256( - hashlib.sha256( - b"\x18Bitcoin Signed Message:\n" - + compact.to_bytes(len(message)) - + message - ).digest() - ).digest() - sig = self.ctx.wallet.key.sign_at(derivation, message_hash) - - # Encode sig as base64 string - encoded_sig = base_encode(sig, 64).strip().decode() - self.ctx.display.clear() - self.ctx.display.draw_centered_text( - t("Signature") + ":\n\n%s" % encoded_sig - ) - self.ctx.input.wait_for_button() - title = t("Signed Message") - self.display_qr_codes(encoded_sig, qr_format, title) - self.print_standard_qr(encoded_sig, qr_format, title) - return True - return False - def sign_message(self): """Handler for the 'sign message' menu item""" + from .sign_message_ui import SignMessage - import binascii - import hashlib - from ..baseconv import base_encode - - # Try to read a message from camera - message_filename = "" - data, qr_format = self.capture_qr_code() - - if data is None: - # Try to read a message from a file on the SD card - qr_format = FORMAT_NONE - try: - message_filename, data = self._load_file() - except OSError: - pass - - if data is None: - self.flash_text(t("Failed to load message"), theme.error_color) - return MENU_CONTINUE - - # message read OK! - data = data.encode() if isinstance(data, str) else data - - if self.sign_at_address(data, qr_format): - return MENU_CONTINUE - - message_hash = None - if len(data) == 32: - # It's a sha256 hash already - message_hash = data - else: - if len(data) == 64: - # It may be a hex-encoded sha256 hash - try: - message_hash = binascii.unhexlify(data) - except: - pass - if message_hash is None: - # It's a message, so compute its sha256 hash - message_hash = hashlib.sha256(data).digest() - - # memory management - del data - gc.collect() - - self.ctx.display.clear() - self.ctx.display.draw_centered_text( - t("SHA256:\n%s") % binascii.hexlify(message_hash).decode() - ) - if not self.prompt(t("Sign?"), self.ctx.display.bottom_prompt_line): - return MENU_CONTINUE - - # User confirmed to sign! - sig = self.ctx.wallet.key.sign(message_hash).serialize() - - # Encode sig as base64 string - encoded_sig = base_encode(sig, 64).decode() - self.ctx.display.clear() - self.ctx.display.draw_centered_text(t("Signature") + ":\n\n%s" % encoded_sig) - self.ctx.input.wait_for_button() - - # Show the base64 signed message as a QRCode - title = t("Signed Message") - self.display_qr_codes(encoded_sig, qr_format, title) - self.print_standard_qr(encoded_sig, qr_format, title) - - # memory management - del encoded_sig - gc.collect() - - # Show the public key as a QRCode - pubkey = binascii.hexlify(self.ctx.wallet.key.account.sec()).decode() - self.ctx.display.clear() - - title = t("Hex Public Key") - self.ctx.display.draw_centered_text(title + ":\n\n%s" % pubkey) - self.ctx.input.wait_for_button() - - # Show the public key in hexadecimal format as a QRCode - self.display_qr_codes(pubkey, qr_format, title) - self.print_standard_qr(pubkey, qr_format, title) - - # memory management - gc.collect() - - # Try to save the signature file on the SD card - if self.has_sd_card(): - from .files_operations import SaveFile - - save_page = SaveFile(self.ctx) - save_page.save_file( - sig, - "message", - message_filename, - t("Signature") + ":", - SIGNATURE_FILE_EXTENSION, - SIGNATURE_FILE_SUFFIX, - ) - - # Try to save the public key on the SD card - save_page.save_file( - pubkey, "pubkey", "", title + ":", PUBKEY_FILE_EXTENSION, "", False - ) - - return MENU_CONTINUE + message_signer = SignMessage(self.ctx) + return message_signer.sign_message() def display_wallet(self, wallet, include_qr=True): """Displays a wallet, including its label and abbreviated xpubs. diff --git a/src/krux/pages/sign_message_ui.py b/src/krux/pages/sign_message_ui.py new file mode 100644 index 000000000..4a5daad82 --- /dev/null +++ b/src/krux/pages/sign_message_ui.py @@ -0,0 +1,252 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2023 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import gc +from embit import bip32, compact +import hashlib +import binascii +from . import Page, MENU_CONTINUE +from ..themes import theme +from ..baseconv import base_encode +from ..krux_settings import t +from ..qr import FORMAT_NONE +from ..sd_card import ( + SDHandler, + SIGNATURE_FILE_EXTENSION, + SIGNED_FILE_SUFFIX, + PUBKEY_FILE_EXTENSION, +) + + +class SignMessage(Page): + """Message Signing user interface""" + + def __init__(self, ctx): + super().__init__(ctx, None) + + def sign_at_address(self, data, qr_format): + """Message signed at a derived Bitcoin address - Sparrow/Specter""" + + if data.startswith(b"signmessage"): + data_blocks = data.split(b" ") + if len(data_blocks) >= 3: + derivation = data_blocks[1].decode() + message = b" ".join(data_blocks[2:]) + message = message.split(b":") + if len(message) >= 2 and message[0] == b"ascii": + message = b" ".join(message[1:]) + derivation = bip32.parse_path(derivation) + self.ctx.display.clear() + address = self.ctx.wallet.descriptor.derive( + derivation[4], branch_index=0 + ).address(network=self.ctx.wallet.key.network) + add_chars_amount = ( + self.ctx.display.width() // self.ctx.display.font_width + ) + add_chars_amount -= 10 + add_chars_amount //= 2 + short_address = ( + str(derivation[4]) + + ". " + + address[: add_chars_amount + 3] + + ".." + + address[-add_chars_amount:] + ) + message_to_display = self.ctx.display.to_lines(message.decode()) + if len(message_to_display) > self.ctx.display.total_lines - 10: + # 5 lines are used for prompt and constant texts + message_cut = (self.ctx.display.total_lines - 10) // 2 + message_to_display = ( + message_to_display[:message_cut] + + ["..."] + + message_to_display[-message_cut:] + ) + message_to_display = "\n".join(message_to_display) + + self.ctx.display.draw_hcentered_text( + t("Message:") + + "\n" + + message_to_display + + "\n\n" + + "Address:" + + "\n" + + short_address + ) + if not self.prompt(t("Sign?"), self.ctx.display.bottom_prompt_line): + return True + message_hash = hashlib.sha256( + hashlib.sha256( + b"\x18Bitcoin Signed Message:\n" + + compact.to_bytes(len(message)) + + message + ).digest() + ).digest() + sig = self.ctx.wallet.key.sign_at(derivation, message_hash) + + # Encode sig as base64 string + encoded_sig = base_encode(sig, 64).strip().decode() + self.ctx.display.clear() + self.ctx.display.draw_centered_text( + t("Signature") + ":\n\n%s" % encoded_sig + ) + self.ctx.input.wait_for_button() + title = t("Signed Message") + self.display_qr_codes(encoded_sig, qr_format, title) + self.print_standard_qr(encoded_sig, qr_format, title) + return True + return False + + def print_standard_qr(self, data, qr_format, title="", width=33): + """Loads printer driver and UI""" + # Duplicated in Home, is there a way to share? + # Can be put into __init__ page because contains a Page inside + if self.print_qr_prompt(): + from .print_page import PrintPage + + print_page = PrintPage(self.ctx) + print_page.print_qr(data, qr_format, title, width) + + def _load_file(self, file_ext=""): + # Duplicated in Home, is there a way to share? + # Can be put into __init__ page because contains a Page inside + if self.has_sd_card(): + with SDHandler() as sd: + self.ctx.display.clear() + if self.prompt( + t("Load from SD card?") + "\n\n", self.ctx.display.height() // 2 + ): + from .files_manager import FileManager + + file_manager = FileManager(self.ctx) + filename = file_manager.select_file(file_extension=file_ext) + + if filename: + filename = file_manager.display_file(filename) + + if self.prompt(t("Load?"), self.ctx.display.bottom_prompt_line): + return filename, sd.read_binary(filename) + return "", None + + def sign_message(self): + """Sign message user interface""" + + # Try to read a message from camera + message_filename = "" + data, qr_format = self.capture_qr_code() + + if data is None: + # Try to read a message from a file on the SD card + qr_format = FORMAT_NONE + try: + message_filename, data = self._load_file() + except OSError: + pass + + if data is None: + self.flash_text(t("Failed to load message"), theme.error_color) + return MENU_CONTINUE + + # message read OK! + data = data.encode() if isinstance(data, str) else data + + if self.sign_at_address(data, qr_format): + return MENU_CONTINUE + + message_hash = None + if len(data) == 32: + # It's a sha256 hash already + message_hash = data + else: + if len(data) == 64: + # It may be a hex-encoded sha256 hash + try: + message_hash = binascii.unhexlify(data) + except: + pass + if message_hash is None: + # It's a message, so compute its sha256 hash + message_hash = hashlib.sha256(data).digest() + + # memory management + del data + gc.collect() + + self.ctx.display.clear() + self.ctx.display.draw_centered_text( + t("SHA256:\n%s") % binascii.hexlify(message_hash).decode() + ) + if not self.prompt(t("Sign?"), self.ctx.display.bottom_prompt_line): + return MENU_CONTINUE + + # User confirmed to sign! + sig = self.ctx.wallet.key.sign(message_hash).serialize() + + # Encode sig as base64 string + encoded_sig = base_encode(sig, 64).decode() + self.ctx.display.clear() + self.ctx.display.draw_centered_text(t("Signature") + ":\n\n%s" % encoded_sig) + self.ctx.input.wait_for_button() + + # Show the base64 signed message as a QRCode + title = t("Signed Message") + self.display_qr_codes(encoded_sig, qr_format, title) + self.print_standard_qr(encoded_sig, qr_format, title) + + # memory management + del encoded_sig + gc.collect() + + # Show the public key as a QRCode + pubkey = binascii.hexlify(self.ctx.wallet.key.account.sec()).decode() + self.ctx.display.clear() + + title = t("Hex Public Key") + self.ctx.display.draw_centered_text(title + ":\n\n%s" % pubkey) + self.ctx.input.wait_for_button() + + # Show the public key in hexadecimal format as a QRCode + self.display_qr_codes(pubkey, qr_format, title) + self.print_standard_qr(pubkey, qr_format, title) + + # memory management + gc.collect() + + # Try to save the signature file on the SD card + if self.has_sd_card(): + from .files_operations import SaveFile + + save_page = SaveFile(self.ctx) + save_page.save_file( + sig, + "message", + message_filename, + t("Signature") + ":", + SIGNATURE_FILE_EXTENSION, + SIGNED_FILE_SUFFIX, + ) + + # Try to save the public key on the SD card + save_page.save_file( + pubkey, "pubkey", "", title + ":", PUBKEY_FILE_EXTENSION, "", False + ) + + return MENU_CONTINUE diff --git a/src/krux/sd_card.py b/src/krux/sd_card.py index d877e2617..9fbcb0e25 100644 --- a/src/krux/sd_card.py +++ b/src/krux/sd_card.py @@ -23,6 +23,11 @@ from machine import SDCard from .settings import SD_PATH +SIGNED_FILE_SUFFIX = "-signed" +PSBT_FILE_EXTENSION = ".psbt" +SIGNATURE_FILE_EXTENSION = ".sig" +PUBKEY_FILE_EXTENSION = ".pub" + class SDHandler: """A simple handler to work with files on SDCard""" From d67ee164765c2eb761e1f25e1c8f6c52f396f990 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Mon, 23 Oct 2023 16:47:55 -0300 Subject: [PATCH 057/114] fix screensaver button check --- src/krux/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/krux/context.py b/src/krux/context.py index 48bbcf413..ce6890123 100644 --- a/src/krux/context.py +++ b/src/krux/context.py @@ -93,5 +93,5 @@ def screensaver(self): anim_frame = 0 bg_color, fg_color = fg_color, bg_color - if self.input.wait_for_press(block=False) is not None: + if self.input.wait_for_button(block=False) is not None: break From 7ddb6f4b062a67da3aa8e7a69035cbb1d86805a4 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Mon, 23 Oct 2023 22:17:21 -0300 Subject: [PATCH 058/114] Wallet output descriptor load from and save to SD card --- src/krux/pages/home.py | 68 +++++++++++++++++++++++++++++++++++------- src/krux/sd_card.py | 1 + 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index eaaceead3..456b3a585 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -37,6 +37,7 @@ PUBKEY_FILE_EXTENSION, PSBT_FILE_EXTENSION, SIGNED_FILE_SUFFIX, + JSON_FILE_EXTENSION, ) # to start xpub value without the xpub/zpub/ypub prefix @@ -214,14 +215,37 @@ def wallet(self): else: self.display_wallet(self.ctx.wallet) wallet_data, qr_format = self.ctx.wallet.wallet_qr() + title = t("Wallet output descriptor") self.print_standard_qr( - wallet_data, qr_format, t("Wallet output descriptor") + wallet_data, qr_format, title ) + + # Try to save the Wallet output descriptor on the SD card + if self.has_sd_card(): + from .files_operations import SaveFile + + save_page = SaveFile(self.ctx) + save_page.save_file( + self.ctx.wallet.wallet_data, + self.ctx.wallet.label, + self.ctx.wallet.label, + title + ":", + JSON_FILE_EXTENSION, + ) return MENU_CONTINUE def _load_wallet(self): wallet_data, qr_format = self.capture_qr_code() if wallet_data is None: + # Try to read the wallet output descriptor from a file on the SD card + qr_format = FORMAT_NONE + try: + _, wallet_data = self._load_file(JSON_FILE_EXTENSION) + except OSError: + pass + + if wallet_data is None: + # Both the camera and the file on SD card failed! self.flash_text(t("Failed to load output descriptor"), theme.error_color) return MENU_CONTINUE @@ -415,29 +439,51 @@ def display_wallet(self, wallet, include_qr=True): """ about = wallet.label + "\n" if wallet.is_multisig(): - xpubs = [] - for i, xpub in enumerate(wallet.policy["cosigners"]): - xpubs.append( - str(i + 1) - + ". " - + xpub[WALLET_XPUB_START : WALLET_XPUB_START + WALLET_XPUB_DIGITS] - + ".." - + xpub[len(xpub) - WALLET_XPUB_DIGITS :] + import binascii + + fingerprints = [] + for i, key in enumerate(wallet.descriptor.keys): + fingerprints.append( + str(i + 1) + ". " + binascii.hexlify(key.fingerprint).decode() ) - about += "\n".join(xpubs) + about += "\n".join(fingerprints) else: + about += wallet.key.fingerprint_hex_str() xpub = wallet.key.xpub() about += ( - xpub[WALLET_XPUB_START : WALLET_XPUB_START + WALLET_XPUB_DIGITS] + "\n" + + xpub[WALLET_XPUB_START : WALLET_XPUB_START + WALLET_XPUB_DIGITS] + ".." + xpub[len(xpub) - WALLET_XPUB_DIGITS :] ) + if include_qr: wallet_data, qr_format = wallet.wallet_qr() self.display_qr_codes(wallet_data, qr_format, title=about) else: self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) + # If multisig, show loaded wallet again with all XPUB + if wallet.is_multisig(): + about = wallet.label + "\n" + xpubs = [] + for i, xpub in enumerate(wallet.policy["cosigners"]): + xpubs.append( + str(i + 1) + + ". " + + xpub[WALLET_XPUB_START : WALLET_XPUB_START + WALLET_XPUB_DIGITS] + + ".." + + xpub[len(xpub) - WALLET_XPUB_DIGITS :] + ) + about += "\n".join(xpubs) + + if include_qr: + wallet_data, qr_format = wallet.wallet_qr() + self.display_qr_codes(wallet_data, qr_format, title=about) + else: + self.ctx.input.wait_for_button() + self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) + def print_standard_qr(self, data, qr_format, title="", width=33): """Loads printer driver and UI""" if self.print_qr_prompt(): diff --git a/src/krux/sd_card.py b/src/krux/sd_card.py index 9fbcb0e25..2006ccc68 100644 --- a/src/krux/sd_card.py +++ b/src/krux/sd_card.py @@ -25,6 +25,7 @@ SIGNED_FILE_SUFFIX = "-signed" PSBT_FILE_EXTENSION = ".psbt" +JSON_FILE_EXTENSION = ".json" SIGNATURE_FILE_EXTENSION = ".sig" PUBKEY_FILE_EXTENSION = ".pub" From 156d96c660e9b12864811f26132318ecc686a8b6 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 12:45:12 -0300 Subject: [PATCH 059/114] Fix wallet descriptor export SD --- src/krux/pages/home.py | 10 ++++++---- src/krux/sd_card.py | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 456b3a585..cb736bb2e 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -37,7 +37,8 @@ PUBKEY_FILE_EXTENSION, PSBT_FILE_EXTENSION, SIGNED_FILE_SUFFIX, - JSON_FILE_EXTENSION, + DESCRIPTOR_FILE_EXTENSION, + DESCRIPTOR_FILE_EXTENSION_ALT, ) # to start xpub value without the xpub/zpub/ypub prefix @@ -226,11 +227,12 @@ def wallet(self): save_page = SaveFile(self.ctx) save_page.save_file( - self.ctx.wallet.wallet_data, + self.ctx.wallet.descriptor.to_string(), self.ctx.wallet.label, self.ctx.wallet.label, title + ":", - JSON_FILE_EXTENSION, + DESCRIPTOR_FILE_EXTENSION, + save_as_binary=False ) return MENU_CONTINUE @@ -240,7 +242,7 @@ def _load_wallet(self): # Try to read the wallet output descriptor from a file on the SD card qr_format = FORMAT_NONE try: - _, wallet_data = self._load_file(JSON_FILE_EXTENSION) + _, wallet_data = self._load_file((DESCRIPTOR_FILE_EXTENSION, DESCRIPTOR_FILE_EXTENSION_ALT)) except OSError: pass diff --git a/src/krux/sd_card.py b/src/krux/sd_card.py index 2006ccc68..94d24ff01 100644 --- a/src/krux/sd_card.py +++ b/src/krux/sd_card.py @@ -25,7 +25,8 @@ SIGNED_FILE_SUFFIX = "-signed" PSBT_FILE_EXTENSION = ".psbt" -JSON_FILE_EXTENSION = ".json" +DESCRIPTOR_FILE_EXTENSION = ".txt" +DESCRIPTOR_FILE_EXTENSION_ALT = ".json" SIGNATURE_FILE_EXTENSION = ".sig" PUBKEY_FILE_EXTENSION = ".pub" From 0187b50e016bf05a8460cf6b35d47d0bae11e0bd Mon Sep 17 00:00:00 2001 From: odudex Date: Tue, 24 Oct 2023 13:34:02 -0300 Subject: [PATCH 060/114] descriptor import bugfix remove incompatible tuple arg allow any file extension --- src/krux/pages/home.py | 9 +++------ src/krux/sd_card.py | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index cb736bb2e..68c2d0de1 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -38,7 +38,6 @@ PSBT_FILE_EXTENSION, SIGNED_FILE_SUFFIX, DESCRIPTOR_FILE_EXTENSION, - DESCRIPTOR_FILE_EXTENSION_ALT, ) # to start xpub value without the xpub/zpub/ypub prefix @@ -217,9 +216,7 @@ def wallet(self): self.display_wallet(self.ctx.wallet) wallet_data, qr_format = self.ctx.wallet.wallet_qr() title = t("Wallet output descriptor") - self.print_standard_qr( - wallet_data, qr_format, title - ) + self.print_standard_qr(wallet_data, qr_format, title) # Try to save the Wallet output descriptor on the SD card if self.has_sd_card(): @@ -232,7 +229,7 @@ def wallet(self): self.ctx.wallet.label, title + ":", DESCRIPTOR_FILE_EXTENSION, - save_as_binary=False + save_as_binary=False, ) return MENU_CONTINUE @@ -242,7 +239,7 @@ def _load_wallet(self): # Try to read the wallet output descriptor from a file on the SD card qr_format = FORMAT_NONE try: - _, wallet_data = self._load_file((DESCRIPTOR_FILE_EXTENSION, DESCRIPTOR_FILE_EXTENSION_ALT)) + _, wallet_data = self._load_file() # Allow any extension except OSError: pass diff --git a/src/krux/sd_card.py b/src/krux/sd_card.py index 94d24ff01..42d122a4b 100644 --- a/src/krux/sd_card.py +++ b/src/krux/sd_card.py @@ -26,7 +26,6 @@ SIGNED_FILE_SUFFIX = "-signed" PSBT_FILE_EXTENSION = ".psbt" DESCRIPTOR_FILE_EXTENSION = ".txt" -DESCRIPTOR_FILE_EXTENSION_ALT = ".json" SIGNATURE_FILE_EXTENSION = ".sig" PUBKEY_FILE_EXTENSION = ".pub" From fdbc4b10c7c6f51c60587f672ad6671b5f5a4cfc Mon Sep 17 00:00:00 2001 From: odudex Date: Tue, 24 Oct 2023 13:34:51 -0300 Subject: [PATCH 061/114] remove unnecessary screen clean --- src/krux/pages/files_operations.py | 2 -- src/krux/pages/tiny_seed.py | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/krux/pages/files_operations.py b/src/krux/pages/files_operations.py index f1020a2ee..5c4968eb6 100644 --- a/src/krux/pages/files_operations.py +++ b/src/krux/pages/files_operations.py @@ -72,12 +72,10 @@ def save_file( sd.write_binary(filename, data) else: sd.write(filename, data) - self.ctx.display.clear() self.flash_text(t("Saved to SD card:\n%s") % filename) else: filename_undefined = False except: - self.ctx.display.clear() self.flash_text(t("SD card not detected.")) def _set_filename( diff --git a/src/krux/pages/tiny_seed.py b/src/krux/pages/tiny_seed.py index c9a6e41b8..03204f654 100644 --- a/src/krux/pages/tiny_seed.py +++ b/src/krux/pages/tiny_seed.py @@ -906,7 +906,6 @@ def _process_12w_scan(self, page_seed_numbers): if words: # If words confirmed return words # Else esc command was given, turn camera on again and reset words - self.ctx.display.clear() self.flash_text( t("Scanning words 1-12 again") + "\n\n" + t("Wait for the capture") ) @@ -927,14 +926,12 @@ def _process_24w_pg0_scan(self, page_seed_numbers): words = self.tiny_seed.enter_tiny_seed(True, page_seed_numbers, True) self.capturing = False if words is not None: # Fisrt 12 words confirmed, moving to 13-24 - self.ctx.display.clear() self.flash_text( t("Scanning words 13-24") + "\n\n" + t("Wait for the capture") ) self._run_camera() return words # Esc command was given - self.ctx.display.clear() self.flash_text( t("Scanning words 1-12 again") + "\n\n" + t("TOUCH or ENTER to capture") ) From 999ec4a1bf98513eb546df6bd7d8c3581476fbf1 Mon Sep 17 00:00:00 2001 From: odudex Date: Tue, 24 Oct 2023 14:54:34 -0300 Subject: [PATCH 062/114] version to beta 4 --- pyproject.toml | 2 +- src/krux/metadata.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 755dd2e74..4427eaecb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ [tool.poetry] name = "krux" -version = "24.04.beta3" +version = "24.04.beta4" description = "Open-source signing device firmware for Bitcoin" authors = ["Jeff S "] diff --git a/src/krux/metadata.py b/src/krux/metadata.py index 7590dad98..6876e72d1 100644 --- a/src/krux/metadata.py +++ b/src/krux/metadata.py @@ -19,5 +19,5 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -VERSION = "24.04.beta3" +VERSION = "24.04.beta4" SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b" From be78d9d9bd07651be609a617af1eeaf4e9d66621 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 17:44:52 -0300 Subject: [PATCH 063/114] file_extension now accepts tuple or list --- src/krux/pages/files_manager.py | 20 ++++++++++++++------ src/krux/pages/home.py | 3 ++- src/krux/sd_card.py | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/krux/pages/files_manager.py b/src/krux/pages/files_manager.py index dd4d9a0a8..a95792346 100644 --- a/src/krux/pages/files_manager.py +++ b/src/krux/pages/files_manager.py @@ -65,12 +65,20 @@ def select_file( dir_files = os.listdir(path) for filename in dir_files: - # only include files that match extension and directories - if ( - # No extension filter - file_extension == "" - # Matches filter - or filename.endswith(file_extension) + + extension_match = False + if type(file_extension) == str: + # No extension filter or matches + extension_match = filename.endswith(file_extension) + else: + # Check for any matches for tuple / list + for ext in file_extension: + if filename.endswith(ext): + extension_match = True + break + + if ( + extension_match # Is a directory or SDHandler.dir_exists(path + "/" + filename) ): diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 68c2d0de1..8d8eb0380 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -38,6 +38,7 @@ PSBT_FILE_EXTENSION, SIGNED_FILE_SUFFIX, DESCRIPTOR_FILE_EXTENSION, + JSON_FILE_EXTENSION, ) # to start xpub value without the xpub/zpub/ypub prefix @@ -239,7 +240,7 @@ def _load_wallet(self): # Try to read the wallet output descriptor from a file on the SD card qr_format = FORMAT_NONE try: - _, wallet_data = self._load_file() # Allow any extension + _, wallet_data = self._load_file((DESCRIPTOR_FILE_EXTENSION, JSON_FILE_EXTENSION)) except OSError: pass diff --git a/src/krux/sd_card.py b/src/krux/sd_card.py index 42d122a4b..46549e031 100644 --- a/src/krux/sd_card.py +++ b/src/krux/sd_card.py @@ -26,6 +26,7 @@ SIGNED_FILE_SUFFIX = "-signed" PSBT_FILE_EXTENSION = ".psbt" DESCRIPTOR_FILE_EXTENSION = ".txt" +JSON_FILE_EXTENSION = ".json" SIGNATURE_FILE_EXTENSION = ".sig" PUBKEY_FILE_EXTENSION = ".pub" From ad20ed87cd7c05191b23b20ae69e02bf42499f6a Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 18:11:35 -0300 Subject: [PATCH 064/114] Changed wallet output multisig display --- src/krux/pages/home.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 8d8eb0380..526f374c0 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -457,7 +457,7 @@ def display_wallet(self, wallet, include_qr=True): + xpub[len(xpub) - WALLET_XPUB_DIGITS :] ) - if include_qr: + if not wallet.is_multisig() and include_qr: wallet_data, qr_format = wallet.wallet_qr() self.display_qr_codes(wallet_data, qr_format, title=about) else: @@ -478,8 +478,12 @@ def display_wallet(self, wallet, include_qr=True): about += "\n".join(xpubs) if include_qr: + self.ctx.input.wait_for_button() + self.ctx.display.clear() + self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) + self.ctx.input.wait_for_button() wallet_data, qr_format = wallet.wallet_qr() - self.display_qr_codes(wallet_data, qr_format, title=about) + self.display_qr_codes(wallet_data, qr_format, title=wallet.label) else: self.ctx.input.wait_for_button() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) From b531b3f8d37d243b40ffd3e448a17c39cdb97b19 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 18:27:57 -0300 Subject: [PATCH 065/114] add try except block around displayQRCode (because of out of memory issues with large QRs) --- src/krux/pages/home.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 526f374c0..4e9aea57b 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -482,8 +482,17 @@ def display_wallet(self, wallet, include_qr=True): self.ctx.display.clear() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) self.ctx.input.wait_for_button() - wallet_data, qr_format = wallet.wallet_qr() - self.display_qr_codes(wallet_data, qr_format, title=wallet.label) + + # Try to show the wallet output descriptor as a QRCode + try: + wallet_data, qr_format = wallet.wallet_qr() + self.display_qr_codes(wallet_data, qr_format, title=wallet.label) + except Exception as e: + self.ctx.display.clear() + self.ctx.display.draw_centered_text( + t("Error:\n%s") % repr(e), theme.error_color + ) + self.ctx.input.wait_for_button() else: self.ctx.input.wait_for_button() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) From 2ea65457dd2e9fc73eefaa13d3625bfc9cfb1817 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 18:36:42 -0300 Subject: [PATCH 066/114] fix home test_sign_message --- tests/pages/test_home.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 342209836..24b881c55 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -614,7 +614,7 @@ def test_wallet(mocker, m5stickv, tdata): from krux.qr import FORMAT_PMOFN cases = [ - # Don't load + # 0 Don't load ( False, tdata.SINGLESIG_12_WORD_KEY, @@ -622,7 +622,7 @@ def test_wallet(mocker, m5stickv, tdata): None, [BUTTON_PAGE], ), - # Load, good data, accept + # 1 Load, good data, accept ( False, tdata.SINGLESIG_12_WORD_KEY, @@ -630,7 +630,7 @@ def test_wallet(mocker, m5stickv, tdata): None, [BUTTON_ENTER, BUTTON_ENTER], ), - # Load, good data, decline + # 2 Load, good data, decline ( False, tdata.SINGLESIG_12_WORD_KEY, @@ -638,11 +638,11 @@ def test_wallet(mocker, m5stickv, tdata): None, [BUTTON_ENTER, BUTTON_PAGE], ), - # Load, bad capture + # 3 Load, bad capture (False, tdata.SINGLESIG_12_WORD_KEY, None, None, [BUTTON_ENTER]), - # Load, bad wallet data + # 4 Load, bad wallet data (False, tdata.SINGLESIG_12_WORD_KEY, "{}", None, [BUTTON_ENTER, BUTTON_ENTER]), - # No print prompt + # 5 No print prompt ( True, tdata.SINGLESIG_12_WORD_KEY, @@ -650,7 +650,7 @@ def test_wallet(mocker, m5stickv, tdata): None, [BUTTON_ENTER], ), - # Print + # 6 Print ( True, tdata.SINGLESIG_12_WORD_KEY, @@ -658,7 +658,7 @@ def test_wallet(mocker, m5stickv, tdata): MockPrinter(), [BUTTON_ENTER, BUTTON_ENTER], ), - # Decline to print + # 7 Decline to print ( True, tdata.SINGLESIG_12_WORD_KEY, @@ -666,16 +666,20 @@ def test_wallet(mocker, m5stickv, tdata): MockPrinter(), [BUTTON_ENTER, BUTTON_PAGE], ), - # Multisig wallet, no print prompt + # 8 Multisig wallet, no print prompt ( True, tdata.MULTISIG_12_WORD_KEY, tdata.SPECTER_MULTISIG_WALLET_DATA, None, - [BUTTON_ENTER], + [BUTTON_ENTER, BUTTON_ENTER], ), ] + + num = 0 for case in cases: + print("case: %d" % num) + num = num + 1 wallet = Wallet(case[1]) if case[0]: wallet.load(case[2], FORMAT_PMOFN) @@ -1031,7 +1035,7 @@ def test_sign_psbt(mocker, m5stickv, tdata): def test_sign_message(mocker, m5stickv, tdata): import binascii - from krux.pages.home import Home + from krux.pages.sign_message_ui import SignMessage from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV from krux.qr import FORMAT_NONE @@ -1165,7 +1169,7 @@ def test_sign_message(mocker, m5stickv, tdata): wallet = Wallet(tdata.SINGLESIG_SIGNING_KEY) ctx = create_ctx(mocker, case[3], wallet, case[2]) - home = Home(ctx) + home = SignMessage(ctx) mocker.patch.object(home, "capture_qr_code", new=lambda: (case[0], case[1])) mocker.patch.object( home, From d958433c87994c827b5f5ae78d59e94ad4adf9d5 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 17:44:52 -0300 Subject: [PATCH 067/114] file_extension now accepts tuple or list --- src/krux/pages/files_manager.py | 20 ++++++++++++++------ src/krux/pages/home.py | 3 ++- src/krux/sd_card.py | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/krux/pages/files_manager.py b/src/krux/pages/files_manager.py index dd4d9a0a8..a95792346 100644 --- a/src/krux/pages/files_manager.py +++ b/src/krux/pages/files_manager.py @@ -65,12 +65,20 @@ def select_file( dir_files = os.listdir(path) for filename in dir_files: - # only include files that match extension and directories - if ( - # No extension filter - file_extension == "" - # Matches filter - or filename.endswith(file_extension) + + extension_match = False + if type(file_extension) == str: + # No extension filter or matches + extension_match = filename.endswith(file_extension) + else: + # Check for any matches for tuple / list + for ext in file_extension: + if filename.endswith(ext): + extension_match = True + break + + if ( + extension_match # Is a directory or SDHandler.dir_exists(path + "/" + filename) ): diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 68c2d0de1..8d8eb0380 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -38,6 +38,7 @@ PSBT_FILE_EXTENSION, SIGNED_FILE_SUFFIX, DESCRIPTOR_FILE_EXTENSION, + JSON_FILE_EXTENSION, ) # to start xpub value without the xpub/zpub/ypub prefix @@ -239,7 +240,7 @@ def _load_wallet(self): # Try to read the wallet output descriptor from a file on the SD card qr_format = FORMAT_NONE try: - _, wallet_data = self._load_file() # Allow any extension + _, wallet_data = self._load_file((DESCRIPTOR_FILE_EXTENSION, JSON_FILE_EXTENSION)) except OSError: pass diff --git a/src/krux/sd_card.py b/src/krux/sd_card.py index 42d122a4b..46549e031 100644 --- a/src/krux/sd_card.py +++ b/src/krux/sd_card.py @@ -26,6 +26,7 @@ SIGNED_FILE_SUFFIX = "-signed" PSBT_FILE_EXTENSION = ".psbt" DESCRIPTOR_FILE_EXTENSION = ".txt" +JSON_FILE_EXTENSION = ".json" SIGNATURE_FILE_EXTENSION = ".sig" PUBKEY_FILE_EXTENSION = ".pub" From c5e3ed5afdbf13d64d591392f964a0fb7103ec13 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 18:11:35 -0300 Subject: [PATCH 068/114] Changed wallet output multisig display --- src/krux/pages/home.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 8d8eb0380..526f374c0 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -457,7 +457,7 @@ def display_wallet(self, wallet, include_qr=True): + xpub[len(xpub) - WALLET_XPUB_DIGITS :] ) - if include_qr: + if not wallet.is_multisig() and include_qr: wallet_data, qr_format = wallet.wallet_qr() self.display_qr_codes(wallet_data, qr_format, title=about) else: @@ -478,8 +478,12 @@ def display_wallet(self, wallet, include_qr=True): about += "\n".join(xpubs) if include_qr: + self.ctx.input.wait_for_button() + self.ctx.display.clear() + self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) + self.ctx.input.wait_for_button() wallet_data, qr_format = wallet.wallet_qr() - self.display_qr_codes(wallet_data, qr_format, title=about) + self.display_qr_codes(wallet_data, qr_format, title=wallet.label) else: self.ctx.input.wait_for_button() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) From 842e3d651b5dbf9740509d8ddfd691924c7ca591 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 18:27:57 -0300 Subject: [PATCH 069/114] add try except block around displayQRCode (because of out of memory issues with large QRs) --- src/krux/pages/home.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 526f374c0..4e9aea57b 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -482,8 +482,17 @@ def display_wallet(self, wallet, include_qr=True): self.ctx.display.clear() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) self.ctx.input.wait_for_button() - wallet_data, qr_format = wallet.wallet_qr() - self.display_qr_codes(wallet_data, qr_format, title=wallet.label) + + # Try to show the wallet output descriptor as a QRCode + try: + wallet_data, qr_format = wallet.wallet_qr() + self.display_qr_codes(wallet_data, qr_format, title=wallet.label) + except Exception as e: + self.ctx.display.clear() + self.ctx.display.draw_centered_text( + t("Error:\n%s") % repr(e), theme.error_color + ) + self.ctx.input.wait_for_button() else: self.ctx.input.wait_for_button() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) From 8a09667923a3ecebd98be55550124fef232724a2 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Tue, 24 Oct 2023 18:36:42 -0300 Subject: [PATCH 070/114] fix home test_sign_message --- tests/pages/test_home.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 342209836..24b881c55 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -614,7 +614,7 @@ def test_wallet(mocker, m5stickv, tdata): from krux.qr import FORMAT_PMOFN cases = [ - # Don't load + # 0 Don't load ( False, tdata.SINGLESIG_12_WORD_KEY, @@ -622,7 +622,7 @@ def test_wallet(mocker, m5stickv, tdata): None, [BUTTON_PAGE], ), - # Load, good data, accept + # 1 Load, good data, accept ( False, tdata.SINGLESIG_12_WORD_KEY, @@ -630,7 +630,7 @@ def test_wallet(mocker, m5stickv, tdata): None, [BUTTON_ENTER, BUTTON_ENTER], ), - # Load, good data, decline + # 2 Load, good data, decline ( False, tdata.SINGLESIG_12_WORD_KEY, @@ -638,11 +638,11 @@ def test_wallet(mocker, m5stickv, tdata): None, [BUTTON_ENTER, BUTTON_PAGE], ), - # Load, bad capture + # 3 Load, bad capture (False, tdata.SINGLESIG_12_WORD_KEY, None, None, [BUTTON_ENTER]), - # Load, bad wallet data + # 4 Load, bad wallet data (False, tdata.SINGLESIG_12_WORD_KEY, "{}", None, [BUTTON_ENTER, BUTTON_ENTER]), - # No print prompt + # 5 No print prompt ( True, tdata.SINGLESIG_12_WORD_KEY, @@ -650,7 +650,7 @@ def test_wallet(mocker, m5stickv, tdata): None, [BUTTON_ENTER], ), - # Print + # 6 Print ( True, tdata.SINGLESIG_12_WORD_KEY, @@ -658,7 +658,7 @@ def test_wallet(mocker, m5stickv, tdata): MockPrinter(), [BUTTON_ENTER, BUTTON_ENTER], ), - # Decline to print + # 7 Decline to print ( True, tdata.SINGLESIG_12_WORD_KEY, @@ -666,16 +666,20 @@ def test_wallet(mocker, m5stickv, tdata): MockPrinter(), [BUTTON_ENTER, BUTTON_PAGE], ), - # Multisig wallet, no print prompt + # 8 Multisig wallet, no print prompt ( True, tdata.MULTISIG_12_WORD_KEY, tdata.SPECTER_MULTISIG_WALLET_DATA, None, - [BUTTON_ENTER], + [BUTTON_ENTER, BUTTON_ENTER], ), ] + + num = 0 for case in cases: + print("case: %d" % num) + num = num + 1 wallet = Wallet(case[1]) if case[0]: wallet.load(case[2], FORMAT_PMOFN) @@ -1031,7 +1035,7 @@ def test_sign_psbt(mocker, m5stickv, tdata): def test_sign_message(mocker, m5stickv, tdata): import binascii - from krux.pages.home import Home + from krux.pages.sign_message_ui import SignMessage from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV from krux.qr import FORMAT_NONE @@ -1165,7 +1169,7 @@ def test_sign_message(mocker, m5stickv, tdata): wallet = Wallet(tdata.SINGLESIG_SIGNING_KEY) ctx = create_ctx(mocker, case[3], wallet, case[2]) - home = Home(ctx) + home = SignMessage(ctx) mocker.patch.object(home, "capture_qr_code", new=lambda: (case[0], case[1])) mocker.patch.object( home, From a429a08d5ba04d7df4d859996a1d5d1faad9fb68 Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 25 Oct 2023 12:33:07 -0300 Subject: [PATCH 071/114] add method to fit long strings into single line --- src/krux/pages/__init__.py | 15 ++++++++++++++ src/krux/pages/addresses.py | 29 +++------------------------ src/krux/pages/files_manager.py | 7 +++---- src/krux/pages/home.py | 25 +++++++---------------- src/krux/pages/sign_message_ui.py | 33 ++++++++++++++++--------------- 5 files changed, 45 insertions(+), 64 deletions(-) diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 991d60879..b7e7795db 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -467,6 +467,21 @@ def prompt(self, text, offset_y=0): # BUTTON_ENTER return answer + def fit_to_line(self, text, prefix="", fixed_chars=0): + """Fits text into a line, removing central content and leaving ends""" + + add_chars_amount = ( + self.ctx.display.usable_width() // self.ctx.display.font_width + ) + add_chars_amount -= len(prefix) + fixed_chars + 2 + add_chars_amount //= 2 + return ( + prefix + + text[: add_chars_amount + fixed_chars] + + ".." + + text[-add_chars_amount:] + ) + def has_sd_card(self): """Checks if the device has a SD card inserted""" self.ctx.display.clear() diff --git a/src/krux/pages/addresses.py b/src/krux/pages/addresses.py index 343749a03..aa464d1ad 100644 --- a/src/krux/pages/addresses.py +++ b/src/krux/pages/addresses.py @@ -21,7 +21,6 @@ # THE SOFTWARE. import gc -import board from ..krux_settings import t from ..themes import theme from ..qr import FORMAT_NONE @@ -33,9 +32,6 @@ ) LIST_ADDRESS_QTD = 4 # qtd of address per page -LIST_ADDRESS_DIGITS = 8 # len on large devices per menu item -LIST_ADDRESS_DIGITS_SMALL = 4 # len on small devices per menu item - SCAN_ADDRESS_LIMIT = 20 @@ -71,19 +67,6 @@ def list_address_type(self, addr_type=0): """Handler for the 'receive addresses' or 'change addresses' menu item""" # only show address for single-sig or multisig with wallet output descriptor loaded if self.ctx.wallet.is_loaded() or not self.ctx.wallet.is_multisig(): - custom_start_digits = ( - LIST_ADDRESS_DIGITS + 3 - ) # 3 more because of bc1 address - custom_end_digts = LIST_ADDRESS_DIGITS - custom_separator = ". " - if board.config["type"] == "m5stickv": - custom_start_digits = ( - LIST_ADDRESS_DIGITS_SMALL + 3 - ) # 3 more because of bc1 address - custom_end_digts = LIST_ADDRESS_DIGITS_SMALL - custom_separator = " " - start_digits = custom_start_digits - loading_txt = t("Loading receive address %d..") if addr_type == 1: loading_txt = t("Loading change address %d..") @@ -105,17 +88,11 @@ def list_address_type(self, addr_type=0): self.ctx.display.clear() self.ctx.display.draw_centered_text(loading_txt % (num_checked + 1)) - if num_checked + 1 > 99: - start_digits = custom_start_digits - 1 - pos_str = str(num_checked + 1) - qr_title = pos_str + ". " + addr + pos_str = str(num_checked + 1) + ". " + qr_title = pos_str + addr items.append( ( - pos_str - + custom_separator - + addr[:start_digits] - + ".." - + addr[len(addr) - custom_end_digts :], + self.fit_to_line(addr, pos_str, fixed_chars=3), lambda address=addr, title=qr_title: self.show_address( address, title ), diff --git a/src/krux/pages/files_manager.py b/src/krux/pages/files_manager.py index a95792346..d012a5e80 100644 --- a/src/krux/pages/files_manager.py +++ b/src/krux/pages/files_manager.py @@ -65,9 +65,8 @@ def select_file( dir_files = os.listdir(path) for filename in dir_files: - - extension_match = False - if type(file_extension) == str: + extension_match = False + if isinstance(file_extension, str): # No extension filter or matches extension_match = filename.endswith(file_extension) else: @@ -77,7 +76,7 @@ def select_file( extension_match = True break - if ( + if ( extension_match # Is a directory or SDHandler.dir_exists(path + "/" + filename) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 4e9aea57b..e0514c6d5 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -43,8 +43,6 @@ # to start xpub value without the xpub/zpub/ypub prefix WALLET_XPUB_START = 4 -# len of the xpub to show -WALLET_XPUB_DIGITS = 4 class Home(Page): @@ -240,7 +238,9 @@ def _load_wallet(self): # Try to read the wallet output descriptor from a file on the SD card qr_format = FORMAT_NONE try: - _, wallet_data = self._load_file((DESCRIPTOR_FILE_EXTENSION, JSON_FILE_EXTENSION)) + _, wallet_data = self._load_file( + (DESCRIPTOR_FILE_EXTENSION, JSON_FILE_EXTENSION) + ) except OSError: pass @@ -450,12 +450,7 @@ def display_wallet(self, wallet, include_qr=True): else: about += wallet.key.fingerprint_hex_str() xpub = wallet.key.xpub() - about += ( - "\n" - + xpub[WALLET_XPUB_START : WALLET_XPUB_START + WALLET_XPUB_DIGITS] - + ".." - + xpub[len(xpub) - WALLET_XPUB_DIGITS :] - ) + about += "\n" + self.fit_to_line(xpub) if not wallet.is_multisig() and include_qr: wallet_data, qr_format = wallet.wallet_qr() @@ -468,13 +463,7 @@ def display_wallet(self, wallet, include_qr=True): about = wallet.label + "\n" xpubs = [] for i, xpub in enumerate(wallet.policy["cosigners"]): - xpubs.append( - str(i + 1) - + ". " - + xpub[WALLET_XPUB_START : WALLET_XPUB_START + WALLET_XPUB_DIGITS] - + ".." - + xpub[len(xpub) - WALLET_XPUB_DIGITS :] - ) + xpubs.append(self.fit_to_line(xpub, str(i + 1) + ". ")) about += "\n".join(xpubs) if include_qr: @@ -482,7 +471,7 @@ def display_wallet(self, wallet, include_qr=True): self.ctx.display.clear() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) self.ctx.input.wait_for_button() - + # Try to show the wallet output descriptor as a QRCode try: wallet_data, qr_format = wallet.wallet_qr() @@ -492,7 +481,7 @@ def display_wallet(self, wallet, include_qr=True): self.ctx.display.draw_centered_text( t("Error:\n%s") % repr(e), theme.error_color ) - self.ctx.input.wait_for_button() + self.ctx.input.wait_for_button() else: self.ctx.input.wait_for_button() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) diff --git a/src/krux/pages/sign_message_ui.py b/src/krux/pages/sign_message_ui.py index 4a5daad82..9a73cf6bf 100644 --- a/src/krux/pages/sign_message_ui.py +++ b/src/krux/pages/sign_message_ui.py @@ -20,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. +import board import gc from embit import bip32, compact import hashlib @@ -59,28 +60,28 @@ def sign_at_address(self, data, qr_format): address = self.ctx.wallet.descriptor.derive( derivation[4], branch_index=0 ).address(network=self.ctx.wallet.key.network) - add_chars_amount = ( - self.ctx.display.width() // self.ctx.display.font_width - ) - add_chars_amount -= 10 - add_chars_amount //= 2 - short_address = ( - str(derivation[4]) - + ". " - + address[: add_chars_amount + 3] - + ".." - + address[-add_chars_amount:] + short_address = self.fit_to_line( + address, str(derivation[4]) + ". ", fixed_chars=3 ) + # Amount of lines to subtract for free room for message + subtract_lines = 6 if board.config["type"] == "m5stickv" else 10 + message_to_display = self.ctx.display.to_lines(message.decode()) - if len(message_to_display) > self.ctx.display.total_lines - 10: - # 5 lines are used for prompt and constant texts - message_cut = (self.ctx.display.total_lines - 10) // 2 + if ( + len(message_to_display) + > self.ctx.display.total_lines - subtract_lines + ): + message_cut = ( + self.ctx.display.total_lines - subtract_lines + ) // 2 message_to_display = ( message_to_display[:message_cut] - + ["..."] + + ["\n...\n"] + message_to_display[-message_cut:] ) - message_to_display = "\n".join(message_to_display) + message_to_display = "".join(message_to_display) + else: + message_to_display = message.decode() self.ctx.display.draw_hcentered_text( t("Message:") From e232b7d59216994697060b3444d932a069294500 Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 25 Oct 2023 14:04:06 -0300 Subject: [PATCH 072/114] add utils file containing shared subpages shared print and load file subpage methods --- src/krux/pages/home.py | 42 ++++----------------- src/krux/pages/sign_message_ui.py | 42 +++------------------ src/krux/pages/utils.py | 61 +++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 70 deletions(-) create mode 100644 src/krux/pages/utils.py diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index e0514c6d5..793de2995 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -21,6 +21,7 @@ # THE SOFTWARE. import gc +from .utils import Utils from ..themes import theme from ..display import DEFAULT_PADDING from ..psbt import PSBTSigner @@ -33,7 +34,6 @@ MENU_EXIT, ) from ..sd_card import ( - SDHandler, PUBKEY_FILE_EXTENSION, PSBT_FILE_EXTENSION, SIGNED_FILE_SUFFIX, @@ -64,6 +64,7 @@ def __init__(self, ctx): ], ), ) + self.utils = Utils(self.ctx) def mnemonic(self): """Handler for the 'mnemonic' menu item""" @@ -105,7 +106,7 @@ def display_standard_qr(self): title = t("Plaintext QR") data = self.ctx.wallet.key.mnemonic self.display_qr_codes(data, FORMAT_NONE, title) - self.print_standard_qr(data, FORMAT_NONE, title) + self.utils.print_standard_qr(data, FORMAT_NONE, title) return MENU_CONTINUE def display_seed_qr(self, binary=False): @@ -184,7 +185,7 @@ def public_key(self): ].upper() xpub = self.ctx.wallet.key.key_expression(version) self.display_qr_codes(xpub, FORMAT_NONE, title) - self.print_standard_qr(xpub, FORMAT_NONE, title) + self.utils.print_standard_qr(xpub, FORMAT_NONE, title) # Try to save the XPUB file on the SD card if self.has_sd_card(): @@ -215,7 +216,7 @@ def wallet(self): self.display_wallet(self.ctx.wallet) wallet_data, qr_format = self.ctx.wallet.wallet_qr() title = t("Wallet output descriptor") - self.print_standard_qr(wallet_data, qr_format, title) + self.utils.print_standard_qr(wallet_data, qr_format, title) # Try to save the Wallet output descriptor on the SD card if self.has_sd_card(): @@ -238,7 +239,7 @@ def _load_wallet(self): # Try to read the wallet output descriptor from a file on the SD card qr_format = FORMAT_NONE try: - _, wallet_data = self._load_file( + _, wallet_data = self.utils.load_file( (DESCRIPTOR_FILE_EXTENSION, JSON_FILE_EXTENSION) ) except OSError: @@ -331,7 +332,7 @@ def sign_psbt(self): # Try to read a PSBT from a file on the SD card qr_format = FORMAT_NONE try: - psbt_filename, data = self._load_file(PSBT_FILE_EXTENSION) + psbt_filename, data = self.utils.load_file(PSBT_FILE_EXTENSION) except OSError: pass @@ -375,7 +376,7 @@ def sign_psbt(self): title = t("Signed PSBT") try: self.display_qr_codes(qr_signed_psbt, qr_format) - self.print_standard_qr(qr_signed_psbt, qr_format, title, width=45) + self.utils.print_standard_qr(qr_signed_psbt, qr_format, title, width=45) except Exception as e: self.ctx.log.exception( "Exception occurred in sign_psbt when trying to show the qr_signed_psbt" @@ -405,25 +406,6 @@ def sign_psbt(self): ) return MENU_CONTINUE - def _load_file(self, file_ext=""): - if self.has_sd_card(): - with SDHandler() as sd: - self.ctx.display.clear() - if self.prompt( - t("Load from SD card?") + "\n\n", self.ctx.display.height() // 2 - ): - from .files_manager import FileManager - - file_manager = FileManager(self.ctx) - filename = file_manager.select_file(file_extension=file_ext) - - if filename: - filename = file_manager.display_file(filename) - - if self.prompt(t("Load?"), self.ctx.display.bottom_prompt_line): - return filename, sd.read_binary(filename) - return "", None - def sign_message(self): """Handler for the 'sign message' menu item""" from .sign_message_ui import SignMessage @@ -485,11 +467,3 @@ def display_wallet(self, wallet, include_qr=True): else: self.ctx.input.wait_for_button() self.ctx.display.draw_hcentered_text(about, offset_y=DEFAULT_PADDING) - - def print_standard_qr(self, data, qr_format, title="", width=33): - """Loads printer driver and UI""" - if self.print_qr_prompt(): - from .print_page import PrintPage - - print_page = PrintPage(self.ctx) - print_page.print_qr(data, qr_format, title, width) diff --git a/src/krux/pages/sign_message_ui.py b/src/krux/pages/sign_message_ui.py index 9a73cf6bf..249a3cc9f 100644 --- a/src/krux/pages/sign_message_ui.py +++ b/src/krux/pages/sign_message_ui.py @@ -31,11 +31,11 @@ from ..krux_settings import t from ..qr import FORMAT_NONE from ..sd_card import ( - SDHandler, SIGNATURE_FILE_EXTENSION, SIGNED_FILE_SUFFIX, PUBKEY_FILE_EXTENSION, ) +from .utils import Utils class SignMessage(Page): @@ -43,6 +43,7 @@ class SignMessage(Page): def __init__(self, ctx): super().__init__(ctx, None) + self.utils = Utils(self.ctx) def sign_at_address(self, data, qr_format): """Message signed at a derived Bitcoin address - Sparrow/Specter""" @@ -112,41 +113,10 @@ def sign_at_address(self, data, qr_format): self.ctx.input.wait_for_button() title = t("Signed Message") self.display_qr_codes(encoded_sig, qr_format, title) - self.print_standard_qr(encoded_sig, qr_format, title) + self.utils.print_standard_qr(encoded_sig, qr_format, title) return True return False - def print_standard_qr(self, data, qr_format, title="", width=33): - """Loads printer driver and UI""" - # Duplicated in Home, is there a way to share? - # Can be put into __init__ page because contains a Page inside - if self.print_qr_prompt(): - from .print_page import PrintPage - - print_page = PrintPage(self.ctx) - print_page.print_qr(data, qr_format, title, width) - - def _load_file(self, file_ext=""): - # Duplicated in Home, is there a way to share? - # Can be put into __init__ page because contains a Page inside - if self.has_sd_card(): - with SDHandler() as sd: - self.ctx.display.clear() - if self.prompt( - t("Load from SD card?") + "\n\n", self.ctx.display.height() // 2 - ): - from .files_manager import FileManager - - file_manager = FileManager(self.ctx) - filename = file_manager.select_file(file_extension=file_ext) - - if filename: - filename = file_manager.display_file(filename) - - if self.prompt(t("Load?"), self.ctx.display.bottom_prompt_line): - return filename, sd.read_binary(filename) - return "", None - def sign_message(self): """Sign message user interface""" @@ -158,7 +128,7 @@ def sign_message(self): # Try to read a message from a file on the SD card qr_format = FORMAT_NONE try: - message_filename, data = self._load_file() + message_filename, data = self.utils.load_file() except OSError: pass @@ -210,7 +180,7 @@ def sign_message(self): # Show the base64 signed message as a QRCode title = t("Signed Message") self.display_qr_codes(encoded_sig, qr_format, title) - self.print_standard_qr(encoded_sig, qr_format, title) + self.utils.print_standard_qr(encoded_sig, qr_format, title) # memory management del encoded_sig @@ -226,7 +196,7 @@ def sign_message(self): # Show the public key in hexadecimal format as a QRCode self.display_qr_codes(pubkey, qr_format, title) - self.print_standard_qr(pubkey, qr_format, title) + self.utils.print_standard_qr(pubkey, qr_format, title) # memory management gc.collect() diff --git a/src/krux/pages/utils.py b/src/krux/pages/utils.py new file mode 100644 index 000000000..aef39c36d --- /dev/null +++ b/src/krux/pages/utils.py @@ -0,0 +1,61 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2023 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from . import Page +from ..krux_settings import t +from ..sd_card import SDHandler + + +class Utils(Page): + """Methods as subpages, shared by other pages""" + + def __init__(self, ctx): + super().__init__(ctx, None) + + def print_standard_qr(self, data, qr_format, title="", width=33): + """Loads printer driver and UI""" + # Only loads printer related modules if needed + if self.print_qr_prompt(): + from .print_page import PrintPage + + print_page = PrintPage(self.ctx) + print_page.print_qr(data, qr_format, title, width) + + def load_file(self, file_ext=""): + """Load a file from SD card""" + if self.has_sd_card(): + with SDHandler() as sd: + self.ctx.display.clear() + if self.prompt( + t("Load from SD card?") + "\n\n", self.ctx.display.height() // 2 + ): + from .files_manager import FileManager + + file_manager = FileManager(self.ctx) + filename = file_manager.select_file(file_extension=file_ext) + + if filename: + filename = file_manager.display_file(filename) + + if self.prompt(t("Load?"), self.ctx.display.bottom_prompt_line): + return filename, sd.read_binary(filename) + return "", None From 0752bcf5d8f13be31e08f3c141177eee9a19151e Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 25 Oct 2023 14:26:47 -0300 Subject: [PATCH 073/114] expand utils' print usage --- src/krux/pages/addresses.py | 8 +++----- src/krux/pages/qr_view.py | 13 ++++--------- src/krux/pages/utils.py | 4 ++-- 3 files changed, 9 insertions(+), 16 deletions(-) diff --git a/src/krux/pages/addresses.py b/src/krux/pages/addresses.py index aa464d1ad..6db47ba84 100644 --- a/src/krux/pages/addresses.py +++ b/src/krux/pages/addresses.py @@ -24,6 +24,7 @@ from ..krux_settings import t from ..themes import theme from ..qr import FORMAT_NONE +from .utils import Utils from . import ( Page, Menu, @@ -41,6 +42,7 @@ class Addresses(Page): def __init__(self, ctx): super().__init__(ctx, None) self.ctx = ctx + self.utils = Utils(self.ctx) def addresses_menu(self): """Handler for the 'address' menu item""" @@ -132,11 +134,7 @@ def list_address_type(self, addr_type=0): def show_address(self, addr, title="", qr_format=FORMAT_NONE): """Show addr provided as a QRCode""" self.display_qr_codes(addr, qr_format, title) - if self.print_qr_prompt(): - from .print_page import PrintPage - - print_page = PrintPage(self.ctx) - print_page.print_qr(addr, qr_format, title) + self.utils.print_standard_qr(addr, qr_format, title) return MENU_CONTINUE def pre_scan_address(self): diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index 88e3858e0..4245e3826 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -22,12 +22,12 @@ import qrcode from embit.wordlists.bip39 import WORDLIST -from . import Page +from . import Page, MENU_CONTINUE +from .utils import Utils from ..themes import theme, WHITE, BLACK from ..krux_settings import t from ..qr import get_size, add_qr_frame from ..display import DEFAULT_PADDING -from . import MENU_CONTINUE from ..input import ( BUTTON_ENTER, BUTTON_PAGE, @@ -67,6 +67,7 @@ def __init__(self, ctx, binary=False, data=None, title=None): self.region_size = 7 if self.qr_size == 21 else 5 self.columns = (self.qr_size + self.region_size - 1) // self.region_size self.lr_index = 0 + self.utils = Utils(self.ctx) def _seed_qr(self): words = self.ctx.wallet.key.mnemonic.split(" ") @@ -321,12 +322,6 @@ def display_seed_qr(self): self.ctx.display.clear() if self.prompt(t("Are you sure?"), self.ctx.display.height() // 2): break - if not self.print_qr_prompt(): - return MENU_CONTINUE - - from .print_page import PrintPage - - print_page = PrintPage(self.ctx) - print_page.print_qr(self.code, title=self.title, is_qr=True) + self.utils.print_standard_qr(self.code, title=self.title, is_qr=True) return MENU_CONTINUE diff --git a/src/krux/pages/utils.py b/src/krux/pages/utils.py index aef39c36d..92d4c3bd7 100644 --- a/src/krux/pages/utils.py +++ b/src/krux/pages/utils.py @@ -31,14 +31,14 @@ class Utils(Page): def __init__(self, ctx): super().__init__(ctx, None) - def print_standard_qr(self, data, qr_format, title="", width=33): + def print_standard_qr(self, data, qr_format=None, title="", width=33, is_qr=False): """Loads printer driver and UI""" # Only loads printer related modules if needed if self.print_qr_prompt(): from .print_page import PrintPage print_page = PrintPage(self.ctx) - print_page.print_qr(data, qr_format, title, width) + print_page.print_qr(data, qr_format, title, width, is_qr) def load_file(self, file_ext=""): """Load a file from SD card""" From a28e1ae6643798445e26bfed6bcca35e0e7d39c2 Mon Sep 17 00:00:00 2001 From: Jean Do Date: Thu, 26 Oct 2023 09:21:43 -0400 Subject: [PATCH 074/114] tests: home.print_standard_qr becomes home.utils.print_standard_qr --- tests/pages/test_home.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 24b881c55..e7ab855e0 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -256,7 +256,7 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): home = Home(ctx) mocker.spy(home, "display_qr_codes") - mocker.spy(home, "print_standard_qr") + mocker.spy(home.utils, "print_standard_qr") home.mnemonic() title = "Plaintext QR" @@ -264,7 +264,7 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): ctx.wallet.key.mnemonic, FORMAT_NONE, title ) if case[1] is not None: - home.print_standard_qr.assert_called_with( + home.utils.print_standard_qr.assert_called_with( ctx.wallet.key.mnemonic, FORMAT_NONE, title ) assert ctx.input.wait_for_button.call_count == len(case[2]) @@ -485,7 +485,7 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): home = Home(ctx) mocker.spy(home, "display_qr_codes") - mocker.spy(home, "print_standard_qr") + mocker.spy(home.utils, "print_standard_qr") home.mnemonic() @@ -494,7 +494,7 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): ctx.wallet.key.mnemonic, FORMAT_NONE, title ) if case[1] is not None: - home.print_standard_qr.assert_called_with( + home.utils.print_standard_qr.assert_called_with( ctx.wallet.key.mnemonic, FORMAT_NONE, title ) @@ -575,7 +575,7 @@ def test_public_key(mocker, m5stickv, tdata): home = Home(ctx) mocker.spy(home, "display_qr_codes") - mocker.spy(home, "print_standard_qr") + mocker.spy(home.utils, "print_standard_qr") home.public_key() @@ -602,7 +602,7 @@ def test_public_key(mocker, m5stickv, tdata): ] home.display_qr_codes.assert_has_calls(display_qr_calls) if case[1] is not None: - home.print_standard_qr.assert_has_calls(print_qr_calls) + home.utils.print_standard_qr.assert_has_calls(print_qr_calls) assert ctx.input.wait_for_button.call_count == len(case[2]) @@ -694,7 +694,7 @@ def test_wallet(mocker, m5stickv, tdata): "display_qr_codes", new=lambda data, qr_format, title=None: ctx.input.wait_for_button(), ) - mocker.spy(home, "print_standard_qr") + mocker.spy(home.utils, "print_standard_qr") mocker.spy(home, "capture_qr_code") mocker.spy(home, "display_wallet") @@ -702,7 +702,7 @@ def test_wallet(mocker, m5stickv, tdata): if case[0]: home.display_wallet.assert_called_once() - home.print_standard_qr.assert_called_once() + home.utils.print_standard_qr.assert_called_once() else: if case[4][0] == BUTTON_ENTER: home.capture_qr_code.assert_called_once() @@ -997,7 +997,7 @@ def test_sign_psbt(mocker, m5stickv, tdata): ) mocker.spy(home, "capture_qr_code") mocker.spy(home, "display_qr_codes") - mocker.spy(home, "print_standard_qr") + mocker.spy(home.utils, "print_standard_qr") # case SD available if case[10] is not None: mocker.patch("os.listdir", new=mocker.MagicMock(return_value=["test.psbt"])) @@ -1024,7 +1024,7 @@ def test_sign_psbt(mocker, m5stickv, tdata): home.capture_qr_code.assert_called_once() if case[5]: # signed! home.display_qr_codes.assert_called_once() - home.print_standard_qr.assert_called_once() + home.utils.print_standard_qr.assert_called_once() else: home.display_qr_codes.assert_not_called() else: @@ -1176,7 +1176,7 @@ def test_sign_message(mocker, m5stickv, tdata): "display_qr_codes", new=lambda data, qr_format, title=None: ctx.input.wait_for_button(), ) - mocker.spy(home, "print_standard_qr") + mocker.spy(home.utils, "print_standard_qr") mocker.spy(home, "capture_qr_code") mocker.spy(home, "display_qr_codes") if case[6] is not None: @@ -1203,7 +1203,7 @@ def test_sign_message(mocker, m5stickv, tdata): mocker.call(case[5], case[1], "Hex Public Key"), ] ) - home.print_standard_qr.assert_has_calls( + home.utils.print_standard_qr.assert_has_calls( [ mocker.call(case[4], case[1], "Signed Message"), mocker.call(case[5], case[1], "Hex Public Key"), @@ -1211,6 +1211,6 @@ def test_sign_message(mocker, m5stickv, tdata): ) else: home.display_qr_codes.assert_not_called() - home.print_standard_qr.assert_not_called() + home.utils.print_standard_qr.assert_not_called() assert ctx.input.wait_for_button.call_count == len(case[3]) From 19b37fe1bbf5861c688de97fe0c67ca933a18358 Mon Sep 17 00:00:00 2001 From: Jean Do Date: Thu, 26 Oct 2023 10:46:19 -0400 Subject: [PATCH 075/114] tests: test_wallet() one more "enter" for last test case --- tests/pages/test_home.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index e7ab855e0..912ca8c0a 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -672,7 +672,7 @@ def test_wallet(mocker, m5stickv, tdata): tdata.MULTISIG_12_WORD_KEY, tdata.SPECTER_MULTISIG_WALLET_DATA, None, - [BUTTON_ENTER, BUTTON_ENTER], + [BUTTON_ENTER, BUTTON_ENTER, BUTTON_ENTER], ), ] From 5ae184587496a9e4f2c31293b04b30d4d5f76ade Mon Sep 17 00:00:00 2001 From: Jean Do Date: Thu, 26 Oct 2023 10:47:05 -0400 Subject: [PATCH 076/114] tests: screensaver waits for button instead of press --- tests/test_context.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_context.py b/tests/test_context.py index 7cb623f49..dfbe16c41 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -73,7 +73,7 @@ def test_screensaver(mocker, m5stickv): ██ ██ ██ ██ ██ ██ - """[ +"""[ 1:-1 ].split( "\n" @@ -94,7 +94,7 @@ def test_screensaver(mocker, m5stickv): time_seq.append(tmp) btn_seq.append(BUTTON_ENTER) - c.input.wait_for_press = mocker.MagicMock(side_effect=btn_seq) + c.input.wait_for_button = mocker.MagicMock(side_effect=btn_seq) time.ticks_ms = mocker.MagicMock(side_effect=time_seq) c.screensaver() @@ -105,4 +105,4 @@ def test_screensaver(mocker, m5stickv): c.display.draw_line_hcentered_with_fullw_bg.assert_any_call( logo[5], 5, theme.bg_color, theme.fg_color ) - c.input.wait_for_press.assert_called() + c.input.wait_for_button.assert_called() From f0c49b48364328bfd38590a79a6de2cd2799cdd7 Mon Sep 17 00:00:00 2001 From: Odudex Date: Tue, 31 Oct 2023 16:36:31 -0300 Subject: [PATCH 077/114] save QR codes as image on SD card - basic --- src/krux/pages/__init__.py | 5 +- src/krux/pages/encryption_ui.py | 2 +- src/krux/pages/home.py | 2 +- src/krux/pages/qr_view.py | 109 ++++++++++++++++++++++++++++---- src/krux/pages/tools.py | 2 +- 5 files changed, 102 insertions(+), 18 deletions(-) diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index b7e7795db..8a149d97a 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -368,7 +368,7 @@ def print_qr_prompt(self): """Prompts the user to print a QR code in the specified format if a printer is connected """ - if Settings().hardware.printer.driver == "none": + if not self.has_printer(): return False self.ctx.display.clear() @@ -482,6 +482,9 @@ def fit_to_line(self, text, prefix="", fixed_chars=0): + text[-add_chars_amount:] ) + def has_printer(self): + return Settings().hardware.printer.driver != "none" + def has_sd_card(self): """Checks if the device has a SD card inserted""" self.ctx.display.clear() diff --git a/src/krux/pages/encryption_ui.py b/src/krux/pages/encryption_ui.py index dbb5fb6dd..0914b208b 100644 --- a/src/krux/pages/encryption_ui.py +++ b/src/krux/pages/encryption_ui.py @@ -222,7 +222,7 @@ def encrypted_qr_code(self): from .qr_view import SeedQRView seed_qr_view = SeedQRView(self.ctx, data=qr_data, title=mnemonic_id) - seed_qr_view.display_seed_qr() + seed_qr_view.display_qr() class LoadEncryptedMnemonic(Page): diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 793de2995..ecb7cce61 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -115,7 +115,7 @@ def display_seed_qr(self, binary=False): from .qr_view import SeedQRView seed_qr_view = SeedQRView(self.ctx, binary) - return seed_qr_view.display_seed_qr() + return seed_qr_view.display_qr() def stackbit(self): """Displays which numbers 1248 user should punch on 1248 steel card""" diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index 4245e3826..5827dd836 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -22,8 +22,8 @@ import qrcode from embit.wordlists.bip39 import WORDLIST -from . import Page, MENU_CONTINUE -from .utils import Utils +from . import Page, Menu, MENU_CONTINUE, MENU_EXIT +from ..sd_card import SDHandler from ..themes import theme, WHITE, BLACK from ..krux_settings import t from ..qr import get_size, add_qr_frame @@ -67,7 +67,6 @@ def __init__(self, ctx, binary=False, data=None, title=None): self.region_size = 7 if self.qr_size == 21 else 5 self.columns = (self.qr_size + self.region_size - 1) // self.region_size self.lr_index = 0 - self.utils = Utils(self.ctx) def _seed_qr(self): words = self.ctx.wallet.key.mnemonic.split(" ") @@ -279,10 +278,89 @@ def draw_grided_qr(self, mode): self.qr_size * grid_pad + 1, theme.highlight_color, ) + def save_bpm_image(self): + """Saves QR code image as compact B&W bitmap format file""" + size, code = add_qr_frame(self.code) + qr_image_file = ( + "P4\n# Krux\n".encode() + + str(size).encode() + + (" ").encode() + + str(size).encode() + + ("\n").encode() + ) + lines = code.strip().split("\n") + for bit_string_line in lines: + if size%8: + bit_string_line += "0"*(8-size%8) + line = int(bit_string_line, 2).to_bytes((self.qr_size+7)//8, "big") + qr_image_file += line + with SDHandler() as sd: + sd.write_binary("QR_Code.bpm", qr_image_file) + + def save_bmp_image(self, resolution): + """Save QR code image as .bmp file""" + # TODO: Try Compression? + import image + import lcd + + self.ctx.display.clear() + self.ctx.display.draw_centered_text(t("Saving ...")) + size, code = add_qr_frame(self.code) + raw_image = image.Image(size=(size, size)) + x_index = 0 + y_index = 0 + for qr_char in code: + if qr_char in ("0","1"): + if qr_char == "0": + raw_image.set_pixel((x_index, y_index), lcd.WHITE) + if qr_char == "1": + raw_image.set_pixel((x_index, y_index), lcd.BLACK) + if x_index == size - 1: + x_index = 0 + y_index += 1 + else: + x_index += 1 + bmp_img = image.Image(size=(resolution, resolution), copy_to_fb=True) + scale = resolution//size + bmp_img.draw_image( + raw_image, + 0, + 0, + x_scale=scale, + y_scale=scale, + ) + bmp_img.save("/sd/QR_Code.bmp") + + def save_qr_image_menu(self): + """Options to save QR codes as images on SD card""" + # TODO: Block raw mnemonics saving + # TODO: Allow custom file name + size = self.qr_size + 2 + resolutions = [] + resolution = size + for _ in range(4): + resolution *= 2 + if resolution <= 480: + resolutions.append(resolution) + qr_menu = [] + qr_menu.append(("%dx%d - PBM" % (size, size), self.save_bpm_image)) + for resolution in resolutions: + qr_menu.append(("%dx%d - BMP" % (resolution, resolution), lambda res=resolution: self.save_bmp_image(res))) + submenu = Menu( self.ctx, qr_menu) + _, status = submenu.run_loop() + return MENU_EXIT + + def print_qr(self): + "Printer handler" + from .utils import Utils + + utils = Utils(self.ctx) + utils.print_standard_qr(self.code, title=self.title, is_qr=True) + return MENU_EXIT + + def display_qr(self): + """Displays QR codes in multiple modes""" - def display_seed_qr(self): - """Disables touch and displays compact SeedQR code with grid to help - drawing""" if self.title: label = self.title else: @@ -298,8 +376,6 @@ def display_seed_qr(self): label, self.ctx.display.qr_offset() + self.ctx.display.font_height, ) - # # Avoid the need of double click - # self.ctx.input.buttons_active = True button = self.ctx.input.wait_for_button() if button in (BUTTON_PAGE, SWIPE_LEFT): # page, swipe mode += 1 @@ -319,9 +395,14 @@ def display_seed_qr(self): self.lr_index %= self.qr_size elif mode in (REGION_MODE, ZOOMED_R_MODE): self.lr_index %= self.columns * self.columns - self.ctx.display.clear() - if self.prompt(t("Are you sure?"), self.ctx.display.height() // 2): - break - self.utils.print_standard_qr(self.code, title=self.title, is_qr=True) - - return MENU_CONTINUE + qr_menu = [] + qr_menu.append((t("Leave QR Viewer"), lambda: MENU_EXIT)) + if self.has_sd_card(): + qr_menu.append((t("Save QR Image to SD Card"), self.save_qr_image_menu)) + if self.has_printer(): + qr_menu.append((t("Print to QR"), self.print_qr)) + qr_menu.append((t("Back"), lambda: None)) + submenu = Menu( self.ctx, qr_menu) + _, status = submenu.run_loop() + if status == MENU_EXIT: + return MENU_CONTINUE diff --git a/src/krux/pages/tools.py b/src/krux/pages/tools.py index 8450d1935..e5df3e84d 100644 --- a/src/krux/pages/tools.py +++ b/src/krux/pages/tools.py @@ -138,5 +138,5 @@ def create_qr(self): title = t("Custom QR Code") seed_qr_view = SeedQRView(self.ctx, data=text, title=title) - return seed_qr_view.display_seed_qr() + return seed_qr_view.display_qr() return MENU_CONTINUE From 17503159d5e63928ba7c28b1c34a02427c54e383 Mon Sep 17 00:00:00 2001 From: odudex Date: Tue, 31 Oct 2023 22:56:53 -0300 Subject: [PATCH 078/114] add menu offset option --- src/krux/pages/__init__.py | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 8a149d97a..9262e23b4 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -560,11 +560,12 @@ class Menu: and invoke menu item callbacks that return a status """ - def __init__(self, ctx, menu): + def __init__(self, ctx, menu, offset=0): self.ctx = ctx self.menu = menu + self.menu_offset = offset max_viewable = min( - (self.ctx.display.height() - 2 * DEFAULT_PADDING) + (self.ctx.display.height() - 2 * DEFAULT_PADDING - self.menu_offset) // (2 * self.ctx.display.font_height), len(self.menu), ) @@ -581,7 +582,16 @@ def run_loop(self, start_from_index=None): selected_item_index = start_from_index while True: gc.collect() - self.ctx.display.clear() + if self.menu_offset: + self.ctx.display.fill_rectangle( + 0, + self.menu_offset, + self.ctx.display.width(), + self.ctx.display.height() - self.menu_offset, + theme.bg_color, + ) + else: + self.ctx.display.clear() if self.ctx.input.touch is not None: self._draw_touch_menu(selected_item_index) else: @@ -731,10 +741,13 @@ def _draw_touch_menu(self, selected_item_index): for menu_item in self.menu_view: offset_y += len(self.ctx.display.to_lines(menu_item[0])) + 1 Page.y_keypad_map.append(offset_y) - height_multiplier = self.ctx.display.height() - 2 * DEFAULT_PADDING + height_multiplier = ( + self.ctx.display.height() - 2 * DEFAULT_PADDING - self.menu_offset + ) height_multiplier //= offset_y Page.y_keypad_map = [ - n * height_multiplier + DEFAULT_PADDING for n in Page.y_keypad_map + n * height_multiplier + DEFAULT_PADDING + self.menu_offset + for n in Page.y_keypad_map ] self.ctx.input.touch.y_regions = Page.y_keypad_map @@ -745,10 +758,6 @@ def _draw_touch_menu(self, selected_item_index): 0, y, self.ctx.display.width(), 1, theme.frame_color ) height = Page.y_keypad_map[i + 1] - y - if selected_item_index == i and self.ctx.input.buttons_active: - self.ctx.display.fill_rectangle( - 0, y + 1, self.ctx.display.width(), height - 2, theme.fg_color - ) # draw centralized strings in regions for i, menu_item in enumerate(self.menu_view): @@ -759,6 +768,13 @@ def _draw_touch_menu(self, selected_item_index): offset_y += Page.y_keypad_map[i] for j, text in enumerate(menu_item_lines): if selected_item_index == i and self.ctx.input.buttons_active: + self.ctx.display.fill_rectangle( + 0, + offset_y + 1 - self.ctx.display.font_height // 2, + self.ctx.display.width(), + (len(menu_item_lines) + 1) * self.ctx.display.font_height, + theme.fg_color, + ) self.ctx.display.draw_hcentered_text( text, offset_y + self.ctx.display.font_height * j, From a7eb214f2ef304931161799f76ce78cddd98fd35 Mon Sep 17 00:00:00 2001 From: odudex Date: Tue, 31 Oct 2023 22:57:23 -0300 Subject: [PATCH 079/114] add infobox option to hcentered text --- src/krux/display.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/krux/display.py b/src/krux/display.py index cdae02730..b6e115bb1 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -294,9 +294,20 @@ def draw_hcentered_text( offset_y=DEFAULT_PADDING, color=theme.fg_color, bg_color=theme.bg_color, + info_box = False ): """Draws text horizontally-centered on the display, at the given offset_y""" lines = text if isinstance(text, list) else self.to_lines(text) + if info_box: + bg_color = theme.disabled_color + self.fill_rectangle( + DEFAULT_PADDING -1, + offset_y - 1, + self.usable_width() + 2, + (len(lines)+1)*self.font_height + 2, + bg_color + ) + for i, line in enumerate(lines): if len(line) > 0: offset_x = self._obtain_hcentered_offset(line) From e57c7dcea070915ab69267587185c9575c130894 Mon Sep 17 00:00:00 2001 From: odudex Date: Tue, 31 Oct 2023 23:22:15 -0300 Subject: [PATCH 080/114] save QR as image: fix typo, add saved message --- src/krux/pages/qr_view.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index 5827dd836..d840ace68 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -278,7 +278,7 @@ def draw_grided_qr(self, mode): self.qr_size * grid_pad + 1, theme.highlight_color, ) - def save_bpm_image(self): + def save_pbm_image(self): """Saves QR code image as compact B&W bitmap format file""" size, code = add_qr_frame(self.code) qr_image_file = ( @@ -294,8 +294,10 @@ def save_bpm_image(self): bit_string_line += "0"*(8-size%8) line = int(bit_string_line, 2).to_bytes((self.qr_size+7)//8, "big") qr_image_file += line + filename = "QR_Code.pbm" with SDHandler() as sd: - sd.write_binary("QR_Code.bpm", qr_image_file) + sd.write_binary(filename, qr_image_file) + self.flash_text(t("Saved to SD card:\n%s") % filename) def save_bmp_image(self, resolution): """Save QR code image as .bmp file""" @@ -329,7 +331,9 @@ def save_bmp_image(self, resolution): x_scale=scale, y_scale=scale, ) - bmp_img.save("/sd/QR_Code.bmp") + filename = "QR_Code.bmp" + bmp_img.save("/sd/" + filename) + self.flash_text(t("Saved to SD card:\n%s") % filename) def save_qr_image_menu(self): """Options to save QR codes as images on SD card""" @@ -342,13 +346,19 @@ def save_qr_image_menu(self): resolution *= 2 if resolution <= 480: resolutions.append(resolution) + self.ctx.display.clear() + self.ctx.display.draw_hcentered_text( + t("Resolution - Format"), + self.ctx.display.font_height, + info_box=True + ) qr_menu = [] - qr_menu.append(("%dx%d - PBM" % (size, size), self.save_bpm_image)) + qr_menu.append(("%dx%d - PBM" % (size, size), self.save_pbm_image)) for resolution in resolutions: qr_menu.append(("%dx%d - BMP" % (resolution, resolution), lambda res=resolution: self.save_bmp_image(res))) - submenu = Menu( self.ctx, qr_menu) + submenu = Menu( self.ctx, qr_menu, offset=2*self.ctx.display.font_height) _, status = submenu.run_loop() - return MENU_EXIT + # return MENU_EXIT # Uncomment to exit QR Viewer after saving def print_qr(self): "Printer handler" @@ -356,7 +366,7 @@ def print_qr(self): utils = Utils(self.ctx) utils.print_standard_qr(self.code, title=self.title, is_qr=True) - return MENU_EXIT + # return MENU_EXIT # Uncomment to exit QR Viewer after printing def display_qr(self): """Displays QR codes in multiple modes""" From a2c7c8f1e89b5792ffed9f72a650ace1d7a8fc35 Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 1 Nov 2023 13:41:33 -0300 Subject: [PATCH 081/114] better event handling for simultaneous events imporant when encoder is used --- src/krux/input.py | 12 +++++++++--- src/krux/rotary.py | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/krux/input.py b/src/krux/input.py index 8e9f51564..0925fdac2 100644 --- a/src/krux/input.py +++ b/src/krux/input.py @@ -50,6 +50,7 @@ def __init__(self, screensaver_fallback=None): self.screensaver_active = False self.entropy = 0 self.debounce_time = 0 + self.flushed_flag = False self.enter = None if "BUTTON_A" in board.config["krux"]["pins"]: @@ -178,10 +179,16 @@ def wait_for_press( """Wait for first button press or for wait_duration ms. Use block to wait indefinitely""" start_time = time.ticks_ms() + self.debounce_time = time.ticks_ms() if not self.flushed_flag else 0 while time.ticks_ms() < self.debounce_time + DEBOUNCE: - pass - if block: self.flush_events() + if not self.flushed_flag or block: + # Makes sure events that happened between pages load are cleared. + # On animated pages, where block=False, intermediary events must be checked, + # so events won't be cleared after flushed_flag is set + self.flush_events() + self.flushed_flag = not block + self.screensaver_time = start_time while True: if self.enter_event(): @@ -273,7 +280,6 @@ def wait_for_button(self, block=True, enable_screensaver=False): if self.swipe_down_value() == PRESSED: btn = SWIPE_DOWN - self.debounce_time = time.ticks_ms() return btn def flush_events(self): diff --git a/src/krux/rotary.py b/src/krux/rotary.py index 5bf8b9666..5e0ca3ed4 100644 --- a/src/krux/rotary.py +++ b/src/krux/rotary.py @@ -107,7 +107,7 @@ class EncoderPage(Button): def event(self): """Returns encoder events while mimics Krux GPIO Buttons behavior""" if encoder.value > 0: - encoder.value -= 1 + encoder.value = 0 return True return False @@ -118,6 +118,6 @@ class EncoderPagePrev(Button): def event(self): """Returns encoder events while mimics Krux GPIO Buttons behavior""" if encoder.value < 0: - encoder.value += 1 + encoder.value = 0 return True return False From 0988ecca64fd42909f8372f517956864672b9c9c Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 1 Nov 2023 13:43:12 -0300 Subject: [PATCH 082/114] block QR code image export for raw private keys black --- src/krux/display.py | 10 ++++----- src/krux/pages/__init__.py | 2 +- src/krux/pages/encryption_ui.py | 2 +- src/krux/pages/qr_view.py | 36 ++++++++++++++++++--------------- src/krux/pages/tools.py | 2 +- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/krux/display.py b/src/krux/display.py index b6e115bb1..ecf7121ca 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -294,20 +294,20 @@ def draw_hcentered_text( offset_y=DEFAULT_PADDING, color=theme.fg_color, bg_color=theme.bg_color, - info_box = False + info_box=False, ): """Draws text horizontally-centered on the display, at the given offset_y""" lines = text if isinstance(text, list) else self.to_lines(text) if info_box: bg_color = theme.disabled_color self.fill_rectangle( - DEFAULT_PADDING -1, + DEFAULT_PADDING - 1, offset_y - 1, self.usable_width() + 2, - (len(lines)+1)*self.font_height + 2, - bg_color + (len(lines) + 1) * self.font_height + 2, + bg_color, ) - + for i, line in enumerate(lines): if len(line) > 0: offset_x = self._obtain_hcentered_offset(line) diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 9262e23b4..bba652c11 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -483,6 +483,7 @@ def fit_to_line(self, text, prefix="", fixed_chars=0): ) def has_printer(self): + """Checks if the device has a printer setup""" return Settings().hardware.printer.driver != "none" def has_sd_card(self): @@ -757,7 +758,6 @@ def _draw_touch_menu(self, selected_item_index): self.ctx.display.fill_rectangle( 0, y, self.ctx.display.width(), 1, theme.frame_color ) - height = Page.y_keypad_map[i + 1] - y # draw centralized strings in regions for i, menu_item in enumerate(self.menu_view): diff --git a/src/krux/pages/encryption_ui.py b/src/krux/pages/encryption_ui.py index 0914b208b..ea224e78a 100644 --- a/src/krux/pages/encryption_ui.py +++ b/src/krux/pages/encryption_ui.py @@ -222,7 +222,7 @@ def encrypted_qr_code(self): from .qr_view import SeedQRView seed_qr_view = SeedQRView(self.ctx, data=qr_data, title=mnemonic_id) - seed_qr_view.display_qr() + seed_qr_view.display_qr(allow_export=True) class LoadEncryptedMnemonic(Page): diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index d840ace68..db40b9312 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -278,6 +278,7 @@ def draw_grided_qr(self, mode): self.qr_size * grid_pad + 1, theme.highlight_color, ) + def save_pbm_image(self): """Saves QR code image as compact B&W bitmap format file""" size, code = add_qr_frame(self.code) @@ -290,9 +291,9 @@ def save_pbm_image(self): ) lines = code.strip().split("\n") for bit_string_line in lines: - if size%8: - bit_string_line += "0"*(8-size%8) - line = int(bit_string_line, 2).to_bytes((self.qr_size+7)//8, "big") + if size % 8: + bit_string_line += "0" * (8 - size % 8) + line = int(bit_string_line, 2).to_bytes((self.qr_size + 7) // 8, "big") qr_image_file += line filename = "QR_Code.pbm" with SDHandler() as sd: @@ -312,7 +313,7 @@ def save_bmp_image(self, resolution): x_index = 0 y_index = 0 for qr_char in code: - if qr_char in ("0","1"): + if qr_char in ("0", "1"): if qr_char == "0": raw_image.set_pixel((x_index, y_index), lcd.WHITE) if qr_char == "1": @@ -323,7 +324,7 @@ def save_bmp_image(self, resolution): else: x_index += 1 bmp_img = image.Image(size=(resolution, resolution), copy_to_fb=True) - scale = resolution//size + scale = resolution // size bmp_img.draw_image( raw_image, 0, @@ -334,7 +335,7 @@ def save_bmp_image(self, resolution): filename = "QR_Code.bmp" bmp_img.save("/sd/" + filename) self.flash_text(t("Saved to SD card:\n%s") % filename) - + def save_qr_image_menu(self): """Options to save QR codes as images on SD card""" # TODO: Block raw mnemonics saving @@ -348,18 +349,21 @@ def save_qr_image_menu(self): resolutions.append(resolution) self.ctx.display.clear() self.ctx.display.draw_hcentered_text( - t("Resolution - Format"), - self.ctx.display.font_height, - info_box=True + t("Resolution - Format"), self.ctx.display.font_height, info_box=True ) qr_menu = [] qr_menu.append(("%dx%d - PBM" % (size, size), self.save_pbm_image)) for resolution in resolutions: - qr_menu.append(("%dx%d - BMP" % (resolution, resolution), lambda res=resolution: self.save_bmp_image(res))) - submenu = Menu( self.ctx, qr_menu, offset=2*self.ctx.display.font_height) - _, status = submenu.run_loop() + qr_menu.append( + ( + "%dx%d - BMP" % (resolution, resolution), + lambda res=resolution: self.save_bmp_image(res), + ) + ) + submenu = Menu(self.ctx, qr_menu, offset=2 * self.ctx.display.font_height) + submenu.run_loop() # return MENU_EXIT # Uncomment to exit QR Viewer after saving - + def print_qr(self): "Printer handler" from .utils import Utils @@ -368,7 +372,7 @@ def print_qr(self): utils.print_standard_qr(self.code, title=self.title, is_qr=True) # return MENU_EXIT # Uncomment to exit QR Viewer after printing - def display_qr(self): + def display_qr(self, allow_export=False): """Displays QR codes in multiple modes""" if self.title: @@ -407,12 +411,12 @@ def display_qr(self): self.lr_index %= self.columns * self.columns qr_menu = [] qr_menu.append((t("Leave QR Viewer"), lambda: MENU_EXIT)) - if self.has_sd_card(): + if self.has_sd_card() and allow_export: qr_menu.append((t("Save QR Image to SD Card"), self.save_qr_image_menu)) if self.has_printer(): qr_menu.append((t("Print to QR"), self.print_qr)) qr_menu.append((t("Back"), lambda: None)) - submenu = Menu( self.ctx, qr_menu) + submenu = Menu(self.ctx, qr_menu) _, status = submenu.run_loop() if status == MENU_EXIT: return MENU_CONTINUE diff --git a/src/krux/pages/tools.py b/src/krux/pages/tools.py index e5df3e84d..667830f8f 100644 --- a/src/krux/pages/tools.py +++ b/src/krux/pages/tools.py @@ -138,5 +138,5 @@ def create_qr(self): title = t("Custom QR Code") seed_qr_view = SeedQRView(self.ctx, data=text, title=title) - return seed_qr_view.display_qr() + return seed_qr_view.display_qr(allow_export=True) return MENU_CONTINUE From 3faee7d5364819a6df754556ffcaa92ad1e6c0c4 Mon Sep 17 00:00:00 2001 From: Odudex Date: Wed, 1 Nov 2023 17:03:52 -0300 Subject: [PATCH 083/114] parallelizes public key options --- pyproject.toml | 2 +- src/krux/metadata.py | 2 +- src/krux/pages/__init__.py | 21 ++++++----- src/krux/pages/home.py | 77 +++++++++++++++++++++++++++----------- src/krux/pages/qr_view.py | 1 - 5 files changed, 70 insertions(+), 33 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4427eaecb..d621e3f43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ [tool.poetry] name = "krux" -version = "24.04.beta4" +version = "24.04.beta5" description = "Open-source signing device firmware for Bitcoin" authors = ["Jeff S "] diff --git a/src/krux/metadata.py b/src/krux/metadata.py index 6876e72d1..3a2f69272 100644 --- a/src/krux/metadata.py +++ b/src/krux/metadata.py @@ -19,5 +19,5 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -VERSION = "24.04.beta4" +VERSION = "24.04.beta5" SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b" diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index bba652c11..9f8fee117 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -787,15 +787,18 @@ def _draw_touch_menu(self, selected_item_index): ) def _draw_menu(self, selected_item_index): - offset_y = len(self.menu_view) * 2 - extra_lines = 0 - for menu_item in self.menu_view: - extra_lines += len(self.ctx.display.to_lines(menu_item[0])) - 1 - offset_y += extra_lines - offset_y *= self.ctx.display.font_height - offset_y = self.ctx.display.height() - offset_y - offset_y //= 2 - offset_y += self.ctx.display.font_height // 2 + if self.menu_offset: + offset_y = self.menu_offset + self.ctx.display.font_height // 2 + else: + offset_y = len(self.menu_view) * 2 + extra_lines = 0 + for menu_item in self.menu_view: + extra_lines += len(self.ctx.display.to_lines(menu_item[0])) - 1 + offset_y += extra_lines + offset_y *= self.ctx.display.font_height + offset_y = self.ctx.display.height() - offset_y + offset_y //= 2 + offset_y += self.ctx.display.font_height // 2 for i, menu_item in enumerate(self.menu_view): menu_item_lines = self.ctx.display.to_lines(menu_item[0]) delta_y = (len(menu_item_lines) + 1) * self.ctx.display.font_height diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index ecb7cce61..44a1ace5f 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -167,19 +167,49 @@ def encrypt_mnemonic(self): def public_key(self): """Handler for the 'xpub' menu item""" - zpub = "Zpub" if self.ctx.wallet.key.multisig else "zpub" - for version in [None, self.ctx.wallet.key.network[zpub]]: + + def _save_xpub_to_sd(version): + from .files_operations import SaveFile + + save_page = SaveFile(self.ctx) + xpub = self.ctx.wallet.key.key_expression(version) + title = self.ctx.wallet.key.account_pubkey_str(version)[ + :WALLET_XPUB_START + ].upper() + save_page.save_file( + xpub, + title, + title, + title + ":", + PUBKEY_FILE_EXTENSION, + save_as_binary=False, + ) + + def _pub_key_text(version): + pub_text_menu_items = [] + if self.has_sd_card(): + pub_text_menu_items.append( + (t("Save to SD card?"), lambda ver=version: _save_xpub_to_sd(ver)) + ) + pub_text_menu_items.append((t("Back"), lambda: MENU_EXIT)) + full_pub_key = self.ctx.wallet.key.account_pubkey_str(version) + menu_offset = 5 + len(self.ctx.display.to_lines(full_pub_key)) + menu_offset *= self.ctx.display.font_height + pub_key_menu = Menu(self.ctx, pub_text_menu_items, offset=menu_offset) self.ctx.display.clear() - self.ctx.display.draw_centered_text( - self.ctx.wallet.key.fingerprint_hex_str(True) + self.ctx.display.draw_hcentered_text( + self.ctx.wallet.key.fingerprint_hex_str() + "\n\n" - + self.ctx.wallet.key.derivation_str(True) + + self.ctx.wallet.key.derivation_str() + "\n\n" - + self.ctx.wallet.key.account_pubkey_str(version) + + full_pub_key, + offset_y=self.ctx.display.font_height, + info_box=True, ) - self.ctx.input.wait_for_button() + pub_key_menu.run_loop() - # title receives first 4 chars (ex: XPUB) + def _pub_key_qr(version): + # TODO: Add menu to offer print and export as image title = self.ctx.wallet.key.account_pubkey_str(version)[ :WALLET_XPUB_START ].upper() @@ -187,19 +217,24 @@ def public_key(self): self.display_qr_codes(xpub, FORMAT_NONE, title) self.utils.print_standard_qr(xpub, FORMAT_NONE, title) - # Try to save the XPUB file on the SD card - if self.has_sd_card(): - from .files_operations import SaveFile - - save_page = SaveFile(self.ctx) - save_page.save_file( - xpub, - title, - title, - title + ":", - PUBKEY_FILE_EXTENSION, - save_as_binary=False, - ) + zpub = "Zpub" if self.ctx.wallet.key.multisig else "zpub" + pub_key_menu_items = [] + for version in [None, self.ctx.wallet.key.network[zpub]]: + title = self.ctx.wallet.key.account_pubkey_str(version)[ + :WALLET_XPUB_START + ].upper() + pub_key_menu_items.append( + (title + " - " + t("Text"), lambda ver=version: _pub_key_text(ver)) + ) + pub_key_menu_items.append( + (title + " - " + t("QR Code"), lambda ver=version: _pub_key_qr(ver)) + ) + pub_key_menu_items.append((t("Back"), lambda: MENU_EXIT)) + pub_key_menu = Menu(self.ctx, pub_key_menu_items) + while True: + _, status = pub_key_menu.run_loop() + if status == MENU_EXIT: + break return MENU_CONTINUE diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index db40b9312..0f012dda8 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -338,7 +338,6 @@ def save_bmp_image(self, resolution): def save_qr_image_menu(self): """Options to save QR codes as images on SD card""" - # TODO: Block raw mnemonics saving # TODO: Allow custom file name size = self.qr_size + 2 resolutions = [] From 0d147055f5584c375b8aee411312c581dc8eb315 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Thu, 2 Nov 2023 22:34:54 -0300 Subject: [PATCH 084/114] fixed wallet descriptor display for multisig --- src/krux/pages/__init__.py | 2 +- src/krux/pages/home.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 9f8fee117..0f3cc9792 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -468,7 +468,7 @@ def prompt(self, text, offset_y=0): return answer def fit_to_line(self, text, prefix="", fixed_chars=0): - """Fits text into a line, removing central content and leaving ends""" + """Fits text with prefix plus fixed_chars at the beginning into one line, removing the central content and leaving the ends""" add_chars_amount = ( self.ctx.display.usable_width() // self.ctx.display.font_width diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 44a1ace5f..c6251d6b1 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -454,7 +454,7 @@ def display_wallet(self, wallet, include_qr=True): which will contain the same data as was originally loaded, in the same QR format """ - about = wallet.label + "\n" + about = [wallet.label] if wallet.is_multisig(): import binascii @@ -463,11 +463,11 @@ def display_wallet(self, wallet, include_qr=True): fingerprints.append( str(i + 1) + ". " + binascii.hexlify(key.fingerprint).decode() ) - about += "\n".join(fingerprints) + about.extend(fingerprints) else: - about += wallet.key.fingerprint_hex_str() + about.append(wallet.key.fingerprint_hex_str()) xpub = wallet.key.xpub() - about += "\n" + self.fit_to_line(xpub) + about.append(self.fit_to_line(xpub)) if not wallet.is_multisig() and include_qr: wallet_data, qr_format = wallet.wallet_qr() @@ -477,11 +477,11 @@ def display_wallet(self, wallet, include_qr=True): # If multisig, show loaded wallet again with all XPUB if wallet.is_multisig(): - about = wallet.label + "\n" + about = [wallet.label] xpubs = [] for i, xpub in enumerate(wallet.policy["cosigners"]): xpubs.append(self.fit_to_line(xpub, str(i + 1) + ". ")) - about += "\n".join(xpubs) + about.extend(xpubs) if include_qr: self.ctx.input.wait_for_button() From 34828742695ba1854812dc2bdba679b6c12191f9 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Fri, 3 Nov 2023 09:36:29 -0300 Subject: [PATCH 085/114] Fix line breaker on text with multiple lines and exact match on the screen width --- src/krux/display.py | 17 ++++++++++++++++- tests/pages/test_qr_view.py | 2 +- tests/test_display.py | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/krux/display.py b/src/krux/display.py index ecf7121ca..436fae2a3 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -198,7 +198,22 @@ def to_lines(self, text): # is less than the amount of columns. If it's exactly equal, # a newline will be implicit. if len(words[-1]) < columns: - words[-1] += "\n" + add_new_line = True + # check for exact match with 2 words + if ( + len(words) > 1 + and len(words[-1]) + len(words[-2]) + 1 == columns + ): + add_new_line = False + # check for exact match with 3 words + if ( + len(words) > 2 + and len(words[-1]) + len(words[-2]) + len(words[-3]) + 2 + == columns + ): + add_new_line = False + if add_new_line: + words[-1] += "\n" num_words = len(words) diff --git a/tests/pages/test_qr_view.py b/tests/pages/test_qr_view.py index 09dd492cc..fd0f862b7 100644 --- a/tests/pages/test_qr_view.py +++ b/tests/pages/test_qr_view.py @@ -23,5 +23,5 @@ def test_load_qr_view(amigo_tft, mocker): ctx.input.wait_for_button = mocker.MagicMock(side_effect=BTN_SEQUENCE) data = "test code" seed_qr_view = SeedQRView(ctx, data=data, title="Test QR Code") - seed_qr_view.display_seed_qr() + seed_qr_view.display_qr() assert ctx.display.draw_qr_code.call_count == 8 diff --git a/tests/test_display.py b/tests/test_display.py index a7cc384da..cc6e937f2 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -182,6 +182,9 @@ def test_to_lines(mocker, m5stickv): cases = [ (135, "Two Words", ["Two Words"]), + (135, "Two Words", ["Two Words"]), + (135, "Two Words", ["Two Words"]), + (135, "Two Words", ["Two Words"]), (135, "Two\nWords", ["Two", "Words"]), (135, "Two\n\nWords", ["Two", "", "Words"]), (135, "Two\n\n\nWords", ["Two", "", "", "Words"]), @@ -307,6 +310,40 @@ def test_to_lines(mocker, m5stickv): assert lines == case[2] +def test_to_lines_exact_match_amigo(mocker, amigo_tft): + from krux.display import Display + + cases = [ + (320, "01234 0123456789012345678", ["01234 0123456789012345678"]), + (320, "0123456789 01234567890 01234", ["0123456789", "01234567890 01234"]), + (320, "01234567890123456789012345", ["0123456789012345678901234", "5"]), + ( + 320, + "01234 0123456789012345678\n01234 0123456789012345678", + ["01234 0123456789012345678", "01234 0123456789012345678"], + ), + ( + 320, + "01 34 0123456789012345678\n01234 0123456789012345678", + ["01 34 0123456789012345678", "01234 0123456789012345678"], + ), + ( + 320, + "01 345 0123456789012345678\n01234 0123456789012345678", + ["01 345", "0123456789012345678", "01234 0123456789012345678"], + ), + ] + for case in cases: + mocker.patch( + "krux.display.lcd", + new=mocker.MagicMock(width=mocker.MagicMock(return_value=case[0])), + ) + d = Display() + lines = d.to_lines(case[1]) + print(lines) + assert lines == case[2] + + def test_outline(mocker, m5stickv): mocker.patch("krux.display.lcd", new=mocker.MagicMock()) import krux From 1d70620031354c7a343a02bde67d946dca7e9afd Mon Sep 17 00:00:00 2001 From: tadeubas Date: Fri, 3 Nov 2023 09:42:01 -0300 Subject: [PATCH 086/114] maixpy using last commit from sipeed_update --- firmware/MaixPy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/MaixPy b/firmware/MaixPy index 349ba9394..bab9a5fc9 160000 --- a/firmware/MaixPy +++ b/firmware/MaixPy @@ -1 +1 @@ -Subproject commit 349ba9394d1578ce316036c53866c4abf1d9ddec +Subproject commit bab9a5fc9111d176da1daebdeec44da73e7845ba From afc9df61ac203bd755cddd2f85867bd50f651b01 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Fri, 3 Nov 2023 09:51:15 -0300 Subject: [PATCH 087/114] fix test_mnemonic_compact_qr --- tests/pages/test_home.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 912ca8c0a..481f42f60 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -277,7 +277,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): from krux.qr import FORMAT_NONE cases = [ - # No print prompt + # 0 - No print prompt ( Wallet(tdata.SINGLESIG_12_WORD_KEY), None, @@ -286,13 +286,14 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave - BUTTON_ENTER, # Are you sure? yes + BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), + # 1 ( Wallet(tdata.SINGLESIG_24_WORD_KEY), None, @@ -301,14 +302,14 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave - BUTTON_ENTER, # Are you sure? yes + BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), - # Print + # 2 - Print ( Wallet(tdata.SINGLESIG_12_WORD_KEY), MockPrinter(), @@ -317,14 +318,14 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave - BUTTON_ENTER, # Are you sure? yes - BUTTON_ENTER, # say yes to print prompt + BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), + # 3 ( Wallet(tdata.SINGLESIG_24_WORD_KEY), MockPrinter(), @@ -333,15 +334,14 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave - BUTTON_ENTER, # Are you sure? yes - BUTTON_ENTER, # say yes to print prompt + BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), - # Decline to print + # 4 - Decline to print ( Wallet(tdata.SINGLESIG_12_WORD_KEY), MockPrinter(), @@ -350,14 +350,14 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave - BUTTON_ENTER, # Are you sure? yes - BUTTON_PAGE, # say no to print prompt + BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), + # 5 ( Wallet(tdata.SINGLESIG_24_WORD_KEY), MockPrinter(), @@ -366,8 +366,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave - BUTTON_ENTER, # Are you sure? yes - BUTTON_PAGE, # say no to print prompt + BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, From e7ea217b2f52e6a8493720e2545e7ed1bc610223 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Fri, 3 Nov 2023 09:59:59 -0300 Subject: [PATCH 088/114] Unfinished fix to test_public_key --- tests/pages/test_home.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 481f42f60..71966af72 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -503,22 +503,29 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): def test_public_key(mocker, m5stickv, tdata): from krux.pages.home import Home from krux.wallet import Wallet - from krux.input import BUTTON_ENTER, BUTTON_PAGE + from krux.input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV from krux.qr import FORMAT_NONE cases = [ - # No print prompt + # 0 - No print prompt ( Wallet(tdata.SINGLESIG_12_WORD_KEY), None, - [BUTTON_ENTER, BUTTON_ENTER, BUTTON_ENTER, BUTTON_ENTER], + [ + BUTTON_ENTER, # XPUB - Text + BUTTON_PAGE, # move Back - child + BUTTON_ENTER, # Press Back - child + BUTTON_PAGE_PREV, # Move Back - father + BUTTON_ENTER # Press Back - father + ], ), + # 1 ( Wallet(tdata.MULTISIG_12_WORD_KEY), None, [BUTTON_ENTER, BUTTON_ENTER, BUTTON_ENTER, BUTTON_ENTER], ), - # Print + # 2 - Print ( Wallet(tdata.SINGLESIG_12_WORD_KEY), MockPrinter(), @@ -531,6 +538,7 @@ def test_public_key(mocker, m5stickv, tdata): BUTTON_ENTER, ], ), + # 3 ( Wallet(tdata.MULTISIG_12_WORD_KEY), MockPrinter(), @@ -543,7 +551,7 @@ def test_public_key(mocker, m5stickv, tdata): BUTTON_ENTER, ], ), - # Decline to print + # 4 - Decline to print ( Wallet(tdata.SINGLESIG_12_WORD_KEY), MockPrinter(), @@ -556,6 +564,7 @@ def test_public_key(mocker, m5stickv, tdata): BUTTON_PAGE, ], ), + # 5 ( Wallet(tdata.MULTISIG_12_WORD_KEY), MockPrinter(), @@ -569,7 +578,10 @@ def test_public_key(mocker, m5stickv, tdata): ], ), ] + num = 0 for case in cases: + print(num) + num += 1 ctx = create_ctx(mocker, case[2], case[0], case[1]) home = Home(ctx) From 192fdd8917a93cbb79a64de2b682bf6d02b3485b Mon Sep 17 00:00:00 2001 From: tadeubas Date: Fri, 3 Nov 2023 10:40:19 -0300 Subject: [PATCH 089/114] black --- tests/pages/test_home.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 71966af72..5ca20e3a4 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -512,11 +512,11 @@ def test_public_key(mocker, m5stickv, tdata): Wallet(tdata.SINGLESIG_12_WORD_KEY), None, [ - BUTTON_ENTER, # XPUB - Text - BUTTON_PAGE, # move Back - child - BUTTON_ENTER, # Press Back - child - BUTTON_PAGE_PREV, # Move Back - father - BUTTON_ENTER # Press Back - father + BUTTON_ENTER, # XPUB - Text + BUTTON_PAGE, # move Back - child + BUTTON_ENTER, # Press Back - child + BUTTON_PAGE_PREV, # Move Back - father + BUTTON_ENTER, # Press Back - father ], ), # 1 From 465e1250e2e720b40378e7793a341fc3574a6fad Mon Sep 17 00:00:00 2001 From: tadeubas Date: Fri, 3 Nov 2023 16:17:05 -0300 Subject: [PATCH 090/114] 12/24 word confirm when loading from digits (oct hex) --- src/krux/pages/login.py | 27 +++++++++++++++++++++++++-- tests/pages/test_login.py | 8 +++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/krux/pages/login.py b/src/krux/pages/login.py index 936082ae2..208b75eda 100644 --- a/src/krux/pages/login.py +++ b/src/krux/pages/login.py @@ -303,7 +303,30 @@ def _load_qr_passphrase(self): return MENU_CONTINUE return data - def _load_key_from_words(self, words): + def _get_words_numbers(self, words, charset): + word_numbers = [] + for word in words: + word_numbers.append(WORDLIST.index(word) + 1) + + if charset == DIGITS_HEX: + for i, number in enumerate(word_numbers): + word_numbers[i] = hex(number)[2:].upper() + + if charset == DIGITS_OCT: + for i, number in enumerate(word_numbers): + word_numbers[i] = oct(number)[2:] + + numbers_str = [str(value) for value in word_numbers] + return " ".join(numbers_str) + + def _load_key_from_words(self, words, charset=LETTERS): + if charset != LETTERS: + numbers_str = self._get_words_numbers(words, charset) + self.display_mnemonic(numbers_str) + if not self.prompt(t("Continue?"), self.ctx.display.bottom_prompt_line): + return MENU_CONTINUE + self.ctx.display.clear() + mnemonic = " ".join(words) self.display_mnemonic(mnemonic) if not self.prompt(t("Continue?"), self.ctx.display.bottom_prompt_line): @@ -531,7 +554,7 @@ def _load_key_from_keypad( ): words.append(word) - return self._load_key_from_words(words) + return self._load_key_from_words(words, charset) return MENU_CONTINUE diff --git a/tests/pages/test_login.py b/tests/pages/test_login.py index 9b8107b19..6ae173b89 100644 --- a/tests/pages/test_login.py +++ b/tests/pages/test_login.py @@ -1080,6 +1080,7 @@ def test_load_key_from_digits(m5stickv, mocker, mocker_printer): ) + [ BUTTON_ENTER, # Done? + BUTTON_ENTER, # 12 numbers confirm BUTTON_ENTER, # 12 word confirm BUTTON_PAGE, # 1 press to move to Scan passphrase BUTTON_PAGE, # 1 press to move to No passphrase @@ -1107,6 +1108,7 @@ def test_load_key_from_digits(m5stickv, mocker, mocker_printer): + [BUTTON_ENTER] + [ BUTTON_ENTER, # Done? + BUTTON_ENTER, # 12 numbers confirm BUTTON_ENTER, # 12 word confirm BUTTON_PAGE, # 1 press to move to Scan passphrase BUTTON_PAGE, # 1 press to move to No passphrase @@ -1119,7 +1121,7 @@ def test_load_key_from_digits(m5stickv, mocker, mocker_printer): ] num = 0 for case in cases: - print(num) + print("case:", num) num = num + 1 ctx = create_ctx(mocker, case[0]) login = Login(ctx) @@ -1156,6 +1158,7 @@ def test_load_12w_from_hexadecimal(m5stickv, mocker, mocker_printer): ) + [ BUTTON_ENTER, # Done? + BUTTON_ENTER, # 12 numbers confirm BUTTON_ENTER, # 12 word confirm BUTTON_PAGE, # 1 press to move to Scan passphrase BUTTON_PAGE, # 1 press to move to No passphrase @@ -1223,6 +1226,7 @@ def test_possible_letters_from_hexadecimal(m5stickv, mocker, mocker_printer): ) + [ BUTTON_ENTER, # Done? + BUTTON_ENTER, # 12 numbers confirm BUTTON_ENTER, # 12 word confirm BUTTON_PAGE, # 1 press to move to Scan passphrase BUTTON_PAGE, # 1 press to move to No passphrase @@ -1268,6 +1272,7 @@ def test_load_12w_from_octal(m5stickv, mocker, mocker_printer): ) + [ BUTTON_ENTER, # Done? + BUTTON_ENTER, # 12 numbers confirm BUTTON_ENTER, # 12 word confirm BUTTON_PAGE, # 1 press to move to Scan passphrase BUTTON_PAGE, # 1 press to move to No passphrase @@ -1328,6 +1333,7 @@ def test_possible_letters_from_octal(m5stickv, mocker, mocker_printer): ) + [ BUTTON_ENTER, # Done? + BUTTON_ENTER, # 12 numbers confirm BUTTON_ENTER, # 12 word confirm BUTTON_PAGE, # 1 press to move to Scan passphrase BUTTON_PAGE, # 1 press to move to No passphrase From 8fac87f8b9bb438e35711e31080cf68724d270e0 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Fri, 3 Nov 2023 22:28:59 -0300 Subject: [PATCH 091/114] Addresses page now shows more lines on big screens --- src/krux/display.py | 6 ++++++ src/krux/pages/__init__.py | 3 +-- src/krux/pages/addresses.py | 15 ++++++++------- tests/pages/test_home.py | 2 ++ tests/shared_mocks.py | 3 +++ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/krux/display.py b/src/krux/display.py index 436fae2a3..9f7be161d 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -375,3 +375,9 @@ def set_backlight(self, level): level = max(0, min(level, 8)) val = (level + 7) << 4 self.i2c.writeto_mem(0x34, 0x91, int(val)) + + def max_lines(self, line_offset=0): + """The max lines of text supported by the display""" + return (self.height() - 2 * DEFAULT_PADDING - line_offset) // ( + 2 * self.font_height + ) diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index 0f3cc9792..c2cbfbc0e 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -566,8 +566,7 @@ def __init__(self, ctx, menu, offset=0): self.menu = menu self.menu_offset = offset max_viewable = min( - (self.ctx.display.height() - 2 * DEFAULT_PADDING - self.menu_offset) - // (2 * self.ctx.display.font_height), + self.ctx.display.max_lines(self.menu_offset), len(self.menu), ) self.menu_view = ListView(self.menu, max_viewable) diff --git a/src/krux/pages/addresses.py b/src/krux/pages/addresses.py index 6db47ba84..0e60b8e93 100644 --- a/src/krux/pages/addresses.py +++ b/src/krux/pages/addresses.py @@ -32,7 +32,6 @@ MENU_EXIT, ) -LIST_ADDRESS_QTD = 4 # qtd of address per page SCAN_ADDRESS_LIMIT = 20 @@ -73,19 +72,21 @@ def list_address_type(self, addr_type=0): if addr_type == 1: loading_txt = t("Loading change address %d..") + max_addresses = self.ctx.display.max_lines() - 3 + num_checked = 0 while True: items = [] - if num_checked + 1 > LIST_ADDRESS_QTD: + if num_checked + 1 > max_addresses: items.append( ( - "%d..%d" % (num_checked - LIST_ADDRESS_QTD, num_checked), + "%d..%d" % (num_checked - max_addresses, num_checked), lambda: MENU_EXIT, ) ) for addr in self.ctx.wallet.obtain_addresses( - num_checked, limit=LIST_ADDRESS_QTD, branch_index=addr_type + num_checked, limit=max_addresses, branch_index=addr_type ): self.ctx.display.clear() self.ctx.display.draw_centered_text(loading_txt % (num_checked + 1)) @@ -105,7 +106,7 @@ def list_address_type(self, addr_type=0): items.append( ( - "%d..%d" % (num_checked + 1, num_checked + LIST_ADDRESS_QTD), + "%d..%d" % (num_checked + 1, num_checked + max_addresses), lambda: MENU_EXIT, ) ) @@ -125,9 +126,9 @@ def list_address_type(self, addr_type=0): if index == len(submenu.menu) - 2: stay_on_this_addr_menu = False # Prev - if index == 0 and num_checked > LIST_ADDRESS_QTD: + if index == 0 and num_checked > max_addresses: stay_on_this_addr_menu = False - num_checked -= 2 * LIST_ADDRESS_QTD + num_checked -= 2 * max_addresses return MENU_CONTINUE diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 5ca20e3a4..c72e7e501 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -87,6 +87,7 @@ def create_ctx(mocker, btn_seq, wallet=None, printer=None, touch_seq=None): ctx = mock_context(mocker) ctx.power_manager.battery_charge_remaining.return_value = 1 ctx.input.wait_for_button = mocker.MagicMock(side_effect=btn_seq) + ctx.display.max_lines = mocker.MagicMock(return_value=7) ctx.wallet = wallet ctx.printer = printer @@ -611,6 +612,7 @@ def test_public_key(mocker, m5stickv, tdata): "ZPUB", ), ] + # TODO: Fix here to match the changes on XPUB screen home.display_qr_codes.assert_has_calls(display_qr_calls) if case[1] is not None: home.utils.print_standard_qr.assert_has_calls(print_qr_calls) diff --git a/tests/shared_mocks.py b/tests/shared_mocks.py index 4de80b3c3..6e3055b47 100644 --- a/tests/shared_mocks.py +++ b/tests/shared_mocks.py @@ -347,6 +347,7 @@ def mock_context(mocker): width=mocker.MagicMock(return_value=135), height=mocker.MagicMock(return_value=240), to_lines=mocker.MagicMock(return_value=[""]), + max_lines=mocker.MagicMock(return_value=7), ), ) elif board.config["type"] == "dock": @@ -364,6 +365,7 @@ def mock_context(mocker): width=mocker.MagicMock(return_value=240), height=mocker.MagicMock(return_value=320), to_lines=mocker.MagicMock(return_value=[""]), + max_lines=mocker.MagicMock(return_value=9), ), ) elif board.config["type"].startswith("amigo"): @@ -374,5 +376,6 @@ def mock_context(mocker): width=mocker.MagicMock(return_value=320), height=mocker.MagicMock(return_value=480), to_lines=mocker.MagicMock(return_value=[""]), + max_lines=mocker.MagicMock(return_value=9), ), ) From 315f2e0e5b7e305f4b860f0c9fce9378494f3c16 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Sun, 5 Nov 2023 20:05:41 -0300 Subject: [PATCH 092/114] test_mnemonic_compact_qr print options --- tests/pages/test_home.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index c72e7e501..99c939346 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -278,7 +278,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): from krux.qr import FORMAT_NONE cases = [ - # 0 - No print prompt + # 0 - 12W ( Wallet(tdata.SINGLESIG_12_WORD_KEY), None, @@ -294,7 +294,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # click on back to return to home init screen ], ), - # 1 + # 1 - 24W ( Wallet(tdata.SINGLESIG_24_WORD_KEY), None, @@ -310,7 +310,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # click on back to return to home init screen ], ), - # 2 - Print + # 2 - 12W Print ( Wallet(tdata.SINGLESIG_12_WORD_KEY), MockPrinter(), @@ -319,6 +319,10 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave + BUTTON_PAGE, # change to Print + BUTTON_ENTER, # Print + BUTTON_ENTER, # Print confirm + BUTTON_ENTER, # Leave BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -326,7 +330,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # click on back to return to home init screen ], ), - # 3 + # 3 - 24W Print ( Wallet(tdata.SINGLESIG_24_WORD_KEY), MockPrinter(), @@ -335,6 +339,10 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave + BUTTON_PAGE, # change to Print + BUTTON_ENTER, # Print + BUTTON_ENTER, # Print confirm + BUTTON_ENTER, # Leave BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -342,7 +350,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # click on back to return to home init screen ], ), - # 4 - Decline to print + # 4 - 12W Print, Decline to print ( Wallet(tdata.SINGLESIG_12_WORD_KEY), MockPrinter(), @@ -351,6 +359,10 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave + BUTTON_PAGE, # change to Print + BUTTON_ENTER, # Print + BUTTON_PAGE, # Print decline + BUTTON_ENTER, # Leave BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -358,7 +370,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # click on back to return to home init screen ], ), - # 5 + # 5 - 24W Print, Decline to print ( Wallet(tdata.SINGLESIG_24_WORD_KEY), MockPrinter(), @@ -367,6 +379,10 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave + BUTTON_PAGE, # change to Print + BUTTON_ENTER, # Print + BUTTON_PAGE, # Print decline + BUTTON_ENTER, # Leave BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, From e627c8a7ab445eef9414093adce104312fba57ca Mon Sep 17 00:00:00 2001 From: odudex Date: Mon, 6 Nov 2023 11:40:13 -0300 Subject: [PATCH 093/114] allow custom file name for exported QR code images --- src/krux/pages/files_operations.py | 4 +-- src/krux/pages/qr_view.py | 42 ++++++++++++++++++++---------- src/krux/sd_card.py | 2 ++ 3 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/krux/pages/files_operations.py b/src/krux/pages/files_operations.py index 5c4968eb6..050a2d3aa 100644 --- a/src/krux/pages/files_operations.py +++ b/src/krux/pages/files_operations.py @@ -59,7 +59,7 @@ def save_file( file_description + "\n" + t("Save to SD card?") + "\n\n", self.ctx.display.height() // 2, ): - filename, filename_undefined = self._set_filename( + filename, filename_undefined = self.set_filename( filename, empty_name, file_suffix, @@ -78,7 +78,7 @@ def save_file( except: self.flash_text(t("SD card not detected.")) - def _set_filename( + def set_filename( self, curr_filename="", empty_filename="some_file", suffix="", file_extension="" ): """Helper to set the filename based on a suggestion and the user input""" diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index 0f012dda8..209ceeb16 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -279,8 +279,10 @@ def draw_grided_qr(self, mode): theme.highlight_color, ) - def save_pbm_image(self): + def save_pbm_image(self, file_name): """Saves QR code image as compact B&W bitmap format file""" + from ..sd_card import PBM_IMAGE_EXTENSION + size, code = add_qr_frame(self.code) qr_image_file = ( "P4\n# Krux\n".encode() @@ -295,13 +297,15 @@ def save_pbm_image(self): bit_string_line += "0" * (8 - size % 8) line = int(bit_string_line, 2).to_bytes((self.qr_size + 7) // 8, "big") qr_image_file += line - filename = "QR_Code.pbm" + file_name += PBM_IMAGE_EXTENSION with SDHandler() as sd: - sd.write_binary(filename, qr_image_file) - self.flash_text(t("Saved to SD card:\n%s") % filename) + sd.write_binary(file_name, qr_image_file) + self.flash_text(t("Saved to SD card:\n%s") % file_name) - def save_bmp_image(self, resolution): + def save_bmp_image(self, file_name, resolution): """Save QR code image as .bmp file""" + from ..sd_card import BMP_IMAGE_EXTENSION + # TODO: Try Compression? import image import lcd @@ -332,31 +336,41 @@ def save_bmp_image(self, resolution): x_scale=scale, y_scale=scale, ) - filename = "QR_Code.bmp" - bmp_img.save("/sd/" + filename) - self.flash_text(t("Saved to SD card:\n%s") % filename) + file_name += BMP_IMAGE_EXTENSION + bmp_img.save("/sd/" + file_name) + self.flash_text(t("Saved to SD card:\n%s") % file_name) def save_qr_image_menu(self): """Options to save QR codes as images on SD card""" # TODO: Allow custom file name + from .files_operations import SaveFile + + file_saver = SaveFile(self.ctx) + file_name, filename_undefined = file_saver.set_filename( + self.title.replace(" ", "_"), + ) + if filename_undefined: + return size = self.qr_size + 2 - resolutions = [] + bmp_resolutions = [] resolution = size for _ in range(4): resolution *= 2 if resolution <= 480: - resolutions.append(resolution) + bmp_resolutions.append(resolution) self.ctx.display.clear() self.ctx.display.draw_hcentered_text( t("Resolution - Format"), self.ctx.display.font_height, info_box=True ) qr_menu = [] - qr_menu.append(("%dx%d - PBM" % (size, size), self.save_pbm_image)) - for resolution in resolutions: + qr_menu.append( + ("%dx%d - PBM" % (size, size), lambda: self.save_pbm_image(file_name)) + ) + for bmp_resolution in bmp_resolutions: qr_menu.append( ( - "%dx%d - BMP" % (resolution, resolution), - lambda res=resolution: self.save_bmp_image(res), + "%dx%d - BMP" % (bmp_resolution, bmp_resolution), + lambda res=bmp_resolution: self.save_bmp_image(file_name, res), ) ) submenu = Menu(self.ctx, qr_menu, offset=2 * self.ctx.display.font_height) diff --git a/src/krux/sd_card.py b/src/krux/sd_card.py index 46549e031..5cbb33d62 100644 --- a/src/krux/sd_card.py +++ b/src/krux/sd_card.py @@ -29,6 +29,8 @@ JSON_FILE_EXTENSION = ".json" SIGNATURE_FILE_EXTENSION = ".sig" PUBKEY_FILE_EXTENSION = ".pub" +BMP_IMAGE_EXTENSION = ".bmp" +PBM_IMAGE_EXTENSION = ".pbm" class SDHandler: From e0f0c9fa1f78784be4b271e9e2e761abac405dce Mon Sep 17 00:00:00 2001 From: odudex Date: Mon, 6 Nov 2023 12:52:42 -0300 Subject: [PATCH 094/114] line break fix - a more generalist method --- src/krux/display.py | 31 +++++++++++++------------------ src/krux/pages/__init__.py | 3 ++- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/krux/display.py b/src/krux/display.py index 9f7be161d..ea6946099 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -194,26 +194,21 @@ def to_lines(self, text): words.append(subword) if len(subwords) > 1 and i < len(subwords) - 1: - # Only add newline to the end of the word if the word - # is less than the amount of columns. If it's exactly equal, - # a newline will be implicit. - if len(words[-1]) < columns: - add_new_line = True - # check for exact match with 2 words + # Only add newline to the end of the last word of the slug if its length + # is less than the amount of columns. + # If it's exactly equal, a newline will be implicit. + slug_len = len(words[-1]) + for x_index in range(1, len(words)): + # Length of maximum words that fit the line if ( - len(words) > 1 - and len(words[-1]) + len(words[-2]) + 1 == columns + slug_len + len(words[-x_index - 1]) + 1 <= columns + and "\n" not in words[-x_index - 1] ): - add_new_line = False - # check for exact match with 3 words - if ( - len(words) > 2 - and len(words[-1]) + len(words[-2]) + len(words[-3]) + 2 - == columns - ): - add_new_line = False - if add_new_line: - words[-1] += "\n" + slug_len += len(words[-x_index - 1]) + 1 + else: + break + if slug_len < columns: + words[-1] += "\n" num_words = len(words) diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index c2cbfbc0e..f2db6d5d2 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -468,7 +468,8 @@ def prompt(self, text, offset_y=0): return answer def fit_to_line(self, text, prefix="", fixed_chars=0): - """Fits text with prefix plus fixed_chars at the beginning into one line, removing the central content and leaving the ends""" + """Fits text with prefix plus fixed_chars at the beginning into one line, + removing the central content and leaving the ends""" add_chars_amount = ( self.ctx.display.usable_width() // self.ctx.display.font_width From 9e7d421bb1b7b917ebb6cbe0e9c268343c9c249b Mon Sep 17 00:00:00 2001 From: tadeubas Date: Mon, 6 Nov 2023 13:06:58 -0300 Subject: [PATCH 095/114] more test_to_lines_exact_match_amigo --- tests/test_display.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/test_display.py b/tests/test_display.py index cc6e937f2..9bbf579e1 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -327,6 +327,16 @@ def test_to_lines_exact_match_amigo(mocker, amigo_tft): "01 34 0123456789012345678\n01234 0123456789012345678", ["01 34 0123456789012345678", "01234 0123456789012345678"], ), + ( + 320, + "01 01 01 01 01 01 01 01 0\n01 01 01 01 01 01 01 0123", + ["01 01 01 01 01 01 01 01 0", "01 01 01 01 01 01 01 0123"], + ), + ( + 320, + "0 0 0 0 0 0 0 0 0 0 0 0 0\n01 01 01 01 01 01 01 0123", + ["0 0 0 0 0 0 0 0 0 0 0 0 0", "01 01 01 01 01 01 01 0123"], + ), ( 320, "01 345 0123456789012345678\n01234 0123456789012345678", From 290c1cb7e2c9298ac3dbfdda662d057d8d51d8aa Mon Sep 17 00:00:00 2001 From: tadeubas Date: Mon, 6 Nov 2023 15:54:14 -0300 Subject: [PATCH 096/114] Adding info on docs regarding dice rolls --- docs/getting-started/usage/generating-a-mnemonic.en.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/usage/generating-a-mnemonic.en.md b/docs/getting-started/usage/generating-a-mnemonic.en.md index 533338ed1..1d5cdbd16 100644 --- a/docs/getting-started/usage/generating-a-mnemonic.en.md +++ b/docs/getting-started/usage/generating-a-mnemonic.en.md @@ -53,8 +53,13 @@ Note: For 12-word mnemonics, only the first half of the SHA256 hash is used (128

+### How to verify + +Don't trust, verify. We encourage you not to trust any claim you cannot verify yourself. Therefore, there are wallets that use compatible algorithms to calculate the entropy derived from dice rolls. You can use the [SeedSigner](https://seedsigner.com/) or Coldcard hardware wallets, or even the [Bitcoiner Guide website](https://bitcoiner.guide/seed/), they share the same logic that Krux uses and will give the same mnemonic. + ## Alternatives -See [here](https://vault12.com/securemycrypto/cryptocurrency-security-how-to/seed-phrase-creation/) for good methods to generate a mnemonic manually, or visit [Ian Coleman's BIP-39 Tool](https://iancoleman.io/bip39/) offline or on an airgapped device to generate one automatically. -It's worth noting that Ian's tool is able to take a mnemonic and generate a QR code that Krux can read in via the QR input method mentioned on the next page. +You can use any other offline airgapped devices to generate your mnemonic. If you want to use a regular PC, a common strategy is to boot the PC using [Tails](https://tails.boum.org/) from a USB stick, without connecting the device to the internet, and then use a copy of the the [Bitcoiner Guide website](https://bitcoiner.guide/seed/) or even [Ian Coleman's BIP-39 Tool](https://iancoleman.io/bip39/). It's worth noting that both generate a QR code that Krux can read via the QR input method mentioned on the next page (Loading a Mnemonic). + +See [here](https://vault12.com/securemycrypto/cryptocurrency-security-how-to/seed-phrase-creation/) for other good methods to generate a mnemonic manually. From 9873f1838201da228765533b9a701438efa2b50d Mon Sep 17 00:00:00 2001 From: Odudex Date: Mon, 6 Nov 2023 17:03:31 -0300 Subject: [PATCH 097/114] small fixes and standardization --- src/krux/krux_settings.py | 3 --- src/krux/pages/addresses.py | 2 +- src/krux/pages/home.py | 2 +- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/krux/krux_settings.py b/src/krux/krux_settings.py index 44b0ae363..f2046eb98 100644 --- a/src/krux/krux_settings.py +++ b/src/krux/krux_settings.py @@ -344,9 +344,6 @@ class ThemeSettings(SettingsNamespace): DARK_THEME = 0 LIGHT_THEME = 1 ORANGE_THEME = 3 - DARK_THEME_NAME = "Dark" - LIGHT_THEME_NAME = "Light" - ORANGE_THEME_NAME = "Orange" GREEN_THEME = 4 PINK_THEME = 5 DARK_THEME_NAME = "Dark" diff --git a/src/krux/pages/addresses.py b/src/krux/pages/addresses.py index 0e60b8e93..3ef6963a7 100644 --- a/src/krux/pages/addresses.py +++ b/src/krux/pages/addresses.py @@ -58,7 +58,7 @@ def addresses_menu(self): (t("Scan Address"), self.pre_scan_address), (t("Receive Addresses"), self.list_address_type), (t("Change Addresses"), lambda: self.list_address_type(1)), - (t("Back"), lambda: MENU_EXIT), + (t("Back"), lambda: None), ], ) submenu.run_loop() diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index c6251d6b1..2c169bef8 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -327,7 +327,7 @@ def addresses_menu(self): from .addresses import Addresses adresses = Addresses(self.ctx) - adresses.addresses_menu() + return adresses.addresses_menu() def sign(self): """Handler for the 'sign' menu item""" From 338164725c16cc3354e72d5e195d6c1ab78be937 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Mon, 6 Nov 2023 17:35:57 -0300 Subject: [PATCH 098/114] fix pylint --- .pylintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pylintrc b/.pylintrc index 7b012eb3f..1b79ac93b 100644 --- a/.pylintrc +++ b/.pylintrc @@ -531,7 +531,7 @@ max-attributes=11 max-bool-expr=5 # Maximum number of branch for function / method body. -max-branches=22 +max-branches=23 # Maximum number of locals for function / method body. max-locals=25 From 04c0b7cbf89575262516230ad2ebc2af1a84d813 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Mon, 6 Nov 2023 17:37:23 -0300 Subject: [PATCH 099/114] added display_mnemonic_numbers to home --- src/krux/pages/__init__.py | 10 +++--- src/krux/pages/home.py | 54 +++++++++++++++++++++++++++++--- src/krux/pages/login.py | 36 ++++++++++----------- src/krux/pages/print_page.py | 6 ++-- src/krux/pages/utils.py | 27 ++++++++++++++++ tests/pages/test_home.py | 59 +++++++++++++++++++++++++++-------- tests/pages/test_stackbit.py | 2 ++ tests/pages/test_tiny_seed.py | 1 + 8 files changed, 149 insertions(+), 46 deletions(-) diff --git a/src/krux/pages/__init__.py b/src/krux/pages/__init__.py index f2db6d5d2..e6aec6875 100644 --- a/src/krux/pages/__init__.py +++ b/src/krux/pages/__init__.py @@ -331,18 +331,18 @@ def display_qr_codes(self, data, qr_format, title=""): done = True # interval done in input.py using timers - def display_mnemonic(self, mnemonic): + def display_mnemonic(self, mnemonic, suffix=""): """Displays the 12 or 24-word list of words to the user""" words = mnemonic.split(" ") word_list = [ str(i + 1) + "." + (" " if i + 1 < 10 else " ") + word for i, word in enumerate(words) ] + header = t("BIP39") + " " + suffix self.ctx.display.clear() - self.ctx.display.draw_hcentered_text(t("BIP39 Mnemonic")) + self.ctx.display.draw_hcentered_text(header) starting_y_offset = DEFAULT_PADDING // 4 + ( - len(self.ctx.display.to_lines(t("BIP39 Mnemonic"))) - * self.ctx.display.font_height + len(self.ctx.display.to_lines(header)) * self.ctx.display.font_height + self.ctx.display.font_height ) for i, word in enumerate(word_list[:12]): @@ -353,7 +353,7 @@ def display_mnemonic(self, mnemonic): if board.config["type"] == "m5stickv": self.ctx.input.wait_for_button() self.ctx.display.clear() - self.ctx.display.draw_hcentered_text(t("BIP39 Mnemonic")) + self.ctx.display.draw_hcentered_text(header) for i, word in enumerate(word_list[12:]): offset_x = DEFAULT_PADDING offset_y = starting_y_offset + (i * self.ctx.display.font_height) diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index c6251d6b1..de0137253 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -71,7 +71,13 @@ def mnemonic(self): submenu = Menu( self.ctx, [ - (t("Words"), self.display_mnemonic_words), + ( + t("Words"), + lambda: self.show_mnemonic( + self.ctx.wallet.key.mnemonic, t("Mnemonic") + ), + ), + (t("Numbers"), self.display_mnemonic_numbers), (t("Plaintext QR"), self.display_standard_qr), (t("Compact SeedQR"), lambda: self.display_seed_qr(True)), (t("SeedQR"), self.display_seed_qr), @@ -83,9 +89,9 @@ def mnemonic(self): submenu.run_loop() return MENU_CONTINUE - def display_mnemonic_words(self): - """Displays only the mnemonic words""" - self.display_mnemonic(self.ctx.wallet.key.mnemonic) + def show_mnemonic(self, mnemonic, suffix=""): + """Displays only the mnemonic words or indices""" + self.display_mnemonic(mnemonic, suffix) self.ctx.input.wait_for_button() # Avoid printing text on a cnc @@ -98,7 +104,45 @@ def display_mnemonic_words(self): from .print_page import PrintPage print_page = PrintPage(self.ctx) - print_page.print_mnemonic_text() + print_page.print_mnemonic_text(mnemonic, suffix) + return MENU_CONTINUE + + def display_mnemonic_numbers(self): + """Handler for the 'numbers' menu item""" + submenu = Menu( + self.ctx, + [ + ( + t("Decimal"), + lambda: self.show_mnemonic( + Utils.get_mnemonic_numbers( + self.ctx.wallet.key.mnemonic, Utils.BASE_DEC + ), + Utils.BASE_DEC_SUFFIX, + ), + ), + ( + t("Hexadecimal"), + lambda: self.show_mnemonic( + Utils.get_mnemonic_numbers( + self.ctx.wallet.key.mnemonic, Utils.BASE_HEX + ), + Utils.BASE_HEX_SUFFIX, + ), + ), + ( + t("Octal"), + lambda: self.show_mnemonic( + Utils.get_mnemonic_numbers( + self.ctx.wallet.key.mnemonic, Utils.BASE_OCT + ), + Utils.BASE_OCT_SUFFIX, + ), + ), + (t("Back"), lambda: MENU_EXIT), + ], + ) + submenu.run_loop() return MENU_CONTINUE def display_standard_qr(self): diff --git a/src/krux/pages/login.py b/src/krux/pages/login.py index 208b75eda..b03383260 100644 --- a/src/krux/pages/login.py +++ b/src/krux/pages/login.py @@ -24,6 +24,7 @@ from embit.networks import NETWORKS from embit.wordlists.bip39 import WORDLIST from embit import bip39 +from .utils import Utils from ..themes import theme from ..krux_settings import Settings from ..qr import FORMAT_UR @@ -303,32 +304,27 @@ def _load_qr_passphrase(self): return MENU_CONTINUE return data - def _get_words_numbers(self, words, charset): - word_numbers = [] - for word in words: - word_numbers.append(WORDLIST.index(word) + 1) - - if charset == DIGITS_HEX: - for i, number in enumerate(word_numbers): - word_numbers[i] = hex(number)[2:].upper() - - if charset == DIGITS_OCT: - for i, number in enumerate(word_numbers): - word_numbers[i] = oct(number)[2:] - - numbers_str = [str(value) for value in word_numbers] - return " ".join(numbers_str) - def _load_key_from_words(self, words, charset=LETTERS): + mnemonic = " ".join(words) + if charset != LETTERS: - numbers_str = self._get_words_numbers(words, charset) - self.display_mnemonic(numbers_str) + charset_type = { + DIGITS: Utils.BASE_DEC, + DIGITS_HEX: Utils.BASE_HEX, + DIGITS_OCT: Utils.BASE_OCT, + } + suffix_dict = { + DIGITS: Utils.BASE_DEC_SUFFIX, + DIGITS_HEX: Utils.BASE_HEX_SUFFIX, + DIGITS_OCT: Utils.BASE_OCT_SUFFIX, + } + numbers_str = Utils.get_mnemonic_numbers(mnemonic, charset_type[charset]) + self.display_mnemonic(numbers_str, suffix_dict[charset]) if not self.prompt(t("Continue?"), self.ctx.display.bottom_prompt_line): return MENU_CONTINUE self.ctx.display.clear() - mnemonic = " ".join(words) - self.display_mnemonic(mnemonic) + self.display_mnemonic(mnemonic, t("Mnemonic")) if not self.prompt(t("Continue?"), self.ctx.display.bottom_prompt_line): return MENU_CONTINUE self.ctx.display.clear() diff --git a/src/krux/pages/print_page.py b/src/krux/pages/print_page.py index eb4f825e8..17f939501 100644 --- a/src/krux/pages/print_page.py +++ b/src/krux/pages/print_page.py @@ -66,14 +66,14 @@ def print_qr(self, data, qr_format=FORMAT_NONE, title="", width=33, is_qr=False) self._send_qr_to_printer(qr_code, i, count) i += 1 - def print_mnemonic_text(self): + def print_mnemonic_text(self, mnemonic, suffix=""): """Prints Mnemonics words as text""" self.ctx.display.clear() self.ctx.display.draw_hcentered_text( t("Printing ..."), self.ctx.display.height() // 2 ) - self.printer.print_string(t("Mnemonic") + "\n\n") - words = self.ctx.wallet.key.mnemonic.split(" ") + self.printer.print_string(t("BIP39") + " " + suffix + "\n\n") + words = mnemonic.split(" ") lines = len(words) // 3 for i in range(lines): index = i + 1 diff --git a/src/krux/pages/utils.py b/src/krux/pages/utils.py index 92d4c3bd7..f620678a8 100644 --- a/src/krux/pages/utils.py +++ b/src/krux/pages/utils.py @@ -23,11 +23,20 @@ from . import Page from ..krux_settings import t from ..sd_card import SDHandler +from embit.wordlists.bip39 import WORDLIST class Utils(Page): """Methods as subpages, shared by other pages""" + BASE_DEC = 10 + BASE_HEX = 16 + BASE_OCT = 8 + + BASE_DEC_SUFFIX = "DEC" + BASE_HEX_SUFFIX = "HEX" + BASE_OCT_SUFFIX = "OCT" + def __init__(self, ctx): super().__init__(ctx, None) @@ -59,3 +68,21 @@ def load_file(self, file_ext=""): if self.prompt(t("Load?"), self.ctx.display.bottom_prompt_line): return filename, sd.read_binary(filename) return "", None + + @staticmethod + def get_mnemonic_numbers(words, base=BASE_DEC): + """Returns the mnemonic as indices in decimal, hexadecimal, or octal""" + word_numbers = [] + for word in words.split(" "): + word_numbers.append(WORDLIST.index(word) + 1) + + if base == Utils.BASE_HEX: + for i, number in enumerate(word_numbers): + word_numbers[i] = hex(number)[2:].upper() + + if base == Utils.BASE_OCT: + for i, number in enumerate(word_numbers): + word_numbers[i] = oct(number)[2:] + + numbers_str = [str(value) for value in word_numbers] + return " ".join(numbers_str) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 99c939346..c9c89a7b1 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -158,7 +158,7 @@ def test_mnemonic_words(mocker, m5stickv, tdata): mocker.spy(home, "display_mnemonic") home.mnemonic() - home.display_mnemonic.assert_called_with(ctx.wallet.key.mnemonic) + home.display_mnemonic.assert_called_with(ctx.wallet.key.mnemonic, "Mnemonic") assert ctx.input.wait_for_button.call_count == len(case[2]) @@ -175,10 +175,12 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): None, # printer [ BUTTON_PAGE, - BUTTON_ENTER, + BUTTON_PAGE, # select Plaintext QR + BUTTON_ENTER, # click BUTTON_ENTER, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -187,10 +189,12 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): None, # printer [ BUTTON_PAGE, - BUTTON_ENTER, + BUTTON_PAGE, # select Plaintext QR + BUTTON_ENTER, # click BUTTON_ENTER, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -200,11 +204,13 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): MockPrinter(), [ BUTTON_PAGE, - BUTTON_ENTER, + BUTTON_PAGE, # select Plaintext QR + BUTTON_ENTER, # click BUTTON_ENTER, BUTTON_ENTER, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -213,11 +219,13 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): MockPrinter(), [ BUTTON_PAGE, - BUTTON_ENTER, + BUTTON_PAGE, # select Plaintext QR + BUTTON_ENTER, # click BUTTON_ENTER, BUTTON_ENTER, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -227,11 +235,13 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): MockPrinter(), [ BUTTON_PAGE, - BUTTON_ENTER, + BUTTON_PAGE, # select Plaintext QR + BUTTON_ENTER, # click BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -240,11 +250,13 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): MockPrinter(), [ BUTTON_PAGE, - BUTTON_ENTER, + BUTTON_PAGE, # select Plaintext QR + BUTTON_ENTER, # click BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -285,12 +297,14 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): [ BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, # select Compact SeedQR BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -301,12 +315,14 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): [ BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, # select Compact SeedQR BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -317,6 +333,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): [ BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, # select Compact SeedQR BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave BUTTON_PAGE, # change to Print @@ -327,6 +344,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -337,6 +355,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): [ BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, # select Compact SeedQR BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave BUTTON_PAGE, # change to Print @@ -347,6 +366,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -357,6 +377,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): [ BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, # select Compact SeedQR BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave BUTTON_PAGE, # change to Print @@ -367,6 +388,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -377,6 +399,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): [ BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, # select Compact SeedQR BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave BUTTON_PAGE, # change to Print @@ -387,6 +410,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], ), @@ -412,6 +436,8 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): from krux.input import BUTTON_TOUCH, BUTTON_PAGE_PREV, BUTTON_ENTER from krux.qr import FORMAT_NONE + position = [2, 0] + cases = [ # No print prompt ( @@ -422,9 +448,10 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): BUTTON_TOUCH, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], - [1, 0], + position, ), ( Wallet(tdata.SINGLESIG_24_WORD_KEY), @@ -434,9 +461,10 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): BUTTON_TOUCH, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], - [1, 0], + position, ), # Print ( @@ -448,9 +476,10 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): BUTTON_TOUCH, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], - [1, 0, 0], + position + [0], ), ( Wallet(tdata.SINGLESIG_24_WORD_KEY), @@ -461,9 +490,10 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): BUTTON_TOUCH, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], - [1, 0, 0], + position + [0], ), # Decline to print ( @@ -475,9 +505,10 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): BUTTON_TOUCH, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], - [1, 0, 1], + position + [1], ), ( Wallet(tdata.SINGLESIG_24_WORD_KEY), @@ -488,9 +519,10 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): BUTTON_TOUCH, BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, + BUTTON_PAGE_PREV, BUTTON_ENTER, # click on back to return to home init screen ], - [1, 0, 1], + position + [1], ), ] num = 0 @@ -628,6 +660,7 @@ def test_public_key(mocker, m5stickv, tdata): "ZPUB", ), ] + # TODO: Fix here to match the changes on XPUB screen home.display_qr_codes.assert_has_calls(display_qr_calls) if case[1] is not None: diff --git a/tests/pages/test_stackbit.py b/tests/pages/test_stackbit.py index 03c51bd34..7cc191253 100644 --- a/tests/pages/test_stackbit.py +++ b/tests/pages/test_stackbit.py @@ -14,6 +14,7 @@ def test_export_mnemonic_stackbit(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, # Open Stackbit BUTTON_ENTER, # PG2 BUTTON_ENTER, # PG3 @@ -45,6 +46,7 @@ def test_export_mnemonic_stackbit_amigo(mocker, amigo_tft, tdata): BUTTON_PAGE, BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, # Open Stackbit BUTTON_ENTER, # PG2 BUTTON_ENTER, # PG3 diff --git a/tests/pages/test_tiny_seed.py b/tests/pages/test_tiny_seed.py index 3a72b01e1..1b229e400 100644 --- a/tests/pages/test_tiny_seed.py +++ b/tests/pages/test_tiny_seed.py @@ -18,6 +18,7 @@ def test_export_mnemonic_tiny_seed_menu(mocker, m5stickv, tdata): BUTTON_PAGE, BUTTON_PAGE, BUTTON_PAGE, + BUTTON_PAGE, BUTTON_ENTER, # Open TinySeed BUTTON_ENTER, # go to page 2 BUTTON_ENTER, # Leave From f6763f8039d76fdba5d54a0ec6efc79eed01c698 Mon Sep 17 00:00:00 2001 From: odudex Date: Tue, 7 Nov 2023 15:48:37 -0300 Subject: [PATCH 100/114] dedicated files for mnemonic and pubkey viewers --- src/krux/pages/home.py | 213 ++------------------------------ src/krux/pages/mnemonic_view.py | 176 ++++++++++++++++++++++++++ src/krux/pages/pub_key_view.py | 118 ++++++++++++++++++ tests/pages/test_home.py | 62 +++++----- tests/pages/test_stackbit.py | 20 +-- tests/pages/test_tiny_seed.py | 10 +- tests/test_input.py | 6 + 7 files changed, 353 insertions(+), 252 deletions(-) create mode 100644 src/krux/pages/mnemonic_view.py create mode 100644 src/krux/pages/pub_key_view.py diff --git a/src/krux/pages/home.py b/src/krux/pages/home.py index 6cc6b710d..78f844041 100644 --- a/src/krux/pages/home.py +++ b/src/krux/pages/home.py @@ -26,7 +26,7 @@ from ..display import DEFAULT_PADDING from ..psbt import PSBTSigner from ..qr import FORMAT_NONE, FORMAT_PMOFN -from ..krux_settings import t, Settings, THERMAL_ADAFRUIT_TXT +from ..krux_settings import t from . import ( Page, Menu, @@ -34,16 +34,12 @@ MENU_EXIT, ) from ..sd_card import ( - PUBKEY_FILE_EXTENSION, PSBT_FILE_EXTENSION, SIGNED_FILE_SUFFIX, DESCRIPTOR_FILE_EXTENSION, JSON_FILE_EXTENSION, ) -# to start xpub value without the xpub/zpub/ypub prefix -WALLET_XPUB_START = 4 - class Home(Page): """Home is the main menu page of the app""" @@ -68,139 +64,10 @@ def __init__(self, ctx): def mnemonic(self): """Handler for the 'mnemonic' menu item""" - submenu = Menu( - self.ctx, - [ - ( - t("Words"), - lambda: self.show_mnemonic( - self.ctx.wallet.key.mnemonic, t("Mnemonic") - ), - ), - (t("Numbers"), self.display_mnemonic_numbers), - (t("Plaintext QR"), self.display_standard_qr), - (t("Compact SeedQR"), lambda: self.display_seed_qr(True)), - (t("SeedQR"), self.display_seed_qr), - (t("Stackbit 1248"), self.stackbit), - (t("Tiny Seed"), self.tiny_seed), - (t("Back"), lambda: MENU_EXIT), - ], - ) - submenu.run_loop() - return MENU_CONTINUE - - def show_mnemonic(self, mnemonic, suffix=""): - """Displays only the mnemonic words or indices""" - self.display_mnemonic(mnemonic, suffix) - self.ctx.input.wait_for_button() - - # Avoid printing text on a cnc - if Settings().hardware.printer.driver == THERMAL_ADAFRUIT_TXT: - self.ctx.display.clear() - if self.prompt( - t("Print?\n\n%s\n\n") % Settings().hardware.printer.driver, - self.ctx.display.height() // 2, - ): - from .print_page import PrintPage - - print_page = PrintPage(self.ctx) - print_page.print_mnemonic_text(mnemonic, suffix) - return MENU_CONTINUE - - def display_mnemonic_numbers(self): - """Handler for the 'numbers' menu item""" - submenu = Menu( - self.ctx, - [ - ( - t("Decimal"), - lambda: self.show_mnemonic( - Utils.get_mnemonic_numbers( - self.ctx.wallet.key.mnemonic, Utils.BASE_DEC - ), - Utils.BASE_DEC_SUFFIX, - ), - ), - ( - t("Hexadecimal"), - lambda: self.show_mnemonic( - Utils.get_mnemonic_numbers( - self.ctx.wallet.key.mnemonic, Utils.BASE_HEX - ), - Utils.BASE_HEX_SUFFIX, - ), - ), - ( - t("Octal"), - lambda: self.show_mnemonic( - Utils.get_mnemonic_numbers( - self.ctx.wallet.key.mnemonic, Utils.BASE_OCT - ), - Utils.BASE_OCT_SUFFIX, - ), - ), - (t("Back"), lambda: MENU_EXIT), - ], - ) - submenu.run_loop() - return MENU_CONTINUE - - def display_standard_qr(self): - """Displays regular words QR code""" - title = t("Plaintext QR") - data = self.ctx.wallet.key.mnemonic - self.display_qr_codes(data, FORMAT_NONE, title) - self.utils.print_standard_qr(data, FORMAT_NONE, title) - return MENU_CONTINUE - - def display_seed_qr(self, binary=False): - """Display Seed QR with with different view modes""" - - from .qr_view import SeedQRView + from .mnemonic_view import MnemonicsView - seed_qr_view = SeedQRView(self.ctx, binary) - return seed_qr_view.display_qr() - - def stackbit(self): - """Displays which numbers 1248 user should punch on 1248 steel card""" - from .stack_1248 import Stackbit - - stackbit = Stackbit(self.ctx) - word_index = 1 - words = self.ctx.wallet.key.mnemonic.split(" ") - - while word_index < len(words): - y_offset = 2 * self.ctx.display.font_height - for _ in range(6): - stackbit.export_1248(word_index, y_offset, words[word_index - 1]) - if self.ctx.display.height() > 240: - y_offset += 3 * self.ctx.display.font_height - else: - y_offset += 5 + 2 * self.ctx.display.font_height - word_index += 1 - self.ctx.input.wait_for_button() - - # removed the hability to go back in favor or the Krux UI patter (always move forward) - # if self.ctx.input.wait_for_button() == BUTTON_PAGE_PREV: - # if word_index > 12: - # word_index -= 12 - # else: - # word_index = 1 - self.ctx.display.clear() - return MENU_CONTINUE - - def tiny_seed(self): - """Displays the seed in Tiny Seed format""" - from .tiny_seed import TinySeed - - tiny_seed = TinySeed(self.ctx) - tiny_seed.export() - - # Allow to print on thermal printer only - if Settings().hardware.printer.driver == THERMAL_ADAFRUIT_TXT: - if self.print_qr_prompt(): - tiny_seed.print_tiny_seed() - return MENU_CONTINUE + mnemonics_viewer = MnemonicsView(self.ctx) + return mnemonics_viewer.mnemonic() def encrypt_mnemonic(self): """Handler for Mnemonic > Encrypt Mnemonic menu item""" @@ -211,76 +78,10 @@ def encrypt_mnemonic(self): def public_key(self): """Handler for the 'xpub' menu item""" + from .pub_key_view import PubkeyView - def _save_xpub_to_sd(version): - from .files_operations import SaveFile - - save_page = SaveFile(self.ctx) - xpub = self.ctx.wallet.key.key_expression(version) - title = self.ctx.wallet.key.account_pubkey_str(version)[ - :WALLET_XPUB_START - ].upper() - save_page.save_file( - xpub, - title, - title, - title + ":", - PUBKEY_FILE_EXTENSION, - save_as_binary=False, - ) - - def _pub_key_text(version): - pub_text_menu_items = [] - if self.has_sd_card(): - pub_text_menu_items.append( - (t("Save to SD card?"), lambda ver=version: _save_xpub_to_sd(ver)) - ) - pub_text_menu_items.append((t("Back"), lambda: MENU_EXIT)) - full_pub_key = self.ctx.wallet.key.account_pubkey_str(version) - menu_offset = 5 + len(self.ctx.display.to_lines(full_pub_key)) - menu_offset *= self.ctx.display.font_height - pub_key_menu = Menu(self.ctx, pub_text_menu_items, offset=menu_offset) - self.ctx.display.clear() - self.ctx.display.draw_hcentered_text( - self.ctx.wallet.key.fingerprint_hex_str() - + "\n\n" - + self.ctx.wallet.key.derivation_str() - + "\n\n" - + full_pub_key, - offset_y=self.ctx.display.font_height, - info_box=True, - ) - pub_key_menu.run_loop() - - def _pub_key_qr(version): - # TODO: Add menu to offer print and export as image - title = self.ctx.wallet.key.account_pubkey_str(version)[ - :WALLET_XPUB_START - ].upper() - xpub = self.ctx.wallet.key.key_expression(version) - self.display_qr_codes(xpub, FORMAT_NONE, title) - self.utils.print_standard_qr(xpub, FORMAT_NONE, title) - - zpub = "Zpub" if self.ctx.wallet.key.multisig else "zpub" - pub_key_menu_items = [] - for version in [None, self.ctx.wallet.key.network[zpub]]: - title = self.ctx.wallet.key.account_pubkey_str(version)[ - :WALLET_XPUB_START - ].upper() - pub_key_menu_items.append( - (title + " - " + t("Text"), lambda ver=version: _pub_key_text(ver)) - ) - pub_key_menu_items.append( - (title + " - " + t("QR Code"), lambda ver=version: _pub_key_qr(ver)) - ) - pub_key_menu_items.append((t("Back"), lambda: MENU_EXIT)) - pub_key_menu = Menu(self.ctx, pub_key_menu_items) - while True: - _, status = pub_key_menu.run_loop() - if status == MENU_EXIT: - break - - return MENU_CONTINUE + pubkey_viewer = PubkeyView(self.ctx) + return pubkey_viewer.public_key() def wallet(self): """Handler for the 'wallet' menu item""" diff --git a/src/krux/pages/mnemonic_view.py b/src/krux/pages/mnemonic_view.py new file mode 100644 index 000000000..19387b371 --- /dev/null +++ b/src/krux/pages/mnemonic_view.py @@ -0,0 +1,176 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2023 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from .utils import Utils +from ..qr import FORMAT_NONE +from ..krux_settings import t, Settings, THERMAL_ADAFRUIT_TXT +from . import ( + Page, + Menu, + MENU_CONTINUE, + MENU_EXIT, +) + + +class MnemonicsView(Page): + """UI to show mnemonic in different formats""" + + def __init__(self, ctx): + super().__init__(ctx, None) + self.ctx = ctx + self.utils = Utils(self.ctx) + + def mnemonic(self): + """Menu with export mnemonic formats""" + submenu = Menu( + self.ctx, + [ + ( + t("Words"), + lambda: self.show_mnemonic( + self.ctx.wallet.key.mnemonic, t("Mnemonic") + ), + ), + (t("Numbers"), self.display_mnemonic_numbers), + (t("Plaintext QR"), self.display_standard_qr), + (t("Compact SeedQR"), lambda: self.display_seed_qr(True)), + (t("SeedQR"), self.display_seed_qr), + (t("Stackbit 1248"), self.stackbit), + (t("Tiny Seed"), self.tiny_seed), + (t("Back"), lambda: MENU_EXIT), + ], + ) + submenu.run_loop() + return MENU_CONTINUE + + def show_mnemonic(self, mnemonic, suffix=""): + """Displays only the mnemonic words or indices""" + self.display_mnemonic(mnemonic, suffix) + self.ctx.input.wait_for_button() + + # Avoid printing text on a cnc + if Settings().hardware.printer.driver == THERMAL_ADAFRUIT_TXT: + self.ctx.display.clear() + if self.prompt( + t("Print?\n\n%s\n\n") % Settings().hardware.printer.driver, + self.ctx.display.height() // 2, + ): + from .print_page import PrintPage + + print_page = PrintPage(self.ctx) + print_page.print_mnemonic_text(mnemonic, suffix) + return MENU_CONTINUE + + def display_mnemonic_numbers(self): + """Handler for the 'numbers' menu item""" + submenu = Menu( + self.ctx, + [ + ( + t("Decimal"), + lambda: self.show_mnemonic( + Utils.get_mnemonic_numbers( + self.ctx.wallet.key.mnemonic, Utils.BASE_DEC + ), + Utils.BASE_DEC_SUFFIX, + ), + ), + ( + t("Hexadecimal"), + lambda: self.show_mnemonic( + Utils.get_mnemonic_numbers( + self.ctx.wallet.key.mnemonic, Utils.BASE_HEX + ), + Utils.BASE_HEX_SUFFIX, + ), + ), + ( + t("Octal"), + lambda: self.show_mnemonic( + Utils.get_mnemonic_numbers( + self.ctx.wallet.key.mnemonic, Utils.BASE_OCT + ), + Utils.BASE_OCT_SUFFIX, + ), + ), + (t("Back"), lambda: MENU_EXIT), + ], + ) + submenu.run_loop() + return MENU_CONTINUE + + def display_standard_qr(self): + """Displays regular words QR code""" + title = t("Plaintext QR") + data = self.ctx.wallet.key.mnemonic + self.display_qr_codes(data, FORMAT_NONE, title) + self.utils.print_standard_qr(data, FORMAT_NONE, title) + return MENU_CONTINUE + + def display_seed_qr(self, binary=False): + """Display Seed QR with with different view modes""" + + from .qr_view import SeedQRView + + seed_qr_view = SeedQRView(self.ctx, binary) + return seed_qr_view.display_qr() + + def stackbit(self): + """Displays which numbers 1248 user should punch on 1248 steel card""" + from .stack_1248 import Stackbit + + stackbit = Stackbit(self.ctx) + word_index = 1 + words = self.ctx.wallet.key.mnemonic.split(" ") + + while word_index < len(words): + y_offset = 2 * self.ctx.display.font_height + for _ in range(6): + stackbit.export_1248(word_index, y_offset, words[word_index - 1]) + if self.ctx.display.height() > 240: + y_offset += 3 * self.ctx.display.font_height + else: + y_offset += 5 + 2 * self.ctx.display.font_height + word_index += 1 + self.ctx.input.wait_for_button() + + # removed the hability to go back in favor or the Krux UI patter (always move forward) + # if self.ctx.input.wait_for_button() == BUTTON_PAGE_PREV: + # if word_index > 12: + # word_index -= 12 + # else: + # word_index = 1 + self.ctx.display.clear() + return MENU_CONTINUE + + def tiny_seed(self): + """Displays the seed in Tiny Seed format""" + from .tiny_seed import TinySeed + + tiny_seed = TinySeed(self.ctx) + tiny_seed.export() + + # Allow to print on thermal printer only + if Settings().hardware.printer.driver == THERMAL_ADAFRUIT_TXT: + if self.print_qr_prompt(): + tiny_seed.print_tiny_seed() + return MENU_CONTINUE diff --git a/src/krux/pages/pub_key_view.py b/src/krux/pages/pub_key_view.py new file mode 100644 index 000000000..4427c06f4 --- /dev/null +++ b/src/krux/pages/pub_key_view.py @@ -0,0 +1,118 @@ +# The MIT License (MIT) + +# Copyright (c) 2021-2023 Krux contributors + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +from .utils import Utils +from ..qr import FORMAT_NONE +from ..krux_settings import t +from . import ( + Page, + Menu, + MENU_CONTINUE, + MENU_EXIT, +) + +from ..sd_card import PUBKEY_FILE_EXTENSION + +# to start xpub value without the xpub/zpub/ypub prefix +WALLET_XPUB_START = 4 + + +class PubkeyView(Page): + """UI to show and export extended public key""" + + def __init__(self, ctx): + super().__init__(ctx, None) + self.ctx = ctx + self.utils = Utils(self.ctx) + + def public_key(self): + """Handler for the 'xpub' menu item""" + + def _save_xpub_to_sd(version): + from .files_operations import SaveFile + + save_page = SaveFile(self.ctx) + xpub = self.ctx.wallet.key.key_expression(version) + title = self.ctx.wallet.key.account_pubkey_str(version)[ + :WALLET_XPUB_START + ].upper() + save_page.save_file( + xpub, + title, + title, + title + ":", + PUBKEY_FILE_EXTENSION, + save_as_binary=False, + ) + + def _pub_key_text(version): + pub_text_menu_items = [] + if self.has_sd_card(): + pub_text_menu_items.append( + (t("Save to SD card?"), lambda ver=version: _save_xpub_to_sd(ver)) + ) + pub_text_menu_items.append((t("Back"), lambda: MENU_EXIT)) + full_pub_key = self.ctx.wallet.key.account_pubkey_str(version) + menu_offset = 5 + len(self.ctx.display.to_lines(full_pub_key)) + menu_offset *= self.ctx.display.font_height + pub_key_menu = Menu(self.ctx, pub_text_menu_items, offset=menu_offset) + self.ctx.display.clear() + self.ctx.display.draw_hcentered_text( + self.ctx.wallet.key.fingerprint_hex_str() + + "\n\n" + + self.ctx.wallet.key.derivation_str() + + "\n\n" + + full_pub_key, + offset_y=self.ctx.display.font_height, + info_box=True, + ) + pub_key_menu.run_loop() + + def _pub_key_qr(version): + # TODO: Add menu to offer print and export as image + title = self.ctx.wallet.key.account_pubkey_str(version)[ + :WALLET_XPUB_START + ].upper() + xpub = self.ctx.wallet.key.key_expression(version) + self.display_qr_codes(xpub, FORMAT_NONE, title) + self.utils.print_standard_qr(xpub, FORMAT_NONE, title) + + zpub = "Zpub" if self.ctx.wallet.key.multisig else "zpub" + pub_key_menu_items = [] + for version in [None, self.ctx.wallet.key.network[zpub]]: + title = self.ctx.wallet.key.account_pubkey_str(version)[ + :WALLET_XPUB_START + ].upper() + pub_key_menu_items.append( + (title + " - " + t("Text"), lambda ver=version: _pub_key_text(ver)) + ) + pub_key_menu_items.append( + (title + " - " + t("QR Code"), lambda ver=version: _pub_key_qr(ver)) + ) + pub_key_menu_items.append((t("Back"), lambda: MENU_EXIT)) + pub_key_menu = Menu(self.ctx, pub_key_menu_items) + while True: + _, status = pub_key_menu.run_loop() + if status == MENU_EXIT: + break + + return MENU_CONTINUE diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index c9c89a7b1..652b98c86 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -105,7 +105,7 @@ def create_ctx(mocker, btn_seq, wallet=None, printer=None, touch_seq=None): def test_mnemonic_words(mocker, m5stickv, tdata): - from krux.pages.home import Home + from krux.pages.mnemonic_view import MnemonicsView from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV from krux.qr import FORMAT_NONE @@ -153,17 +153,17 @@ def test_mnemonic_words(mocker, m5stickv, tdata): print(num) num = num + 1 ctx = create_ctx(mocker, case[2], case[0], case[1]) - home = Home(ctx) + mnemonics = MnemonicsView(ctx) - mocker.spy(home, "display_mnemonic") - home.mnemonic() + mocker.spy(mnemonics, "display_mnemonic") + mnemonics.mnemonic() - home.display_mnemonic.assert_called_with(ctx.wallet.key.mnemonic, "Mnemonic") + mnemonics.display_mnemonic.assert_called_with(ctx.wallet.key.mnemonic, "Mnemonic") assert ctx.input.wait_for_button.call_count == len(case[2]) def test_mnemonic_standard_qr(mocker, m5stickv, tdata): - from krux.pages.home import Home + from krux.pages.mnemonic_view import MnemonicsView from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV from krux.qr import FORMAT_NONE @@ -266,25 +266,25 @@ def test_mnemonic_standard_qr(mocker, m5stickv, tdata): print(num) num = num + 1 ctx = create_ctx(mocker, case[2], case[0], case[1]) - home = Home(ctx) + mnemonics = MnemonicsView(ctx) - mocker.spy(home, "display_qr_codes") - mocker.spy(home.utils, "print_standard_qr") - home.mnemonic() + mocker.spy(mnemonics, "display_qr_codes") + mocker.spy(mnemonics.utils, "print_standard_qr") + mnemonics.mnemonic() title = "Plaintext QR" - home.display_qr_codes.assert_called_with( + mnemonics.display_qr_codes.assert_called_with( ctx.wallet.key.mnemonic, FORMAT_NONE, title ) if case[1] is not None: - home.utils.print_standard_qr.assert_called_with( + mnemonics.utils.print_standard_qr.assert_called_with( ctx.wallet.key.mnemonic, FORMAT_NONE, title ) assert ctx.input.wait_for_button.call_count == len(case[2]) def test_mnemonic_compact_qr(mocker, m5stickv, tdata): - from krux.pages.home import Home + from krux.pages.mnemonic_view import MnemonicsView from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV from krux.qr import FORMAT_NONE @@ -420,18 +420,18 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): print(num) num = num + 1 ctx = create_ctx(mocker, case[2], case[0], case[1]) - home = Home(ctx) + mnemonics = MnemonicsView(ctx) - mocker.spy(home, "display_seed_qr") - home.mnemonic() + mocker.spy(mnemonics, "display_seed_qr") + mnemonics.mnemonic() - home.display_seed_qr.assert_called_once() + mnemonics.display_seed_qr.assert_called_once() assert ctx.input.wait_for_button.call_count == len(case[2]) def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): - from krux.pages.home import Home + from krux.pages.mnemonic_view import MnemonicsView from krux.wallet import Wallet from krux.input import BUTTON_TOUCH, BUTTON_PAGE_PREV, BUTTON_ENTER from krux.qr import FORMAT_NONE @@ -530,19 +530,19 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): print(num) num = num + 1 ctx = create_ctx(mocker, case[2], case[0], case[1], touch_seq=case[3]) - home = Home(ctx) + mnemonics = MnemonicsView(ctx) - mocker.spy(home, "display_qr_codes") - mocker.spy(home.utils, "print_standard_qr") + mocker.spy(mnemonics, "display_qr_codes") + mocker.spy(mnemonics.utils, "print_standard_qr") - home.mnemonic() + mnemonics.mnemonic() title = "Plaintext QR" - home.display_qr_codes.assert_called_with( + mnemonics.display_qr_codes.assert_called_with( ctx.wallet.key.mnemonic, FORMAT_NONE, title ) if case[1] is not None: - home.utils.print_standard_qr.assert_called_with( + mnemonics.utils.print_standard_qr.assert_called_with( ctx.wallet.key.mnemonic, FORMAT_NONE, title ) @@ -550,7 +550,7 @@ def test_mnemonic_st_qr_touch(mocker, amigo_tft, tdata): def test_public_key(mocker, m5stickv, tdata): - from krux.pages.home import Home + from krux.pages.pub_key_view import PubkeyView from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV from krux.qr import FORMAT_NONE @@ -632,12 +632,12 @@ def test_public_key(mocker, m5stickv, tdata): print(num) num += 1 ctx = create_ctx(mocker, case[2], case[0], case[1]) - home = Home(ctx) + pub_key_viewer = PubkeyView(ctx) - mocker.spy(home, "display_qr_codes") - mocker.spy(home.utils, "print_standard_qr") + mocker.spy(pub_key_viewer, "display_qr_codes") + mocker.spy(pub_key_viewer.utils, "print_standard_qr") - home.public_key() + pub_key_viewer.public_key() version = "Zpub" if ctx.wallet.key.multisig else "zpub" display_qr_calls = [ @@ -662,9 +662,9 @@ def test_public_key(mocker, m5stickv, tdata): ] # TODO: Fix here to match the changes on XPUB screen - home.display_qr_codes.assert_has_calls(display_qr_calls) + pub_key_viewer.display_qr_codes.assert_has_calls(display_qr_calls) if case[1] is not None: - home.utils.print_standard_qr.assert_has_calls(print_qr_calls) + pub_key_viewer.utils.print_standard_qr.assert_has_calls(print_qr_calls) assert ctx.input.wait_for_button.call_count == len(case[2]) diff --git a/tests/pages/test_stackbit.py b/tests/pages/test_stackbit.py index 7cc191253..718bd0e92 100644 --- a/tests/pages/test_stackbit.py +++ b/tests/pages/test_stackbit.py @@ -2,7 +2,7 @@ def test_export_mnemonic_stackbit(mocker, m5stickv, tdata): - from krux.pages.home import Home + from krux.pages.mnemonic_view import MnemonicsView from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE @@ -26,15 +26,15 @@ def test_export_mnemonic_stackbit(mocker, m5stickv, tdata): ], ] ctx = create_ctx(mocker, case[2], case[0], case[1]) - home = Home(ctx) - mocker.spy(home, "stackbit") - home.mnemonic() - home.stackbit.assert_called_once() + mnemonics = MnemonicsView(ctx) + mocker.spy(mnemonics, "stackbit") + mnemonics.mnemonic() + mnemonics.stackbit.assert_called_once() assert ctx.input.wait_for_button.call_count == len(case[2]) def test_export_mnemonic_stackbit_amigo(mocker, amigo_tft, tdata): - from krux.pages.home import Home + from krux.pages.mnemonic_view import MnemonicsView from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE @@ -58,10 +58,10 @@ def test_export_mnemonic_stackbit_amigo(mocker, amigo_tft, tdata): ], ] ctx = create_ctx(mocker, case[2], case[0], case[1]) - home = Home(ctx) - mocker.spy(home, "stackbit") - home.mnemonic() - home.stackbit.assert_called_once() + mnemonics = MnemonicsView(ctx) + mocker.spy(mnemonics, "stackbit") + mnemonics.mnemonic() + mnemonics.stackbit.assert_called_once() assert ctx.input.wait_for_button.call_count == len(case[2]) diff --git a/tests/pages/test_tiny_seed.py b/tests/pages/test_tiny_seed.py index 1b229e400..463daac09 100644 --- a/tests/pages/test_tiny_seed.py +++ b/tests/pages/test_tiny_seed.py @@ -3,7 +3,7 @@ def test_export_mnemonic_tiny_seed_menu(mocker, m5stickv, tdata): - from krux.pages.home import Home + from krux.pages.mnemonic_view import MnemonicsView from krux.wallet import Wallet from krux.input import BUTTON_ENTER, BUTTON_PAGE @@ -28,10 +28,10 @@ def test_export_mnemonic_tiny_seed_menu(mocker, m5stickv, tdata): ], ] ctx = create_ctx(mocker, case[2], case[0], case[1]) - home = Home(ctx) - mocker.spy(home, "tiny_seed") - home.mnemonic() - home.tiny_seed.assert_called_once() + mnemonics = MnemonicsView(ctx) + mocker.spy(mnemonics, "tiny_seed") + mnemonics.mnemonic() + mnemonics.tiny_seed.assert_called_once() assert ctx.input.wait_for_button.call_count == len(case[2]) diff --git a/tests/test_input.py b/tests/test_input.py index 1f1008f94..fc3812119 100644 --- a/tests/test_input.py +++ b/tests/test_input.py @@ -237,6 +237,7 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 2000) + time.sleep(0.1) mocker.patch.object(input, "enter_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -265,6 +266,7 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 1100) + time.sleep(0.1) mocker.patch.object(input, "enter_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -294,6 +296,7 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 1100) + time.sleep(0.1) mocker.patch.object(input, "page_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -323,6 +326,7 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 1100) + time.sleep(0.1) mocker.patch.object(input, "page_prev_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -352,6 +356,7 @@ def release(): mocker.patch.object(time, "ticks_ms", new=lambda: 1000) time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 1100) + time.sleep(0.1) mocker.patch.object(input, "touch_value", new=lambda: RELEASED) assert input.entropy == 0 @@ -707,6 +712,7 @@ def release(): time.sleep(0.1) mocker.patch.object(time, "ticks_ms", new=lambda: 200) mocker.patch.object(input, "enter_event", new=lambda: False) + time.sleep(0.1) mocker.patch.object(input, "enter_value", new=lambda: RELEASED) assert input.entropy == 0 From aa757a3d92b006782d30205b4d1628ffc810db28 Mon Sep 17 00:00:00 2001 From: tadeubas Date: Wed, 8 Nov 2023 11:25:53 -0300 Subject: [PATCH 101/114] Display to_lines fixed by ChatGPT 3.5 --- src/krux/display.py | 31 +++++++++++-------------------- tests/test_display.py | 1 + 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/krux/display.py b/src/krux/display.py index ea6946099..2ba5ff741 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -181,36 +181,27 @@ def to_lines(self, text): columns = self.usable_width() // self.font_width else: columns = self.width() // self.font_width - words = [] + + # Processing the words and maintaining newline characters + processed_text = [] for word in text.split(" "): subwords = word.split("\n") for i, subword in enumerate(subwords): if len(subword) > columns: j = 0 while j < len(subword): - words.append(subword[j : j + columns]) + processed_text.append(subword[j : j + columns]) j += columns else: - words.append(subword) + processed_text.append(subword) if len(subwords) > 1 and i < len(subwords) - 1: - # Only add newline to the end of the last word of the slug if its length - # is less than the amount of columns. - # If it's exactly equal, a newline will be implicit. - slug_len = len(words[-1]) - for x_index in range(1, len(words)): - # Length of maximum words that fit the line - if ( - slug_len + len(words[-x_index - 1]) + 1 <= columns - and "\n" not in words[-x_index - 1] - ): - slug_len += len(words[-x_index - 1]) + 1 - else: - break - if slug_len < columns: - words[-1] += "\n" - - num_words = len(words) + # Ensure proper handling of newline characters at the end of lines + if not processed_text[-1].endswith("\n"): + processed_text.append("\n") + + num_words = len(processed_text) + words = processed_text # calculate cost of all pairs of words cost_between = [[0 for _ in range(num_words + 1)] for _ in range(num_words + 1)] diff --git a/tests/test_display.py b/tests/test_display.py index 9bbf579e1..d5eb2abc0 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -241,6 +241,7 @@ def test_to_lines(mocker, m5stickv): "52aad7bd7dcce121", "", "", + "", "Install?", ], ), From f287f3e49ce747f2ef152bd701a246f8395bc19e Mon Sep 17 00:00:00 2001 From: tadeubas Date: Wed, 8 Nov 2023 13:48:39 -0300 Subject: [PATCH 102/114] New FAQ item - Why insert an SD card into my device --- docs/faq.en.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/faq.en.md b/docs/faq.en.md index 7a1af5e9a..20ae002b7 100644 --- a/docs/faq.en.md +++ b/docs/faq.en.md @@ -72,4 +72,7 @@ If after flashing `maixpy_amigo_tft` to your device you notice that the buttons Starting from version 23.09.0, Krux supports SD card hot plugging. If you are using older versions, it may only detect the SD card at boot, so make sure Krux is turned off when inserting the microSD into it. To test the card compatibility use Krux [Tools>Check SD Card](getting-started/features/tools.md/#check-sd-card). Make sure the SD card is using MBR/DOS partition table and FAT32 format. -Here is some [supported microSD cards](https://github.com/m5stack/m5-docs/blob/master/docs/en/core/m5stickv.md#tf-cardmicrosd-test), and here is the MaixPy FAQ explaining [Why my micro SD card cannot be read](https://wiki.sipeed.com/soft/maixpy/en/others/maixpy_faq.html#Micro-SD-card-cannot-be-read). \ No newline at end of file +Here is some [supported microSD cards](https://github.com/m5stack/m5-docs/blob/master/docs/en/core/m5stickv.md#tf-cardmicrosd-test), and here is the MaixPy FAQ explaining [Why my micro SD card cannot be read](https://wiki.sipeed.com/soft/maixpy/en/others/maixpy_faq.html#Micro-SD-card-cannot-be-read). + +## Why insert an SD card into my device? What is it for? Does it save something? +SD card use is optional, most people use Krux only with QR codes. But you can use SD card to to upgrade the firmware, save settings, cnc/file, QR codes, XPUBs, encrypted mnemonics, and to save and load PSBTs, messages and wallet output descriptors. \ No newline at end of file From 64614078fa0fc54e5b6aa143e5b22c4928820c18 Mon Sep 17 00:00:00 2001 From: odudex Date: Wed, 8 Nov 2023 14:30:21 -0300 Subject: [PATCH 103/114] bugfix - QR viewer index overflow on regions mode --- src/krux/pages/qr_view.py | 74 +++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index 209ceeb16..6bfe98276 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -111,24 +111,27 @@ def highlight_qr_region(self, code, region=(0, 0, 0, 0), zoom=False): offset = (self.ctx.display.width() - qr_width) // 2 for y in range(reg_height): # vertical blocks loop for x in range(reg_width): # horizontal blocks loop - xy_index = (reg_y + y + 1) * (size + 1) - xy_index += reg_x + x + 1 - if code[xy_index] == "0": - self.ctx.display.fill_rectangle( - offset + (offset_x + x) * scale, - offset + (offset_y + y) * scale, - scale, - scale, - WHITE, - ) - else: - self.ctx.display.fill_rectangle( - offset + (offset_x + x) * scale, - offset + (offset_y + y) * scale, - scale, - scale, - BLACK, - ) + y_index = reg_y + y + 1 + x_index = reg_x + x + 1 + xy_index = y_index * (size + 1) + xy_index += x_index + if y_index < size and x_index < size: + if code[xy_index] == "0": + self.ctx.display.fill_rectangle( + offset + (offset_x + x) * scale, + offset + (offset_y + y) * scale, + scale, + scale, + WHITE, + ) + else: + self.ctx.display.fill_rectangle( + offset + (offset_x + x) * scale, + offset + (offset_y + y) * scale, + scale, + scale, + BLACK, + ) def _region_legend(self, row, column): region_char = chr(65 + row) @@ -235,29 +238,38 @@ def draw_grided_qr(self, mode): ), ) line_offset = grid_pad * row * self.region_size - colunm_offset = grid_pad * column * self.region_size + column_offset = grid_pad * column * self.region_size + draw_limit = grid_offset + self.qr_size * grid_pad for i in range(self.region_size + 1): - x_position = grid_offset + colunm_offset - x_lenght = self.region_size * grid_pad + 1 - display_transpose = x_position + x_lenght - self.ctx.display.width() - if display_transpose > 0: - x_lenght -= display_transpose + x_position = grid_offset + column_offset + x_length = self.region_size * grid_pad + 1 + transposed = x_position + x_length - draw_limit + if transposed > 0: + x_length -= transposed + y_position = grid_offset + i * grid_pad + line_offset + if y_position > draw_limit: + break self.ctx.display.fill_rectangle( x_position, - grid_offset + i * grid_pad + line_offset, - x_lenght, + y_position, + x_length, grid_size, theme.highlight_color, ) for i in range(self.region_size + 1): - x_position = grid_offset + i * grid_pad + colunm_offset - if x_position > self.ctx.display.width(): + x_position = grid_offset + i * grid_pad + column_offset + if x_position > draw_limit: break + y_position = grid_offset + line_offset + y_length = self.region_size * grid_pad + 1 + transposed = y_position + y_length - draw_limit + if transposed > 0: + y_length -= transposed self.ctx.display.fill_rectangle( x_position, - grid_offset + line_offset, + y_position, grid_size, - self.region_size * grid_pad + 1, + y_length, theme.highlight_color, ) self._region_legend(row, column) @@ -360,7 +372,7 @@ def save_qr_image_menu(self): bmp_resolutions.append(resolution) self.ctx.display.clear() self.ctx.display.draw_hcentered_text( - t("Resolution - Format"), self.ctx.display.font_height, info_box=True + t("Res. - Format"), self.ctx.display.font_height, info_box=True ) qr_menu = [] qr_menu.append( From 9505d36783e0fdca75ee2bf5307ca32ce39378d9 Mon Sep 17 00:00:00 2001 From: odudex Date: Wed, 8 Nov 2023 14:38:33 -0300 Subject: [PATCH 104/114] info_box and partial menus adjustments typos --- .pylintrc | 2 +- pyproject.toml | 2 +- src/krux/display.py | 11 +++++------ src/krux/metadata.py | 2 +- src/krux/pages/mnemonic_view.py | 2 +- src/krux/pages/utils.py | 2 +- src/krux/themes.py | 2 +- 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.pylintrc b/.pylintrc index 1b79ac93b..7b012eb3f 100644 --- a/.pylintrc +++ b/.pylintrc @@ -531,7 +531,7 @@ max-attributes=11 max-bool-expr=5 # Maximum number of branch for function / method body. -max-branches=23 +max-branches=22 # Maximum number of locals for function / method body. max-locals=25 diff --git a/pyproject.toml b/pyproject.toml index d621e3f43..82767e79f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ [tool.poetry] name = "krux" -version = "24.04.beta5" +version = "24.04.beta6" description = "Open-source signing device firmware for Bitcoin" authors = ["Jeff S "] diff --git a/src/krux/display.py b/src/krux/display.py index 2ba5ff741..99f96d588 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -302,10 +302,10 @@ def draw_hcentered_text( if info_box: bg_color = theme.disabled_color self.fill_rectangle( - DEFAULT_PADDING - 1, + DEFAULT_PADDING - 3, offset_y - 1, - self.usable_width() + 2, - (len(lines) + 1) * self.font_height + 2, + self.usable_width() + 6, + (len(lines)) * self.font_height + 2, bg_color, ) @@ -364,6 +364,5 @@ def set_backlight(self, level): def max_lines(self, line_offset=0): """The max lines of text supported by the display""" - return (self.height() - 2 * DEFAULT_PADDING - line_offset) // ( - 2 * self.font_height - ) + pad = DEFAULT_PADDING if line_offset else 2 * DEFAULT_PADDING + return (self.height() - pad - line_offset) // (2 * self.font_height) diff --git a/src/krux/metadata.py b/src/krux/metadata.py index 3a2f69272..cc0fae378 100644 --- a/src/krux/metadata.py +++ b/src/krux/metadata.py @@ -19,5 +19,5 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -VERSION = "24.04.beta5" +VERSION = "24.04.beta6" SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b" diff --git a/src/krux/pages/mnemonic_view.py b/src/krux/pages/mnemonic_view.py index 19387b371..6816c31bc 100644 --- a/src/krux/pages/mnemonic_view.py +++ b/src/krux/pages/mnemonic_view.py @@ -63,7 +63,7 @@ def mnemonic(self): return MENU_CONTINUE def show_mnemonic(self, mnemonic, suffix=""): - """Displays only the mnemonic words or indices""" + """Displays only the mnemonic words or indexes""" self.display_mnemonic(mnemonic, suffix) self.ctx.input.wait_for_button() diff --git a/src/krux/pages/utils.py b/src/krux/pages/utils.py index f620678a8..5a89bd647 100644 --- a/src/krux/pages/utils.py +++ b/src/krux/pages/utils.py @@ -71,7 +71,7 @@ def load_file(self, file_ext=""): @staticmethod def get_mnemonic_numbers(words, base=BASE_DEC): - """Returns the mnemonic as indices in decimal, hexadecimal, or octal""" + """Returns the mnemonic as indexes in decimal, hexadecimal, or octal""" word_numbers = [] for word in words.split(" "): word_numbers.append(WORDLIST.index(word) + 1) diff --git a/src/krux/themes.py b/src/krux/themes.py index 2c3e6d6e4..2aef6e747 100644 --- a/src/krux/themes.py +++ b/src/krux/themes.py @@ -59,7 +59,7 @@ "background": BLACK, "foreground": WHITE, "frame": DARKGREY, - "disabled": LIGHTBLACK, + "disabled": DARKGREY, "go": GREEN, "esc_no": RED, "del": YELLOW, From 35a81543dc29f6d998918ef95facb4cad75a098a Mon Sep 17 00:00:00 2001 From: odudex Date: Wed, 8 Nov 2023 16:41:47 -0300 Subject: [PATCH 105/114] add test to loop through QR code regions --- tests/pages/test_home.py | 4 +++- tests/pages/test_qr_view.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 652b98c86..4ad5b1ec1 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -158,7 +158,9 @@ def test_mnemonic_words(mocker, m5stickv, tdata): mocker.spy(mnemonics, "display_mnemonic") mnemonics.mnemonic() - mnemonics.display_mnemonic.assert_called_with(ctx.wallet.key.mnemonic, "Mnemonic") + mnemonics.display_mnemonic.assert_called_with( + ctx.wallet.key.mnemonic, "Mnemonic" + ) assert ctx.input.wait_for_button.call_count == len(case[2]) diff --git a/tests/pages/test_qr_view.py b/tests/pages/test_qr_view.py index fd0f862b7..724f96f39 100644 --- a/tests/pages/test_qr_view.py +++ b/tests/pages/test_qr_view.py @@ -25,3 +25,35 @@ def test_load_qr_view(amigo_tft, mocker): seed_qr_view = SeedQRView(ctx, data=data, title="Test QR Code") seed_qr_view.display_qr() assert ctx.display.draw_qr_code.call_count == 8 + + +def test_loop_through_regions(amigo_tft, mocker): + from krux.pages.qr_view import SeedQRView + from krux.input import BUTTON_ENTER, SWIPE_LEFT, SWIPE_RIGHT + from ..test_encryption import CBC_ENCRYPTED_QR + + BTN_SEQUENCE = ( + [ + SWIPE_LEFT, # lines mode + BUTTON_ENTER, # move to line 1 + SWIPE_LEFT, # zoomed regions mode + SWIPE_LEFT, # regions mode + ] + + [BUTTON_ENTER] * 49 # Loop through regions and return to A1 + + [ + SWIPE_LEFT, # grided mode + SWIPE_LEFT, # back to standard mode + SWIPE_LEFT, # lines mode again + SWIPE_RIGHT, # back to standard mode + BUTTON_ENTER, # leave + BUTTON_ENTER, # confirm + BUTTON_ENTER, # confirm + ] + ) + + ctx = mock_context(mocker) + ctx.input.wait_for_button = mocker.MagicMock(side_effect=BTN_SEQUENCE) + data = CBC_ENCRYPTED_QR # Will produce an QR code with 48 regions, max=G7 + seed_qr_view = SeedQRView(ctx, data=data, title="Test QR Code") + seed_qr_view.display_qr() + assert ctx.display.draw_qr_code.call_count == 57 From b56a33f85842a67348c98ac70d11a00e56634c76 Mon Sep 17 00:00:00 2001 From: odudex Date: Sun, 12 Nov 2023 13:37:10 -0300 Subject: [PATCH 106/114] use binary img to store and handle QR codes --- firmware/MaixPy | 2 +- src/krux/display.py | 6 +-- src/krux/pages/qr_view.py | 104 +++++++++++++++++++++----------------- src/krux/qr.py | 27 +++------- 4 files changed, 68 insertions(+), 71 deletions(-) diff --git a/firmware/MaixPy b/firmware/MaixPy index bab9a5fc9..aee8339e0 160000 --- a/firmware/MaixPy +++ b/firmware/MaixPy @@ -1 +1 @@ -Subproject commit bab9a5fc9111d176da1daebdeec44da73e7845ba +Subproject commit aee8339e0761f98c374c7a0beaa3aa4b4df26818 diff --git a/src/krux/display.py b/src/krux/display.py index 99f96d588..46683d4f5 100644 --- a/src/krux/display.py +++ b/src/krux/display.py @@ -23,7 +23,6 @@ import board from machine import I2C from .themes import theme -from .qr import add_qr_frame DEFAULT_PADDING = 10 FONT_WIDTH, FONT_HEIGHT = board.config["krux"]["display"]["font"] @@ -348,9 +347,8 @@ def draw_qr_code( self, offset_y, qr_code, dark_color=QR_DARK_COLOR, light_color=QR_LIGHT_COLOR ): """Draws a QR code on the screen""" - _, qr_code = add_qr_frame(qr_code) - lcd.draw_qr_code( - offset_y, qr_code, self.width(), dark_color, light_color, theme.bg_color + lcd.draw_qr_code_binary( + offset_y, qr_code, self.width(), dark_color, light_color, light_color ) def set_backlight(self, level): diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index 6bfe98276..57c47b271 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -26,7 +26,7 @@ from ..sd_card import SDHandler from ..themes import theme, WHITE, BLACK from ..krux_settings import t -from ..qr import get_size, add_qr_frame +from ..qr import get_size from ..display import DEFAULT_PADDING from ..input import ( BUTTON_ENTER, @@ -54,7 +54,7 @@ def __init__(self, ctx, binary=False, data=None, title=None): self.ctx = ctx self.binary = binary if data: - self.code = qrcode.encode_to_string(data) + self.code = qrcode.encode(data) self.title = title else: if self.binary: @@ -73,11 +73,11 @@ def _seed_qr(self): numbers = "" for word in words: numbers += str("%04d" % WORDLIST.index(word)) - return qrcode.encode_to_string(numbers) + return qrcode.encode(numbers) def _binary_seed_qr(self): binary_seed = self._to_compact_seed_qr(self.ctx.wallet.key.mnemonic) - return qrcode.encode_to_string(binary_seed) + return qrcode.encode(binary_seed) def _to_compact_seed_qr(self, mnemonic): mnemonic = mnemonic.split(" ") @@ -91,38 +91,38 @@ def _to_compact_seed_qr(self, mnemonic): def highlight_qr_region(self, code, region=(0, 0, 0, 0), zoom=False): """Draws in white a highlighted region of the QR code""" reg_x, reg_y, reg_width, reg_height = region - size, code = add_qr_frame(code) max_width = self.ctx.display.width() if zoom: max_width -= DEFAULT_PADDING - if size == 23: # 21 + 2(frame) + if self.qr_size == 21: qr_size = 7 else: qr_size = 5 offset_x = 0 offset_y = 0 + scale = max_width // qr_size else: - qr_size = size - offset_x = reg_x + 1 - offset_y = reg_y + 1 - - scale = max_width // qr_size + qr_size = self.qr_size + offset_x = reg_x + offset_y = reg_y + scale = max_width // (qr_size + 2) qr_width = qr_size * scale offset = (self.ctx.display.width() - qr_width) // 2 for y in range(reg_height): # vertical blocks loop for x in range(reg_width): # horizontal blocks loop - y_index = reg_y + y + 1 - x_index = reg_x + x + 1 - xy_index = y_index * (size + 1) + y_index = reg_y + y + x_index = reg_x + x + xy_index = y_index * self.qr_size xy_index += x_index - if y_index < size and x_index < size: - if code[xy_index] == "0": + if y_index < self.qr_size and x_index < self.qr_size: + bit_value = code[xy_index >> 3] & (1 << (xy_index % 8)) + if bit_value: self.ctx.display.fill_rectangle( offset + (offset_x + x) * scale, offset + (offset_y + y) * scale, scale, scale, - WHITE, + BLACK, ) else: self.ctx.display.fill_rectangle( @@ -130,7 +130,7 @@ def highlight_qr_region(self, code, region=(0, 0, 0, 0), zoom=False): offset + (offset_y + y) * scale, scale, scale, - BLACK, + WHITE, ) def _region_legend(self, row, column): @@ -291,27 +291,46 @@ def draw_grided_qr(self, mode): theme.highlight_color, ) + def add_frame(self, binary_image, size): + """Adds a 1 block frame to QR codes""" + new_size = size + 2 + # Create a new bytearray to store the framed image + framed_image = bytearray(b"\x00" * ((new_size * new_size + 7) >> 3)) + # Copy the original image into the center of the framed image + for y in range(0, size): + for x in range(0, size): + original_index = y * size + x + original_bit = ( + binary_image[original_index >> 3] >> (original_index % 8) + ) & 1 + if original_bit: + framed_index = (y + 1) * new_size + x + 1 + framed_image[framed_index >> 3] |= 1 << (framed_index % 8) + + return framed_image, new_size + def save_pbm_image(self, file_name): """Saves QR code image as compact B&W bitmap format file""" from ..sd_card import PBM_IMAGE_EXTENSION - size, code = add_qr_frame(self.code) - qr_image_file = ( - "P4\n# Krux\n".encode() - + str(size).encode() - + (" ").encode() - + str(size).encode() - + ("\n").encode() - ) - lines = code.strip().split("\n") - for bit_string_line in lines: - if size % 8: - bit_string_line += "0" * (8 - size % 8) - line = int(bit_string_line, 2).to_bytes((self.qr_size + 7) // 8, "big") - qr_image_file += line + code, size = self.add_frame(self.code, self.qr_size) + pbm_data = bytearray() + pbm_data.extend(("P4\n{0} {0}\n".format(size)).encode()) + for row in range(size): + byte = 0 + for col in range(size): + bit_index = row * size + col + if code[bit_index >> 3] & (1 << (bit_index % 8)): + byte |= 1 << (7 - (col % 8)) + + # If we filled a byte or reached the end of the row, append it + if col % 8 == 7 or col == size - 1: + pbm_data.append(byte) + byte = 0 + file_name += PBM_IMAGE_EXTENSION with SDHandler() as sd: - sd.write_binary(file_name, qr_image_file) + sd.write_binary(file_name, pbm_data) self.flash_text(t("Saved to SD card:\n%s") % file_name) def save_bmp_image(self, file_name, resolution): @@ -324,21 +343,16 @@ def save_bmp_image(self, file_name, resolution): self.ctx.display.clear() self.ctx.display.draw_centered_text(t("Saving ...")) - size, code = add_qr_frame(self.code) + code, size = self.add_frame(self.code, self.qr_size) raw_image = image.Image(size=(size, size)) - x_index = 0 - y_index = 0 - for qr_char in code: - if qr_char in ("0", "1"): - if qr_char == "0": - raw_image.set_pixel((x_index, y_index), lcd.WHITE) - if qr_char == "1": + for y_index in range(0, size): + for x_index in range(0, size): + index = y_index * size + x_index + bit_value = (code[index >> 3] >> (index % 8)) & 1 + if bit_value: raw_image.set_pixel((x_index, y_index), lcd.BLACK) - if x_index == size - 1: - x_index = 0 - y_index += 1 else: - x_index += 1 + raw_image.set_pixel((x_index, y_index), lcd.WHITE) bmp_img = image.Image(size=(resolution, resolution), copy_to_fb=True) scale = resolution // size bmp_img.draw_image( diff --git a/src/krux/qr.py b/src/krux/qr.py index b4e4deba5..bb972758d 100644 --- a/src/krux/qr.py +++ b/src/krux/qr.py @@ -107,7 +107,7 @@ def to_qr_codes(data, max_width, qr_format): the max_width constraint """ if qr_format == FORMAT_NONE: - code = qrcode.encode_to_string(data) + code = qrcode.encode(data) yield (code, 1) else: num_parts = find_min_num_parts(data, max_width, qr_format) @@ -123,35 +123,20 @@ def to_qr_codes(data, max_width, qr_format): part = part_number + data[i * part_size :] else: part = part_number + data[i * part_size : i * part_size + part_size] - code = qrcode.encode_to_string(part) + code = qrcode.encode(part) yield (code, num_parts) elif qr_format == FORMAT_UR: encoder = UREncoder(data, part_size, 0) while True: part = encoder.next_part() - code = qrcode.encode_to_string(part) + code = qrcode.encode(part) yield (code, encoder.fountain_encoder.seq_len()) -def add_qr_frame(qr_code): - """Add a 1 block white border around the code before displaying""" - qr_code = qr_code.strip() - lines = qr_code.split("\n") - size = len(lines) - size += 2 - new_lines = ["0" * size] - for line in lines: - new_lines.append("0" + line + "0") - new_lines.append("0" * size) - return size, "\n".join(new_lines) - - def get_size(qr_code): """Returns the size of the qr code as the number of chars until the first newline""" - size = 0 - while qr_code[size] != "\n": - size += 1 - return size + size = math.sqrt(len(qr_code) * 8) + return int(size) def data_len(data): @@ -178,7 +163,7 @@ def find_min_num_parts(data, max_width, qr_format): # The worst-case number of bytes needed to store one QR Code, up to and including # version 40. This value equals 3918, which is just under 4 kilobytes. if len(part) < 3918: - code = qrcode.encode_to_string(part) + code = qrcode.encode(part) if get_size(code) <= max_width: break num_parts += 1 From 77af0249b4bfe456d4d5ebf423cc23fd213226dc Mon Sep 17 00:00:00 2001 From: Odudex Date: Mon, 13 Nov 2023 17:10:05 -0300 Subject: [PATCH 107/114] adapt thermal print QR code to binary images --- src/krux/printers/thermal.py | 43 +++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/src/krux/printers/thermal.py b/src/krux/printers/thermal.py index 3b6b0929e..96edd7173 100644 --- a/src/krux/printers/thermal.py +++ b/src/krux/printers/thermal.py @@ -131,30 +131,37 @@ def clear(self): def print_qr_code(self, qr_code): """Prints a QR code, scaling it up as large as possible""" - size = 0 - while qr_code[size] != "\n": - size += 1 + from ..qr import get_size + + size = get_size(qr_code) scale = Settings().hardware.printer.thermal.adafruit.paper_width // size - scale *= Settings().hardware.printer.thermal.adafruit.scale - scale //= 200 # 100*2 because printer will scale 2X later to save data + scale *= Settings().hardware.printer.thermal.adafruit.scale # Scale in % + scale //= 200 # 100% * 2 because printer will scale 2X later to save data # Being at full size sometimes makes prints more faded (can't apply too much heat?) line_bytes_size = (size * scale + 7) // 8 # amount of bytes per line - self.set_bitmap_mode(line_bytes_size, scale * size, 3) - for y in range(size): - # Scale the line (width) by scaling factor - line = 0 - for char in qr_code[y * (size + 1) : y * (size + 1) + size]: - bit = int(char) - for _ in range(scale): - line <<= 1 - line |= bit - line_bytes = line.to_bytes(line_bytes_size, "big") - # Print height * scale lines out to scale by - + self.set_bitmap_mode(line_bytes_size, size * scale, 3) + for row in range(size): + byte = 0 + line_bytes = bytearray() + for col in range(size): + bit_index = row * size + col + bit = qr_code[bit_index >> 3] & (1 << (bit_index % 8)) + for i in range(scale): + byte <<= 1 + if bit: + byte |= 1 + end_line = col == size - 1 and i == scale - 1 + shift_index = (col * scale + i) % 8 + # If we filled a byte or reached the end of the row, append it + if shift_index == 7 or end_line: + if end_line: + # Shift pending bits if on last byte of row + byte <<= 7 - shift_index + line_bytes.append(byte) + byte = 0 for _ in range(scale): - # command += line_bytes self.uart_conn.write(line_bytes) time.sleep_ms(self.dot_print_time) self.feed(4) From 37de1155f25697b08fb43f78d9b799be2e1428fe Mon Sep 17 00:00:00 2001 From: Odudex Date: Tue, 14 Nov 2023 10:59:03 -0300 Subject: [PATCH 108/114] add"Back to Main Menu" at bottom of qr viewer menu --- src/krux/pages/qr_view.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/krux/pages/qr_view.py b/src/krux/pages/qr_view.py index 57c47b271..b2d3a3868 100644 --- a/src/krux/pages/qr_view.py +++ b/src/krux/pages/qr_view.py @@ -449,12 +449,12 @@ def display_qr(self, allow_export=False): elif mode in (REGION_MODE, ZOOMED_R_MODE): self.lr_index %= self.columns * self.columns qr_menu = [] - qr_menu.append((t("Leave QR Viewer"), lambda: MENU_EXIT)) + qr_menu.append((t("Return to QR Viewer"), lambda: None)) if self.has_sd_card() and allow_export: qr_menu.append((t("Save QR Image to SD Card"), self.save_qr_image_menu)) if self.has_printer(): qr_menu.append((t("Print to QR"), self.print_qr)) - qr_menu.append((t("Back"), lambda: None)) + qr_menu.append((t("Back to Main Menu"), lambda: MENU_EXIT)) submenu = Menu(self.ctx, qr_menu) _, status = submenu.run_loop() if status == MENU_EXIT: From 32e87174c871af0ec7eb41bb19a36dddf50708a1 Mon Sep 17 00:00:00 2001 From: Odudex Date: Tue, 14 Nov 2023 12:48:30 -0300 Subject: [PATCH 109/114] simulator: compatibility to binary image QR code --- simulator/kruxsim/mocks/lcd.py | 46 +++++++++++++++++++++++++++++++ simulator/kruxsim/mocks/qrcode.py | 21 ++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/simulator/kruxsim/mocks/lcd.py b/simulator/kruxsim/mocks/lcd.py index 555ff5436..5e0772f27 100644 --- a/simulator/kruxsim/mocks/lcd.py +++ b/simulator/kruxsim/mocks/lcd.py @@ -21,6 +21,7 @@ # THE SOFTWARE. import sys import os +import math from unittest import mock import pygame as pg import cv2 @@ -174,6 +175,50 @@ def run(): light_color = rgb565torgb888(light_color) pg.event.post(pg.event.Event(events.LCD_DRAW_QR_CODE_EVENT, {"f": run})) +def draw_qr_code_binary(offset_y, code_bin, max_width, dark_color, light_color, background): + def run(): + starting_size = int(math.sqrt(len(code_bin) * 8)) + block_size_divisor = starting_size + 2; # adds 2 to create room for a 1 block border + scale = max_width // block_size_divisor + width = starting_size * scale + border_size = (max_width - width) // 2 + opposite_border_offset = border_size + width - 1 + # Top border + for rx in range(max_width): + for ry in range(border_size): + screen.set_at((rx, ry),light_color) + + # Bottom border + for rx in range(max_width): + for ry in range(opposite_border_offset, max_width): + screen.set_at((rx, ry),light_color) + + # Left border + for rx in range(border_size): + for ry in range(border_size, opposite_border_offset): + screen.set_at((rx, ry),light_color) + + # Right border + for rx in range(opposite_border_offset, max_width): + for ry in range(border_size, opposite_border_offset): + screen.set_at((rx, ry),light_color) + # QR code rendering + for og_y in range(starting_size): + for og_x in range(starting_size): + og_yx_index = og_y * starting_size + og_x + color_byte = code_bin[og_yx_index >> 3] + color_byte &= (1 << (og_yx_index % 8)) + color = dark_color if color_byte else light_color + for i in range(scale): + y = border_size + og_y * scale + i + for j in range(scale): + x = border_size + og_x * scale + j + screen.set_at((x, y),color) + + dark_color = rgb565torgb888(dark_color) + light_color = rgb565torgb888(light_color) + pg.event.post(pg.event.Event(events.LCD_DRAW_QR_CODE_EVENT, {"f": run})) + def fill_rectangle(x, y, w, h, color): def run(): @@ -205,6 +250,7 @@ def run(): height=height, draw_string=draw_string, draw_qr_code=draw_qr_code, + draw_qr_code_binary=draw_qr_code_binary, fill_rectangle=fill_rectangle, BLACK=COLOR_BLACK, WHITE=COLOR_WHITE, diff --git a/simulator/kruxsim/mocks/qrcode.py b/simulator/kruxsim/mocks/qrcode.py index b727de39e..bc6feb56f 100644 --- a/simulator/kruxsim/mocks/qrcode.py +++ b/simulator/kruxsim/mocks/qrcode.py @@ -53,8 +53,29 @@ def encode_to_string(data): return new_code_str +def encode(data): + # Uses string encoded qr as it already cleaned up the frames + # PyQRcode also doesn't offer any binary output + + frame_less_qr = encode_to_string(data) + size = 0 + while frame_less_qr[size] != "\n": + size += 1 + binary_qr = bytearray(b"\x00" * ((size * size + 7) // 8)) + for y in range(size): + for x in range(size): + bit_index = y * size + x + bit_string_index = y * (size + 1) + x + if frame_less_qr[bit_string_index] == "1": + binary_qr[bit_index>>3] |= 1 << (bit_index % 8) + return binary_qr + + + + if "qrcode" not in sys.modules: sys.modules["qrcode"] = mock.MagicMock( encode_to_string=encode_to_string, + encode = encode, ) From 8d5522021a23db0d48185ad6829f799038a36ff8 Mon Sep 17 00:00:00 2001 From: Odudex Date: Tue, 14 Nov 2023 16:14:02 -0300 Subject: [PATCH 110/114] fix tests - binary image QR , menu changes update version, changelog --- CHANGELOG.md | 6 +++ pyproject.toml | 2 +- src/krux/metadata.py | 2 +- tests/conftest.py | 3 +- tests/pages/test_home.py | 18 ++++++++- tests/pages/test_qr_view.py | 8 ++-- tests/shared_mocks.py | 16 ++++++++ tests/test_display.py | 80 ++----------------------------------- 8 files changed, 50 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5d6d8f41..dc1d6dc78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,12 @@ Optional screensaver to reduce pixels' burn-in and grab attention of the user wh ### Update Embit to version 0.7 Use latest Embit release +### Optimized QR codes +QR codes rendering is faster and uses less RAM + +### Export Mnemonic Numbers +To match the input options, export mnemonics as decimnal, hexadecimal or octal numbers + # Version 23.09.0 - September 12, 2023 After a long year, new features are finally coming out of beta and making their way into a stable release. Also @jreesun appointed @odudex as the new lead maintainer of the project. diff --git a/pyproject.toml b/pyproject.toml index 82767e79f..3571947d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ [tool.poetry] name = "krux" -version = "24.04.beta6" +version = "24.04.beta7" description = "Open-source signing device firmware for Bitcoin" authors = ["Jeff S "] diff --git a/src/krux/metadata.py b/src/krux/metadata.py index cc0fae378..52dd1683e 100644 --- a/src/krux/metadata.py +++ b/src/krux/metadata.py @@ -19,5 +19,5 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -VERSION = "24.04.beta6" +VERSION = "24.04.beta7" SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b" diff --git a/tests/conftest.py b/tests/conftest.py index e94a35f34..bbb9ed37f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,6 +4,7 @@ board_dock, board_m5stickv, encode_to_string, + encode, statvfs, ) @@ -26,7 +27,7 @@ def mp_modules(mocker, monkeypatch): monkeypatch.setitem( sys.modules, "qrcode", - mocker.MagicMock(encode_to_string=encode_to_string), + mocker.MagicMock(encode_to_string=encode_to_string, encode=encode), ) monkeypatch.setitem(sys.modules, "secp256k1", mocker.MagicMock(wraps=secp256k1)) monkeypatch.setitem(sys.modules, "urandom", random) diff --git a/tests/pages/test_home.py b/tests/pages/test_home.py index 4ad5b1ec1..06db1241f 100644 --- a/tests/pages/test_home.py +++ b/tests/pages/test_home.py @@ -302,6 +302,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, # select Compact SeedQR BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave + BUTTON_PAGE_PREV, # Move to leave QR Viewer BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -320,6 +321,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_PAGE, # select Compact SeedQR BUTTON_ENTER, # Open Compact SeedQR BUTTON_ENTER, # Leave + BUTTON_PAGE_PREV, # Move to leave QR Viewer BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -342,6 +344,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # Print BUTTON_ENTER, # Print confirm BUTTON_ENTER, # Leave + BUTTON_PAGE_PREV, # Move to leave QR Viewer BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -364,6 +367,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # Print BUTTON_ENTER, # Print confirm BUTTON_ENTER, # Leave + BUTTON_PAGE_PREV, # Move to leave QR Viewer BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -386,6 +390,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # Print BUTTON_PAGE, # Print decline BUTTON_ENTER, # Leave + BUTTON_PAGE_PREV, # Move to leave QR Viewer BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -408,6 +413,7 @@ def test_mnemonic_compact_qr(mocker, m5stickv, tdata): BUTTON_ENTER, # Print BUTTON_PAGE, # Print decline BUTTON_ENTER, # Leave + BUTTON_PAGE_PREV, # Move to leave QR Viewer BUTTON_ENTER, # Leave QR Viewer BUTTON_PAGE_PREV, # change to btn Back BUTTON_PAGE_PREV, @@ -566,11 +572,21 @@ def test_public_key(mocker, m5stickv, tdata): BUTTON_ENTER, # XPUB - Text BUTTON_PAGE, # move Back - child BUTTON_ENTER, # Press Back - child + BUTTON_PAGE, # move to XPUB - QR + BUTTON_ENTER, # Enter XPUB - QR + BUTTON_PAGE_PREV, # move Back - child + BUTTON_ENTER, # Press Back - child + BUTTON_PAGE, # move to XPUB - QR + BUTTON_PAGE, # move to ZPUB - Text + BUTTON_PAGE, # move to ZPUB - QR + BUTTON_ENTER, # Enter ZPUB - QR + BUTTON_PAGE_PREV, # move Back - child + BUTTON_ENTER, # Press Back - child BUTTON_PAGE_PREV, # Move Back - father BUTTON_ENTER, # Press Back - father ], ), - # 1 + # 1 TODO: From now on tests are broken, it's worth wait for final version before fix ( Wallet(tdata.MULTISIG_12_WORD_KEY), None, diff --git a/tests/pages/test_qr_view.py b/tests/pages/test_qr_view.py index 724f96f39..9727aeb34 100644 --- a/tests/pages/test_qr_view.py +++ b/tests/pages/test_qr_view.py @@ -3,7 +3,7 @@ def test_load_qr_view(amigo_tft, mocker): from krux.pages.qr_view import SeedQRView - from krux.input import BUTTON_ENTER, SWIPE_LEFT, SWIPE_RIGHT + from krux.input import BUTTON_ENTER, BUTTON_PAGE_PREV, SWIPE_LEFT, SWIPE_RIGHT BTN_SEQUENCE = [ SWIPE_LEFT, # lines mode @@ -15,7 +15,7 @@ def test_load_qr_view(amigo_tft, mocker): SWIPE_LEFT, # lines mode again SWIPE_RIGHT, # back to standard mode BUTTON_ENTER, # leave - BUTTON_ENTER, # confirm + BUTTON_PAGE_PREV, # move to Back to Main Menu BUTTON_ENTER, # confirm ] @@ -29,7 +29,7 @@ def test_load_qr_view(amigo_tft, mocker): def test_loop_through_regions(amigo_tft, mocker): from krux.pages.qr_view import SeedQRView - from krux.input import BUTTON_ENTER, SWIPE_LEFT, SWIPE_RIGHT + from krux.input import BUTTON_ENTER, BUTTON_PAGE_PREV, SWIPE_LEFT, SWIPE_RIGHT from ..test_encryption import CBC_ENCRYPTED_QR BTN_SEQUENCE = ( @@ -46,7 +46,7 @@ def test_loop_through_regions(amigo_tft, mocker): SWIPE_LEFT, # lines mode again SWIPE_RIGHT, # back to standard mode BUTTON_ENTER, # leave - BUTTON_ENTER, # confirm + BUTTON_PAGE_PREV, # move to Back to Main Menu BUTTON_ENTER, # confirm ] ) diff --git a/tests/shared_mocks.py b/tests/shared_mocks.py index 6e3055b47..605a0f84b 100644 --- a/tests/shared_mocks.py +++ b/tests/shared_mocks.py @@ -31,6 +31,22 @@ def encode_to_string(data): return new_code_str +def encode(data): + # Uses string encoded qr as it already cleaned up the frames + # PyQRcode also doesn't offer any binary output + + frame_less_qr = encode_to_string(data) + size = 0 + while frame_less_qr[size] != "\n": + size += 1 + binary_qr = bytearray(b"\x00" * ((size * size + 7) // 8)) + for y in range(size): + for x in range(size): + bit_index = y * size + x + bit_string_index = y * (size + 1) + x + if frame_less_qr[bit_string_index] == "1": + binary_qr[bit_index>>3] |= 1 << (bit_index % 8) + return binary_qr def get_mock_open(files: dict[str, str]): def open_mock(filename, *args, **kwargs): diff --git a/tests/test_display.py b/tests/test_display.py index d5eb2abc0..a3c584da6 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -1,78 +1,4 @@ -TEST_QR = """ -111111100111000100010011001111111 -100000101001100100101111001000001 -101110101001100001000001001011101 -101110100010101000110011101011101 -101110101101001110000101001011101 -100000101010100111011110101000001 -111111101010101010101010101111111 -000000001111101101101111000000000 -110100110101111010010110101110110 -001101000100111011101100101000001 -010101101010100000011000111110101 -001101010101010100111100010011001 -010110110010110011001100001000000 -011100011010100010010110101010001 -100110100001101011101101000110110 -000100001001011001110100010011011 -001011111100100011011110001010001 -111100011111010010100001110000000 -000111111110011000000010000110111 -101101000111100111001100101010001 -100010111100110010110100110100011 -011001011000110011001010111000011 -110111100110111010111000111000101 -011000000100011110011100001111001 -100101110101110011011111111110000 -000000001000101000011111100010001 -111111101111110010000010101010110 -100000100101110111011100100010011 -101110100010000101010110111110000 -101110101111101010100100001111111 -101110100100001000000010110110011 -100000101001000011110101100111000 -111111101000011010001101101011010 -""".strip() - -TEST_QR_WITH_BORDER = """ -00000000000000000000000000000000000 -01111111001110001000100110011111110 -01000001010011001001011110010000010 -01011101010011000010000010010111010 -01011101000101010001100111010111010 -01011101011010011100001010010111010 -01000001010101001110111101010000010 -01111111010101010101010101011111110 -00000000011111011011011110000000000 -01101001101011110100101101011101100 -00011010001001110111011001010000010 -00101011010101000000110001111101010 -00011010101010101001111000100110010 -00101101100101100110011000010000000 -00111000110101000100101101010100010 -01001101000011010111011010001101100 -00001000010010110011101000100110110 -00010111111001000110111100010100010 -01111000111110100101000011100000000 -00001111111100110000000100001101110 -01011010001111001110011001010100010 -01000101111001100101101001101000110 -00110010110001100110010101110000110 -01101111001101110101110001110001010 -00110000001000111100111000011110010 -01001011101011100110111111111100000 -00000000010001010000111111000100010 -01111111011111100100000101010101100 -01000001001011101110111001000100110 -01011101000100001010101101111100000 -01011101011111010101001000011111110 -01011101001000010000000101101100110 -01000001010010000111101011001110000 -01111111010000110100011011010110100 -00000000000000000000000000000000000 -""".strip() - -DEFAULT_BG_COLOR = 0x0000 # Black +TEST_QR = bytearray(b'\x7fn\xfd\x830\x08v9\xd6\xedj\xa0\xdbUU7\xc8\xa0\xe0_U\x7f\x00i\x00\xe3\xd61P\x08\xf5Q\xef^\xfe`\xe8\xc1\x7f\xdex\x936Y\x91\xb8\xeb\xd29c\xd5\xd4\x7f\x00\n#\xfe\xcd\xd7\rJ\x8e\xd9\xe5\xf8\xb9K\xe6x\x17\xb9\xca\xa0\x9a\x9a\x7f\xbb\x1b\x01') def test_init(mocker, m5stickv): @@ -501,6 +427,6 @@ def test_draw_qr_code(mocker, m5stickv): d.draw_qr_code(0, TEST_QR) - krux.display.lcd.draw_qr_code.assert_called_with( - 0, TEST_QR_WITH_BORDER, 135, QR_DARK_COLOR, QR_LIGHT_COLOR, DEFAULT_BG_COLOR + krux.display.lcd.draw_qr_code_binary.assert_called_with( + 0, TEST_QR, 135, QR_DARK_COLOR, QR_LIGHT_COLOR, QR_LIGHT_COLOR ) From 28748aee013cda8e42a4c556eced89d1a2e0f4af Mon Sep 17 00:00:00 2001 From: aglkm Date: Thu, 16 Nov 2023 18:06:50 +0300 Subject: [PATCH 111/114] index fix --- src/krux/pages/addresses.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/krux/pages/addresses.py b/src/krux/pages/addresses.py index 3ef6963a7..8d6d6c1ec 100644 --- a/src/krux/pages/addresses.py +++ b/src/krux/pages/addresses.py @@ -80,7 +80,7 @@ def list_address_type(self, addr_type=0): if num_checked + 1 > max_addresses: items.append( ( - "%d..%d" % (num_checked - max_addresses, num_checked), + "%d..%d" % (num_checked - max_addresses + 1, num_checked), lambda: MENU_EXIT, ) ) From c5fa1d129040603376dfcf025130679204262a28 Mon Sep 17 00:00:00 2001 From: odudex Date: Fri, 17 Nov 2023 13:24:21 -0300 Subject: [PATCH 112/114] bugfix: ensure PBKDF2 iter. are multiple of 10000 --- docs/getting-started/settings.en.md | 2 ++ src/krux/encryption.py | 21 ++++++++++++++++++--- src/krux/pages/settings_page.py | 14 ++++++++++++-- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/docs/getting-started/settings.en.md b/docs/getting-started/settings.en.md index 0f4ca013c..d353c36bf 100644 --- a/docs/getting-started/settings.en.md +++ b/docs/getting-started/settings.en.md @@ -27,6 +27,8 @@ When you enter a encryption key it is not directly used to encrypt your data. As If you increase this value it will make the encryption harder, at the cost of taking longer to encrypt and decrypt your mnemonics +Values must be multiple of 10,000. This was done to save data space on QR codes, also, intermediary values wouldn't significantly affect safety or computation time. +
#### Encryption Mode diff --git a/src/krux/encryption.py b/src/krux/encryption.py index f882c838f..90857940a 100644 --- a/src/krux/encryption.py +++ b/src/krux/encryption.py @@ -46,6 +46,8 @@ "AES-CBC": PBKDF2_HMAC_CBC, } +QR_CODE_ITER_MULTIPLE = 10000 + class AESCipher: """Helper for AES encrypt/decrypt""" @@ -214,12 +216,22 @@ def create(self, key, mnemonic_id, mnemonic, i_vector=None): """Joins necessary data and creates encrypted mnemonic QR codes""" name_lenght = len(mnemonic_id.encode()) version = VERSION_NUMBER[Settings().encryption.version] - key_iterations = Settings().encryption.pbkdf2_iterations + ten_k_iterations = Settings().encryption.pbkdf2_iterations + + # Divide iterations by a Multiple(10,000) to save space + ten_k_iterations //= QR_CODE_ITER_MULTIPLE + + # Add public data bytes qr_code_data = name_lenght.to_bytes(1, "big") qr_code_data += mnemonic_id.encode() qr_code_data += version.to_bytes(1, "big") - qr_code_data += (key_iterations // 10000).to_bytes(3, "big") - encryptor = AESCipher(key, mnemonic_id, Settings().encryption.pbkdf2_iterations) + qr_code_data += ten_k_iterations.to_bytes(3, "big") + + # Restore the iterations value assuring is a multiple of 10,000 + ten_k_iterations *= QR_CODE_ITER_MULTIPLE + + # Encrypted data + encryptor = AESCipher(key, mnemonic_id, ten_k_iterations) mode = VERSION_MODE[Settings().encryption.version] words = mnemonic.split(" ") checksum_bits = 8 if len(words) == 24 else 4 @@ -231,7 +243,10 @@ def create(self, key, mnemonic_id, mnemonic, i_vector=None): bytes_to_encrypt += hashlib.sha256(bytes_to_encrypt).digest()[:16] base64_encrypted = encryptor.encrypt(bytes_to_encrypt, mode, i_vector) bytes_encrypted = base_decode(base64_encrypted, 64) + + # Add encrypted data bytes qr_code_data += bytes_encrypted + return qr_code_data def public_data(self, data): diff --git a/src/krux/pages/settings_page.py b/src/krux/pages/settings_page.py index 0a38f1736..f77849e25 100644 --- a/src/krux/pages/settings_page.py +++ b/src/krux/pages/settings_page.py @@ -36,10 +36,11 @@ BitcoinSettings, TouchSettings, EncoderSettings, + t, ) from ..input import BUTTON_ENTER, BUTTON_PAGE, BUTTON_PAGE_PREV, BUTTON_TOUCH -from ..krux_settings import t from ..sd_card import SDHandler +from ..encryption import QR_CODE_ITER_MULTIPLE from . import ( Page, Menu, @@ -394,7 +395,16 @@ def number_setting(self, settings_namespace, setting): new_value = setting.numtype(new_value) if setting.value_range[0] <= new_value <= setting.value_range[1]: - setting.__set__(settings_namespace, new_value) + if ( + setting.attr == "pbkdf2_iterations" + and (new_value % QR_CODE_ITER_MULTIPLE) != 0 + ): + self.flash_text( + t("Value must be multiple of %s") % QR_CODE_ITER_MULTIPLE, + theme.error_color, + ) + else: + setting.__set__(settings_namespace, new_value) else: self.flash_text( t("Value %s out of range: [%s, %s]") From 3ffe96de625d584c7ecabdf214479ae3b03a9625 Mon Sep 17 00:00:00 2001 From: odudex Date: Sat, 18 Nov 2023 07:17:15 -0300 Subject: [PATCH 113/114] change version --- pyproject.toml | 2 +- src/krux/metadata.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3571947d1..585611163 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -22,7 +22,7 @@ [tool.poetry] name = "krux" -version = "24.04.beta7" +version = "24.04.beta8" description = "Open-source signing device firmware for Bitcoin" authors = ["Jeff S "] diff --git a/src/krux/metadata.py b/src/krux/metadata.py index 52dd1683e..e26e26c3f 100644 --- a/src/krux/metadata.py +++ b/src/krux/metadata.py @@ -19,5 +19,5 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -VERSION = "24.04.beta7" +VERSION = "24.04.beta8" SIGNER_PUBKEY = "03339e883157e45891e61ca9df4cd3bb895ef32d475b8e793559ea10a36766689b" From 8f70e62e423cfe58838befb3bdaf315f1d7dfe27 Mon Sep 17 00:00:00 2001 From: odudex Date: Mon, 20 Nov 2023 15:02:04 -0300 Subject: [PATCH 114/114] fix French translation and merge from main adjusts black --- CHANGELOG.md | 7 +- i18n/translations/de-DE.json | 3 - i18n/translations/es-MX.json | 3 - i18n/translations/fr-FR.json | 5 +- i18n/translations/nl-NL.json | 3 - i18n/translations/pl-PL.json | 3 - i18n/translations/pt-BR.json | 3 - i18n/translations/ru-RU.json | 3 - i18n/translations/vi-VN.json | 3 - src/krux/translations.py | 2967 +++++++++++++++++----------------- tests/pages/test_qr_view.py | 4 +- tests/shared_mocks.py | 6 +- tests/test_display.py | 4 +- 13 files changed, 1489 insertions(+), 1525 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47cb999b8..b5b0edae2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# Changelog 24.04.beta3 - October 9, 2023 +# Changelog 24.04.beta8 - November 20, 2023 ## Changes @@ -21,7 +21,10 @@ Use latest Embit release QR codes rendering is faster and uses less RAM ### Export Mnemonic Numbers -To match the input options, export mnemonics as decimnal, hexadecimal or octal numbers +To match the input options, export mnemonics as decimal, hexadecimal or octal numbers + +### Export QR codes as images to SD Card +Some QR codes can be exported as images to SD card # Version 23.09.1 - November 18, 2023 diff --git a/i18n/translations/de-DE.json b/i18n/translations/de-DE.json index 9066a8832..1305e33ed 100644 --- a/i18n/translations/de-DE.json +++ b/i18n/translations/de-DE.json @@ -19,7 +19,6 @@ "Anti-glare disabled": "Blendschutz deaktiviert", "Anti-glare enabled": "Blendschutz aktiviert", "Are you sure?": "Bist Du sicher?", - "BIP39 Mnemonic": "BIP39 Mnemonic", "Back": "Zurück", "Backing up bootloader..\n\n%d%%": "Bootloader wird gesichert..\n\n%d%%", "Bad signature": "Ungültige Signatur", @@ -187,7 +186,6 @@ "Scan Key QR code": "Schlüssel QR-Code scannen", "Scanning words 1-12 again": "Wörter 1-12 erneut scannen", "Scanning words 13-24": "Wörter 13-24 scannen", - "Screensaver": "Bildschirmschoner", "SeedQR": "SeedQR", "Self-transfer or Change (%d): ": "Selbstübertragung oder Change (%d): ", "Settings": "Einstellungen", @@ -233,7 +231,6 @@ "Via D6": "Via D6", "Via Manual Input": "Via manueller Eingabe", "Wait for the capture": "Warte auf die Erfassung", - "Wait time": "Wartezeit", "Wallet Descriptor": "Wallet-Deskriptor", "Wallet output descriptor": "Wallet Ausgabedeskriptor", "Wallet output descriptor loaded!": "Wallet Ausgabedeskriptor geladen!", diff --git a/i18n/translations/es-MX.json b/i18n/translations/es-MX.json index 97bb38352..dbff6bd65 100644 --- a/i18n/translations/es-MX.json +++ b/i18n/translations/es-MX.json @@ -19,7 +19,6 @@ "Anti-glare disabled": "Antideslumbrante desactivado", "Anti-glare enabled": "Antideslumbrante habilitado", "Are you sure?": "¿Estas seguro?", - "BIP39 Mnemonic": "BIP39 Mnemónico", "Back": "Atrás", "Backing up bootloader..\n\n%d%%": "Copia de seguridad del cargador de arranque..\n\n%d%%", "Bad signature": "Mala asignatura", @@ -187,7 +186,6 @@ "Scan Key QR code": "Escanear el código QR", "Scanning words 1-12 again": "Escaneo de palabras 1-12 de nuevo", "Scanning words 13-24": "Escaneo de palabras 13-24", - "Screensaver": "Protector de pantalla", "SeedQR": "Seedqr", "Self-transfer or Change (%d): ": "Autotransferencia o Cambio (%d): ", "Settings": "Ajustes", @@ -233,7 +231,6 @@ "Via D6": "Via D6", "Via Manual Input": "Mediante entrada manual", "Wait for the capture": "Espera la captura", - "Wait time": "Tiempo de espera", "Wallet Descriptor": "Descriptor de Cartera", "Wallet output descriptor": "Descriptor de salida de billetera", "Wallet output descriptor loaded!": "¡Se ha cargado el descriptor de salida de la cartera!", diff --git a/i18n/translations/fr-FR.json b/i18n/translations/fr-FR.json index 4a5b7db1c..3f2ef4339 100644 --- a/i18n/translations/fr-FR.json +++ b/i18n/translations/fr-FR.json @@ -19,7 +19,6 @@ "Anti-glare disabled": "Anti-éblouissement désactivé", "Anti-glare enabled": "Anti-éblouissement activé", "Are you sure?": "Es-tu sûr?", - "BIP39 Mnemonic": "BIP39 Mnémonique", "Back": "Retour", "Backing up bootloader..\n\n%d%%": "Sauvegarde du chargeur de démarrage..\n\n%d%%", "Bad signature": "Mauvaise signature", @@ -187,7 +186,6 @@ "Scan Key QR code": "Scanner le code QR de la clé", "Scanning words 1-12 again": "Analyser à nouveau les mots 1 à 12", "Scanning words 13-24": "Analyser les mots 13 à 24", - "Screensaver": "Économiseur d'écran", "SeedQR": "Seedqr", "Self-transfer or Change (%d): ": "Auto-transfert ou changement (%d): ", "Settings": "Paramètres", @@ -227,13 +225,12 @@ "Use camera's entropy to create a new mnemonic": "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", "Used: ": "Utilisé: ", "Value %s out of range: [%s, %s]": "Valeur %s hors de portée: [%s, %s]", - "Value must be multiple of %s": "La valeur doit être multiple de %s", + "Value must be multiple of %s": "La valeur doit être un multiple de %s", "Via Camera": "Par caméra", "Via D20": "Via D20", "Via D6": "Via D6", "Via Manual Input": "Par saisie manuelle", "Wait for the capture": "Attendez la capture", - "Wait time": "Temps d'attente", "Wallet Descriptor": "Descripteur de Portefeuille", "Wallet output descriptor": "Descripteur de sortie du portefeuille", "Wallet output descriptor loaded!": "Descripteur de sortie du portefeuille chargé!", diff --git a/i18n/translations/nl-NL.json b/i18n/translations/nl-NL.json index 48e3dc9d9..112100180 100644 --- a/i18n/translations/nl-NL.json +++ b/i18n/translations/nl-NL.json @@ -19,7 +19,6 @@ "Anti-glare disabled": "Anti reflecterend uitgeschakeld", "Anti-glare enabled": "Anti reflecterend ingeschakeld", "Are you sure?": "Weet je het zeker?", - "BIP39 Mnemonic": "BIP-39 geheugensteun", "Back": "Terug", "Backing up bootloader..\n\n%d%%": "Backup van de bootloader...\n\n%d%%", "Bad signature": "Ongeldige handtekening", @@ -187,7 +186,6 @@ "Scan Key QR code": "QR code sleutel scannen", "Scanning words 1-12 again": "Woorden 1 t/m 12 opnieuw scannen", "Scanning words 13-24": "Woorden 13 t/m 24 scannen", - "Screensaver": "Screensaver", "SeedQR": "SeedQR", "Self-transfer or Change (%d): ": "Zelf overschrijving of wisselgeld (%d): ", "Settings": "Instellingen", @@ -233,7 +231,6 @@ "Via D6": "Via D6", "Via Manual Input": "Via handmatige invoer", "Wait for the capture": "Wacht op opname", - "Wait time": "Wacht tijd", "Wallet Descriptor": "Descriptor", "Wallet output descriptor": "Portemonnee descriptor", "Wallet output descriptor loaded!": "Portemonnee descriptor geladen!", diff --git a/i18n/translations/pl-PL.json b/i18n/translations/pl-PL.json index cab710773..45f270a75 100644 --- a/i18n/translations/pl-PL.json +++ b/i18n/translations/pl-PL.json @@ -19,7 +19,6 @@ "Anti-glare disabled": "Niepełnosprawne przeciwblokowane", "Anti-glare enabled": "Włączona anty-zabawa", "Are you sure?": "Jesteś pewny?", - "BIP39 Mnemonic": "BIP39 Mnemonic", "Back": "Z powrotem", "Backing up bootloader..\n\n%d%%": "Kopie zapasowe bootloader ..\n\n%d %%", "Bad signature": "zły podpis", @@ -187,7 +186,6 @@ "Scan Key QR code": "Skanuj kod QR", "Scanning words 1-12 again": "Znowu skanowanie słów 1-12", "Scanning words 13-24": "Skanowanie słów 13-24", - "Screensaver": "Wygaszacz ekranu", "SeedQR": "Seedqr", "Self-transfer or Change (%d): ": "Samo-transfer lub zmiana (%d):", "Settings": "Ustawienia", @@ -232,7 +230,6 @@ "Via D6": "Przez D6", "Via Manual Input": "Poprzez ręczne wejście", "Wait for the capture": "Poczekaj na schwytanie", - "Wait time": "Czas oczekiwania", "Wallet Descriptor": "Deskryptor portfela", "Wallet output descriptor": "Deskryptor wyjściowy portfela", "Wallet output descriptor loaded!": "Załadowany deskryptor wyjściowy portfela!", diff --git a/i18n/translations/pt-BR.json b/i18n/translations/pt-BR.json index dc8619bd9..a9f049226 100644 --- a/i18n/translations/pt-BR.json +++ b/i18n/translations/pt-BR.json @@ -19,7 +19,6 @@ "Anti-glare disabled": "Antirreflexo desativado", "Anti-glare enabled": "Antirreflexo ativado", "Are you sure?": "Tem certeza?", - "BIP39 Mnemonic": "Mnemônico BIP39", "Back": "Voltar", "Backing up bootloader..\n\n%d%%": "Backing up bootloader..\n\n%d%%", "Bad signature": "Assinatura Inválida", @@ -187,7 +186,6 @@ "Scan Key QR code": "Escanear código QR da chave", "Scanning words 1-12 again": "Escaneando as palavras 1-12 novamente", "Scanning words 13-24": "Escaneando as palavras 13-24", - "Screensaver": "Protetor de tela", "SeedQR": "SeedQR", "Self-transfer or Change (%d): ": "Autotransferência ou Troco (%d): ", "Settings": "Configurações", @@ -233,7 +231,6 @@ "Via D6": "Via D6", "Via Manual Input": "Por entrada manual", "Wait for the capture": "Aguarde a captura", - "Wait time": "Tempo de espera", "Wallet Descriptor": "Descritor de Carteira", "Wallet output descriptor": "Descritor da carteira", "Wallet output descriptor loaded!": "Descritor de saída da carteira carregado!", diff --git a/i18n/translations/ru-RU.json b/i18n/translations/ru-RU.json index 1aeff13d9..2a4e4cb60 100644 --- a/i18n/translations/ru-RU.json +++ b/i18n/translations/ru-RU.json @@ -19,7 +19,6 @@ "Anti-glare disabled": "Антиблик отключен", "Anti-glare enabled": "Антиблик включен", "Are you sure?": "Вы уверены?", - "BIP39 Mnemonic": "BIP39 Мнемоника", "Back": "Назад", "Backing up bootloader..\n\n%d%%": "Резервное копирование загрузчика..\n\n%d%%", "Bad signature": "Плохая подпись", @@ -187,7 +186,6 @@ "Scan Key QR code": "Отсканировать Ключ QR код", "Scanning words 1-12 again": "Сканирование слов 1-12 снова", "Scanning words 13-24": "Сканирование слов 13-24", - "Screensaver": "Заставка", "SeedQR": "SeedQR", "Self-transfer or Change (%d): ": "Трансфер самому себе или Сдача (%d): ", "Settings": "Настройки", @@ -232,7 +230,6 @@ "Via D6": "С Помощью D6", "Via Manual Input": "С Помощью Ручного Ввода", "Wait for the capture": "Дождитесь Захвата", - "Wait time": "Время ожидания", "Wallet Descriptor": "Дескриптор Кошелька", "Wallet output descriptor": "Выходной дескриптор кошелька", "Wallet output descriptor loaded!": "Выходной дескриптор кошелька загружен!", diff --git a/i18n/translations/vi-VN.json b/i18n/translations/vi-VN.json index 076b3106c..ce8294faf 100644 --- a/i18n/translations/vi-VN.json +++ b/i18n/translations/vi-VN.json @@ -19,7 +19,6 @@ "Anti-glare disabled": "Chống lóa bị vô hiệu hóa", "Anti-glare enabled": "Đã bật chống lóa", "Are you sure?": "Bạn có chắc không?", - "BIP39 Mnemonic": "Mã mnemonic dạng chuẩn BIP39", "Back": "Trở lại", "Backing up bootloader..\n\n%d%%": "Sao lưu bộ tải khởi động..\n\n%d%%", "Bad signature": "Chữ ký xấu", @@ -187,7 +186,6 @@ "Scan Key QR code": "Quét mã QR khóa", "Scanning words 1-12 again": "Quét lại từ 1-12", "Scanning words 13-24": "Quét từ 13-24", - "Screensaver": "Bảo vệ màn hình", "SeedQR": "SEEDQR", "Self-transfer or Change (%d): ": "Tự chuyển nhượng hoặc Thay đổi (%d): ", "Settings": "Cài đặt", @@ -233,7 +231,6 @@ "Via D6": "Qua D6", "Via Manual Input": "Thông qua đầu vào thủ công", "Wait for the capture": "Chờ bắt", - "Wait time": "Thời gian chờ đợi", "Wallet Descriptor": "Trình mô tả ví", "Wallet output descriptor": "Ví đầu ra mô tả", "Wallet output descriptor loaded!": "Đã tải bộ mô tả đầu ra của ví!", diff --git a/src/krux/translations.py b/src/krux/translations.py index 7d2de0de3..16ef4e2c5 100644 --- a/src/krux/translations.py +++ b/src/krux/translations.py @@ -21,500 +21,495 @@ # THE SOFTWARE. # pylint: disable=C0301 translation_table = { - "de-DE": { - 1185266064: "%d von %d Multisig", - 2004520398: "%d. Change: \n\n%s\n\n", - 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", - 3264377309: "%d. Ausgaben: \n\n%s\n\n", - 2399232215: "%s\n\nist eine gültige Change Adresse!", - 3921290840: "%s\n\nist eine gültige Empfangsadresse!", - 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", - 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", - 3348584292: "(Experimental)", - 2739590230: "12 Wörter", - 1310058127: "24 Wörter", + "nl-NL": { + 1185266064: "%d van %d multisig", + 2004520398: "%d. Wisselgeld: \n\n%s\n\n", + 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", + 3264377309: "%d. Uitgaven: \n\n%s\n\n", + 2399232215: "%s\n\nis een valide wisselgeld adres!", + 3921290840: "%s\n\nis een valide ontvangst adres!", + 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", + 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", + 3348584292: "(Experimenteel)", + 2739590230: "12 woorden", + 1310058127: "24 woorden", 2743272264: "ABC", - 1949634023: "Über", + 1949634023: "Over", 1517128857: "Adafruit", - 3270727197: "Adresse", - 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", - 283202181: "Richte Kamera und Tiny Seed korrekt aus.", - 88746165: "Blendschutz deaktiviert", - 1521033296: "Blendschutz aktiviert", - 1056821534: "Bist Du sicher?", - 3247612282: "BIP39 Mnemonic", - 3455872521: "Zurück", - 2541860807: "Bootloader wird gesichert..\n\n%d%%", - 2256777600: "Ungültige Signatur", - 3937333362: "Baudrate", + 3270727197: "Adres", + 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", + 283202181: "Richt de camera en Tiny Seed op de juiste manier.", + 88746165: "Anti reflecterend uitgeschakeld", + 1521033296: "Anti reflecterend ingeschakeld", + 1056821534: "Weet je het zeker?", + 3455872521: "Terug", + 2541860807: "Backup van de bootloader...\n\n%d%%", + 2256777600: "Ongeldige handtekening", + 3937333362: "Baudratio", 427617266: "Bitcoin", - 928727036: "Randpolsterung", + 928727036: "Rand opvulling", 213030954: "CNC", - 1207696150: "Change Adresse", - 3126552510: "Change Adressen", - 1583186953: "Thema ändern und neu starten?", - 2697733395: "Änderungen auf SD-Karte gespeichert!", - 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", - 3442025874: "Prüfe SD-Karte", - 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", - 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", - 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", - 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", - 2470115694: "Suche nach SD-Karte..", - 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", - 2407028014: "Kompakt SeedQR", - 4041895036: "Weiter?", - 4094072796: "Erstelle QR-Code", - 167798282: "QR-Code aus Text erzeugen?", - 2767642191: "Erstellt:", - 3513215254: "Benutzerdefinierte QR-Code", - 124617190: "Schnitttiefe", - 597912140: "Cut-Methode", - 2504034831: "Dezimal", - 2751113454: "Entschlüsseln?", - 3510912550: "Löschen %s?", - 1016609898: "Datei löschen?", - 1364509700: "Mnemonic löschen", - 4102535566: "Tiefe pro Durchgang", - 2791699253: "Ableitung: %s", - 1230133196: "Geräte-Flash-Speicher nicht erkannt.", - 3836852788: "Fertig?", + 1207696150: "Change", + 3126552510: "Wisselgeldadres", + 1583186953: "Thema veranderen en opnieuw opstarten?", + 2697733395: "Wijzigingen aanhouden op SD kaart!", + 388908871: "Wijzigingen blijven van kracht tot afsluiten.", + 3442025874: "Controleer SD kaart", + 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", + 2856261511: "Na %d geen wisselgeld adressen gevonden.", + 2788541416: "Na %d geen ontvangst adressen gevonden.", + 2446472910: "Wisselgeldadres %d controleren...", + 2470115694: "SD kaart controleren...", + 3655273987: "Ontvangstadres %d controleren...", + 2407028014: "Compact SeedQR", + 4041895036: "Doorgaan?", + 4094072796: "QR code maken", + 167798282: "QR code maken van tekst?", + 2767642191: "Aangemaakt: ", + 3513215254: "Aangepaste QR code", + 124617190: "Snijdiepte", + 597912140: "Snijmethode", + 2504034831: "Decimaal", + 2751113454: "Ontsleutelen?", + 3510912550: "Verwijderen %s?", + 1016609898: "Bestand verwijderen?", + 1364509700: "Geheugensteun verwijderen", + 4102535566: "Diepte per pas", + 2791699253: "Afgeleide: %s", + 1230133196: "Opslag op apparaat is niet gedetecteerd.", + 3836852788: "Klaar?", 382368239: "Driver", 3978947916: "Encoder", - 4090746898: "Encoder-Entprellung", - 374684711: "Verschlüssel Mnemonic", - 1244124409: "Verschlüsselter QR-Code", - 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", - 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", - 350279787: "Verschlüsselung", - 2601598799: "Verschlüsselungsmodus", - 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", - 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", - 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", - 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", - 784361051: "Fehler:\n%s", + 4090746898: "Encoder-debounce", + 374684711: "Geheugensteun versleutelen", + 1244124409: "Versleutelde QR code", + 2968548114: "Versleutelde geheugensteun was niet opgeslagen", + 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", + 350279787: "Versleutelen", + 2601598799: "Versleutel modus", + 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", + 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", + 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", + 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", + 784361051: "Fout:\n%s", 1505332462: "Esc", - 3838465623: "Dateien durchsuchen?", - 4170881190: "Auf SD-Karte exportieren..", - 1711312434: "Öffentlicher Schlüssel", - 383371114: "Entschlüsselung fehlgeschlagen", - 3048830188: "PSBT konnte nicht geladen werden", - 4192663412: "Adresse konnte nicht geladen werden", - 1996021743: "Schlüssel konnte nicht geladen werden", - 1108715658: "Nachricht konnte nicht geladen werden", - 1081425878: "Mnemonic konnte nicht geladen werden", - 928667220: "Ausgabedeskriptor konnte nicht geladen werden", - 1620572516: "Passphrase konnte nicht geladen werden", - 2946146830: "Mnemonic konnte nicht gespeichert werden", - 1303554751: "Gebühr: ", - 104500973: "Vorschubgeschwindigkeit", - 3313339187: "Dateiname", - 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", - 3737729752: "Fingerabdruck: %s", - 2542772894: "Die Firmware übersteigt die maximale Größe: %d", - 1406590538: "Flötendurchmesser", - 3086093110: "Frei: ", - 1893243331: "Vom Speicher", + 3838465623: "Bestanden verkennen?", + 4170881190: "Exporteren naar SD-kaart..", + 1711312434: "Uitgebreide publieke sleutel", + 383371114: "Ontsleutelen is niet gelukt", + 3048830188: "PSBT laden is niet gelukt", + 4192663412: "Adres laden is niet gelukt", + 1996021743: "Sleutel laden is niet gelukt", + 1108715658: "Bericht laden is niet gelukt", + 1081425878: "Geheugensteun laden is niet gelukt", + 928667220: "Descriptor laden is niet gelukt", + 1620572516: "Wachtwoord laden is niet gelukt", + 2946146830: "Geheugensteun opslaan is niet gelukt", + 1303554751: "Tarief: ", + 104500973: "Voedingssnelheid", + 3313339187: "Bestandsnaam", + 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", + 3737729752: "Vingerafdruk: %s", + 2542772894: "Firmware overschrijdt de maximale grootte: %d", + 1406590538: "Fluit diameter", + 3086093110: "Vrij: ", + 1893243331: "Uit data-opslag", 4120536442: "GRBL", - 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", - 602716148: "Go", - 3580020863: "Hex öffentlicher Schlüssel", - 2691246967: "Hexadezimal", - 2736309107: "ID existiert bereits\n", - 1706005805: "Unvollständiger Ausgabedeskriptor", - 631342955: "Input (%d): ", - 2585599782: "Ungültige Adresse", - 2874529150: "Ungültiger Bootloader", - 4093416954: "Ungültige mnemonische Lange", - 1422874211: "Ungültiger öffentlicher Schlüssel", - 2443867979: "Ungültige Wallet:\n%s", - 4122897393: "Umkehren", - 3000888649: "Schlüssel", - 2686333978: "Schlüssel:", - 4123798664: "Krux\n\n\nVersion\n%s", - 3835918229: "Krux Drucker Test-QR", - 766317539: "Sprache", - 972436696: "Leitungsverzögerung", - 3596093890: "Linie: ", - 2820726296: "Mnemonic laden", - 879727077: "Von SD-Karte laden?", - 669106195: "Eine laden?", + 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", + 602716148: "Ga", + 3580020863: "Hex publieke sleutel", + 2691246967: "Hexadecimaal", + 2736309107: "ID bestaat al\n", + 1706005805: "Incomplete portemonnee descriptor", + 631342955: "Invoer (%d): ", + 2585599782: "Ongeldig adres", + 2874529150: "Ongeldige bootloader", + 4093416954: "Ongeldige geheugensteun lengte", + 1422874211: "Ongeldige publieke sleutel", + 2443867979: "Ongeldige portemonnee:\n%s", + 4122897393: "Omkeren", + 3000888649: "Sleutel", + 2686333978: "Sleutel: ", + 4123798664: "Krux\n\n\nVersie\n%s", + 3835918229: "Krux printer test QR", + 766317539: "Taal", + 972436696: "Lijn vertraging", + 3596093890: "Lijn: ", + 2820726296: "Geheugensteun laden", + 879727077: "Laden vanaf SD-kaart?", + 669106195: "Laden?", 3330705289: "Laden?", - 2596531078: "Lade Kamera..", - 596389387: "Lade Change Adresse %d..", - 336702608: "Drucker wird geladen..", - 2538883522: "Lade Empfangsadresse %d..", - 3159494909: "Wird geladen..", - 1177338798: "Spracheinstellung", - 2817059741: "Speicherort", - 63976957: "Log Level", - 86530918: "Logging", - 2917810189: "Maximale Länge überschritten (%s)", - 2030045667: "Nachricht", - 3928301843: "Fehlende Signaturdatei", - 1948316555: "Mnemonic", - 2123991188: "Mnemonische ID", - 3911073154: "Mnemonische Speicher-ID", - 570639842: "Mnemonic wurde nicht entschlüsselt", - 1746030071: "Mnemonic wurde nicht verschlüsselt", - 1458925155: "Geändert:", + 2596531078: "Camera laden...", + 596389387: "Wisselgeldadres %d laden...", + 336702608: "Laadprinter..", + 2538883522: "Ontvangstadres %d laden...", + 3159494909: "Laden...", + 1177338798: "Taal", + 2817059741: "Opslaglocatie", + 63976957: "Log niveau", + 86530918: "Debug logs", + 2917810189: "Maximale lengte overschreden (%s)", + 2030045667: "Bericht", + 3928301843: "Handtekening bestand mist", + 1948316555: "Geheugensteun", + 2123991188: "Geheugensteun ID", + 3911073154: "Geheugensteun opslag ID", + 570639842: "Geheugensteun is niet ontsleuteld", + 1746030071: "Geheugensteun is niet versleuteld", + 1458925155: "Aangepast: ", 1845376098: "Multisig", - 2939797024: "Netzwerk", - 73574491: "Neue Mnemonic", - 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", - 4063104189: "Nein", - 3927838899: "Keine BIP39 Passphrase", - 4092516657: "Nicht genug Würfe!", - 1577637745: "Oktal", - 3312581301: "PBKDF2-Iter.", + 2939797024: "Netwerk", + 73574491: "Geheugensteun aanmaken", + 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", + 4063104189: "Nee", + 3927838899: "Geen BIP-39 wachtwoord", + 4092516657: "Niet genoeg gedobbeld!", + 1577637745: "Octaal", + 3312581301: "PBKDF2 iter.", 721090621: "PSBT", - 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", - 2987800462: "Papierbreite", - 3050763890: "Teil\n%d / %d", - 3559456868: "Teilegröße", - 4249903283: "Passphrase", - 3712257341: "Passphrase:", - 140802882: "Speicher", - 1703779997: "Klartext-QR", - 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", - 784609464: "Tauchrate", - 3037062877: "Drucke Test-QR", - 4278257699: "Als QR-Code drucken?\n\n%s\n\n", - 516488026: "Drucken?\n\n%s\n\n", - 1123106929: "Drucker", - 3903571079: "Druckertreiber nicht gesetzt!", - 2609799302: "Drucken\n%d / %d", - 844861889: "Wird gedruckt ...", - 2580599003: "Weiter?", - 556126964: "Wird bearbeitet ...", - 1848310591: "QR-Code", - 710709610: "RX Pin", - 2697857197: "Empfangen", - 1746677167: "Empfangsadresse", - 364354944: "Region: ", - 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", - 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", - 856795528: "Würfe:\n\n%s", - 255086803: "Würfe: %d\n", - 3976793317: "SD-Karte", - 2827687530: "SD-Karte nicht erkannt", - 2736513298: "SD-Karte nicht erkannt.", - 3593785196: "SHA256 der Würfe:\n\n%s", - 1143278725: "SHA256 des Snapshots:\n\n%s", + 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", + 2987800462: "Papier breedte", + 3050763890: "Deel\n%d / %d", + 3559456868: "Deel grootte", + 4249903283: "Wachtwoord", + 3712257341: "Wachtwoord: ", + 140802882: "Opslag", + 1703779997: "Platte tekst QR", + 3561756278: "Laadt een portemonnee descriptor in", + 784609464: "Duik tarief", + 3037062877: "Test QR afdrukken", + 4278257699: "Afdrukken naar QR?\n\n%s\n\n", + 516488026: "Afdrukken?\n\n%s\n\n", + 1123106929: "Printer", + 3903571079: "Printer driver niet ingesteld!", + 2609799302: "Afdruk\n%d / %d", + 844861889: "Afdrukken...", + 2580599003: "Doorgaan?", + 556126964: "Verwerken...", + 1848310591: "QR code", + 710709610: "RX pin", + 2697857197: "Ontvangen", + 1746677167: "Ontvangstadres", + 364354944: "Regio: ", + 1662254634: "Controleer gescande gegevens en bewerk indien nodig", + 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", + 856795528: "Gedobbeld:\n\n%s", + 255086803: "Gedobbeld: %d\n", + 3976793317: "SD kaart", + 2827687530: "SD kaart niet gedetecteerd", + 2736513298: "SD kaart niet gedetecteerd.", + 3593785196: "Gedobbelde SHA256:\n\n%s", + 1143278725: "Momentopname van SHA256:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Auf SD-Karte speichern?", - 810036588: "Auf SD-Karte gespeichert:\n%s", - 763824768: "Skala", - 4117455079: "Adresse\nscannen", - 3219991109: "Scan BIP39 Passphrase", - 2537207336: "Schlüssel QR-Code scannen", - 4006316572: "Wörter 1-12 erneut scannen", - 2736506158: "Wörter 13-24 scannen", - 3593497655: "Bildschirmschoner", + 3531742595: "Opslaan op SD-kaart?", + 810036588: "Opgeslagen op SD-kaart:\n%s", + 763824768: "Schaal", + 4117455079: "Adres scannen", + 3219991109: "BIP-39 wachtwoord scannen", + 2537207336: "QR code sleutel scannen", + 4006316572: "Woorden 1 t/m 12 opnieuw scannen", + 2736506158: "Woorden 13 t/m 24 scannen", 266935239: "SeedQR", - 1698829144: "Selbstübertragung oder Change (%d): ", - 473154195: "Einstellungen", - 1825881236: "Ausschalten", - 2120776272: "Herunterfahren..", - 1061961408: "Signieren", - 4282338366: "Signieren?", - 746161122: "Signatur", - 1988416729: "Signierte Nachricht", - 3672006076: "Signierte PSBT", - 2281377987: "Single-Sig", - 4221794628: "Größe: ", - 2344747135: "Einige Schecks können nicht durchgeführt werden.", - 2309020186: "Ausgabe (%d): ", + 1698829144: "Zelf overschrijving of wisselgeld (%d): ", + 473154195: "Instellingen", + 1825881236: "Afsluiten", + 2120776272: "Bezig met afsluiten...", + 1061961408: "Ondertekenen", + 4282338366: "Ondertekenen?", + 746161122: "Handtekening", + 1988416729: "Bericht ondertekend", + 3672006076: "PSBT ondertekend", + 2281377987: "Enkele sleutel", + 4221794628: "Grootte: ", + 2344747135: "Sommige controles kunnen niet worden uitgevoerd.", + 2309020186: "Uitgaven (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Auf Flash speichern", - 720041451: "Auf der SD-Karte speichern", - 3514476519: "Wischen um den Modus zu ändern", - 1898550184: "TOUCH oder ENTER zum Erfassen", - 4228215415: "TX Pin", - 2612594937: "Text", + 3303592908: "Opslaan op apparaat", + 720041451: "Opslaan op SD kaart", + 3514476519: "Verander modus", + 1898550184: "TIK of ENTER voor opname", + 4228215415: "TX pin", + 2612594937: "Tekst", 1454688268: "Thema", 1180180513: "Thermisch", 4119292117: "Tiny Seed", 1732872974: "Tiny Seed (Bits)", - 725348723: "Werkzeuge", - 3684696112: "Berühre Schwellenwert", - 2978718564: "Touchscreen", - 2732611775: "Weiter versuchen?", - 1487826746: "BIP39 Passphrase eingeben", - 2061556020: "Schlüssel eingeben", - 2089395053: "Einheit", - 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", - 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", - 2736001501: "Firmware wird aktualisiert..\n\n%d%%", - 2674953168: "Verwende eine schwarze Hintergrundfläche.", - 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", - 236075140: "Belegt: ", - 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", - 989428076: "Der Wert muss ein Vielfaches von %s sein", - 4191058607: "Via Kamera", + 725348723: "Hulpmiddelen", + 3684696112: "Aanraak gevoeligheid", + 2978718564: "Aanraakscherm", + 2732611775: "Meer proberen?", + 1487826746: "Voer BIP-39 wachtwoord in", + 2061556020: "Voer sleutel in", + 2089395053: "Eenheid", + 2845607430: "Bootloader updaten...\n\n%d%%", + 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", + 2736001501: "Firmware upgraden...\n\n%d%%", + 2674953168: "Gebruik een donker achergrond.", + 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", + 236075140: "Gebruikt: ", + 4003084591: "Waarde %s is buiten bereik: [%s, %s]", + 989428076: "Waarde moet meerdere van %s zijn", + 4191058607: "Via camera", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Via manueller Eingabe", - 2504354847: "Warte auf die Erfassung", - 3992434312: "Wartezeit", - 2297028319: "Wallet-Deskriptor", - 4232654916: "Wallet Ausgabedeskriptor", - 2587172867: "Wallet Ausgabedeskriptor geladen!", - 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", - 2671738224: "Warnung:", - 797660533: "Wort %d", - 3742424146: "Wortnummern", - 2965123464: "Wörter", - 1303016265: "Ja", - 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", - 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", + 590330112: "Via handmatige invoer", + 2504354847: "Wacht op opname", + 2297028319: "Descriptor", + 4232654916: "Portemonnee descriptor", + 2587172867: "Portemonnee descriptor geladen!", + 2499782468: "Portemonnee descriptor niet gevonden.", + 2671738224: "Waarschuwing:", + 797660533: "Woord %d", + 3742424146: "Woord nummers", + 2965123464: "Woorden", + 1303016265: "Yes", + 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", + 2569054451: "Veranderingen worden opgeslagen op SD kaart.", }, - "es-MX": { - 1185266064: "%d de %d multisig", - 2004520398: "%d. Cambio: \n\n%s\n\n", - 3862364126: "%d. Autotransferencia: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n¡es una dirección de cambio válida!", - 3921290840: "%s\n\nes un dirección de depósito válido!", - 1808355833: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de cambio", - 1306127065: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de depósito", - 3348584292: "(Experimental)", - 2739590230: "12 palabras", - 1310058127: "24 palabras", + "vi-VN": { + 1185266064: "%d của %d đa chữ kí", + 2004520398: "%d. Thay đổi: \n\n%s\n\n", + 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", + 3264377309: "%d. Chi tiêu: \n\n%s\n\n", + 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", + 3921290840: "%s\n\nlà một địa chỉ khả dụng!", + 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", + 3348584292: "(Thực nghiệm)", + 2739590230: "12 từ", + 1310058127: "24 từ", 2743272264: "ABC", - 1949634023: "Nosotros", + 1949634023: "Về chúng tôi", 1517128857: "Adafruit", - 3270727197: "Dirección", - 2574498267: "Entropía adicional desde la cámara requerida para el modo AES-CBC", - 283202181: "Alinee la cámara y Tiny Seed correctamente.", - 88746165: "Antideslumbrante desactivado", - 1521033296: "Antideslumbrante habilitado", - 1056821534: "¿Estas seguro?", - 3247612282: "BIP39 Mnemónico", - 3455872521: "Atrás", - 2541860807: "Copia de seguridad del cargador de arranque..\n\n%d%%", - 2256777600: "Mala asignatura", - 3937333362: "Velocidad en baudios", + 3270727197: "Địa chỉ", + 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", + 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", + 88746165: "Chống lóa bị vô hiệu hóa", + 1521033296: "Đã bật chống lóa", + 1056821534: "Bạn có chắc không?", + 3455872521: "Trở lại", + 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", + 2256777600: "Chữ ký xấu", + 3937333362: "Tốc độ baud", 427617266: "Bitcoin", - 928727036: "Relleno de borde", + 928727036: "Đệm viền", 213030954: "CNC", - 1207696150: "Cambio", - 3126552510: "Direcciones de Cambio", - 1583186953: "Cambiar de tema y reiniciar?", - 2697733395: "¡Cambios guardados en la tarjeta SD!", - 388908871: "Los cambios durarán hasta que se apague.", - 3442025874: "Verifique la tarjeta SD", - 3119547911: "¿Compruebe que la dirección pertenece a esta cartera?", - 2856261511: "La dirección de cambio %d no coincide.", - 2788541416: "Comprobado %d dirección de depósito sin coincidencias.", - 2446472910: "Verificación de coincidencia de dirección de cambio %d ..", - 2470115694: "Comprobación de la tarjeta SD..", - 3655273987: "Comprobando la dirección de depósito %d para alguna coincidencia..", - 2407028014: "SeedQR Compacto", - 4041895036: "¿Continuar?", - 4094072796: "Crear código QR", - 167798282: "¿Crear código QR desde el texto?", - 2767642191: "Creado: ", - 3513215254: "Código QR personalizado", - 124617190: "Profundidad de corte", - 597912140: "Método de corte", - 2504034831: "Decimal", - 2751113454: "Descifrar?", - 3510912550: "Eliminar %s?", - 1016609898: "¿Borrar archivo?", - 1364509700: "Eliminar mnemónico", - 4102535566: "Profundidad por pasada", - 2791699253: "Derivación: %s", - 1230133196: "Almacenamiento flash del dispositivo no detectado.", - 3836852788: "¿Listo?", - 382368239: "Operador", - 3978947916: "Codificador", - 4090746898: "Antirrebote del codificador", - 374684711: "Cifrado mnemónico", - 1244124409: "Código QR cifrado", - 2968548114: "Mnemonic cifrado no se almacenó", - 3315319371: "Mnemónica cifrada fue almacenada con ID:", - 350279787: "Encriptación", - 2601598799: "Modo de encriptación", - 3504179008: "Ingrese cada palabra de su mnemónico BIP-39 como un número del 1 al 2048.", - 1100685007: "Ingrese cada palabra de su mnemónico BIP-39 como un número en hexadecimal del 1 al 800.", - 4090266642: "Ingrese cada palabra de su mnemónico BIP-39 como un número en octal del 1 al 4000.", - 2780625730: "Ingrese cada palabra de su mnemónico BIP-39.", - 784361051: "Error:\n%s", + 1207696150: "Thay đổi", + 3126552510: "Thay địa chỉ", + 1583186953: "Thay đổi chủ đề và khởi động lại?", + 2697733395: "Thay đổi được lưu trên thẻ SD!", + 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", + 3442025874: "Kiểm tra thẻ SD", + 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", + 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", + 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", + 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", + 2470115694: "Kiểm tra thẻ SD..", + 3655273987: "Đang kiểm tra %d địa chỉ..", + 2407028014: "SeedQR nhỏ gọn", + 4041895036: "Tiếp tục?", + 4094072796: "Tạo mã QR", + 167798282: "Tạo mã QR từ văn bản?", + 2767642191: "Tạo:", + 3513215254: "Mã QR tùy chỉnh", + 124617190: "Chiều sâu cắt", + 597912140: "Phương pháp cắt", + 2504034831: "Số thập phân", + 2751113454: "Phản đối?", + 3510912550: "Xóa %s?", + 1016609898: "Xóa tài liệu?", + 1364509700: "Xóa ghi nhớ", + 4102535566: "Độ sâu mỗi lần vượt qua", + 2791699253: "Nguồn gốc: %s", + 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", + 3836852788: "Hoàn tất?", + 382368239: "Người cầm lái", + 3978947916: "Mã hoá", + 4090746898: "Gỡ lỗi bộ mã hóa", + 374684711: "Mã hóa Mnemonic", + 1244124409: "Mã QR được mã hóa", + 2968548114: "MNemon được mã hóa không được lưu trữ", + 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", + 350279787: "Mã hóa", + 2601598799: "Chế độ mã hóa", + 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", + 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", + 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", + 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", + 784361051: "Lỗi:\n%s", 1505332462: "Esc", - 3838465623: "Explorar archivos?", - 4170881190: "Exportando a la tarjeta SD..", - 1711312434: "Llave Pública", - 383371114: "No se descife", - 3048830188: "No se puede cargar la PSBT", - 4192663412: "No se puede cargar la address", - 1996021743: "No se pudo cargar la clave", - 1108715658: "No se pudo cargar el mensaje", - 1081425878: "No se puede cargar la mnemotécnica", - 928667220: "No se pudo cargar el descriptor de salida", - 1620572516: "No se pudo cargar frase de pases", - 2946146830: "No pudo almacenar mnemonic", - 1303554751: "Comisión: ", - 104500973: "Tasa de alimentación", - 3313339187: "Nombre del archivo", - 1982637349: "El nombre de archivo %s existe en la tarjeta SD, ¿sobrescribir?", - 3737729752: "Huella Dactilar: %s", - 2542772894: "El firmware supera el tamaño máximo: %d", - 1406590538: "Diámetro de la flauta", - 3086093110: "Libre: ", - 1893243331: "Desde el almacenamiento", + 3838465623: "Khám phá các tập tin?", + 4170881190: "Xuất vào thẻ SD ..", + 1711312434: "Khóa công cộng", + 383371114: "Không giải mã được", + 3048830188: "Tải PSBT thất bại", + 4192663412: "Tải địa chỉ thất bại", + 1996021743: "Không tải khóa", + 1108715658: "Không tải được tin nhắn", + 1081425878: "Tải mã mnemonic thất bại", + 928667220: "Không thể tải bộ mô tả đầu ra", + 1620572516: "Không tải được cụm mật khẩu", + 2946146830: "Không lưu trữ MNemonic", + 1303554751: "Phí: ", + 104500973: "Tỷ lệ thức ăn", + 3313339187: "Tên tệp", + 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", + 3737729752: "Dấu vân tay: %s", + 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", + 1406590538: "Đường kính ống sáo", + 3086093110: "Khả dụng: ", + 1893243331: "Từ lưu trữ", 4120536442: "GRBL", - 299338213: "¿Darle a este mnemónico una identificación personalizada?De lo contrario se utilizará la huella digital actual", - 602716148: "Ir", - 3580020863: "Clave pública hexadecimal", - 2691246967: "Hexadecimal", - 2736309107: "ID ya existe\n", - 1706005805: "Descriptor incompleto", - 631342955: "Entradas (%d): ", - 2585599782: "Dirección inválida", - 2874529150: "Cargador de arranque inválido", - 4093416954: "Longitud mnemotécnica no válida", - 1422874211: "Tecla pública inválida", - 2443867979: "Cartera inválida:\n%s", - 4122897393: "Invertir", - 3000888649: "Clave", - 2686333978: "Clave:", - 4123798664: "Krux\n\n\nVersión\n%s", - 3835918229: "Prueba de impresora Krux QR", - 766317539: "Idioma", - 972436696: "Retraso de línea", - 3596093890: "Línea: ", - 2820726296: "Cargar el mnemónico", - 879727077: "¿Cargar desde la tarjeta SD?", - 669106195: "¿Cargar algo?", - 3330705289: "¿Cargar?", - 2596531078: "Cargando Camara..", - 596389387: "Cargando dirección de cambio %d..", - 336702608: "Cargando impresora..", - 2538883522: "Cargando dirección de recepción %d..", - 3159494909: "Cargando..", - 1177338798: "Idioma", - 2817059741: "Ubicación", - 63976957: "Nivel de registro", - 86530918: "Registro", - 2917810189: "Longitud máxima excedida (%s)", - 2030045667: "Mensaje", - 3928301843: "Falta de firma faltante", - 1948316555: "Mnemotécnica", - 2123991188: "Identificación de lo mnemónico", - 3911073154: "ID de almacenamiento mnemónico", - 570639842: "Mnemonic no fue descifrado", - 1746030071: "Mnemonic no fue descifrado", - 1458925155: "Modificado: ", - 1845376098: "Multisig", - 2939797024: "La red", - 73574491: "Nuevo Mnemónico", - 2792272353: "Nuevo firmware detectado.\n\nSHA256:\n%s\n\n\n\n¿Instalar?", - 4063104189: "No", - 3927838899: "Sin frase de contraseña BIP39", - 4092516657: "¡No hay suficientes rollos!", - 1577637745: "Octales", - 3312581301: "Iter. PBKDF2", + 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", + 602716148: "Đến", + 3580020863: "Khóa công khai Hex", + 2691246967: "Thập lục phân", + 2736309107: "Id đã tồn tại\n", + 1706005805: "Bộ mô tả đầu ra chưa hoàn chỉnh", + 631342955: "Đầu vào (%d): ", + 2585599782: "Địa chỉ không hợp lệ", + 2874529150: "Bộ tải khởi động không hợp lệ", + 4093416954: "Độ dài mã mnemonic không hợp lệ", + 1422874211: "Khóa công khai không hợp lệ", + 2443867979: "Ví không hợp lệ:\n%s", + 4122897393: "Đảo ngược", + 3000888649: "Chìa khóa", + 2686333978: "Chìa khóa:", + 4123798664: "Krux\n\n\nPhiên Bản\n%s", + 3835918229: "QR kiểm tra máy in Krux", + 766317539: "Ngôn ngữ", + 972436696: "Độ trễ Dòng", + 3596093890: "Đường kẻ: ", + 2820726296: "Tải mã mnemonic", + 879727077: "Tải từ thẻ SD?", + 669106195: "Tải một?", + 3330705289: "Tải?", + 2596531078: "Đang tải máy ảnh..", + 596389387: "Đang tải thay đổi địa chỉ %d..", + 336702608: "Tải máy in ..", + 2538883522: "Đang tải địa chỉ nhận %d..", + 3159494909: "Đang tải..", + 1177338798: "Ngôn ngữ", + 2817059741: "Vị trí cửa hàng", + 63976957: "Log Level", + 86530918: "Khai thác gỗ", + 2917810189: "Chiều dài tối đa vượt quá (%s)", + 2030045667: "Tin nhắn", + 3928301843: "Thiếu tập tin chữ ký", + 1948316555: "Mã mnemonic", + 2123991188: "ID ghi nhớ", + 3911073154: "ID lưu trữ ghi nhớ", + 570639842: "Ghi nhớ không được giải mã", + 1746030071: "Ghi nhớ không được mã hóa", + 1458925155: "Đã sửa đổi:", + 1845376098: "Đa chữ kí", + 2939797024: "Mạng lưới", + 73574491: "Mnemonic mới", + 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", + 4063104189: "Không", + 3927838899: "Không có cụm mật khẩu BIP39", + 4092516657: "Không đủ cuộn!", + 1577637745: "Bát phân", + 3312581301: "Lặp lại PBKDF2", 721090621: "PSBT", - 995862913: "Pinte los puntos perforados de negro para que puedan ser detectados.", - 2987800462: "Ancho del papel", - 3050763890: "Parte\n%d / %d", - 3559456868: "Tamaño de la pieza", - 4249903283: "Contraseña", - 3712257341: "Frase de pases:", - 140802882: "Salvar", - 1703779997: "QR de Texto", - 3561756278: "Cargue un descriptor de billetera", - 784609464: "Tasa de caída", - 3037062877: "Prueba de impresión QR", - 4278257699: "¿Imprimir con Codigo QR?\n\n%s\n\n", - 516488026: "¿Impresión?\n\n%s\n\n", - 1123106929: "Impresora", - 3903571079: "¡El controlador de impresora no está configurado!", - 2609799302: "Imprimiendo\n%d / %d", - 844861889: "Imprimiendo ...", - 2580599003: "¿Continuar?", - 556126964: "Procesando ...", - 1848310591: "Código QR", - 710709610: "RX Alfiler", - 2697857197: "Recepción", - 1746677167: "Direcciones de Recepción", - 364354944: "Región: ", - 1662254634: "Revise los datos escaneados, edítelos si es necesario", - 770350922: "Tira el dado al menos %d veces para generar un mnemotécnico.", - 856795528: "Rollos:\n\n%s", - 255086803: "Rollos: %d\n", - 3976793317: "Tarjeta SD", - 2827687530: "Tarjeta SD no detectada", - 2736513298: "Tarjeta SD no detectada.", - 3593785196: "SHA256 de rollos:\n\n%s", - 1143278725: "SHA256 de la instantánea:\n\n%s", + 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", + 2987800462: "Chiều rộng giấy", + 3050763890: "Phần\n%d / %d", + 3559456868: "Kích thước một phần", + 4249903283: "Cụm mật khẩu", + 3712257341: "Cụm cụm:", + 140802882: "Vị trí lưu", + 1703779997: "Văn bản rõ QR", + 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", + 784609464: "Tỷ lệ sụt giảm", + 3037062877: "In kiểm tra QR", + 4278257699: "In ra mã QR?\n\n%s\n\n", + 516488026: "In?\n\n%s\n\n", + 1123106929: "Máy in", + 3903571079: "Trình điều khiển máy in không đặt!", + 2609799302: "Đang in\n%d / %d", + 844861889: "In ấn ...", + 2580599003: "Thực hiện?", + 556126964: "Xử lý ...", + 1848310591: "Mã QR", + 710709610: "RX Ghim", + 2697857197: "Nhận được", + 1746677167: "Nhận địa chỉ", + 364354944: "Vùng: ", + 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", + 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", + 856795528: "Súc sắc cuộn:\n\n%s", + 255086803: "Súc sắc cuộn: %d\n", + 3976793317: "Thẻ SD", + 2827687530: "Thẻ SD không được phát hiện", + 2736513298: "Thẻ SD không được phát hiện.", + 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", + 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "¿Guardar en la tarjeta SD?", - 810036588: "Guardado en la tarjeta SD:\n%s", - 763824768: "Escala", - 4117455079: "Escanear Dirección", - 3219991109: "Escanear frase de pases BIP39", - 2537207336: "Escanear el código QR", - 4006316572: "Escaneo de palabras 1-12 de nuevo", - 2736506158: "Escaneo de palabras 13-24", - 3593497655: "Protector de pantalla", - 266935239: "Seedqr", - 1698829144: "Autotransferencia o Cambio (%d): ", - 473154195: "Ajustes", - 1825881236: "Apagar", - 2120776272: "Apagando..", - 1061961408: "Firmar", - 4282338366: "¿Firmar?", - 746161122: "Firma", - 1988416729: "Mensaje firmado", - 3672006076: "PSBT firmado", - 2281377987: "Single-sig", - 4221794628: "Espacio: ", - 2344747135: "No se pueden realizar algunos cheques.", - 2309020186: "Gastos (%d): ", + 3531742595: "Lưu vào thẻ SD?", + 810036588: "Đã lưu vào thẻ SD:\n%s", + 763824768: "Cái cân", + 4117455079: "Quét địa chỉ", + 3219991109: "Quét BIP39 Cụm cụm", + 2537207336: "Quét mã QR khóa", + 4006316572: "Quét lại từ 1-12", + 2736506158: "Quét từ 13-24", + 266935239: "SEEDQR", + 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", + 473154195: "Cài đặt", + 1825881236: "Tắt", + 2120776272: "Đang tắt..", + 1061961408: "Chữ kí", + 4282338366: "Kí?", + 746161122: "Chữ ký", + 1988416729: "Tin nhắn đã ký", + 3672006076: "Đã ký PSBT", + 2281377987: "Khóa đơn", + 4221794628: "Dung lượng: ", + 2344747135: "Một số kiểm tra không thể được thực hiện.", + 2309020186: "Chi tiêu (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Almacenar en flash", - 720041451: "Almacenar en la tarjeta SD", - 3514476519: "Deslizar para cambiar de modo", - 1898550184: "TOQUE o ENTER para capturar", - 4228215415: "TX Alfiler", - 2612594937: "Texto", - 1454688268: "Tema", - 1180180513: "Térmico", + 3303592908: "Lưu trữ trên flash", + 720041451: "Lưu trữ trên thẻ SD", + 3514476519: "Vuốt để thay đổi chế độ", + 1898550184: "TOUCH hoặc ENTER để chụp", + 4228215415: "TX Ghim", + 2612594937: "Chữ", + 1454688268: "Chủ đề", + 1180180513: "Nhiệt", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Herramientas", - 3684696112: "Umbral Táctil", - 2978718564: "Pantalla táctil", - 2732611775: "¿Intentar con mas?", - 1487826746: "Escriba la frase de pases BIP39", - 2061556020: "Introduzca la clave", - 2089395053: "Unidad", - 2845607430: "Actualización de Bootloader..\n\n%d%%", - 4164597446: "Actualización completa.\n\nApagando..", - 2736001501: "Actualización de firmware..\n\n%d%%", - 2674953168: "Use una superficie de fondo negra.", - 2402455261: "Use la entropía de la cámara para crear una nueva mnemónica", - 236075140: "Usado: ", - 4003084591: "Valor %s fuera del rango: [ %s, %s]", - 4191058607: "Vía cámara", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Mediante entrada manual", - 2504354847: "Espera la captura", - 3992434312: "Tiempo de espera", - 2297028319: "Descriptor de Cartera", - 4232654916: "Descriptor de salida de billetera", - 2587172867: "¡Se ha cargado el descriptor de salida de la cartera!", - 2499782468: "No se encontró el descriptor de salida de la cartera.", - 2671738224: "Advertencia:", - 797660533: "Palabra %d", - 3742424146: "Números de palabra", - 2965123464: "Palabras", - 1303016265: "Sí", - 771968845: "Sus cambios se guardarán en el almacenamiento flash del dispositivo.", - 2569054451: "Sus cambios se guardarán en la tarjeta SD.", + 1732872974: "Tiny Seed (bit)", + 725348723: "Công cụ", + 3684696112: "Ngưỡng cảm ứng", + 2978718564: "Màn hình cảm ứng", + 2732611775: "Thử thêm nữa?", + 1487826746: "Nhập cụm BIP39", + 2061556020: "Nhập khóa", + 2089395053: "Đơn vị", + 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", + 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", + 2736001501: "Nâng cấp firmware..\n\n%d%%", + 2674953168: "Sử dụng bề mặt nền đen.", + 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", + 236075140: "Đã sử dụng: ", + 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", + 989428076: "Giá trị phải là bội của %s", + 4191058607: "Qua máy ảnh", + 1254681955: "Qua D20", + 525309547: "Qua D6", + 590330112: "Thông qua đầu vào thủ công", + 2504354847: "Chờ bắt", + 2297028319: "Trình mô tả ví", + 4232654916: "Ví đầu ra mô tả", + 2587172867: "Đã tải bộ mô tả đầu ra của ví!", + 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", + 2671738224: "Cảnh báo:", + 797660533: "Kí tự %d", + 3742424146: "Từ số", + 2965123464: "Từ ngữ", + 1303016265: "Đúng", + 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", + 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", }, "fr-FR": { 1185266064: "%d de %d multisignature", @@ -537,7 +532,6 @@ 88746165: "Anti-éblouissement désactivé", 1521033296: "Anti-éblouissement activé", 1056821534: "Es-tu sûr?", - 3247612282: "BIP39 Mnémonique", 3455872521: "Retour", 2541860807: "Sauvegarde du chargeur de démarrage..\n\n%d%%", 2256777600: "Mauvaise signature", @@ -644,7 +638,7 @@ 2817059741: "Emplacement", 63976957: "Niveau de journalisation", 86530918: "Enregistrement", - 2917810189: "Longueur maximale dépassée (% s)", + 2917810189: "Longueur maximale dépassée (%s)", 2030045667: "Message", 3928301843: "Fichier de signature manquant", 1948316555: "Mnémonique", @@ -695,7 +689,7 @@ 2827687530: "Carte SD non détectée", 2736513298: "Carte SD non détectée.", 3593785196: "SHA256 de rouleaux:\n\n%s", - 1143278725: "Sha256 de Snapshot:\n\n% s", + 1143278725: "Sha256 de Snapshot:\n\n%s", 3338679392: "SHA256:\n%s", 3531742595: "Enregistrer sur la carte SD ?", 810036588: "Enregistré sur la carte SD :\n%s", @@ -705,7 +699,6 @@ 2537207336: "Scanner le code QR de la clé", 4006316572: "Analyser à nouveau les mots 1 à 12", 2736506158: "Analyser les mots 13 à 24", - 3593497655: "Économiseur d'écran", 266935239: "Seedqr", 1698829144: "Auto-transfert ou changement (%d): ", 473154195: "Paramètres", @@ -744,271 +737,513 @@ 2674953168: "Utilisez une surface de fond noire.", 2402455261: "Utilisez l'entropie de la caméra pour créer un nouveau mnémonique", 236075140: "Utilisé: ", - 4003084591: "Valeur% s hors de portée: [% s,% s]", + 4003084591: "Valeur %s hors de portée: [%s, %s]", + 989428076: "La valeur doit être un multiple de %s", 4191058607: "Par caméra", 1254681955: "Via D20", 525309547: "Via D6", - 590330112: "Par saisie manuelle", - 2504354847: "Attendez la capture", - 3992434312: "Temps d'attente", - 2297028319: "Descripteur de Portefeuille", - 4232654916: "Descripteur de sortie du portefeuille", - 2587172867: "Descripteur de sortie du portefeuille chargé!", - 2499782468: "Descripteur de sortie du portefeuille introuvable.", - 2671738224: "Avertissement:", - 797660533: "Mot %d", - 3742424146: "Numéros de mots", - 2965123464: "Mots", - 1303016265: "Oui", - 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", - 2569054451: "Vos modifications seront conservées sur la carte SD.", + 590330112: "Par saisie manuelle", + 2504354847: "Attendez la capture", + 2297028319: "Descripteur de Portefeuille", + 4232654916: "Descripteur de sortie du portefeuille", + 2587172867: "Descripteur de sortie du portefeuille chargé!", + 2499782468: "Descripteur de sortie du portefeuille introuvable.", + 2671738224: "Avertissement:", + 797660533: "Mot %d", + 3742424146: "Numéros de mots", + 2965123464: "Mots", + 1303016265: "Oui", + 771968845: "Vos modifications seront conservées sur le stockage flash de l'appareil.", + 2569054451: "Vos modifications seront conservées sur la carte SD.", + }, + "pt-BR": { + 1185266064: "%d da %d multisig", + 2004520398: "%d. Troco: \n\n%s\n\n", + 3862364126: "%d. Autotransferência: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n é um endereço de troco válido!", + 3921290840: "%s\n\né um endereço de recepção válido!", + 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", + 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", + 3348584292: "(Experimental)", + 2739590230: "12 palavras", + 1310058127: "24 palavras", + 2743272264: "ABC", + 1949634023: "Sobre", + 1517128857: "Adafruit", + 3270727197: "Endereço", + 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", + 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", + 88746165: "Antirreflexo desativado", + 1521033296: "Antirreflexo ativado", + 1056821534: "Tem certeza?", + 3455872521: "Voltar", + 2541860807: "Backing up bootloader..\n\n%d%%", + 2256777600: "Assinatura Inválida", + 3937333362: "Baudrate", + 427617266: "Bitcoin", + 928727036: "Borda", + 213030954: "CNC", + 1207696150: "Troco", + 3126552510: "Endereços de Troco", + 1583186953: "Mudar o tema e reiniciar?", + 2697733395: "Mudanças salvas no cartão SD!", + 388908871: "Alterações só durarão até o desligamento.", + 3442025874: "Verifique o cartão SD", + 3119547911: "Verificar se este endereço pertence a carteira?", + 2856261511: "Endereço de troco %d não corresponde.", + 2788541416: "Endereço de recebimento %d não corresponde.", + 2446472910: "Verificando correspondência do endereço de troco %d ..", + 2470115694: "Verificando o cartão SD..", + 3655273987: "Verificando correspondência do endereço de recebimento %d ..", + 2407028014: "SeedQR Compacto", + 4041895036: "Continuar?", + 4094072796: "Gerar Código QR", + 167798282: "Gerar código QR do texto?", + 2767642191: "Criado: ", + 3513215254: "Código QR Customizado", + 124617190: "Profundidade de Corte", + 597912140: "Método de Corte", + 2504034831: "Decimal", + 2751113454: "Descriptografar?", + 3510912550: "Excluir %s?", + 1016609898: "Excluir Arquivo?", + 1364509700: "Excluir Mnemônico", + 4102535566: "Profundidade da Passagem", + 2791699253: "Derivação: %s", + 1230133196: "Armazenamento flash do dispositivo não detectado.", + 3836852788: "Feito?", + 382368239: "Driver", + 3978947916: "Codificador", + 4090746898: "Debounce do Encoder", + 374684711: "Criptografar Mnemônico", + 1244124409: "Código QR Criptografado", + 2968548114: "Mnemonic criptografado não foi armazenado", + 3315319371: "Mnemônico criptografado foi armazenado com ID:", + 350279787: "Criptografia", + 2601598799: "Modo de Criptografia", + 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", + 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", + 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", + 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", + 784361051: "Erro:\n%s", + 1505332462: "Esc", + 3838465623: "Explorar arquivos?", + 4170881190: "Exportando para o cartão SD..", + 1711312434: "Chave Pública Estendida", + 383371114: "Falhou em descriptografar", + 3048830188: "Falhou ao carregar PSBT", + 4192663412: "Falhou ao carregar endereço", + 1996021743: "Falha ao carregar a chave", + 1108715658: "Falhou ao carregar mensagem", + 1081425878: "Falhou ao carregar mnemônico", + 928667220: "Falha ao carregar o descritor de saída", + 1620572516: "Falha ao carregar a senha", + 2946146830: "Falhou ao armazenar mnemônico", + 1303554751: "Taxa: ", + 104500973: "Taxa de Alimentação", + 3313339187: "Nome do arquivo", + 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", + 3737729752: "Impressão digital: %s", + 2542772894: "Firmware excede o tamanho máximo: %d", + 1406590538: "Diâmetro da Fresa", + 3086093110: "Livre: ", + 1893243331: "Do Armazenamento", + 4120536442: "GRBL", + 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", + 602716148: "Ir", + 3580020863: "Chave pública hexadecimal", + 2691246967: "Hexadecimal", + 2736309107: "Id já existe\n", + 1706005805: "Descritor incompleto", + 631342955: "Entradas (%d): ", + 2585599782: "Endereço inválido", + 2874529150: "Bootloader inválido", + 4093416954: "Comprimento de mnemônico inválido", + 1422874211: "Chave pública inválida", + 2443867979: "Carteira inválida:\n%s", + 4122897393: "Invertido", + 3000888649: "Chave", + 2686333978: "Chave:", + 4123798664: "Krux\n\n\nVersão\n%s", + 3835918229: "Teste de impressão de QR krux", + 766317539: "Língua", + 972436696: "Atraso de Linha", + 3596093890: "Linha: ", + 2820726296: "Carregar Mnemônico", + 879727077: "Carregar do cartão SD?", + 669106195: "Carregar um?", + 3330705289: "Carregar?", + 2596531078: "Carregando Câmera..", + 596389387: "Carregando endereço de troco %d..", + 336702608: "Carregando impressora..", + 2538883522: "Carregando endereço de recebimento %d..", + 3159494909: "Carregando..", + 1177338798: "Idioma", + 2817059741: "Local", + 63976957: "Nível de log", + 86530918: "Logging", + 2917810189: "Comprimento máximo excedido (%s)", + 2030045667: "Mensagem", + 3928301843: "Arquivo de assinatura faltando", + 1948316555: "Mnemônico", + 2123991188: "ID do mnemônico", + 3911073154: "ID de armazenamento", + 570639842: "Mnemônico não foi descriptografado", + 1746030071: "Mnemônico não foi criptografado", + 1458925155: "Modificado:", + 1845376098: "Multisig", + 2939797024: "Rede", + 73574491: "Novo Mnemônico", + 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", + 4063104189: "Não", + 3927838899: "Sem senha BIP39", + 4092516657: "Jogadas insuficientes!", + 1577637745: "Octal", + 3312581301: "Iter. PBKDF2", + 721090621: "PSBT", + 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", + 2987800462: "Largura do papel", + 3050763890: "Parte\n%d / %d", + 3559456868: "Tamanho da peça", + 4249903283: "Senha", + 3712257341: "Senha:", + 140802882: "Salvar", + 1703779997: "QR em Texto", + 3561756278: "Carregue um descritor da carteira", + 784609464: "Taxa de Mergulho", + 3037062877: "Imprimir QR de teste", + 4278257699: "Imprimir QR?\n\n%s\n\n", + 516488026: "Imprimir?\n\n%s\n\n", + 1123106929: "Impressora", + 3903571079: "Driver de impressora não está definido!", + 2609799302: "Imprimindo\n%d / %d", + 844861889: "Imprimindo ...", + 2580599003: "Seguir?", + 556126964: "Processando ...", + 1848310591: "Código QR", + 710709610: "Pino RX", + 2697857197: "Recebimento", + 1746677167: "Endereços de Recebimento", + 364354944: "Região: ", + 1662254634: "Revise os dados, edite se necessário", + 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", + 856795528: "Jogadas:\n\n%s", + 255086803: "Jogadas: %d\n", + 3976793317: "Cartão SD", + 2827687530: "Cartão SD não detectado", + 2736513298: "Cartão SD não detectado.", + 3593785196: "SHA256 de jogadas:\n\n%s", + 1143278725: "Sha256 da imagem:\n\n%s", + 3338679392: "SHA256:\n%s", + 3531742595: "Salvar no cartão SD?", + 810036588: "Salvo no cartão SD:\n%s", + 763824768: "Escala", + 4117455079: "Escanear Endereço", + 3219991109: "Escanear a senha BIP39", + 2537207336: "Escanear código QR da chave", + 4006316572: "Escaneando as palavras 1-12 novamente", + 2736506158: "Escaneando as palavras 13-24", + 266935239: "SeedQR", + 1698829144: "Autotransferência ou Troco (%d): ", + 473154195: "Configurações", + 1825881236: "Desligar", + 2120776272: "Desligando..", + 1061961408: "Assinar", + 4282338366: "Assinar?", + 746161122: "Assinatura", + 1988416729: "Mensagem Assinada", + 3672006076: "PSBT Assinada", + 2281377987: "Single-sig", + 4221794628: "Total: ", + 2344747135: "Algumas verificações não podem ser realizadas.", + 2309020186: "Gastos (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Armazene na Flash", + 720041451: "Armazene no Cartão SD", + 3514476519: "Deslize para mudar de modo", + 1898550184: "TOQUE ou ENTER para capturar", + 4228215415: "Pino TX", + 2612594937: "Texto", + 1454688268: "Tema", + 1180180513: "Térmica", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (bits)", + 725348723: "Ferramentas", + 3684696112: "Limiar de Toque", + 2978718564: "Touchscreen", + 2732611775: "Tentar mais?", + 1487826746: "Digitar a senha BIP39", + 2061556020: "Digite a Chave", + 2089395053: "Unidade", + 2845607430: "Atualizando bootloader..\n\n%d%%", + 4164597446: "Atualização completa.\n\nDesligando..", + 2736001501: "Atualizando firmware..\n\n%d%%", + 2674953168: "Use uma superfície de fundo preta.", + 2402455261: "Use a entropia da câmera para criar um novo mnemônico", + 236075140: "Usado: ", + 4003084591: "Valor %s fora do alcance: [ %s, %s]", + 989428076: "O valor deve ser múltiplo de %s", + 4191058607: "Pela Câmera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Por entrada manual", + 2504354847: "Aguarde a captura", + 2297028319: "Descritor de Carteira", + 4232654916: "Descritor da carteira", + 2587172867: "Descritor de saída da carteira carregado!", + 2499782468: "O descritor de saída da carteira não foi encontrado.", + 2671738224: "Aviso:", + 797660533: "Palavra %d", + 3742424146: "Números das Palavras", + 2965123464: "Palavras", + 1303016265: "Sim", + 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", + 2569054451: "Suas alterações serão mantidas no cartão SD.", }, - "nl-NL": { - 1185266064: "%d van %d multisig", - 2004520398: "%d. Wisselgeld: \n\n%s\n\n", - 3862364126: "%d. Zelf overschrijving: \n\n%s\n\n", - 3264377309: "%d. Uitgaven: \n\n%s\n\n", - 2399232215: "%s\n\nis een valide wisselgeld adres!", - 3921290840: "%s\n\nis een valide ontvangst adres!", - 1808355833: "%s\n\nwerd NIET GEVONDEN in de eerste %d wisselgeld adressen", - 1306127065: "%s\n\nwerd NIET GEVONDEN in de eerste %d ontvangst adressen", - 3348584292: "(Experimenteel)", - 2739590230: "12 woorden", - 1310058127: "24 woorden", + "ru-RU": { + 1185266064: "%d из %d мультиподпись", + 2004520398: "%d. Сдача: \n\n%s\n\n", + 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", + 3264377309: "%d. Расход: \n\n%s\n\n", + 2399232215: "%s\n\nвалидный адрес сдачи!", + 3921290840: "%s\n\nвалидный адрес получения!", + 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", + 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", + 3348584292: "(Эксперементальный)", + 2739590230: "12 слов", + 1310058127: "24 слова", 2743272264: "ABC", - 1949634023: "Over", + 1949634023: "О Программе", 1517128857: "Adafruit", - 3270727197: "Adres", - 2574498267: "Aanvullende entropie van camera vereist voor AES-CBC modus", - 283202181: "Richt de camera en Tiny Seed op de juiste manier.", - 88746165: "Anti reflecterend uitgeschakeld", - 1521033296: "Anti reflecterend ingeschakeld", - 1056821534: "Weet je het zeker?", - 3247612282: "BIP-39 geheugensteun", - 3455872521: "Terug", - 2541860807: "Backup van de bootloader...\n\n%d%%", - 2256777600: "Ongeldige handtekening", - 3937333362: "Baudratio", - 427617266: "Bitcoin", - 928727036: "Rand opvulling", + 3270727197: "Адрес", + 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", + 283202181: "Правильно совместите камеру и Мини Сид-фразу.", + 88746165: "Антиблик отключен", + 1521033296: "Антиблик включен", + 1056821534: "Вы уверены?", + 3455872521: "Назад", + 2541860807: "Резервное копирование загрузчика..\n\n%d%%", + 2256777600: "Плохая подпись", + 3937333362: "Скорость Передачи Данных", + 427617266: "Биткоин", + 928727036: "Заполнение границ", 213030954: "CNC", - 1207696150: "Change", - 3126552510: "Wisselgeldadres", - 1583186953: "Thema veranderen en opnieuw opstarten?", - 2697733395: "Wijzigingen aanhouden op SD kaart!", - 388908871: "Wijzigingen blijven van kracht tot afsluiten.", - 3442025874: "Controleer SD kaart", - 3119547911: "Controleer of dit adres bij deze portemonnee hoort?", - 2856261511: "Na %d geen wisselgeld adressen gevonden.", - 2788541416: "Na %d geen ontvangst adressen gevonden.", - 2446472910: "Wisselgeldadres %d controleren...", - 2470115694: "SD kaart controleren...", - 3655273987: "Ontvangstadres %d controleren...", - 2407028014: "Compact SeedQR", - 4041895036: "Doorgaan?", - 4094072796: "QR code maken", - 167798282: "QR code maken van tekst?", - 2767642191: "Aangemaakt: ", - 3513215254: "Aangepaste QR code", - 124617190: "Snijdiepte", - 597912140: "Snijmethode", - 2504034831: "Decimaal", - 2751113454: "Ontsleutelen?", - 3510912550: "Verwijderen %s?", - 1016609898: "Bestand verwijderen?", - 1364509700: "Geheugensteun verwijderen", - 4102535566: "Diepte per pas", - 2791699253: "Afgeleide: %s", - 1230133196: "Opslag op apparaat is niet gedetecteerd.", - 3836852788: "Klaar?", - 382368239: "Driver", - 3978947916: "Encoder", - 4090746898: "Encoder-debounce", - 374684711: "Geheugensteun versleutelen", - 1244124409: "Versleutelde QR code", - 2968548114: "Versleutelde geheugensteun was niet opgeslagen", - 3315319371: "Versleutelde geheugensteun is opgeslagen met ID: ", - 350279787: "Versleutelen", - 2601598799: "Versleutel modus", - 3504179008: "Voer elk woord van jouw BIP-39 geheugensteun in als een nummer van 1 tot 2048.", - 1100685007: "Voer elk woord van jouw BIP-39 geheugensteun in als een hexadecimaal van 1 tot 800.", - 4090266642: "Voer elk woord van jouw BIP-39 geheugensteun in als een octaal van 1 tot 4000.", - 2780625730: "Voer elk woord van jouw BIP-39 geheugensteun in.", - 784361051: "Fout:\n%s", - 1505332462: "Esc", - 3838465623: "Bestanden verkennen?", - 4170881190: "Exporteren naar SD-kaart..", - 1711312434: "Uitgebreide publieke sleutel", - 383371114: "Ontsleutelen is niet gelukt", - 3048830188: "PSBT laden is niet gelukt", - 4192663412: "Adres laden is niet gelukt", - 1996021743: "Sleutel laden is niet gelukt", - 1108715658: "Bericht laden is niet gelukt", - 1081425878: "Geheugensteun laden is niet gelukt", - 928667220: "Descriptor laden is niet gelukt", - 1620572516: "Wachtwoord laden is niet gelukt", - 2946146830: "Geheugensteun opslaan is niet gelukt", - 1303554751: "Tarief: ", - 104500973: "Voedingssnelheid", - 3313339187: "Bestandsnaam", - 1982637349: "Bestandsnaam %s OVERSCHRIJVEN op SD kaart?", - 3737729752: "Vingerafdruk: %s", - 2542772894: "Firmware overschrijdt de maximale grootte: %d", - 1406590538: "Fluit diameter", - 3086093110: "Vrij: ", - 1893243331: "Uit data-opslag", - 4120536442: "GRBL", - 299338213: "Eigen ID gebruiken voor geheugensteun? Anders vingerafdruk gebruiken", - 602716148: "Ga", - 3580020863: "Hex publieke sleutel", - 2691246967: "Hexadecimaal", - 2736309107: "ID bestaat al\n", - 1706005805: "Incomplete portemonnee descriptor", - 631342955: "Invoer (%d): ", - 2585599782: "Ongeldig adres", - 2874529150: "Ongeldige bootloader", - 4093416954: "Ongeldige geheugensteun lengte", - 1422874211: "Ongeldige publieke sleutel", - 2443867979: "Ongeldige portemonnee:\n%s", - 4122897393: "Omkeren", - 3000888649: "Sleutel", - 2686333978: "Sleutel: ", - 4123798664: "Krux\n\n\nVersie\n%s", - 3835918229: "Krux printer test QR", - 766317539: "Taal", - 972436696: "Lijn vertraging", - 3596093890: "Lijn: ", - 2820726296: "Geheugensteun laden", - 879727077: "Laden vanaf SD-kaart?", - 669106195: "Laden?", - 3330705289: "Laden?", - 2596531078: "Camera laden...", - 596389387: "Wisselgeldadres %d laden...", - 336702608: "Laadprinter..", - 2538883522: "Ontvangstadres %d laden...", - 3159494909: "Laden...", - 1177338798: "Taal", - 2817059741: "Opslaglocatie", - 63976957: "Log niveau", - 86530918: "Debug logs", - 2917810189: "Maximale lengte overschreden (%s)", - 2030045667: "Bericht", - 3928301843: "Handtekening bestand mist", - 1948316555: "Geheugensteun", - 2123991188: "Geheugensteun ID", - 3911073154: "Geheugensteun opslag ID", - 570639842: "Geheugensteun is niet ontsleuteld", - 1746030071: "Geheugensteun is niet versleuteld", - 1458925155: "Aangepast: ", - 1845376098: "Multisig", - 2939797024: "Netwerk", - 73574491: "Geheugensteun aanmaken", - 2792272353: "Nieuwe firmware gevonden.\n\nSHA256:\n%s\n\n\n\nInstalleren?", - 4063104189: "Nee", - 3927838899: "Geen BIP-39 wachtwoord", - 4092516657: "Niet genoeg gedobbeld!", - 1577637745: "Octaal", - 3312581301: "PBKDF2 iter.", + 1207696150: "Сдача", + 3126552510: "Адрес Сдачи", + 1583186953: "Сменить тему и перезагрузить?", + 2697733395: "Изменения сохранены на SD карте!", + 388908871: "Изменения будут храниться до выключения.", + 3442025874: "Проверить SD Карту", + 3119547911: "Проверить, что адрес принадлежит этому кошельку?", + 2856261511: "Проверено %d адресов сдачи без совпадений.", + 2788541416: "Проверено %d адресов получения без совпадений.", + 2446472910: "Проверяем адрес сдачи %d на совпадение..", + 2470115694: "Проверка SD карты..", + 3655273987: "Проверяем адрес получения %d на совпадение..", + 2407028014: "Компактный SeedQR", + 4041895036: "Продолжить?", + 4094072796: "Создать QR Код", + 167798282: "Создать QR код из текста?", + 2767642191: "Создано", + 3513215254: "Пользовательский QR Код", + 124617190: "Глубина Резки", + 597912140: "Метод Резки", + 2504034831: "Десятичный", + 2751113454: "Расшифровать?", + 3510912550: "Удалить %s?", + 1016609898: "Удалить Файл?", + 1364509700: "Удалить Мнемонику", + 4102535566: "Глубина За Проход", + 2791699253: "Производный путь: %s", + 1230133196: "Флэш память устройства не обнаружена.", + 3836852788: "Готово?", + 382368239: "Драйвер", + 3978947916: "Кодер", + 4090746898: "Дебаунс Кодера", + 374684711: "Зашифровать Мнемонику", + 1244124409: "Зашифрованный QR Код", + 2968548114: "Зашифрованная мнемоника не была сохранена", + 3315319371: "Зашифрованная мнемоника была сохранена с ID: ", + 350279787: "Шифрование", + 2601598799: "Метод шифрования", + 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", + 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", + 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", + 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", + 784361051: "Ошибка:\n%s", + 1505332462: "Выйти", + 3838465623: "Исследовать файлы?", + 4170881190: "Экспортирование на SD карту..", + 1711312434: "Расширенный Публичный Ключ", + 383371114: "Не удалось расшифровать", + 3048830188: "Не удалось загрузить PSBT", + 4192663412: "Не удалось загрузить адрес", + 1996021743: "Не удалось загрузить ключ", + 1108715658: "Не удалось загрузить сообщение", + 1081425878: "Не удалось загрузить мнемонику", + 928667220: "Не удалось загрузить выходной дескриптор", + 1620572516: "Не удалось загрузить фразу-пароль", + 2946146830: "Не удалось сохранить мнемонику", + 1303554751: "Комиссия: ", + 104500973: "Скорость подачи", + 3313339187: "Имя файла", + 1982637349: "Файл %s существует на SD карте, перезаписать?", + 3737729752: "Фингерпринт: %s", + 2542772894: "Прошивка превышает максимальный размер: %d", + 1406590538: "Flute Диаметр", + 3086093110: "Бесплатно: ", + 1893243331: "Из Памяти", + 4120536442: "GRBL", + 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", + 602716148: "OK", + 3580020863: "Шестнадцатеричный Публичный Ключ", + 2691246967: "Шестнадцатеричный", + 2736309107: "ID уже существует\n", + 1706005805: "Неполный выходной дескриптор", + 631342955: "Входы (%d): ", + 2585599782: "Неверный адрес", + 2874529150: "Неверный загрузчик", + 4093416954: "Неверная длина мнемоники", + 1422874211: "Неверный публичный ключ", + 2443867979: "Неверный кошелек:\n%s", + 4122897393: "Инвертировать", + 3000888649: "Ключ", + 2686333978: "Ключ: ", + 4123798664: "Krux\n\n\nВерсия\n%s", + 3835918229: "Тестовый QR Принтера Krux", + 766317539: "Язык", + 972436696: "Задержка Линии", + 3596093890: "Линия: ", + 2820726296: "Загрузить Мнемонику", + 879727077: "Загрузить с SD карты?", + 669106195: "Загрузить одну?", + 3330705289: "Загрузить?", + 2596531078: "Загрузка Камеры..", + 596389387: "Загрузка адреса сдачи %d..", + 336702608: "Загрузка принтера..", + 2538883522: "Загрузка адреса получения %d..", + 3159494909: "Загрузка..", + 1177338798: "Локаль", + 2817059741: "Расположение", + 63976957: "Уровень логирования", + 86530918: "Логирование", + 2917810189: "Максимальная длина превышена (%s)", + 2030045667: "Сообщение", + 3928301843: "Отсутствует файл подписи", + 1948316555: "Мнемоника", + 2123991188: "ID мнемоники", + 3911073154: "ID памяти мнемоники", + 570639842: "Мнемоника не была расшифрована", + 1746030071: "Мнемоника не была зашифрована", + 1458925155: "Изменено: ", + 1845376098: "Мультиподпись", + 2939797024: "Сеть", + 73574491: "Новая Мнемоника", + 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", + 4063104189: "Нет", + 3927838899: "Без BIP39 фразы-пароля", + 4092516657: "Недостаточно бросков!", + 1577637745: "Восьмеричный", + 3312581301: "PBKDF2 Итерации", 721090621: "PSBT", - 995862913: "Maak geperforeerde stippen zwart zodat ze worden gedetecteerd.", - 2987800462: "Papier breedte", - 3050763890: "Deel\n%d / %d", - 3559456868: "Deel grootte", - 4249903283: "Wachtwoord", - 3712257341: "Wachtwoord: ", - 140802882: "Opslag", - 1703779997: "Platte tekst QR", - 3561756278: "Laadt een portemonnee descriptor in", - 784609464: "Duik tarief", - 3037062877: "Test QR afdrukken", - 4278257699: "Afdrukken naar QR?\n\n%s\n\n", - 516488026: "Afdrukken?\n\n%s\n\n", - 1123106929: "Printer", - 3903571079: "Printer driver niet ingesteld!", - 2609799302: "Afdruk\n%d / %d", - 844861889: "Afdrukken...", - 2580599003: "Doorgaan?", - 556126964: "Verwerken...", - 1848310591: "QR code", - 710709610: "RX pin", - 2697857197: "Ontvangen", - 1746677167: "Ontvangstadres", - 364354944: "Regio: ", - 1662254634: "Controleer gescande gegevens en bewerk indien nodig", - 770350922: "Dobbel een dobbelsteen minstens %d keer voor het genereren van een geheugensteun.", - 856795528: "Gedobbeld:\n\n%s", - 255086803: "Gedobbeld: %d\n", - 3976793317: "SD kaart", - 2827687530: "SD kaart niet gedetecteerd", - 2736513298: "SD kaart niet gedetecteerd.", - 3593785196: "Gedobbelde SHA256:\n\n%s", - 1143278725: "Momentopname van SHA256:\n\n%s", + 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", + 2987800462: "Ширина Бумаги", + 3050763890: "Часть\n%d / %d", + 3559456868: "Размер Части", + 4249903283: "Фраза-пароль", + 3712257341: "Фраза-пароль: ", + 140802882: "Постоянная Память", + 1703779997: "QR открытым текстом", + 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", + 784609464: "Скорость Погружения", + 3037062877: "Напечатать Тестовый QR", + 4278257699: "Напечатать в виде QR?\n\n%s\n\n", + 516488026: "Печатать?\n\n%s\n\n", + 1123106929: "Принтер", + 3903571079: "Драйвер Принтера не установлен!", + 2609799302: "Идет печать\n%d / %d", + 844861889: "Идет печать ...", + 2580599003: "Продолжить?", + 556126964: "Обработка ...", + 1848310591: "QR Код", + 710709610: "RX Пин", + 2697857197: "Получить", + 1746677167: "Адрес Получения", + 364354944: "Регион: ", + 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", + 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", + 856795528: "Броски:\n\n%s", + 255086803: "Броски: %d\n", + 3976793317: "SD карта", + 2827687530: "SD карта не обнаружена", + 2736513298: "SD карта не обнаружена.", + 3593785196: "SHA256 бросков:\n\n%s", + 1143278725: "SHA256 снэпшота:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Opslaan op SD-kaart?", - 810036588: "Opgeslagen op SD-kaart:\n%s", - 763824768: "Schaal", - 4117455079: "Adres scannen", - 3219991109: "BIP-39 wachtwoord scannen", - 2537207336: "QR code sleutel scannen", - 4006316572: "Woorden 1 t/m 12 opnieuw scannen", - 2736506158: "Woorden 13 t/m 24 scannen", - 3593497655: "Screensaver", + 3531742595: "Сохранить на SD карту?", + 810036588: "Сохранено на SD карту:\n%s", + 763824768: "Шкала", + 4117455079: "Отсканировать Адрес", + 3219991109: "Отсканировать BIP39 фразу-пароль", + 2537207336: "Отсканировать Ключ QR код", + 4006316572: "Сканирование слов 1-12 снова", + 2736506158: "Сканирование слов 13-24", 266935239: "SeedQR", - 1698829144: "Zelf overschrijving of wisselgeld (%d): ", - 473154195: "Instellingen", - 1825881236: "Afsluiten", - 2120776272: "Bezig met afsluiten...", - 1061961408: "Ondertekenen", - 4282338366: "Ondertekenen?", - 746161122: "Handtekening", - 1988416729: "Bericht ondertekend", - 3672006076: "PSBT ondertekend", - 2281377987: "Enkele sleutel", - 4221794628: "Grootte: ", - 2344747135: "Sommige controles kunnen niet worden uitgevoerd.", - 2309020186: "Uitgaven (%d): ", - 3355862324: "Stackbit 1248", - 3303592908: "Opslaan op apparaat", - 720041451: "Opslaan op SD kaart", - 3514476519: "Verander modus", - 1898550184: "TIK of ENTER voor opname", - 4228215415: "TX pin", - 2612594937: "Tekst", - 1454688268: "Thema", - 1180180513: "Thermisch", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (Bits)", - 725348723: "Hulpmiddelen", - 3684696112: "Aanraak gevoeligheid", - 2978718564: "Aanraakscherm", - 2732611775: "Meer proberen?", - 1487826746: "Voer BIP-39 wachtwoord in", - 2061556020: "Voer sleutel in", - 2089395053: "Eenheid", - 2845607430: "Bootloader updaten...\n\n%d%%", - 4164597446: "Upgrade afgerond.\n\nBezig met afsluiten...", - 2736001501: "Firmware upgraden...\n\n%d%%", - 2674953168: "Gebruik een donker achergrond.", - 2402455261: "Gebruik de camera als entropie voor het aanmaken van een nieuwe geheugensteun", - 236075140: "Gebruikt: ", - 4003084591: "Waarde %s is buiten bereik: [%s, %s]", - 4191058607: "Via camera", - 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Via handmatige invoer", - 2504354847: "Wacht op opname", - 3992434312: "Wacht tijd", - 2297028319: "Descriptor", - 4232654916: "Portemonnee descriptor", - 2587172867: "Portemonnee descriptor geladen!", - 2499782468: "Portemonnee descriptor niet gevonden.", - 2671738224: "Waarschuwing:", - 797660533: "Woord %d", - 3742424146: "Woord nummers", - 2965123464: "Woorden", - 1303016265: "Yes", - 771968845: "Veranderingen worden opgeslagen in opslag van apparaat.", - 2569054451: "Veranderingen worden opgeslagen op SD kaart.", + 1698829144: "Трансфер самому себе или Сдача (%d): ", + 473154195: "Настройки", + 1825881236: "Выключить", + 2120776272: "Выключение..", + 1061961408: "Подписать", + 4282338366: "Подписать?", + 746161122: "Подпись", + 1988416729: "Подписанное Сообщение", + 3672006076: "Подписанное PSBT", + 2281377987: "Одна подпись", + 4221794628: "Размер: ", + 2344747135: "Некоторые проверки не могут быть выполнены.", + 2309020186: "Расход (%d): ", + 3355862324: "Стэкбит 1248", + 3303592908: "Сохранить на Флэш Память", + 720041451: "Сохранить на SD Карту", + 3514476519: "Свайпните, чтобы сменить режим", + 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", + 4228215415: "TX Пин", + 2612594937: "Текст", + 1454688268: "Тема", + 1180180513: "Термальный", + 4119292117: "Мини Сид-фраза", + 1732872974: "Мини Сид-фраза (Биты)", + 725348723: "Инструменты", + 3684696112: "Прикоснитесь Границы", + 2978718564: "Тачскрин", + 2732611775: "Попробовать ещё?", + 1487826746: "Введите BIP39 фразу-пароль", + 2061556020: "Введите Ключ", + 2089395053: "Юнит", + 2845607430: "Обновление загрузчика..\n\n%d%%", + 4164597446: "Обновление завершено.\n\nВыключение..", + 2736001501: "Обновление прошивки..\n\n%d%%", + 2674953168: "Использовать черную фоновую поверхность.", + 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", + 236075140: "Использовано: ", + 4003084591: "Значение %s вне диапозона: [%s, %s]", + 4191058607: "С Помощью Камеры", + 1254681955: "С Помощью D20", + 525309547: "С Помощью D6", + 590330112: "С Помощью Ручного Ввода", + 2504354847: "Дождитесь Захвата", + 2297028319: "Дескриптор Кошелька", + 4232654916: "Выходной дескриптор кошелька", + 2587172867: "Выходной дескриптор кошелька загружен!", + 2499782468: "Выходной дескриптор кошелька не найден.", + 2671738224: "Предупреждение:", + 797660533: "Слово %d", + 3742424146: "Числа Слов", + 2965123464: "Слова", + 1303016265: "Да", + 771968845: "Ваши изменения будут сохранены на флэш памяти устройства.", + 2569054451: "Ваши изменения будут сохранены на SD карте.", }, "pl-PL": { 1185266064: "%d z %d multisig", @@ -1031,7 +1266,6 @@ 88746165: "Niepełnosprawne przeciwblokowane", 1521033296: "Włączona anty-zabawa", 1056821534: "Jesteś pewny?", - 3247612282: "BIP39 Mnemonic", 3455872521: "Z powrotem", 2541860807: "Kopie zapasowe bootloader ..\n\n%d %%", 2256777600: "zły podpis", @@ -1199,7 +1433,6 @@ 2537207336: "Skanuj kod QR", 4006316572: "Znowu skanowanie słów 1-12", 2736506158: "Skanowanie słów 13-24", - 3593497655: "Wygaszacz ekranu", 266935239: "Seedqr", 1698829144: "Samo-transfer lub zmiana (%d):", 473154195: "Ustawienia", @@ -1207,795 +1440,543 @@ 2120776272: "Wyłączanie..", 1061961408: "Podpisać", 4282338366: "Podpisać?", - 746161122: "Podpis", - 1988416729: "Podpisana wiadomość", - 3672006076: "Podpisano PSBT", - 2281377987: "Pojedyncze Sig", - 4221794628: "Rozmiar:", - 2344747135: "Nie można wykonać niektórych kontroli.", - 2309020186: "Wydać (%d):", - 3355862324: "Stackbit 1248", - 3303592908: "Przechowuj na Flash", - 720041451: "Przechowuj na karcie SD", - 3514476519: "Przesuń tryb zmiany", - 1898550184: "Dotknij lub wejdź do przechwytywania", - 4228215415: "Pin TX", - 2612594937: "Tekst", - 1454688268: "Temat", - 1180180513: "Termiczny", - 4119292117: "Małe ziarno", - 1732872974: "Małe nasiona (bity)", - 725348723: "Narzędzia", - 3684696112: "Próg dotykowy", - 2978718564: "Ekran dotykowy", - 2732611775: "Próbuj bardziej?", - 1487826746: "Passówka typu BIP39", - 2061556020: "Klucz typu", - 2089395053: "Jednostka", - 2845607430: "Aktualizacja bootloader ..\n\n%d %%", - 4164597446: "Uaktualnienie zakończone.\n\nshutting w dół ..", - 2736001501: "Aktualizacja oprogramowania układowego ..\n\n%d %%", - 2674953168: "Użyj czarnej powierzchni tła.", - 2402455261: "Użyj entropii aparatu, aby stworzyć nowy mnemonik", - 236075140: "Używany:", - 4003084591: "Wartość %s z zakresu: [ %s, %s]", - 4191058607: "Za pośrednictwem aparatu", - 1254681955: "Via D20", - 525309547: "Przez D6", - 590330112: "Poprzez ręczne wejście", - 2504354847: "Poczekaj na schwytanie", - 3992434312: "Czas oczekiwania", - 2297028319: "Deskryptor portfela", - 4232654916: "Deskryptor wyjściowy portfela", - 2587172867: "Załadowany deskryptor wyjściowy portfela!", - 2499782468: "Nie znaleziono deskryptora wyjściowego portfela.", - 2671738224: "Ostrzeżenie:", - 797660533: "Słowo %d", - 3742424146: "Numery słów", - 2965123464: "Słowa", - 1303016265: "Tak", - 771968845: "Twoje zmiany będą przechowywane w pamięci flash urządzenia.", - 2569054451: "Twoje zmiany będą przechowywane na karcie SD.", - }, - "pt-BR": { - 1185266064: "%d da %d multisig", - 2004520398: "%d. Troco: \n\n%s\n\n", - 3862364126: "%d. Autotransferência: \n\n%s\n\n", - 3264377309: "%d. Gasto: \n\n%s\n\n", - 2399232215: "%s\n\n é um endereço de troco válido!", - 3921290840: "%s\n\né um endereço de recepção válido!", - 1808355833: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de troco", - 1306127065: "%s\n\nNÃO FOI ENCONTRADO nos primeiros %d endereços de recepção", - 3348584292: "(Experimental)", - 2739590230: "12 palavras", - 1310058127: "24 palavras", - 2743272264: "ABC", - 1949634023: "Sobre", - 1517128857: "Adafruit", - 3270727197: "Endereço", - 2574498267: "Entropia adicional da câmera necessária para o modo AES-CBC", - 283202181: "Alinhe a câmera e o Tiny Seed corretamente.", - 88746165: "Antirreflexo desativado", - 1521033296: "Antirreflexo ativado", - 1056821534: "Tem certeza?", - 3247612282: "Mnemônico BIP39", - 3455872521: "Voltar", - 2541860807: "Backing up bootloader..\n\n%d%%", - 2256777600: "Assinatura Inválida", - 3937333362: "Baudrate", - 427617266: "Bitcoin", - 928727036: "Borda", - 213030954: "CNC", - 1207696150: "Troco", - 3126552510: "Endereços de Troco", - 1583186953: "Mudar o tema e reiniciar?", - 2697733395: "Mudanças salvas no cartão SD!", - 388908871: "Alterações só durarão até o desligamento.", - 3442025874: "Verifique o cartão SD", - 3119547911: "Verificar se este endereço pertence a carteira?", - 2856261511: "Endereço de troco %d não corresponde.", - 2788541416: "Endereço de recebimento %d não corresponde.", - 2446472910: "Verificando correspondência do endereço de troco %d ..", - 2470115694: "Verificando o cartão SD..", - 3655273987: "Verificando correspondência do endereço de recebimento %d ..", - 2407028014: "SeedQR Compacto", - 4041895036: "Continuar?", - 4094072796: "Gerar Código QR", - 167798282: "Gerar código QR do texto?", - 2767642191: "Criado: ", - 3513215254: "Código QR Customizado", - 124617190: "Profundidade de Corte", - 597912140: "Método de Corte", - 2504034831: "Decimal", - 2751113454: "Descriptografar?", - 3510912550: "Excluir %s?", - 1016609898: "Excluir Arquivo?", - 1364509700: "Excluir Mnemônico", - 4102535566: "Profundidade da Passagem", - 2791699253: "Derivação: %s", - 1230133196: "Armazenamento flash do dispositivo não detectado.", - 3836852788: "Feito?", - 382368239: "Driver", - 3978947916: "Codificador", - 4090746898: "Debounce do Encoder", - 374684711: "Criptografar Mnemônico", - 1244124409: "Código QR Criptografado", - 2968548114: "Mnemonic criptografado não foi armazenado", - 3315319371: "Mnemônico criptografado foi armazenado com ID:", - 350279787: "Criptografia", - 2601598799: "Modo de Criptografia", - 3504179008: "Digite o número de cada palavra do seu mnemônico BIP-39, de 1 a 2048.", - 1100685007: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em hexadecimal, de 1 a 800.", - 4090266642: "Digite o número de cada palavra do seu mnemônico BIP-39 como um número em octal, de 1 a 4000.", - 2780625730: "Digite cada palavra do seu mnemônico BIP-39.", - 784361051: "Erro:\n%s", - 1505332462: "Esc", - 3838465623: "Explorar arquivos?", - 4170881190: "Exportando para o cartão SD..", - 1711312434: "Chave Pública Estendida", - 383371114: "Falhou em descriptografar", - 3048830188: "Falhou ao carregar PSBT", - 4192663412: "Falhou ao carregar endereço", - 1996021743: "Falha ao carregar a chave", - 1108715658: "Falhou ao carregar mensagem", - 1081425878: "Falhou ao carregar mnemônico", - 928667220: "Falha ao carregar o descritor de saída", - 1620572516: "Falha ao carregar a senha", - 2946146830: "Falhou ao armazenar mnemônico", - 1303554751: "Taxa: ", - 104500973: "Taxa de Alimentação", - 3313339187: "Nome do arquivo", - 1982637349: "O nome do arquivo %s existe no cartão SD, substituir?", - 3737729752: "Impressão digital: %s", - 2542772894: "Firmware excede o tamanho máximo: %d", - 1406590538: "Diâmetro da Fresa", - 3086093110: "Livre: ", - 1893243331: "Do Armazenamento", - 4120536442: "GRBL", - 299338213: "Dê a este mnemônico um ID personalizado? Caso contrário, a impressão digital atual será usada", - 602716148: "Ir", - 3580020863: "Chave pública hexadecimal", - 2691246967: "Hexadecimal", - 2736309107: "Id já existe\n", - 1706005805: "Descritor incompleto", - 631342955: "Entradas (%d): ", - 2585599782: "Endereço inválido", - 2874529150: "Bootloader inválido", - 4093416954: "Comprimento de mnemônico inválido", - 1422874211: "Chave pública inválida", - 2443867979: "Carteira inválida:\n%s", - 4122897393: "Invertido", - 3000888649: "Chave", - 2686333978: "Chave:", - 4123798664: "Krux\n\n\nVersão\n%s", - 3835918229: "Teste de impressão de QR krux", - 766317539: "Língua", - 972436696: "Atraso de Linha", - 3596093890: "Linha: ", - 2820726296: "Carregar Mnemônico", - 879727077: "Carregar do cartão SD?", - 669106195: "Carregar um?", - 3330705289: "Carregar?", - 2596531078: "Carregando Câmera..", - 596389387: "Carregando endereço de troco %d..", - 336702608: "Carregando impressora..", - 2538883522: "Carregando endereço de recebimento %d..", - 3159494909: "Carregando..", - 1177338798: "Idioma", - 2817059741: "Local", - 63976957: "Nível de log", - 86530918: "Logging", - 2917810189: "Comprimento máximo excedido (%s)", - 2030045667: "Mensagem", - 3928301843: "Arquivo de assinatura faltando", - 1948316555: "Mnemônico", - 2123991188: "ID do mnemônico", - 3911073154: "ID de armazenamento", - 570639842: "Mnemônico não foi descriptografado", - 1746030071: "Mnemônico não foi criptografado", - 1458925155: "Modificado:", - 1845376098: "Multisig", - 2939797024: "Rede", - 73574491: "Novo Mnemônico", - 2792272353: "Novo firmware detectado.\n\nSHA256:\n%s\n\n\n\nInstalar?", - 4063104189: "Não", - 3927838899: "Sem senha BIP39", - 4092516657: "Jogadas insuficientes!", - 1577637745: "Octal", - 3312581301: "Iter. PBKDF2", - 721090621: "PSBT", - 995862913: "Pinte os pontos perfurados de preto para que possam ser detectados.", - 2987800462: "Largura do papel", - 3050763890: "Parte\n%d / %d", - 3559456868: "Tamanho da peça", - 4249903283: "Senha", - 3712257341: "Senha:", - 140802882: "Salvar", - 1703779997: "QR em Texto", - 3561756278: "Carregue um descritor da carteira", - 784609464: "Taxa de Mergulho", - 3037062877: "Imprimir QR de teste", - 4278257699: "Imprimir QR?\n\n%s\n\n", - 516488026: "Imprimir?\n\n%s\n\n", - 1123106929: "Impressora", - 3903571079: "Driver de impressora não está definido!", - 2609799302: "Imprimindo\n%d / %d", - 844861889: "Imprimindo ...", - 2580599003: "Seguir?", - 556126964: "Processando ...", - 1848310591: "Código QR", - 710709610: "Pino RX", - 2697857197: "Recebimento", - 1746677167: "Endereços de Recebimento", - 364354944: "Região: ", - 1662254634: "Revise os dados, edite se necessário", - 770350922: "Role o dado pelo menos %d vezes para gerar um mnemônico.", - 856795528: "Jogadas:\n\n%s", - 255086803: "Jogadas: %d\n", - 3976793317: "Cartão SD", - 2827687530: "Cartão SD não detectado", - 2736513298: "Cartão SD não detectado.", - 3593785196: "SHA256 de jogadas:\n\n%s", - 1143278725: "Sha256 da imagem:\n\n%s", - 3338679392: "SHA256:\n%s", - 3531742595: "Salvar no cartão SD?", - 810036588: "Salvo no cartão SD:\n%s", - 763824768: "Escala", - 4117455079: "Escanear Endereço", - 3219991109: "Escanear a senha BIP39", - 2537207336: "Escanear código QR da chave", - 4006316572: "Escaneando as palavras 1-12 novamente", - 2736506158: "Escaneando as palavras 13-24", - 3593497655: "Protetor de tela", - 266935239: "SeedQR", - 1698829144: "Autotransferência ou Troco (%d): ", - 473154195: "Configurações", - 1825881236: "Desligar", - 2120776272: "Desligando..", - 1061961408: "Assinar", - 4282338366: "Assinar?", - 746161122: "Assinatura", - 1988416729: "Mensagem Assinada", - 3672006076: "PSBT Assinada", - 2281377987: "Single-sig", - 4221794628: "Total: ", - 2344747135: "Algumas verificações não podem ser realizadas.", - 2309020186: "Gastos (%d): ", + 746161122: "Podpis", + 1988416729: "Podpisana wiadomość", + 3672006076: "Podpisano PSBT", + 2281377987: "Pojedyncze Sig", + 4221794628: "Rozmiar:", + 2344747135: "Nie można wykonać niektórych kontroli.", + 2309020186: "Wydać (%d):", 3355862324: "Stackbit 1248", - 3303592908: "Armazene na Flash", - 720041451: "Armazene no Cartão SD", - 3514476519: "Deslize para mudar de modo", - 1898550184: "TOQUE ou ENTER para capturar", - 4228215415: "Pino TX", - 2612594937: "Texto", - 1454688268: "Tema", - 1180180513: "Térmica", - 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bits)", - 725348723: "Ferramentas", - 3684696112: "Limiar de Toque", - 2978718564: "Touchscreen", - 2732611775: "Tentar mais?", - 1487826746: "Digitar a senha BIP39", - 2061556020: "Digite a Chave", - 2089395053: "Unidade", - 2845607430: "Atualizando bootloader..\n\n%d%%", - 4164597446: "Atualização completa.\n\nDesligando..", - 2736001501: "Atualizando firmware..\n\n%d%%", - 2674953168: "Use uma superfície de fundo preta.", - 2402455261: "Use a entropia da câmera para criar um novo mnemônico", - 236075140: "Usado: ", - 4003084591: "Valor %s fora do alcance: [ %s, %s]", - 4191058607: "Pela Câmera", + 3303592908: "Przechowuj na Flash", + 720041451: "Przechowuj na karcie SD", + 3514476519: "Przesuń tryb zmiany", + 1898550184: "Dotknij lub wejdź do przechwytywania", + 4228215415: "Pin TX", + 2612594937: "Tekst", + 1454688268: "Temat", + 1180180513: "Termiczny", + 4119292117: "Małe ziarno", + 1732872974: "Małe nasiona (bity)", + 725348723: "Narzędzia", + 3684696112: "Próg dotykowy", + 2978718564: "Ekran dotykowy", + 2732611775: "Próbuj bardziej?", + 1487826746: "Passówka typu BIP39", + 2061556020: "Klucz typu", + 2089395053: "Jednostka", + 2845607430: "Aktualizacja bootloader ..\n\n%d %%", + 4164597446: "Uaktualnienie zakończone.\n\nshutting w dół ..", + 2736001501: "Aktualizacja oprogramowania układowego ..\n\n%d %%", + 2674953168: "Użyj czarnej powierzchni tła.", + 2402455261: "Użyj entropii aparatu, aby stworzyć nowy mnemonik", + 236075140: "Używany:", + 4003084591: "Wartość %s z zakresu: [ %s, %s]", + 4191058607: "Za pośrednictwem aparatu", 1254681955: "Via D20", - 525309547: "Via D6", - 590330112: "Por entrada manual", - 2504354847: "Aguarde a captura", - 3992434312: "Tempo de espera", - 2297028319: "Descritor de Carteira", - 4232654916: "Descritor da carteira", - 2587172867: "Descritor de saída da carteira carregado!", - 2499782468: "O descritor de saída da carteira não foi encontrado.", - 2671738224: "Aviso:", - 797660533: "Palavra %d", - 3742424146: "Números das Palavras", - 2965123464: "Palavras", - 1303016265: "Sim", - 771968845: "Suas alterações serão mantidas no armazenamento flash do dispositivo.", - 2569054451: "Suas alterações serão mantidas no cartão SD.", + 525309547: "Przez D6", + 590330112: "Poprzez ręczne wejście", + 2504354847: "Poczekaj na schwytanie", + 2297028319: "Deskryptor portfela", + 4232654916: "Deskryptor wyjściowy portfela", + 2587172867: "Załadowany deskryptor wyjściowy portfela!", + 2499782468: "Nie znaleziono deskryptora wyjściowego portfela.", + 2671738224: "Ostrzeżenie:", + 797660533: "Słowo %d", + 3742424146: "Numery słów", + 2965123464: "Słowa", + 1303016265: "Tak", + 771968845: "Twoje zmiany będą przechowywane w pamięci flash urządzenia.", + 2569054451: "Twoje zmiany będą przechowywane na karcie SD.", }, - "ru-RU": { - 1185266064: "%d из %d мультиподпись", - 2004520398: "%d. Сдача: \n\n%s\n\n", - 3862364126: "%d. Перевод самому себе: \n\n%s\n\n", - 3264377309: "%d. Расход: \n\n%s\n\n", - 2399232215: "%s\n\nвалидный адрес сдачи!", - 3921290840: "%s\n\nвалидный адрес получения!", - 1808355833: "%s\n\nНЕ НАЙДЕН в первых %d адресах сдачи", - 1306127065: "%s\n\nНЕ НАЙДЕН в первых %d адресах получения", - 3348584292: "(Эксперементальный)", - 2739590230: "12 слов", - 1310058127: "24 слова", + "es-MX": { + 1185266064: "%d de %d multisig", + 2004520398: "%d. Cambio: \n\n%s\n\n", + 3862364126: "%d. Autotransferencia: \n\n%s\n\n", + 3264377309: "%d. Gasto: \n\n%s\n\n", + 2399232215: "%s\n\n¡es una dirección de cambio válida!", + 3921290840: "%s\n\nes un dirección de depósito válido!", + 1808355833: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de cambio", + 1306127065: "%s\n\nNO FUE ENCONTRADO en las primeras %d direcciones de depósito", + 3348584292: "(Experimental)", + 2739590230: "12 palabras", + 1310058127: "24 palabras", 2743272264: "ABC", - 1949634023: "О Программе", + 1949634023: "Nosotros", 1517128857: "Adafruit", - 3270727197: "Адрес", - 2574498267: "Для режима AES-CBC требуется дополнительная энтропия от камеры", - 283202181: "Правильно совместите камеру и Мини Сид-фразу.", - 88746165: "Антиблик отключен", - 1521033296: "Антиблик включен", - 1056821534: "Вы уверены?", - 3247612282: "BIP39 Мнемоника", - 3455872521: "Назад", - 2541860807: "Резервное копирование загрузчика..\n\n%d%%", - 2256777600: "Плохая подпись", - 3937333362: "Скорость Передачи Данных", - 427617266: "Биткоин", - 928727036: "Заполнение границ", + 3270727197: "Dirección", + 2574498267: "Entropía adicional desde la cámara requerida para el modo AES-CBC", + 283202181: "Alinee la cámara y Tiny Seed correctamente.", + 88746165: "Antideslumbrante desactivado", + 1521033296: "Antideslumbrante habilitado", + 1056821534: "¿Estas seguro?", + 3455872521: "Atrás", + 2541860807: "Copia de seguridad del cargador de arranque..\n\n%d%%", + 2256777600: "Mala asignatura", + 3937333362: "Velocidad en baudios", + 427617266: "Bitcoin", + 928727036: "Relleno de borde", 213030954: "CNC", - 1207696150: "Сдача", - 3126552510: "Адрес Сдачи", - 1583186953: "Сменить тему и перезагрузить?", - 2697733395: "Изменения сохранены на SD карте!", - 388908871: "Изменения будут храниться до выключения.", - 3442025874: "Проверить SD Карту", - 3119547911: "Проверить, что адрес принадлежит этому кошельку?", - 2856261511: "Проверено %d адресов сдачи без совпадений.", - 2788541416: "Проверено %d адресов получения без совпадений.", - 2446472910: "Проверяем адрес сдачи %d на совпадение..", - 2470115694: "Проверка SD карты..", - 3655273987: "Проверяем адрес получения %d на совпадение..", - 2407028014: "Компактный SeedQR", - 4041895036: "Продолжить?", - 4094072796: "Создать QR Код", - 167798282: "Создать QR код из текста?", - 2767642191: "Создано", - 3513215254: "Пользовательский QR Код", - 124617190: "Глубина Резки", - 597912140: "Метод Резки", - 2504034831: "Десятичный", - 2751113454: "Расшифровать?", - 3510912550: "Удалить %s?", - 1016609898: "Удалить Файл?", - 1364509700: "Удалить Мнемонику", - 4102535566: "Глубина За Проход", - 2791699253: "Производный путь: %s", - 1230133196: "Флэш память устройства не обнаружена.", - 3836852788: "Готово?", - 382368239: "Драйвер", - 3978947916: "Кодер", - 4090746898: "Дебаунс Кодера", - 374684711: "Зашифровать Мнемонику", - 1244124409: "Зашифрованный QR Код", - 2968548114: "Зашифрованная мнемоника не была сохранена", - 3315319371: "Зашифрованная мнемоника была сохранена с ID: ", - 350279787: "Шифрование", - 2601598799: "Метод шифрования", - 3504179008: "Введите каждое слово вашей мнемоники BIP-39 в виде числа от 1 до 2048.", - 1100685007: "Введите каждое слово вашей мнемоники BIP-39 в виде шестнадцатеричного числа от 1 до 800.", - 4090266642: "Введите каждое слово вашей мнемоники BIP-39 в виде восьмеричного числа от 1 до 4000.", - 2780625730: "Введите каждое слово вашей BIP-39 мнемоники.", - 784361051: "Ошибка:\n%s", - 1505332462: "Выйти", - 3838465623: "Исследовать файлы?", - 4170881190: "Экспортирование на SD карту..", - 1711312434: "Расширенный Публичный Ключ", - 383371114: "Не удалось расшифровать", - 3048830188: "Не удалось загрузить PSBT", - 4192663412: "Не удалось загрузить адрес", - 1996021743: "Не удалось загрузить ключ", - 1108715658: "Не удалось загрузить сообщение", - 1081425878: "Не удалось загрузить мнемонику", - 928667220: "Не удалось загрузить выходной дескриптор", - 1620572516: "Не удалось загрузить фразу-пароль", - 2946146830: "Не удалось сохранить мнемонику", - 1303554751: "Комиссия: ", - 104500973: "Скорость подачи", - 3313339187: "Имя файла", - 1982637349: "Файл %s существует на SD карте, перезаписать?", - 3737729752: "Фингерпринт: %s", - 2542772894: "Прошивка превышает максимальный размер: %d", - 1406590538: "Flute Диаметр", - 3086093110: "Бесплатно: ", - 1893243331: "Из Памяти", + 1207696150: "Cambio", + 3126552510: "Direcciones de Cambio", + 1583186953: "Cambiar de tema y reiniciar?", + 2697733395: "¡Cambios guardados en la tarjeta SD!", + 388908871: "Los cambios durarán hasta que se apague.", + 3442025874: "Verifique la tarjeta SD", + 3119547911: "¿Compruebe que la dirección pertenece a esta cartera?", + 2856261511: "La dirección de cambio %d no coincide.", + 2788541416: "Comprobado %d dirección de depósito sin coincidencias.", + 2446472910: "Verificación de coincidencia de dirección de cambio %d ..", + 2470115694: "Comprobación de la tarjeta SD..", + 3655273987: "Comprobando la dirección de depósito %d para alguna coincidencia..", + 2407028014: "SeedQR Compacto", + 4041895036: "¿Continuar?", + 4094072796: "Crear código QR", + 167798282: "¿Crear código QR desde el texto?", + 2767642191: "Creado: ", + 3513215254: "Código QR personalizado", + 124617190: "Profundidad de corte", + 597912140: "Método de corte", + 2504034831: "Decimal", + 2751113454: "Descifrar?", + 3510912550: "Eliminar %s?", + 1016609898: "¿Borrar archivo?", + 1364509700: "Eliminar mnemónico", + 4102535566: "Profundidad por pasada", + 2791699253: "Derivación: %s", + 1230133196: "Almacenamiento flash del dispositivo no detectado.", + 3836852788: "¿Listo?", + 382368239: "Operador", + 3978947916: "Codificador", + 4090746898: "Antirrebote del codificador", + 374684711: "Cifrado mnemónico", + 1244124409: "Código QR cifrado", + 2968548114: "Mnemonic cifrado no se almacenó", + 3315319371: "Mnemónica cifrada fue almacenada con ID:", + 350279787: "Encriptación", + 2601598799: "Modo de encriptación", + 3504179008: "Ingrese cada palabra de su mnemónico BIP-39 como un número del 1 al 2048.", + 1100685007: "Ingrese cada palabra de su mnemónico BIP-39 como un número en hexadecimal del 1 al 800.", + 4090266642: "Ingrese cada palabra de su mnemónico BIP-39 como un número en octal del 1 al 4000.", + 2780625730: "Ingrese cada palabra de su mnemónico BIP-39.", + 784361051: "Error:\n%s", + 1505332462: "Esc", + 3838465623: "Explorar archivos?", + 4170881190: "Exportando a la tarjeta SD..", + 1711312434: "Llave Pública", + 383371114: "No se descife", + 3048830188: "No se puede cargar la PSBT", + 4192663412: "No se puede cargar la address", + 1996021743: "No se pudo cargar la clave", + 1108715658: "No se pudo cargar el mensaje", + 1081425878: "No se puede cargar la mnemotécnica", + 928667220: "No se pudo cargar el descriptor de salida", + 1620572516: "No se pudo cargar frase de pases", + 2946146830: "No pudo almacenar mnemonic", + 1303554751: "Comisión: ", + 104500973: "Tasa de alimentación", + 3313339187: "Nombre del archivo", + 1982637349: "El nombre de archivo %s existe en la tarjeta SD, ¿sobrescribir?", + 3737729752: "Huella Dactilar: %s", + 2542772894: "El firmware supera el tamaño máximo: %d", + 1406590538: "Diámetro de la flauta", + 3086093110: "Libre: ", + 1893243331: "Desde el almacenamiento", 4120536442: "GRBL", - 299338213: "Назначить этой мнемоники кастомный ID? В ином случае будет использован текущий фингерпринт", - 602716148: "OK", - 3580020863: "Шестнадцатеричный Публичный Ключ", - 2691246967: "Шестнадцатеричный", - 2736309107: "ID уже существует\n", - 1706005805: "Неполный выходной дескриптор", - 631342955: "Входы (%d): ", - 2585599782: "Неверный адрес", - 2874529150: "Неверный загрузчик", - 4093416954: "Неверная длина мнемоники", - 1422874211: "Неверный публичный ключ", - 2443867979: "Неверный кошелек:\n%s", - 4122897393: "Инвертировать", - 3000888649: "Ключ", - 2686333978: "Ключ: ", - 4123798664: "Krux\n\n\nВерсия\n%s", - 3835918229: "Тестовый QR Принтера Krux", - 766317539: "Язык", - 972436696: "Задержка Линии", - 3596093890: "Линия: ", - 2820726296: "Загрузить Мнемонику", - 879727077: "Загрузить с SD карты?", - 669106195: "Загрузить одну?", - 3330705289: "Загрузить?", - 2596531078: "Загрузка Камеры..", - 596389387: "Загрузка адреса сдачи %d..", - 336702608: "Загрузка принтера..", - 2538883522: "Загрузка адреса получения %d..", - 3159494909: "Загрузка..", - 1177338798: "Локаль", - 2817059741: "Расположение", - 63976957: "Уровень логирования", - 86530918: "Логирование", - 2917810189: "Максимальная длина превышена (%s)", - 2030045667: "Сообщение", - 3928301843: "Отсутствует файл подписи", - 1948316555: "Мнемоника", - 2123991188: "ID мнемоники", - 3911073154: "ID памяти мнемоники", - 570639842: "Мнемоника не была расшифрована", - 1746030071: "Мнемоника не была зашифрована", - 1458925155: "Изменено: ", - 1845376098: "Мультиподпись", - 2939797024: "Сеть", - 73574491: "Новая Мнемоника", - 2792272353: "Обнаружена новая прошивка.\n\nSHA256:\n%s\n\n\n\nУстановить?", - 4063104189: "Нет", - 3927838899: "Без BIP39 фразы-пароля", - 4092516657: "Недостаточно бросков!", - 1577637745: "Восьмеричный", - 3312581301: "PBKDF2 Итерации", + 299338213: "¿Darle a este mnemónico una identificación personalizada?De lo contrario se utilizará la huella digital actual", + 602716148: "Ir", + 3580020863: "Clave pública hexadecimal", + 2691246967: "Hexadecimal", + 2736309107: "ID ya existe\n", + 1706005805: "Descriptor incompleto", + 631342955: "Entradas (%d): ", + 2585599782: "Dirección inválida", + 2874529150: "Cargador de arranque inválido", + 4093416954: "Longitud mnemotécnica no válida", + 1422874211: "Tecla pública inválida", + 2443867979: "Cartera inválida:\n%s", + 4122897393: "Invertir", + 3000888649: "Clave", + 2686333978: "Clave:", + 4123798664: "Krux\n\n\nVersión\n%s", + 3835918229: "Prueba de impresora Krux QR", + 766317539: "Idioma", + 972436696: "Retraso de línea", + 3596093890: "Línea: ", + 2820726296: "Cargar el mnemónico", + 879727077: "¿Cargar desde la tarjeta SD?", + 669106195: "¿Cargar algo?", + 3330705289: "¿Cargar?", + 2596531078: "Cargando Camara..", + 596389387: "Cargando dirección de cambio %d..", + 336702608: "Cargando impresora..", + 2538883522: "Cargando dirección de recepción %d..", + 3159494909: "Cargando..", + 1177338798: "Idioma", + 2817059741: "Ubicación", + 63976957: "Nivel de registro", + 86530918: "Registro", + 2917810189: "Longitud máxima excedida (%s)", + 2030045667: "Mensaje", + 3928301843: "Falta de firma faltante", + 1948316555: "Mnemotécnica", + 2123991188: "Identificación de lo mnemónico", + 3911073154: "ID de almacenamiento mnemónico", + 570639842: "Mnemonic no fue descifrado", + 1746030071: "Mnemonic no fue descifrado", + 1458925155: "Modificado: ", + 1845376098: "Multisig", + 2939797024: "La red", + 73574491: "Nuevo Mnemónico", + 2792272353: "Nuevo firmware detectado.\n\nSHA256:\n%s\n\n\n\n¿Instalar?", + 4063104189: "No", + 3927838899: "Sin frase de contraseña BIP39", + 4092516657: "¡No hay suficientes rollos!", + 1577637745: "Octales", + 3312581301: "Iter. PBKDF2", 721090621: "PSBT", - 995862913: "Закрасьте перфорированные точки черным цветом, чтобы их можно было обнаружить.", - 2987800462: "Ширина Бумаги", - 3050763890: "Часть\n%d / %d", - 3559456868: "Размер Части", - 4249903283: "Фраза-пароль", - 3712257341: "Фраза-пароль: ", - 140802882: "Постоянная Память", - 1703779997: "QR открытым текстом", - 3561756278: "Пожалуйста загрузите выходной дескриптор кошелька", - 784609464: "Скорость Погружения", - 3037062877: "Напечатать Тестовый QR", - 4278257699: "Напечатать в виде QR?\n\n%s\n\n", - 516488026: "Печатать?\n\n%s\n\n", - 1123106929: "Принтер", - 3903571079: "Драйвер Принтера не установлен!", - 2609799302: "Идет печать\n%d / %d", - 844861889: "Идет печать ...", - 2580599003: "Продолжить?", - 556126964: "Обработка ...", - 1848310591: "QR Код", - 710709610: "RX Пин", - 2697857197: "Получить", - 1746677167: "Адрес Получения", - 364354944: "Регион: ", - 1662254634: "Просмотрите отсканированные данные, отредактируйте при необходимости", - 770350922: "Бросьте кубик не менее %d раз, чтобы сгенерировать мнемонику.", - 856795528: "Броски:\n\n%s", - 255086803: "Броски: %d\n", - 3976793317: "SD карта", - 2827687530: "SD карта не обнаружена", - 2736513298: "SD карта не обнаружена.", - 3593785196: "SHA256 бросков:\n\n%s", - 1143278725: "SHA256 снэпшота:\n\n%s", + 995862913: "Pinte los puntos perforados de negro para que puedan ser detectados.", + 2987800462: "Ancho del papel", + 3050763890: "Parte\n%d / %d", + 3559456868: "Tamaño de la pieza", + 4249903283: "Contraseña", + 3712257341: "Frase de pases:", + 140802882: "Salvar", + 1703779997: "QR de Texto", + 3561756278: "Cargue un descriptor de billetera", + 784609464: "Tasa de caída", + 3037062877: "Prueba de impresión QR", + 4278257699: "¿Imprimir con Codigo QR?\n\n%s\n\n", + 516488026: "¿Impresión?\n\n%s\n\n", + 1123106929: "Impresora", + 3903571079: "¡El controlador de impresora no está configurado!", + 2609799302: "Imprimiendo\n%d / %d", + 844861889: "Imprimiendo ...", + 2580599003: "¿Continuar?", + 556126964: "Procesando ...", + 1848310591: "Código QR", + 710709610: "RX Alfiler", + 2697857197: "Recepción", + 1746677167: "Direcciones de Recepción", + 364354944: "Región: ", + 1662254634: "Revise los datos escaneados, edítelos si es necesario", + 770350922: "Tira el dado al menos %d veces para generar un mnemotécnico.", + 856795528: "Rollos:\n\n%s", + 255086803: "Rollos: %d\n", + 3976793317: "Tarjeta SD", + 2827687530: "Tarjeta SD no detectada", + 2736513298: "Tarjeta SD no detectada.", + 3593785196: "SHA256 de rollos:\n\n%s", + 1143278725: "SHA256 de la instantánea:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Сохранить на SD карту?", - 810036588: "Сохранено на SD карту:\n%s", - 763824768: "Шкала", - 4117455079: "Отсканировать Адрес", - 3219991109: "Отсканировать BIP39 фразу-пароль", - 2537207336: "Отсканировать Ключ QR код", - 4006316572: "Сканирование слов 1-12 снова", - 2736506158: "Сканирование слов 13-24", - 3593497655: "Заставка", - 266935239: "SeedQR", - 1698829144: "Трансфер самому себе или Сдача (%d): ", - 473154195: "Настройки", - 1825881236: "Выключить", - 2120776272: "Выключение..", - 1061961408: "Подписать", - 4282338366: "Подписать?", - 746161122: "Подпись", - 1988416729: "Подписанное Сообщение", - 3672006076: "Подписанное PSBT", - 2281377987: "Одна подпись", - 4221794628: "Размер: ", - 2344747135: "Некоторые проверки не могут быть выполнены.", - 2309020186: "Расход (%d): ", - 3355862324: "Стэкбит 1248", - 3303592908: "Сохранить на Флэш Память", - 720041451: "Сохранить на SD Карту", - 3514476519: "Свайпните, чтобы сменить режим", - 1898550184: "ПРИКОСНИТЕСЬ или нажмите ВВОД, чтобы захватить", - 4228215415: "TX Пин", - 2612594937: "Текст", - 1454688268: "Тема", - 1180180513: "Термальный", - 4119292117: "Мини Сид-фраза", - 1732872974: "Мини Сид-фраза (Биты)", - 725348723: "Инструменты", - 3684696112: "Прикоснитесь Границы", - 2978718564: "Тачскрин", - 2732611775: "Попробовать ещё?", - 1487826746: "Введите BIP39 фразу-пароль", - 2061556020: "Введите Ключ", - 2089395053: "Юнит", - 2845607430: "Обновление загрузчика..\n\n%d%%", - 4164597446: "Обновление завершено.\n\nВыключение..", - 2736001501: "Обновление прошивки..\n\n%d%%", - 2674953168: "Использовать черную фоновую поверхность.", - 2402455261: "Использовать энтропию камеры, чтобы создать новую мнемонику", - 236075140: "Использовано: ", - 4003084591: "Значение %s вне диапозона: [%s, %s]", - 4191058607: "С Помощью Камеры", - 1254681955: "С Помощью D20", - 525309547: "С Помощью D6", - 590330112: "С Помощью Ручного Ввода", - 2504354847: "Дождитесь Захвата", - 3992434312: "Время ожидания", - 2297028319: "Дескриптор Кошелька", - 4232654916: "Выходной дескриптор кошелька", - 2587172867: "Выходной дескриптор кошелька загружен!", - 2499782468: "Выходной дескриптор кошелька не найден.", - 2671738224: "Предупреждение:", - 797660533: "Слово %d", - 3742424146: "Числа Слов", - 2965123464: "Слова", - 1303016265: "Да", - 771968845: "Ваши изменения будут сохранены на флэш памяти устройства.", - 2569054451: "Ваши изменения будут сохранены на SD карте.", + 3531742595: "¿Guardar en la tarjeta SD?", + 810036588: "Guardado en la tarjeta SD:\n%s", + 763824768: "Escala", + 4117455079: "Escanear Dirección", + 3219991109: "Escanear frase de pases BIP39", + 2537207336: "Escanear el código QR", + 4006316572: "Escaneo de palabras 1-12 de nuevo", + 2736506158: "Escaneo de palabras 13-24", + 266935239: "Seedqr", + 1698829144: "Autotransferencia o Cambio (%d): ", + 473154195: "Ajustes", + 1825881236: "Apagar", + 2120776272: "Apagando..", + 1061961408: "Firmar", + 4282338366: "¿Firmar?", + 746161122: "Firma", + 1988416729: "Mensaje firmado", + 3672006076: "PSBT firmado", + 2281377987: "Single-sig", + 4221794628: "Espacio: ", + 2344747135: "No se pueden realizar algunos cheques.", + 2309020186: "Gastos (%d): ", + 3355862324: "Stackbit 1248", + 3303592908: "Almacenar en flash", + 720041451: "Almacenar en la tarjeta SD", + 3514476519: "Deslizar para cambiar de modo", + 1898550184: "TOQUE o ENTER para capturar", + 4228215415: "TX Alfiler", + 2612594937: "Texto", + 1454688268: "Tema", + 1180180513: "Térmico", + 4119292117: "Tiny Seed", + 1732872974: "Tiny Seed (bits)", + 725348723: "Herramientas", + 3684696112: "Umbral Táctil", + 2978718564: "Pantalla táctil", + 2732611775: "¿Intentar con mas?", + 1487826746: "Escriba la frase de pases BIP39", + 2061556020: "Introduzca la clave", + 2089395053: "Unidad", + 2845607430: "Actualización de Bootloader..\n\n%d%%", + 4164597446: "Actualización completa.\n\nApagando..", + 2736001501: "Actualización de firmware..\n\n%d%%", + 2674953168: "Use una superficie de fondo negra.", + 2402455261: "Use la entropía de la cámara para crear una nueva mnemónica", + 236075140: "Usado: ", + 4003084591: "Valor %s fuera del rango: [ %s, %s]", + 989428076: "El valor debe ser múltiple de %s", + 4191058607: "Vía cámara", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Mediante entrada manual", + 2504354847: "Espera la captura", + 2297028319: "Descriptor de Cartera", + 4232654916: "Descriptor de salida de billetera", + 2587172867: "¡Se ha cargado el descriptor de salida de la cartera!", + 2499782468: "No se encontró el descriptor de salida de la cartera.", + 2671738224: "Advertencia:", + 797660533: "Palabra %d", + 3742424146: "Números de palabra", + 2965123464: "Palabras", + 1303016265: "Sí", + 771968845: "Sus cambios se guardarán en el almacenamiento flash del dispositivo.", + 2569054451: "Sus cambios se guardarán en la tarjeta SD.", }, - "vi-VN": { - 1185266064: "%d của %d đa chữ kí", - 2004520398: "%d. Thay đổi: \n\n%s\n\n", - 3862364126: "%d. Tự chuyển nhượng: \n\n%s\n\n", - 3264377309: "%d. Chi tiêu: \n\n%s\n\n", - 2399232215: "%s\n\nis một địa chỉ thay đổi hợp lệ!", - 3921290840: "%s\n\nlà một địa chỉ khả dụng!", - 1808355833: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 1306127065: "%s\n\nKHÔNG TÌM ĐƯỢC trong địa chỉ %d đầu tiên", - 3348584292: "(Thực nghiệm)", - 2739590230: "12 từ", - 1310058127: "24 từ", + "de-DE": { + 1185266064: "%d von %d Multisig", + 2004520398: "%d. Change: \n\n%s\n\n", + 3862364126: "%d. Selbstübertragung: \n\n%s\n\n", + 3264377309: "%d. Ausgaben: \n\n%s\n\n", + 2399232215: "%s\n\nist eine gültige Change Adresse!", + 3921290840: "%s\n\nist eine gültige Empfangsadresse!", + 1808355833: " %s\n\nwurde in den ersten %d Change Adressen NICHT GEFUNDEN", + 1306127065: "%s\n\nwurde in den ersten %d Empfangsadressen NICHT GEFUNDEN", + 3348584292: "(Experimental)", + 2739590230: "12 Wörter", + 1310058127: "24 Wörter", 2743272264: "ABC", - 1949634023: "Về chúng tôi", + 1949634023: "Über", 1517128857: "Adafruit", - 3270727197: "Địa chỉ", - 2574498267: "Entropy bổ sung từ máy ảnh cần thiết cho chế độ AES-CBC", - 283202181: "Căn chỉnh camera và Tiny Seed đúng cách.", - 88746165: "Chống lóa bị vô hiệu hóa", - 1521033296: "Đã bật chống lóa", - 1056821534: "Bạn có chắc không?", - 3247612282: "Mã mnemonic dạng chuẩn BIP39", - 3455872521: "Trở lại", - 2541860807: "Sao lưu bộ tải khởi động..\n\n%d%%", - 2256777600: "Chữ ký xấu", - 3937333362: "Tốc độ baud", + 3270727197: "Adresse", + 2574498267: "AES-CBC-Modus benötigt zusätzliche Entropie der Kamera", + 283202181: "Richte Kamera und Tiny Seed korrekt aus.", + 88746165: "Blendschutz deaktiviert", + 1521033296: "Blendschutz aktiviert", + 1056821534: "Bist Du sicher?", + 3455872521: "Zurück", + 2541860807: "Bootloader wird gesichert..\n\n%d%%", + 2256777600: "Ungültige Signatur", + 3937333362: "Baudrate", 427617266: "Bitcoin", - 928727036: "Đệm viền", + 928727036: "Randpolsterung", 213030954: "CNC", - 1207696150: "Thay đổi", - 3126552510: "Thay địa chỉ", - 1583186953: "Thay đổi chủ đề và khởi động lại?", - 2697733395: "Thay đổi được lưu trên thẻ SD!", - 388908871: "Thay đổi sẽ kéo dài cho đến khi tắt máy.", - 3442025874: "Kiểm tra thẻ SD", - 3119547911: "Kiểm tra địa chỉ đó có thuộc về ví này không?", - 2856261511: "Đã kiểm tra %d địa chỉ thay đổi không có kết quả phù hợp.", - 2788541416: "Đã kiểm tra %d địa chỉ nhận được và không tìm thấy tương thích.", - 2446472910: "Đang kiểm tra địa chỉ thay đổi %d để khớp..", - 2470115694: "Kiểm tra thẻ SD..", - 3655273987: "Đang kiểm tra %d địa chỉ..", - 2407028014: "SeedQR nhỏ gọn", - 4041895036: "Tiếp tục?", - 4094072796: "Tạo mã QR", - 167798282: "Tạo mã QR từ văn bản?", - 2767642191: "Tạo:", - 3513215254: "Mã QR tùy chỉnh", - 124617190: "Chiều sâu cắt", - 597912140: "Phương pháp cắt", - 2504034831: "Số thập phân", - 2751113454: "Phản đối?", - 3510912550: "Xóa %s?", - 1016609898: "Xóa tài liệu?", - 1364509700: "Xóa ghi nhớ", - 4102535566: "Độ sâu mỗi lần vượt qua", - 2791699253: "Nguồn gốc: %s", - 1230133196: "Không phát hiện bộ lưu trữ flash của thiết bị.", - 3836852788: "Hoàn tất?", - 382368239: "Người cầm lái", - 3978947916: "Mã hoá", - 4090746898: "Gỡ lỗi bộ mã hóa", - 374684711: "Mã hóa Mnemonic", - 1244124409: "Mã QR được mã hóa", - 2968548114: "MNemon được mã hóa không được lưu trữ", - 3315319371: "Mnemonic được mã hóa được lưu trữ với ID:", - 350279787: "Mã hóa", - 2601598799: "Chế độ mã hóa", - 3504179008: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn dưới dạng số từ 1 đến 2048.", - 1100685007: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số thập lục phân từ 1 đến 800.", - 4090266642: "Nhập từng từ trong bản ghi nhớ BIP-39 của bạn dưới dạng số bát phân từ 1 đến 4000.", - 2780625730: "Nhập từng kí tự của mã mnemonic BIP-39 của bạn.", - 784361051: "Lỗi:\n%s", + 1207696150: "Change Adresse", + 3126552510: "Change Adressen", + 1583186953: "Thema ändern und neu starten?", + 2697733395: "Änderungen auf SD-Karte gespeichert!", + 388908871: "Änderungen bleiben bis zum Herunterfahren bestehen.", + 3442025874: "Prüfe SD-Karte", + 3119547911: "Überprüfen, ob diese Adresse zu dieser Wallet gehört?", + 2856261511: "Überprüfte %d Change Adresse ohne Übereinstimmungen.", + 2788541416: "Überprüfte %d Empfangsadressen ohne Übereinstimmungen.", + 2446472910: "Überprüfung der Change Adresse %d auf Übereinstimmung..", + 2470115694: "Suche nach SD-Karte..", + 3655273987: "Überprüfung der Empfangsadresse %d auf Übereinstimmung..", + 2407028014: "Kompakt SeedQR", + 4041895036: "Weiter?", + 4094072796: "Erstelle QR-Code", + 167798282: "QR-Code aus Text erzeugen?", + 2767642191: "Erstellt:", + 3513215254: "Benutzerdefinierte QR-Code", + 124617190: "Schnitttiefe", + 597912140: "Cut-Methode", + 2504034831: "Dezimal", + 2751113454: "Entschlüsseln?", + 3510912550: "Löschen %s?", + 1016609898: "Datei löschen?", + 1364509700: "Mnemonic löschen", + 4102535566: "Tiefe pro Durchgang", + 2791699253: "Ableitung: %s", + 1230133196: "Geräte-Flash-Speicher nicht erkannt.", + 3836852788: "Fertig?", + 382368239: "Driver", + 3978947916: "Encoder", + 4090746898: "Encoder-Entprellung", + 374684711: "Verschlüssel Mnemonic", + 1244124409: "Verschlüsselter QR-Code", + 2968548114: "Verschlüsselte Mnemonic wurde nicht gespeichert", + 3315319371: "Speicherung der verschlüsselten Mnemonic mit ID: ", + 350279787: "Verschlüsselung", + 2601598799: "Verschlüsselungsmodus", + 3504179008: "Gib jedes Wort Deiner BIP-39 Mnemonic als Zahl von 1 bis 2048 ein.", + 1100685007: "Gib jedes Wort Deiner BIP-39 Mnemonic als Hexadezimalzahl von 1 bis 800 ein.", + 4090266642: "Gib jedes Wort Deiner BIP-39 Mnemonic als Oktalzahl von 1 bis 4000 ein.", + 2780625730: "Gib jedes Wort Deiner BIP-39 Mnemonic ein.", + 784361051: "Fehler:\n%s", 1505332462: "Esc", - 3838465623: "Khám phá các tập tin?", - 4170881190: "Xuất vào thẻ SD ..", - 1711312434: "Khóa công cộng", - 383371114: "Không giải mã được", - 3048830188: "Tải PSBT thất bại", - 4192663412: "Tải địa chỉ thất bại", - 1996021743: "Không tải khóa", - 1108715658: "Không tải được tin nhắn", - 1081425878: "Tải mã mnemonic thất bại", - 928667220: "Không thể tải bộ mô tả đầu ra", - 1620572516: "Không tải được cụm mật khẩu", - 2946146830: "Không lưu trữ MNemonic", - 1303554751: "Phí: ", - 104500973: "Tỷ lệ thức ăn", - 3313339187: "Tên tệp", - 1982637349: "Tên tệp %s tồn tại trên thẻ SD, ghi đè lên?", - 3737729752: "Dấu vân tay: %s", - 2542772894: "Phần sụn vượt quá kích thước tối đa: %d", - 1406590538: "Đường kính ống sáo", - 3086093110: "Khả dụng: ", - 1893243331: "Từ lưu trữ", + 3838465623: "Dateien durchsuchen?", + 4170881190: "Auf SD-Karte exportieren..", + 1711312434: "Öffentlicher Schlüssel", + 383371114: "Entschlüsselung fehlgeschlagen", + 3048830188: "PSBT konnte nicht geladen werden", + 4192663412: "Adresse konnte nicht geladen werden", + 1996021743: "Schlüssel konnte nicht geladen werden", + 1108715658: "Nachricht konnte nicht geladen werden", + 1081425878: "Mnemonic konnte nicht geladen werden", + 928667220: "Ausgabedeskriptor konnte nicht geladen werden", + 1620572516: "Passphrase konnte nicht geladen werden", + 2946146830: "Mnemonic konnte nicht gespeichert werden", + 1303554751: "Gebühr: ", + 104500973: "Vorschubgeschwindigkeit", + 3313339187: "Dateiname", + 1982637349: "Dateiname %s existiert auf SD-Karte, überschreiben?", + 3737729752: "Fingerabdruck: %s", + 2542772894: "Die Firmware übersteigt die maximale Größe: %d", + 1406590538: "Flötendurchmesser", + 3086093110: "Frei: ", + 1893243331: "Vom Speicher", 4120536442: "GRBL", - 299338213: "Cung cấp cho Mnemonic này một ID tùy chỉnh?Nếu không thì dấu vân tay hiện tại sẽ được sử dụng", - 602716148: "Đến", - 3580020863: "Khóa công khai Hex", - 2691246967: "Thập lục phân", - 2736309107: "Id đã tồn tại\n", - 1706005805: "Bộ mô tả đầu ra chưa hoàn chỉnh", - 631342955: "Đầu vào (%d): ", - 2585599782: "Địa chỉ không hợp lệ", - 2874529150: "Bộ tải khởi động không hợp lệ", - 4093416954: "Độ dài mã mnemonic không hợp lệ", - 1422874211: "Khóa công khai không hợp lệ", - 2443867979: "Ví không hợp lệ:\n%s", - 4122897393: "Đảo ngược", - 3000888649: "Chìa khóa", - 2686333978: "Chìa khóa:", - 4123798664: "Krux\n\n\nPhiên Bản\n%s", - 3835918229: "QR kiểm tra máy in Krux", - 766317539: "Ngôn ngữ", - 972436696: "Độ trễ Dòng", - 3596093890: "Đường kẻ: ", - 2820726296: "Tải mã mnemonic", - 879727077: "Tải từ thẻ SD?", - 669106195: "Tải một?", - 3330705289: "Tải?", - 2596531078: "Đang tải máy ảnh..", - 596389387: "Đang tải thay đổi địa chỉ %d..", - 336702608: "Tải máy in ..", - 2538883522: "Đang tải địa chỉ nhận %d..", - 3159494909: "Đang tải..", - 1177338798: "Ngôn ngữ", - 2817059741: "Vị trí cửa hàng", + 299338213: "Dieser Mnemonic eine benutzerdefinierte ID zuteilen? Andernfalls wird der aktuelle Fingerabdruck verwendet", + 602716148: "Go", + 3580020863: "Hex öffentlicher Schlüssel", + 2691246967: "Hexadezimal", + 2736309107: "ID existiert bereits\n", + 1706005805: "Unvollständiger Ausgabedeskriptor", + 631342955: "Input (%d): ", + 2585599782: "Ungültige Adresse", + 2874529150: "Ungültiger Bootloader", + 4093416954: "Ungültige mnemonische Lange", + 1422874211: "Ungültiger öffentlicher Schlüssel", + 2443867979: "Ungültige Wallet:\n%s", + 4122897393: "Umkehren", + 3000888649: "Schlüssel", + 2686333978: "Schlüssel:", + 4123798664: "Krux\n\n\nVersion\n%s", + 3835918229: "Krux Drucker Test-QR", + 766317539: "Sprache", + 972436696: "Leitungsverzögerung", + 3596093890: "Linie: ", + 2820726296: "Mnemonic laden", + 879727077: "Von SD-Karte laden?", + 669106195: "Eine laden?", + 3330705289: "Laden?", + 2596531078: "Lade Kamera..", + 596389387: "Lade Change Adresse %d..", + 336702608: "Drucker wird geladen..", + 2538883522: "Lade Empfangsadresse %d..", + 3159494909: "Wird geladen..", + 1177338798: "Spracheinstellung", + 2817059741: "Speicherort", 63976957: "Log Level", - 86530918: "Khai thác gỗ", - 2917810189: "Chiều dài tối đa vượt quá (%s)", - 2030045667: "Tin nhắn", - 3928301843: "Thiếu tập tin chữ ký", - 1948316555: "Mã mnemonic", - 2123991188: "ID ghi nhớ", - 3911073154: "ID lưu trữ ghi nhớ", - 570639842: "Ghi nhớ không được giải mã", - 1746030071: "Ghi nhớ không được mã hóa", - 1458925155: "Đã sửa đổi:", - 1845376098: "Đa chữ kí", - 2939797024: "Mạng lưới", - 73574491: "Mnemonic mới", - 2792272353: "Phát hiện phần sụn mới.\n\nSHA256:\n%s\n\n\n\nCài đặt phần mềm?", - 4063104189: "Không", - 3927838899: "Không có cụm mật khẩu BIP39", - 4092516657: "Không đủ cuộn!", - 1577637745: "Bát phân", - 3312581301: "Lặp lại PBKDF2", + 86530918: "Logging", + 2917810189: "Maximale Länge überschritten (%s)", + 2030045667: "Nachricht", + 3928301843: "Fehlende Signaturdatei", + 1948316555: "Mnemonic", + 2123991188: "Mnemonische ID", + 3911073154: "Mnemonische Speicher-ID", + 570639842: "Mnemonic wurde nicht entschlüsselt", + 1746030071: "Mnemonic wurde nicht verschlüsselt", + 1458925155: "Geändert:", + 1845376098: "Multisig", + 2939797024: "Netzwerk", + 73574491: "Neue Mnemonic", + 2792272353: "Neue Firmware erkannt.\n\nSHA256:\n%s\n\n\n\nInstallieren?", + 4063104189: "Nein", + 3927838899: "Keine BIP39 Passphrase", + 4092516657: "Nicht genug Würfe!", + 1577637745: "Oktal", + 3312581301: "PBKDF2-Iter.", 721090621: "PSBT", - 995862913: "Sơn các chấm đục lỗ màu đen để chúng có thể được phát hiện.", - 2987800462: "Chiều rộng giấy", - 3050763890: "Phần\n%d / %d", - 3559456868: "Kích thước một phần", - 4249903283: "Cụm mật khẩu", - 3712257341: "Cụm cụm:", - 140802882: "Vị trí lưu", - 1703779997: "Văn bản rõ QR", - 3561756278: "Vui lòng tải bộ mô tả đầu ra ví", - 784609464: "Tỷ lệ sụt giảm", - 3037062877: "In kiểm tra QR", - 4278257699: "In ra mã QR?\n\n%s\n\n", - 516488026: "In?\n\n%s\n\n", - 1123106929: "Máy in", - 3903571079: "Trình điều khiển máy in không đặt!", - 2609799302: "Đang in\n%d / %d", - 844861889: "In ấn ...", - 2580599003: "Thực hiện?", - 556126964: "Xử lý ...", - 1848310591: "Mã QR", - 710709610: "RX Ghim", - 2697857197: "Nhận được", - 1746677167: "Nhận địa chỉ", - 364354944: "Vùng: ", - 1662254634: "Xem lại dữ liệu đã quét, chỉnh sửa nếu cần", - 770350922: "Lăn xúc xắc ít nhất %d lần để tạo khả năng ghi nhớ.", - 856795528: "Súc sắc cuộn:\n\n%s", - 255086803: "Súc sắc cuộn: %d\n", - 3976793317: "Thẻ SD", - 2827687530: "Thẻ SD không được phát hiện", - 2736513298: "Thẻ SD không được phát hiện.", - 3593785196: "SHA256 của súc sắc cuộn:\n\n%s", - 1143278725: "Sha256 của ảnh chụp nhanh:\n\n%s", + 995862913: "Male gestanzte Punkte schwarz an, damit sie erkannt werden können.", + 2987800462: "Papierbreite", + 3050763890: "Teil\n%d / %d", + 3559456868: "Teilegröße", + 4249903283: "Passphrase", + 3712257341: "Passphrase:", + 140802882: "Speicher", + 1703779997: "Klartext-QR", + 3561756278: "Bitte lade einen Wallet Ausgabedeskriptor", + 784609464: "Tauchrate", + 3037062877: "Drucke Test-QR", + 4278257699: "Als QR-Code drucken?\n\n%s\n\n", + 516488026: "Drucken?\n\n%s\n\n", + 1123106929: "Drucker", + 3903571079: "Druckertreiber nicht gesetzt!", + 2609799302: "Drucken\n%d / %d", + 844861889: "Wird gedruckt ...", + 2580599003: "Weiter?", + 556126964: "Wird bearbeitet ...", + 1848310591: "QR-Code", + 710709610: "RX Pin", + 2697857197: "Empfangen", + 1746677167: "Empfangsadresse", + 364354944: "Region: ", + 1662254634: "Überprüfe gescannte Daten und bearbeite sie bei Bedarf", + 770350922: "Würfel mindestens %d Mal, um eine Mnemonic zu erzeugen.", + 856795528: "Würfe:\n\n%s", + 255086803: "Würfe: %d\n", + 3976793317: "SD-Karte", + 2827687530: "SD-Karte nicht erkannt", + 2736513298: "SD-Karte nicht erkannt.", + 3593785196: "SHA256 der Würfe:\n\n%s", + 1143278725: "SHA256 des Snapshots:\n\n%s", 3338679392: "SHA256:\n%s", - 3531742595: "Lưu vào thẻ SD?", - 810036588: "Đã lưu vào thẻ SD:\n%s", - 763824768: "Cái cân", - 4117455079: "Quét địa chỉ", - 3219991109: "Quét BIP39 Cụm cụm", - 2537207336: "Quét mã QR khóa", - 4006316572: "Quét lại từ 1-12", - 2736506158: "Quét từ 13-24", - 3593497655: "Bảo vệ màn hình", - 266935239: "SEEDQR", - 1698829144: "Tự chuyển nhượng hoặc Thay đổi (%d): ", - 473154195: "Cài đặt", - 1825881236: "Tắt", - 2120776272: "Đang tắt..", - 1061961408: "Chữ kí", - 4282338366: "Kí?", - 746161122: "Chữ ký", - 1988416729: "Tin nhắn đã ký", - 3672006076: "Đã ký PSBT", - 2281377987: "Khóa đơn", - 4221794628: "Dung lượng: ", - 2344747135: "Một số kiểm tra không thể được thực hiện.", - 2309020186: "Chi tiêu (%d): ", + 3531742595: "Auf SD-Karte speichern?", + 810036588: "Auf SD-Karte gespeichert:\n%s", + 763824768: "Skala", + 4117455079: "Adresse\nscannen", + 3219991109: "Scan BIP39 Passphrase", + 2537207336: "Schlüssel QR-Code scannen", + 4006316572: "Wörter 1-12 erneut scannen", + 2736506158: "Wörter 13-24 scannen", + 266935239: "SeedQR", + 1698829144: "Selbstübertragung oder Change (%d): ", + 473154195: "Einstellungen", + 1825881236: "Ausschalten", + 2120776272: "Herunterfahren..", + 1061961408: "Signieren", + 4282338366: "Signieren?", + 746161122: "Signatur", + 1988416729: "Signierte Nachricht", + 3672006076: "Signierte PSBT", + 2281377987: "Single-Sig", + 4221794628: "Größe: ", + 2344747135: "Einige Schecks können nicht durchgeführt werden.", + 2309020186: "Ausgabe (%d): ", 3355862324: "Stackbit 1248", - 3303592908: "Lưu trữ trên flash", - 720041451: "Lưu trữ trên thẻ SD", - 3514476519: "Vuốt để thay đổi chế độ", - 1898550184: "TOUCH hoặc ENTER để chụp", - 4228215415: "TX Ghim", - 2612594937: "Chữ", - 1454688268: "Chủ đề", - 1180180513: "Nhiệt", + 3303592908: "Auf Flash speichern", + 720041451: "Auf der SD-Karte speichern", + 3514476519: "Wischen um den Modus zu ändern", + 1898550184: "TOUCH oder ENTER zum Erfassen", + 4228215415: "TX Pin", + 2612594937: "Text", + 1454688268: "Thema", + 1180180513: "Thermisch", 4119292117: "Tiny Seed", - 1732872974: "Tiny Seed (bit)", - 725348723: "Công cụ", - 3684696112: "Ngưỡng cảm ứng", - 2978718564: "Màn hình cảm ứng", - 2732611775: "Thử thêm nữa?", - 1487826746: "Nhập cụm BIP39", - 2061556020: "Nhập khóa", - 2089395053: "Đơn vị", - 2845607430: "Cập nhật bộ tải khởi động..\n\n%d%%", - 4164597446: "Nâng cấp hoàn tất.\n\nĐang Tắt..", - 2736001501: "Nâng cấp firmware..\n\n%d%%", - 2674953168: "Sử dụng bề mặt nền đen.", - 2402455261: "Sử dụng entropy của máy ảnh để tạo ra một bản ghi âm mới", - 236075140: "Đã sử dụng: ", - 4003084591: "Giá trị %s ngoài phạm vi: [ %s, %s]", - 4191058607: "Qua máy ảnh", - 1254681955: "Qua D20", - 525309547: "Qua D6", - 590330112: "Thông qua đầu vào thủ công", - 2504354847: "Chờ bắt", - 3992434312: "Thời gian chờ đợi", - 2297028319: "Trình mô tả ví", - 4232654916: "Ví đầu ra mô tả", - 2587172867: "Đã tải bộ mô tả đầu ra của ví!", - 2499782468: "Không tìm thấy bộ mô tả đầu ra ví.", - 2671738224: "Cảnh báo:", - 797660533: "Kí tự %d", - 3742424146: "Từ số", - 2965123464: "Từ ngữ", - 1303016265: "Đúng", - 771968845: "Thay đổi của bạn sẽ được lưu trên bộ nhớ flash của thiết bị.", - 2569054451: "Các thay đổi của bạn sẽ được lưu trên thẻ SD.", + 1732872974: "Tiny Seed (Bits)", + 725348723: "Werkzeuge", + 3684696112: "Berühre Schwellenwert", + 2978718564: "Touchscreen", + 2732611775: "Weiter versuchen?", + 1487826746: "BIP39 Passphrase eingeben", + 2061556020: "Schlüssel eingeben", + 2089395053: "Einheit", + 2845607430: "Bootloader wird aktualisiert..\n\n%d%%", + 4164597446: "Upgrade abgeschlossen.\n\nHerunterfahren..", + 2736001501: "Firmware wird aktualisiert..\n\n%d%%", + 2674953168: "Verwende eine schwarze Hintergrundfläche.", + 2402455261: "Verwende die Entropie der Kamera, um eine neue Mnemonic zu erstellen", + 236075140: "Belegt: ", + 4003084591: "Wert %S außerhalb des Bereichs: [ %s, %s]", + 989428076: "Der Wert muss ein Vielfaches von %s sein", + 4191058607: "Via Kamera", + 1254681955: "Via D20", + 525309547: "Via D6", + 590330112: "Via manueller Eingabe", + 2504354847: "Warte auf die Erfassung", + 2297028319: "Wallet-Deskriptor", + 4232654916: "Wallet Ausgabedeskriptor", + 2587172867: "Wallet Ausgabedeskriptor geladen!", + 2499782468: "Wallet Ausgabedeskriptor nicht gefunden.", + 2671738224: "Warnung:", + 797660533: "Wort %d", + 3742424146: "Wortnummern", + 2965123464: "Wörter", + 1303016265: "Ja", + 771968845: "Änderungen werden im Flash-Speicher des Geräts gespeichert.", + 2569054451: "Änderungen werden auf der SD-Karte gespeichert.", }, } diff --git a/tests/pages/test_qr_view.py b/tests/pages/test_qr_view.py index 9727aeb34..1c67a8551 100644 --- a/tests/pages/test_qr_view.py +++ b/tests/pages/test_qr_view.py @@ -15,7 +15,7 @@ def test_load_qr_view(amigo_tft, mocker): SWIPE_LEFT, # lines mode again SWIPE_RIGHT, # back to standard mode BUTTON_ENTER, # leave - BUTTON_PAGE_PREV, # move to Back to Main Menu + BUTTON_PAGE_PREV, # move to Back to Main Menu BUTTON_ENTER, # confirm ] @@ -46,7 +46,7 @@ def test_loop_through_regions(amigo_tft, mocker): SWIPE_LEFT, # lines mode again SWIPE_RIGHT, # back to standard mode BUTTON_ENTER, # leave - BUTTON_PAGE_PREV, # move to Back to Main Menu + BUTTON_PAGE_PREV, # move to Back to Main Menu BUTTON_ENTER, # confirm ] ) diff --git a/tests/shared_mocks.py b/tests/shared_mocks.py index 605a0f84b..4b3ee1834 100644 --- a/tests/shared_mocks.py +++ b/tests/shared_mocks.py @@ -31,6 +31,7 @@ def encode_to_string(data): return new_code_str + def encode(data): # Uses string encoded qr as it already cleaned up the frames # PyQRcode also doesn't offer any binary output @@ -39,15 +40,16 @@ def encode(data): size = 0 while frame_less_qr[size] != "\n": size += 1 - binary_qr = bytearray(b"\x00" * ((size * size + 7) // 8)) + binary_qr = bytearray(b"\x00" * ((size * size + 7) // 8)) for y in range(size): for x in range(size): bit_index = y * size + x bit_string_index = y * (size + 1) + x if frame_less_qr[bit_string_index] == "1": - binary_qr[bit_index>>3] |= 1 << (bit_index % 8) + binary_qr[bit_index >> 3] |= 1 << (bit_index % 8) return binary_qr + def get_mock_open(files: dict[str, str]): def open_mock(filename, *args, **kwargs): for expected_filename, content in files.items(): diff --git a/tests/test_display.py b/tests/test_display.py index a3c584da6..058af6c31 100644 --- a/tests/test_display.py +++ b/tests/test_display.py @@ -1,4 +1,6 @@ -TEST_QR = bytearray(b'\x7fn\xfd\x830\x08v9\xd6\xedj\xa0\xdbUU7\xc8\xa0\xe0_U\x7f\x00i\x00\xe3\xd61P\x08\xf5Q\xef^\xfe`\xe8\xc1\x7f\xdex\x936Y\x91\xb8\xeb\xd29c\xd5\xd4\x7f\x00\n#\xfe\xcd\xd7\rJ\x8e\xd9\xe5\xf8\xb9K\xe6x\x17\xb9\xca\xa0\x9a\x9a\x7f\xbb\x1b\x01') +TEST_QR = bytearray( + b"\x7fn\xfd\x830\x08v9\xd6\xedj\xa0\xdbUU7\xc8\xa0\xe0_U\x7f\x00i\x00\xe3\xd61P\x08\xf5Q\xef^\xfe`\xe8\xc1\x7f\xdex\x936Y\x91\xb8\xeb\xd29c\xd5\xd4\x7f\x00\n#\xfe\xcd\xd7\rJ\x8e\xd9\xe5\xf8\xb9K\xe6x\x17\xb9\xca\xa0\x9a\x9a\x7f\xbb\x1b\x01" +) def test_init(mocker, m5stickv):