mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[misc] set default size for ReFS and fix multiple other issues
* ReFS only applies for drives that are larger than 512MB * Also fix error handling and messages in format.c * Also add Alt-Q cheat mode for proper size units, and improve human readable size output
This commit is contained in:
parent
0def2bacef
commit
3462ae1062
5 changed files with 66 additions and 44 deletions
|
@ -75,4 +75,10 @@ o Version 1.0.1 (2013.10.28)
|
||||||
- MSG_071 "Unable to create formatting thread." -> "Unable to start thread."
|
- MSG_071 "Unable to create formatting thread." -> "Unable to start thread."
|
||||||
|
|
||||||
o Version 1.0.0 (2013.10.20)
|
o Version 1.0.0 (2013.10.20)
|
||||||
- Initial version
|
- Initial version
|
||||||
|
|
||||||
|
[TODO] (NOTE: THIS PART IS ONLY FOR THE RUFUS DEVELOPER, NOT TRANSLATORS)
|
||||||
|
- MSG_165 should be altered to say image
|
||||||
|
- NEW message for wrong MSG_044 in _StrError()
|
||||||
|
- NEW message for Alt-Q toggle
|
||||||
|
- NEW message for ERROR_NOT_READY
|
|
@ -145,6 +145,9 @@ static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command,
|
||||||
break;
|
break;
|
||||||
case FCC_DEVICE_NOT_READY:
|
case FCC_DEVICE_NOT_READY:
|
||||||
uprintf("The device is not ready");
|
uprintf("The device is not ready");
|
||||||
|
// TODO: set to ERROR_NOT_READY and add relevant translation
|
||||||
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED;
|
||||||
|
break;
|
||||||
case FCC_CANT_QUICK_FORMAT:
|
case FCC_CANT_QUICK_FORMAT:
|
||||||
uprintf("Cannot quick format this volume");
|
uprintf("Cannot quick format this volume");
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_QUICK_FORMAT);
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_QUICK_FORMAT);
|
||||||
|
@ -163,8 +166,9 @@ static BOOLEAN __stdcall FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command,
|
||||||
break;
|
break;
|
||||||
case FCC_VOLUME_TOO_BIG:
|
case FCC_VOLUME_TOO_BIG:
|
||||||
case FCC_VOLUME_TOO_SMALL:
|
case FCC_VOLUME_TOO_SMALL:
|
||||||
uprintf("Volume is too %s", FCC_VOLUME_TOO_BIG?"big":"small");
|
uprintf("Volume is too %s", (Command == FCC_VOLUME_TOO_BIG)?"big":"small");
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INVALID_VOLUME_SIZE);
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_INVALID_VOLUME_SIZE);
|
||||||
|
break;
|
||||||
case FCC_NO_MEDIA_IN_DRIVE:
|
case FCC_NO_MEDIA_IN_DRIVE:
|
||||||
uprintf("No media in drive");
|
uprintf("No media in drive");
|
||||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_MEDIA_IN_DRIVE;
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_MEDIA_IN_DRIVE;
|
||||||
|
@ -701,6 +705,7 @@ static BOOL FormatDrive(DWORD DriveIndex)
|
||||||
wVolumeName = utf8_to_wchar(VolumeName);
|
wVolumeName = utf8_to_wchar(VolumeName);
|
||||||
if (wVolumeName == NULL) {
|
if (wVolumeName == NULL) {
|
||||||
uprintf("Could not read volume name\n");
|
uprintf("Could not read volume name\n");
|
||||||
|
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
// Hey, nice consistency here, Microsoft! - FormatEx() fails if wVolumeName has
|
// Hey, nice consistency here, Microsoft! - FormatEx() fails if wVolumeName has
|
||||||
|
|
80
src/rufus.c
80
src/rufus.c
|
@ -141,7 +141,7 @@ HWND hDeviceList, hPartitionScheme, hFileSystem, hClusterSize, hLabel, hBootType
|
||||||
HWND hISOProgressDlg = NULL, hLogDlg = NULL, hISOProgressBar, hISOFileName, hDiskID;
|
HWND hISOProgressDlg = NULL, hLogDlg = NULL, hISOProgressBar, hISOFileName, hDiskID;
|
||||||
BOOL use_own_c32[NB_OLD_C32] = {FALSE, FALSE}, detect_fakes = TRUE, mbr_selected_by_user = FALSE;
|
BOOL use_own_c32[NB_OLD_C32] = {FALSE, FALSE}, detect_fakes = TRUE, mbr_selected_by_user = FALSE;
|
||||||
BOOL iso_op_in_progress = FALSE, format_op_in_progress = FALSE, right_to_left_mode = FALSE;
|
BOOL iso_op_in_progress = FALSE, format_op_in_progress = FALSE, right_to_left_mode = FALSE;
|
||||||
BOOL enable_HDDs = FALSE, advanced_mode = TRUE, force_update = FALSE;
|
BOOL enable_HDDs = FALSE, advanced_mode = TRUE, force_update = FALSE, use_fake_units = TRUE;
|
||||||
int dialog_showing = 0;
|
int dialog_showing = 0;
|
||||||
uint16_t rufus_version[4], embedded_sl_version[2];
|
uint16_t rufus_version[4], embedded_sl_version[2];
|
||||||
char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
|
char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
|
||||||
|
@ -312,9 +312,11 @@ static BOOL DefineClusterSizes(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReFS (only supported for Windows 8.1 and later and for fixed disks)
|
// ReFS (only supported for Windows 8.1 and later and for fixed disks)
|
||||||
if ((nWindowsVersion >= WINDOWS_8_1_OR_LATER) && (SelectedDrive.Geometry.MediaType == FixedMedia)) {
|
if (SelectedDrive.DiskSize >= 512*MB) {
|
||||||
SelectedDrive.ClusterSize[FS_REFS].Allowed = 0x00000100;
|
if ((nWindowsVersion >= WINDOWS_8_1_OR_LATER) && (SelectedDrive.Geometry.MediaType == FixedMedia)) {
|
||||||
SelectedDrive.ClusterSize[FS_REFS].Default = 1;
|
SelectedDrive.ClusterSize[FS_REFS].Allowed = 0x00000100;
|
||||||
|
SelectedDrive.ClusterSize[FS_REFS].Default = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,7 +600,7 @@ static BOOL PopulateProperties(int ComboIndex)
|
||||||
|
|
||||||
// Set a proposed label according to the size (eg: "256MB", "8GB")
|
// Set a proposed label according to the size (eg: "256MB", "8GB")
|
||||||
safe_sprintf(SelectedDrive.proposed_label, sizeof(SelectedDrive.proposed_label),
|
safe_sprintf(SelectedDrive.proposed_label, sizeof(SelectedDrive.proposed_label),
|
||||||
SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, TRUE));
|
SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, use_fake_units));
|
||||||
|
|
||||||
// Add a tooltip (with the size of the device in parenthesis)
|
// Add a tooltip (with the size of the device in parenthesis)
|
||||||
device_tooltip = (char*) malloc(safe_strlen(DriveID.String[ComboIndex]) + 16);
|
device_tooltip = (char*) malloc(safe_strlen(DriveID.String[ComboIndex]) + 16);
|
||||||
|
@ -823,7 +825,8 @@ static BOOL GetUSBDevices(DWORD devnum)
|
||||||
|
|
||||||
// The empty string is returned for drives that don't have any volumes assigned
|
// The empty string is returned for drives that don't have any volumes assigned
|
||||||
if (drive_letters[0] == 0) {
|
if (drive_letters[0] == 0) {
|
||||||
entry = lmprintf(MSG_046, label, drive_number, SizeToHumanReadable(GetDriveSize(drive_index), FALSE, TRUE));
|
entry = lmprintf(MSG_046, label, drive_number,
|
||||||
|
SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units));
|
||||||
} else {
|
} else {
|
||||||
// We have multiple volumes assigned to the same device (multiple partitions)
|
// We have multiple volumes assigned to the same device (multiple partitions)
|
||||||
// If that is the case, use "Multiple Volumes" instead of the label
|
// If that is the case, use "Multiple Volumes" instead of the label
|
||||||
|
@ -845,7 +848,7 @@ static BOOL GetUSBDevices(DWORD devnum)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
safe_sprintf(&entry_msg[strlen(entry_msg)], sizeof(entry_msg) - strlen(entry_msg),
|
safe_sprintf(&entry_msg[strlen(entry_msg)], sizeof(entry_msg) - strlen(entry_msg),
|
||||||
" [%s]", SizeToHumanReadable(GetDriveSize(drive_index), FALSE, TRUE));
|
" [%s]", SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units));
|
||||||
entry = entry_msg;
|
entry = entry_msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2512,13 +2515,21 @@ relaunch:
|
||||||
while(GetMessage(&msg, NULL, 0, 0)) {
|
while(GetMessage(&msg, NULL, 0, 0)) {
|
||||||
// The following ensures the processing of the ISO progress window messages
|
// The following ensures the processing of the ISO progress window messages
|
||||||
if (!IsWindow(hISOProgressDlg) || !IsDialogMessage(hISOProgressDlg, &msg)) {
|
if (!IsWindow(hISOProgressDlg) || !IsDialogMessage(hISOProgressDlg, &msg)) {
|
||||||
// Alt-S => Disable size limit for ISOs
|
// Alt-B => Toggle fake drive detection during bad blocks check
|
||||||
// By default, Rufus will not copy ISOs that are larger than in size than
|
// By default, Rufus will check for fake USB flash drives that mistakenly present
|
||||||
// the target USB drive. If this is enabled, the size check is disabled.
|
// more capacity than they already have by looping over the flash. This check which
|
||||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'S')) {
|
// is enabled by default is performed by writing the block number sequence and reading
|
||||||
size_check = !size_check;
|
// it back during the bad block check.
|
||||||
PrintStatus2000(lmprintf(MSG_252), size_check);
|
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'B')) {
|
||||||
GetUSBDevices(0);
|
detect_fakes = !detect_fakes;
|
||||||
|
PrintStatus2000(lmprintf(MSG_256), detect_fakes);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Alt-D => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed)
|
||||||
|
// This key is used to disable Windows popup messages when an USB drive is plugged in.
|
||||||
|
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) {
|
||||||
|
PrintStatus(2000, FALSE, MSG_255);
|
||||||
|
existing_key = FALSE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Alt-F => Toggle detection of USB HDDs
|
// Alt-F => Toggle detection of USB HDDs
|
||||||
|
@ -2532,20 +2543,6 @@ relaunch:
|
||||||
CheckDlgButton(hMainDialog, IDC_ENABLE_FIXED_DISKS, enable_HDDs?BST_CHECKED:BST_UNCHECKED);
|
CheckDlgButton(hMainDialog, IDC_ENABLE_FIXED_DISKS, enable_HDDs?BST_CHECKED:BST_UNCHECKED);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Alt-L => Force Large FAT32 format to be used on < 32 GB drives
|
|
||||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'L')) {
|
|
||||||
force_large_fat32 = !force_large_fat32;
|
|
||||||
PrintStatus2000(lmprintf(MSG_254), force_large_fat32);
|
|
||||||
GetUSBDevices(0);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Alt-D => Delete the NoDriveTypeAutorun key on exit (useful if the app crashed)
|
|
||||||
// This key is used to disable Windows popup messages when an USB drive is plugged in.
|
|
||||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'D')) {
|
|
||||||
PrintStatus(2000, FALSE, MSG_255);
|
|
||||||
existing_key = FALSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Alt J => Toggle Joliet support for ISO9660 images
|
// Alt J => Toggle Joliet support for ISO9660 images
|
||||||
// Some ISOs (Ubuntu) have Joliet extensions but expect applications not to use them,
|
// Some ISOs (Ubuntu) have Joliet extensions but expect applications not to use them,
|
||||||
// due to their reliance on filenames that are > 64 chars (the Joliet max length for
|
// due to their reliance on filenames that are > 64 chars (the Joliet max length for
|
||||||
|
@ -2561,14 +2558,11 @@ relaunch:
|
||||||
PrintStatus2000(lmprintf(MSG_258), enable_rockridge);
|
PrintStatus2000(lmprintf(MSG_258), enable_rockridge);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Alt L => Toggle fake drive detection during bad blocks check
|
// Alt-L => Force Large FAT32 format to be used on < 32 GB drives
|
||||||
// By default, Rufus will check for fake USB flash drives that mistakenly present
|
|
||||||
// more capacity than they already have by looping over the flash. This check which
|
|
||||||
// is enabled by default is performed by writing the block number sequence and reading
|
|
||||||
// it back during the bad block check.
|
|
||||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'L')) {
|
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'L')) {
|
||||||
detect_fakes = !detect_fakes;
|
force_large_fat32 = !force_large_fat32;
|
||||||
PrintStatus2000(lmprintf(MSG_256), detect_fakes);
|
PrintStatus2000(lmprintf(MSG_254), force_large_fat32);
|
||||||
|
GetUSBDevices(0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Alt N => Enable NTFS compression
|
// Alt N => Enable NTFS compression
|
||||||
|
@ -2577,6 +2571,13 @@ relaunch:
|
||||||
PrintStatus2000(lmprintf(MSG_260), enable_ntfs_compression);
|
PrintStatus2000(lmprintf(MSG_260), enable_ntfs_compression);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Alt-Q => Use PROPER size units, instead of this whole Kibi/Gibi nonsense
|
||||||
|
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'Q')) {
|
||||||
|
use_fake_units = !use_fake_units;
|
||||||
|
PrintStatus2000("Use PROPER size units:", !use_fake_units);
|
||||||
|
GetUSBDevices(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Alt-R => Remove all the registry keys created by Rufus
|
// Alt-R => Remove all the registry keys created by Rufus
|
||||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'R')) {
|
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'R')) {
|
||||||
PrintStatus(2000, FALSE, DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME "\\" APPLICATION_NAME)?MSG_248:MSG_249);
|
PrintStatus(2000, FALSE, DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME "\\" APPLICATION_NAME)?MSG_248:MSG_249);
|
||||||
|
@ -2584,6 +2585,15 @@ relaunch:
|
||||||
DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME);
|
DeleteRegistryKey(REGKEY_HKCU, COMPANY_NAME);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Alt-S => Disable size limit for ISOs
|
||||||
|
// By default, Rufus will not copy ISOs that are larger than in size than
|
||||||
|
// the target USB drive. If this is enabled, the size check is disabled.
|
||||||
|
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'S')) {
|
||||||
|
size_check = !size_check;
|
||||||
|
PrintStatus2000(lmprintf(MSG_252), size_check);
|
||||||
|
GetUSBDevices(0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Alt U => Force the update check to be successful
|
// Alt U => Force the update check to be successful
|
||||||
// This will set the reported current version of Rufus to 0.0.0.0 when performing an update
|
// This will set the reported current version of Rufus to 0.0.0.0 when performing an update
|
||||||
// check, so that it always succeeds. This is useful for translators.
|
// check, so that it always succeeds. This is useful for translators.
|
||||||
|
|
12
src/rufus.rc
12
src/rufus.rc
|
@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
|
|
||||||
IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
CAPTION "Rufus 1.4.7.447"
|
CAPTION "Rufus 1.4.7.448"
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||||
|
@ -165,7 +165,7 @@ END
|
||||||
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
|
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
|
||||||
CAPTION "Rufus 1.4.7.447"
|
CAPTION "Rufus 1.4.7.448"
|
||||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||||
|
@ -427,8 +427,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,4,7,447
|
FILEVERSION 1,4,7,448
|
||||||
PRODUCTVERSION 1,4,7,447
|
PRODUCTVERSION 1,4,7,448
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -445,13 +445,13 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
||||||
VALUE "FileDescription", "Rufus"
|
VALUE "FileDescription", "Rufus"
|
||||||
VALUE "FileVersion", "1.4.7.447"
|
VALUE "FileVersion", "1.4.7.448"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
|
||||||
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
||||||
VALUE "OriginalFilename", "rufus.exe"
|
VALUE "OriginalFilename", "rufus.exe"
|
||||||
VALUE "ProductName", "Rufus"
|
VALUE "ProductName", "Rufus"
|
||||||
VALUE "ProductVersion", "1.4.7.447"
|
VALUE "ProductVersion", "1.4.7.448"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
|
@ -188,7 +188,8 @@ char* SizeToHumanReadable(uint64_t size, BOOL log, BOOL fake_units)
|
||||||
safe_sprintf(str_size, sizeof(str_size), "%d%s", i_size, _msg_table[MSG_020+suffix-MSG_000]);
|
safe_sprintf(str_size, sizeof(str_size), "%d%s", i_size, _msg_table[MSG_020+suffix-MSG_000]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
safe_sprintf(str_size, sizeof(str_size), "%0.1f %s", hr_size, _msg_table[MSG_020+suffix-MSG_000]);
|
safe_sprintf(str_size, sizeof(str_size), (hr_size * 10.0 - (floor(hr_size) * 10.0)) < 1.0?
|
||||||
|
"%0.0f %s":"%0.1f %s", hr_size, _msg_table[MSG_020+suffix-MSG_000]);
|
||||||
}
|
}
|
||||||
return str_size;
|
return str_size;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue