// #include // #include "tools.h" #include #include "../fs/readers/folderReader.h" #include "../fs/fstypes.h" #include "../fs/fscopy.h" #include #include #include #include "../gfx/gfx.h" #include "../gfx/gfxutils.h" #include "../gfx/menu.h" #include "../hid/hid.h" // #include "utils.h" #include "../utils/utils.h" #include "../fs/fsutils.h" #include #include #include "../warmboot/warmboot_extractor.h" // #include // #include #include #include void _DeleteFileSimple(char *thing){ //char *thing = CombinePaths(path, entry.name); int res = f_unlink(thing); if (res) DrawError(newErrCode(res)); free(thing); } void _RenameFileSimple(char *sourcePath, char *destPath){ int res = f_rename(sourcePath, destPath); if (res){ DrawError(newErrCode(res)); } } ErrCode_t _FolderDelete(const char *path){ int res = 0; ErrCode_t ret = newErrCode(0); u32 x, y; gfx_con_getpos(&x, &y); Vector_t fileVec = ReadFolder(path, &res); if (res){ ret = newErrCode(res); } else { vecDefArray(FSEntry_t *, fs, fileVec); for (int i = 0; i < fileVec.count && !ret.err; i++){ char *temp = CombinePaths(path, fs[i].name); if (fs[i].isDir){ ret = _FolderDelete(temp); } else { res = f_unlink(temp); if (res){ ret = newErrCode(res); } } free(temp); } } if (!ret.err){ res = f_unlink(path); if (res) ret = newErrCode(res); } clearFileVector(&fileVec); return ret; } int _StartsWith(const char *a, const char *b) { if(strncmp(a, b, strlen(b)) == 0) return 1; return 0; } int listdir(char *path, u32 hos_folder, int *deleted_count) { FRESULT res; DIR dir; u32 dirLength = 0; static FILINFO fno; // Open directory. res = f_opendir(&dir, path); if (res != FR_OK) return res; dirLength = strlen(path); for (;;) { // Clear file or folder path. path[dirLength] = 0; // Read a directory item. res = f_readdir(&dir, &fno); // Break on error or end of dir. if (res != FR_OK || fno.fname[0] == 0) break; // Skip official Nintendo dir if started from root. if (!hos_folder && !strcmp(fno.fname, "Nintendo")) continue; // Set new directory or file. memcpy(&path[dirLength], "/", 1); memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1); // Is it a directory? if (fno.fattrib & AM_DIR) { if ( strcmp(fno.fname, ".Trash") == 0 || strcmp(fno.fname, ".Trashes") == 0 || strcmp(fno.fname, ".DS_Store") == 0 || strcmp(fno.fname, ".Spotlight-V100") == 0 || strcmp(fno.fname, ".apDisk") == 0 || strcmp(fno.fname, ".VolumeIcon.icns") == 0 || strcmp(fno.fname, ".fseventsd") == 0 || strcmp(fno.fname, ".TemporaryItems") == 0 ) { _FolderDelete(path); if (deleted_count) (*deleted_count)++; } else { // Only recurse into directories that were not deleted. listdir(path, 0, deleted_count); } if (res != FR_OK) break; } else { if ( strcmp(fno.fname, ".DS_Store") == 0 || strcmp(fno.fname, ".Spotlight-V100") == 0 || strcmp(fno.fname, ".apDisk") == 0 || strcmp(fno.fname, ".VolumeIcon.icns") == 0 || strcmp(fno.fname, ".fseventsd") == 0 || strcmp(fno.fname, ".TemporaryItems") == 0 || _StartsWith(fno.fname, "._") ) { res = f_unlink(path); if (res) DrawError(newErrCode(res)); if (deleted_count) (*deleted_count)++; } } } f_closedir(&dir); return res; } int _fix_attributes(char *path, u32 *total, u32 hos_folder, u32 check_first_run){ FRESULT res; DIR dir; u32 dirLength = 0; static FILINFO fno; if (check_first_run) { // Read file attributes. res = f_stat(path, &fno); if (res != FR_OK) return res; // Check if archive bit is set. if (fno.fattrib & AM_ARC) { *(u32 *)total = *(u32 *)total + 1; f_chmod(path, 0, AM_ARC); } } // Open directory. res = f_opendir(&dir, path); if (res != FR_OK) return res; dirLength = strlen(path); for (;;) { // Clear file or folder path. path[dirLength] = 0; // Read a directory item. res = f_readdir(&dir, &fno); // Break on error or end of dir. if (res != FR_OK || fno.fname[0] == 0) break; // Skip official Nintendo dir if started from root. if (!hos_folder && !strcmp(fno.fname, "Nintendo")) continue; // Set new directory or file. memcpy(&path[dirLength], "/", 1); memcpy(&path[dirLength + 1], fno.fname, strlen(fno.fname) + 1); // Check if archive bit is set. if (fno.fattrib & AM_ARC) { *total = *total + 1; f_chmod(path, 0, AM_ARC); } // Is it a directory? if (fno.fattrib & AM_DIR) { // Set archive bit to NCA folders. if (hos_folder && !strcmp(fno.fname + strlen(fno.fname) - 4, ".nca")) { *total = *total + 1; f_chmod(path, AM_ARC, AM_ARC); } // Enter the directory. res = _fix_attributes(path, total, hos_folder, 0); if (res != FR_OK) break; } } f_closedir(&dir); return res; } void m_entry_fixArchiveBit(u32 type){ gfx_clearscreen(); gfx_printf("\n\n-- Behebe Archive Bit\n\n"); char path[256]; char label[16]; u32 total = 0; if (sd_mount()) { switch (type) { case 0: strcpy(path, "/"); strcpy(label, "SD-Karte"); break; case 1: default: strcpy(path, "/Nintendo"); strcpy(label, "Nintendo Ordner"); break; } gfx_printf("Durchlaufe alle %s Dateien!\nDas kann einige Zeit dauern...\n\n", label); _fix_attributes(path, &total, type, type); gfx_printf("%kAnzahl reparierter Archiv bits: %d!%k", 0xFF96FF00, total, 0xFFCCCCCC); gfx_printf("\n\n Fertig! Druecke eine Taste um zurueckzukehren"); hidWait(); } } static void _fixAMSErrorFolder(const char *titleId, const char *label){ gfx_clearscreen(); gfx_printf("\n\n-- Fix Fehlercode %s --\n\n", label); if (!sd_mount()) { gfx_printf("SD-Karte konnte nicht gemountet werden.\n"); hidWait(); return; } char *path = CpyStr("sd:/atmosphere/contents"); char *full = CombinePaths(path, titleId); free(path); if (FileExists(full)) { gfx_printf("Entferne Ordner %s ...\n", titleId); FolderDelete(full); gfx_printf("Ordner erfolgreich geloescht.\n"); } else { gfx_printf("Ordner %s nicht gefunden (evtl. bereits behoben).\n", titleId); } free(full); gfx_printf("\n\n Fertig! Druecke eine Taste um zurueckzukehren"); hidWait(); } void m_entry_fixAMSError_4200(void){ _fixAMSErrorFolder("4200000000000010", "4200000000000010"); } void m_entry_fixAMSError_6900(void){ _fixAMSErrorFolder("690000000000000D", "690000000000000D"); } void m_entry_fixAMSError_BD00(void){ _fixAMSErrorFolder("010000000000BD00", "010000000000BD00"); } static int _deleteTheme(char* basePath, char* folderId){ int removed = 0; char *path = CombinePaths(basePath, folderId); if (FileExists(path)) { gfx_printf("-- Theme gefunden: %s\n", path); FolderDelete(path); removed = 1; } free(path); return removed; } void m_entry_deleteInstalledThemes(){ gfx_clearscreen(); gfx_printf("\n\n-- Loesche installierte Themes.\n\n"); int count = 0; count += _deleteTheme("sd:/atmosphere/contents", "0100000000001000"); count += _deleteTheme("sd:/atmosphere/contents", "0100000000001007"); count += _deleteTheme("sd:/atmosphere/contents", "0100000000001013"); if (count > 0) gfx_printf("\n%d Theme(s) geloescht.\n", count); else gfx_printf("\nKeine installierten Themes gefunden.\n"); gfx_printf("\n\n Fertig! Druecke eine Taste um zurueckzukehren"); hidWait(); } void m_entry_deleteBootFlags(){ gfx_clearscreen(); gfx_printf("\n\n-- Automatisches starten der sysmodule deaktivieren.\n\n"); char *storedPath = CpyStr("sd:/atmosphere/contents"); int readRes = 0; int count = 0; Vector_t fileVec = ReadFolder(storedPath, &readRes); if (readRes){ clearFileVector(&fileVec); free(storedPath); DrawError(newErrCode(readRes)); } else { vecDefArray(FSEntry_t*, fsEntries, fileVec); for (int i = 0; i < fileVec.count; i++){ char *suf = "/flags/boot2.flag"; char *subPath = CombinePaths(storedPath, fsEntries[i].name); char *flagPath = CombinePaths(subPath, suf); free(subPath); if (FileExists(flagPath)) { gfx_printf("Loesche: %s\n", flagPath); _DeleteFileSimple(flagPath); count++; } else { free(flagPath); } } clearFileVector(&fileVec); free(storedPath); } if (count > 0) gfx_printf("\n%d Boot-Flag(s) geloescht.\n", count); else if (!readRes) gfx_printf("\nKeine Boot-Flags gefunden.\n"); gfx_printf("\n\n Fertig! Druecke eine Taste um zurueckzukehren"); hidWait(); } void m_entry_fixMacSpecialFolders(){ gfx_clearscreen(); gfx_printf("\n\n-- Mac-Ordner reparieren (dies kann ein wenig dauern, bitte warten.)\n\n"); int deleted = 0; char path[1024]; strcpy(path, "sd:/"); listdir(path, 0, &deleted); if (deleted > 0) gfx_printf("\n%d Mac-Datei(en)/Ordner entfernt.\n", deleted); else gfx_printf("\nKeine Mac-Sonderdateien oder -ordner gefunden.\n"); gfx_printf("\n\n Fertig! Druecke eine Taste um zurueckzukehren"); hidWait(); } static u32 _hex_nibble_lower(char c) { if (c >= '0' && c <= '9') return (u32)(c - '0'); if (c >= 'a' && c <= 'f') return (u32)(c - 'a' + 10); return 0xFFFFFFFFu; } static bool _parse_wb_filename_lower(const char *fname, u32 *fuse_out) { // Expected: wb_xx.bin where xx is lowercase hex (exactly 2 chars). // Example: wb_16.bin if (!fname || !fuse_out) return false; // Length check: "wb_" + 2 + ".bin" = 3 + 2 + 4 = 9 if (strlen(fname) != 9) return false; if (strncmp(fname, "wb_", 3) != 0) return false; if (fname[5] != '.') return false; if (strncmp(fname + 6, "bin", 3) != 0) return false; u32 hi = _hex_nibble_lower(fname[3]); u32 lo = _hex_nibble_lower(fname[4]); if (hi == 0xFFFFFFFFu || lo == 0xFFFFFFFFu) return false; *fuse_out = (hi << 4) | lo; return true; } static void _rstrip(char *s) { if (!s) return; int n = (int)strlen(s); while (n > 0) { char c = s[n - 1]; if (c == '\n' || c == '\r' || c == ' ' || c == '\t') s[--n] = 0; else break; } } static char *_ltrim(char *s) { if (!s) return s; while (*s == ' ' || *s == '\t') s++; return s; } static bool _read_line_no_nl(FIL *fp, char *out, u32 out_sz) { if (!fp || !out || out_sz < 2) return false; u32 idx = 0; BYTE b; UINT br = 0; // Return false on immediate EOF. for (;;) { if (idx >= out_sz - 1) break; FRESULT res = f_read(fp, &b, 1, &br); if (res != FR_OK || br == 0) break; if (b == '\n') break; if (b == '\r') continue; out[idx++] = (char)b; } out[idx] = 0; return idx > 0 || br != 0; } static bool _ini_section_exists(const char *ini_path, const char *section_name) { FIL fp; if (f_open(&fp, ini_path, FA_READ) != FR_OK) return false; char line[256]; bool found = false; while (_read_line_no_nl(&fp, line, sizeof(line))) { char *t = _ltrim(line); if (*t == '[') { char *end = strchr(t, ']'); if (end) { *end = 0; if (!strcmp(t + 1, section_name)) { found = true; break; } *end = ']'; } } } f_close(&fp); return found; } static bool _ini_section_warmboot_is(const char *ini_path, const char *section_name, const char *warmboot_value_rel) { FIL fp; if (f_open(&fp, ini_path, FA_READ) != FR_OK) return false; char line[256]; bool in_section = false; bool is_set = false; while (_read_line_no_nl(&fp, line, sizeof(line))) { char *t = _ltrim(line); if (*t == '[') { char *end = strchr(t, ']'); if (end) { *end = 0; in_section = !strcmp(t + 1, section_name); *end = ']'; } continue; } if (!in_section) continue; char *k = _ltrim(line); if (strncmp(k, "warmboot", 8) != 0) continue; // Ensure this is the "warmboot" key (not warmboot2/etc), allowing whitespace before '='. char *p = k + 8; while (*p == ' ' || *p == '\t') p++; if (*p != '=') continue; p++; p = _ltrim(p); _rstrip(p); if (!strcmp(p, warmboot_value_rel)) { is_set = true; break; } } f_close(&fp); return is_set; } static bool _ini_update_section_warmboot(const char *ini_path, const char *section_name, const char *warmboot_value_rel) { char tmp_path[128]; u32 len = strlen(ini_path); if (len + 4 >= sizeof(tmp_path)) return false; strcpy(tmp_path, ini_path); strcat(tmp_path, ".tmp"); FIL in_fp; FIL out_fp; if (f_open(&in_fp, ini_path, FA_READ) != FR_OK) return false; if (f_open(&out_fp, tmp_path, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) { f_close(&in_fp); return false; } char line[256]; bool in_section = false; bool warmboot_seen = false; bool wrote_any = false; // Buffer trailing empty lines in the target section so the inserted/updated // warmboot=... line stays directly after the last non-empty line. #define MAX_PENDING_BLANKS 32 char pending_blanks[MAX_PENDING_BLANKS][256]; u32 pending_blank_count = 0; while (_read_line_no_nl(&in_fp, line, sizeof(line))) { char *t = _ltrim(line); // Section header? if (*t == '[') { if (in_section && !warmboot_seen) { f_printf(&out_fp, "warmboot=%s\n", warmboot_value_rel); warmboot_seen = true; wrote_any = true; } // Flush buffered empty lines after warmboot, so they don't split it. for (u32 i = 0; i < pending_blank_count; i++) { f_printf(&out_fp, "%s\n", pending_blanks[i]); } pending_blank_count = 0; char *end = strchr(t, ']'); if (end) { *end = 0; in_section = !strcmp(t + 1, section_name); *end = ']'; } f_printf(&out_fp, "%s\n", line); wrote_any = true; continue; } if (in_section) { char *k = _ltrim(line); if (strncmp(k, "warmboot", 8) == 0) { // Replace existing warmboot=... line inside the section. // Allow whitespace between key and '='. char *p = k + 8; while (*p == ' ' || *p == '\t') p++; if (*p == '=') { // Keep the buffered empty lines where the original warmboot key appeared. for (u32 i = 0; i < pending_blank_count; i++) { f_printf(&out_fp, "%s\n", pending_blanks[i]); wrote_any = true; } pending_blank_count = 0; f_printf(&out_fp, "warmboot=%s\n", warmboot_value_rel); warmboot_seen = true; wrote_any = true; continue; } } } // If we're in the target section and warmboot isn't present yet, buffer empty lines // so warmboot will not be separated from the last non-empty entry. if (in_section && !warmboot_seen) { if (*t == 0) { if (pending_blank_count < MAX_PENDING_BLANKS) { strncpy(pending_blanks[pending_blank_count], line, 255); pending_blanks[pending_blank_count][255] = 0; pending_blank_count++; } else { for (u32 i = 0; i < pending_blank_count; i++) { f_printf(&out_fp, "%s\n", pending_blanks[i]); wrote_any = true; } pending_blank_count = 0; f_printf(&out_fp, "%s\n", line); wrote_any = true; } continue; } // Non-empty line: flush buffered blanks first. for (u32 i = 0; i < pending_blank_count; i++) { f_printf(&out_fp, "%s\n", pending_blanks[i]); wrote_any = true; } pending_blank_count = 0; } f_printf(&out_fp, "%s\n", line); wrote_any = true; } if (in_section && !warmboot_seen) { f_printf(&out_fp, "warmboot=%s\n", warmboot_value_rel); wrote_any = true; } // Flush trailing empty lines at EOF (after warmboot) if any. for (u32 i = 0; i < pending_blank_count; i++) { f_printf(&out_fp, "%s\n", pending_blanks[i]); wrote_any = true; } pending_blank_count = 0; f_close(&in_fp); f_close(&out_fp); if (!wrote_any) return false; // Replace original with temp. f_unlink(ini_path); f_rename(tmp_path, ini_path); return true; } void m_entry_fixMarikoWarmbootSleep(void) { gfx_clearscreen(); gfx_printf("\n\n-- Mariko Sleep Fix (Warmboot) --\n\n"); char warmboot_rel[64] = {0}; bool warmboot_generated = false; // 1) Generate a fresh warmboot for the currently burnt fuses. // Then we directly update the INI using that result. gfx_printf("Erzeuge neuen Warmboot Cache...\n\n"); warmboot_info_t wb_info; wb_extract_error_t wberr = extract_warmboot_from_pkg1_ex(&wb_info); if (wberr == WB_SUCCESS) { char warmboot_sd_path[128]; get_warmboot_path(warmboot_sd_path, sizeof(warmboot_sd_path), wb_info.burnt_fuses); if (save_warmboot_to_sd(&wb_info, warmboot_sd_path)) { s_printf(warmboot_rel, "warmboot_mariko/wb_%02x.bin", wb_info.burnt_fuses); warmboot_generated = true; gfx_printf("Neues warmboot: %s\n\n", warmboot_rel); } else { gfx_printf("Speichern auf SD fehlgeschlagen.\n\n"); } } else { gfx_printf("Warmboot Extraktion fehlgeschlagen: %s\n\n", wb_error_to_string(wberr)); } if (wb_info.data) free(wb_info.data); // 2) Fallback: pick the newest cached wb_xx.bin from sd:/warmboot_mariko. if (!warmboot_generated) { const char *wb_dir = "sd:/warmboot_mariko"; DIR dir; static FILINFO fno; if (f_opendir(&dir, wb_dir) != FR_OK) { gfx_printf("Ordner nicht gefunden: %s\n\n", wb_dir); gfx_printf("Bitte erst Warmboot-Extractor ausfuehren:\n"); gfx_printf("https://github.com/sthetix/Warmboot-Extractor\n\n"); gfx_printf("Druecke eine Taste um zurueckzukehren"); hidWait(); return; } u32 best_fuse = 0; u32 best_ts = 0; bool found_any = false; for (;;) { FRESULT res = f_readdir(&dir, &fno); if (res != FR_OK || fno.fname[0] == 0) break; if (fno.fattrib & AM_DIR) continue; u32 fuse = 0; if (!_parse_wb_filename_lower(fno.fname, &fuse)) continue; u32 ts = ((u32)fno.fdate << 16) | (u32)fno.ftime; if (!found_any || fuse > best_fuse || (fuse == best_fuse && ts > best_ts)) { best_fuse = fuse; best_ts = ts; found_any = true; } } f_closedir(&dir); if (!found_any) { gfx_printf("Keine passenden Dateien gefunden in %s:\n", wb_dir); gfx_printf("wb_xx.bin (xx = lowercase hex fuse)\n\n"); gfx_printf("Bitte Warmboot-Extractor ausfuehren:\n"); gfx_printf("https://github.com/sthetix/Warmboot-Extractor\n\n"); gfx_printf("Druecke eine Taste um zurueckzukehren"); hidWait(); return; } s_printf(warmboot_rel, "warmboot_mariko/wb_%02x.bin", best_fuse); gfx_printf("Neuestes warmboot: %s\n\n", warmboot_rel); } const char *ini_path = "sd:/bootloader/hekate_ipl.ini"; const char *preferred_section = "CFW-EmuMMC"; if (!_ini_section_exists(ini_path, preferred_section)) { // Fallback: show a section chooser if CFW-EmuMMC doesn't exist. gfx_printf("Section %s nicht gefunden.\n", preferred_section); gfx_printf("Bitte waehle eine INI section.\n\n"); // Collect section names. #define MAX_INI_SECTIONS 20 char section_names[MAX_INI_SECTIONS][64]; int section_count = 0; FIL ini_fp; if (f_open(&ini_fp, ini_path, FA_READ) != FR_OK) { gfx_printf("Datei nicht gefunden: %s\n", ini_path); gfx_printf("Druecke eine Taste um zurueckzukehren"); hidWait(); return; } char line[256]; while (_read_line_no_nl(&ini_fp, line, sizeof(line))) { char *t = _ltrim(line); if (*t != '[') continue; char *end = strchr(t, ']'); if (!end) continue; *end = 0; char *name = t + 1; name = _ltrim(name); _rstrip(name); // Skip empty section headers like "[]" if (!*name) { *end = ']'; continue; } if (strcmp(name, "config") && section_count < MAX_INI_SECTIONS) { strncpy(section_names[section_count], name, 63); section_names[section_count][63] = 0; section_count++; } *end = ']'; } f_close(&ini_fp); if (section_count <= 0) { gfx_printf("Keine INI sections gefunden in %s.\n", ini_path); gfx_printf("Druecke eine Taste um zurueckzukehren"); hidWait(); return; } MenuEntry_t entries[MAX_INI_SECTIONS + 1]; memset(entries, 0, sizeof(entries)); entries[0].optionUnion = COLORTORGB(COLOR_WHITE); entries[0].name = "<- Zurueck"; for (int i = 0; i < section_count; i++) { entries[i + 1].optionUnion = COLORTORGB(COLOR_YELLOW); entries[i + 1].name = section_names[i]; } Vector_t ent = vecFromArray(entries, section_count + 1, sizeof(MenuEntry_t)); int sel = newMenu(&ent, 0, 79, 20, ENABLEB | ALWAYSREDRAW, section_count + 1); // newMenu returns 0 for "<- Back" and also when the user presses B. if (sel == 0) return; if (sel < 0 || sel > section_count) return; const char *selected_section = section_names[sel - 1]; // Continue below with chosen section. // Clear and re-print banner so the header stays visible (success/fail). gfx_clearscreen(); gfx_printf("\n\n-- Mariko Sleep Fix (Warmboot) --\n\n"); if (_ini_section_warmboot_is(ini_path, selected_section, warmboot_rel)) { gfx_printf("\nwarmboot=%s existiert schon in [%s].\n", warmboot_rel, selected_section); gfx_printf("Druecke eine Taste um zurueckzukehren"); hidWait(); return; } _ini_update_section_warmboot(ini_path, selected_section, warmboot_rel); gfx_printf("\nAktualisiert in [%s].\n", selected_section); gfx_printf("Druecke eine Taste um zurueckzukehren"); hidWait(); return; } // Preferred path: always update CFW-EmuMMC directly. if (_ini_section_warmboot_is(ini_path, preferred_section, warmboot_rel)) { gfx_printf("\nwarmboot=%s existiert schon in [%s].\n", warmboot_rel, preferred_section); gfx_printf("Druecke eine Taste um zurueckzukehren"); hidWait(); return; } _ini_update_section_warmboot(ini_path, preferred_section, warmboot_rel); gfx_printf("\nAktualisiert in [%s].\n", preferred_section); gfx_printf("Druecke eine Taste um zurueckzukehren"); hidWait(); } void m_entry_stillNoBootInfo(){ gfx_clearscreen(); gfx_printf("\n\n-- Meine Switch startet immer noch nicht.\n\n"); gfx_printf("%kSteckt eine Spiel-Cardrige im Slot?\n", COLOR_WHITE); gfx_printf("Entferne sie und starte neu.\n\n"); gfx_printf("%kHast du vor kurzem Atmosphere/OmniNX aktualisiert?\n", COLOR_WHITE); gfx_printf("Stecke die SD-Karte in deinen PC, hol das neue Paket vom NiklasCFW Discord-Server und entpacke die .zip Datei auf deine SD-Karte und überschreibe alle Dateien.\nDanach kannst du den OmniNX-Installer-Payload ausfuehren.\n\n"); gfx_printf("%kHast du eine neue SD-Karte gekauft?\n", COLOR_WHITE); gfx_printf("Vergewissere dich das es keine fake/SanDisk Karte ist.\n\n"); gfx_printf("\n\n Druecke eine Taste um zurueckzukehren"); hidWait(); } void m_entry_ViewCredits(){ gfx_clearscreen(); gfx_printf("\nAllgemeinerProblemLoeser %d.%d.%d\nVon Team Neptune - (NiklasCFW Fork - Uebersetzt von Switch Bros.)\n\nBasierend auf TegraExplorer von SuchMemeManySkill,\nLockpick_RCM & Hekate, von shchmue & CTCaer\n\n\n", APL_VER_MJ, APL_VER_MN, APL_VER_BF); hidWait(); } void m_entry_fixAll(){ gfx_clearscreen(); m_entry_deleteBootFlags(); m_entry_deleteInstalledThemes(); m_entry_stillNoBootInfo(); }