mirror of https://github.com/zeldaret/tmc.git
naming and documenting stuff
This commit is contained in:
parent
72f41cb594
commit
dcc674f55f
|
@ -9,13 +9,13 @@
|
||||||
adds r6, r2, #0
|
adds r6, r2, #0
|
||||||
adds r0, r7, #4
|
adds r0, r7, #4
|
||||||
movs r1, #4
|
movs r1, #4
|
||||||
bl sub_0807D1A4
|
bl CalculateChecksum
|
||||||
adds r4, r0, #0
|
adds r4, r0, #0
|
||||||
lsls r4, r4, #0x10
|
lsls r4, r4, #0x10
|
||||||
lsrs r4, r4, #0x10
|
lsrs r4, r4, #0x10
|
||||||
adds r0, r5, #0
|
adds r0, r5, #0
|
||||||
adds r1, r6, #0
|
adds r1, r6, #0
|
||||||
bl sub_0807D1A4
|
bl CalculateChecksum
|
||||||
adds r4, r4, r0
|
adds r4, r4, r0
|
||||||
lsls r4, r4, #0x10
|
lsls r4, r4, #0x10
|
||||||
lsrs r4, r4, #0x10
|
lsrs r4, r4, #0x10
|
||||||
|
|
|
@ -208,13 +208,9 @@ extern u32 sub_0801766C(Entity*);
|
||||||
extern void sub_08004168(Entity*);
|
extern void sub_08004168(Entity*);
|
||||||
extern u32 sub_08052638(u32);
|
extern u32 sub_08052638(u32);
|
||||||
extern void InitDMA(void);
|
extern void InitDMA(void);
|
||||||
extern u32 sub_0807CF08(u32, u8*);
|
|
||||||
extern void sub_0807CF48(u32);
|
|
||||||
extern u32 sub_0807CF10(u8*);
|
extern u32 sub_0807CF10(u8*);
|
||||||
extern void sub_08056208(void);
|
extern void sub_08056208(void);
|
||||||
extern void sub_08050384();
|
extern void sub_08050384();
|
||||||
extern void sub_0807CF68(u32);
|
|
||||||
extern u32 sub_0807CF88(u32, u8*);
|
|
||||||
extern u32 sub_0806F520();
|
extern u32 sub_0806F520();
|
||||||
extern void sub_0806F4E8(Entity*);
|
extern void sub_0806F4E8(Entity*);
|
||||||
extern u32 sub_0806F3E4(Entity*);
|
extern u32 sub_0806F3E4(Entity*);
|
||||||
|
|
|
@ -80,7 +80,6 @@ extern UI gUnk_02032EC0;
|
||||||
void InitScreen();
|
void InitScreen();
|
||||||
|
|
||||||
extern void InitSound(void);
|
extern void InitSound(void);
|
||||||
extern void sub_0807CE90(void);
|
|
||||||
extern void sub_080560B8(void);
|
extern void sub_080560B8(void);
|
||||||
extern void sub_08056208(void);
|
extern void sub_08056208(void);
|
||||||
extern void sub_0804FFE4(void);
|
extern void sub_0804FFE4(void);
|
||||||
|
|
|
@ -46,7 +46,10 @@ typedef struct {
|
||||||
|
|
||||||
extern SaveFile gSave;
|
extern SaveFile gSave;
|
||||||
|
|
||||||
|
u32 InitSaveData(void);
|
||||||
|
|
||||||
s32 sub_0807CF28(u32, SaveFile*);
|
s32 sub_0807CF28(u32, SaveFile*);
|
||||||
u32 sub_0807CF30(SaveFile*);
|
u32 sub_0807CF30(SaveFile*);
|
||||||
|
void SetFileStatusDeleted(u32 index);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -234,7 +234,7 @@ static void sub_08050624(u32 idx) {
|
||||||
int status = sub_0807CF28(idx, saveFile);
|
int status = sub_0807CF28(idx, saveFile);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case SAVE_DELETED:
|
case SAVE_DELETED:
|
||||||
sub_0807CF48(idx);
|
SetFileStatusDeleted(idx);
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case SAVE_EMPTY:
|
case SAVE_EMPTY:
|
||||||
sub_0805194C(idx);
|
sub_0805194C(idx);
|
||||||
|
|
|
@ -26,7 +26,7 @@ void MainLoop(void) {
|
||||||
sub_08055F70();
|
sub_08055F70();
|
||||||
InitSound();
|
InitSound();
|
||||||
InitDMA();
|
InitDMA();
|
||||||
sub_0807CE90();
|
InitSaveData();
|
||||||
sub_080560B8();
|
sub_080560B8();
|
||||||
sub_08056208();
|
sub_08056208();
|
||||||
gUnk_02000010.field_0x4 = 193;
|
gUnk_02000010.field_0x4 = 193;
|
||||||
|
|
133
src/save.c
133
src/save.c
|
@ -20,9 +20,12 @@ static SaveResult HandleSaveInProgress(u32);
|
||||||
static SaveResult HandleSaveDone(u32);
|
static SaveResult HandleSaveDone(u32);
|
||||||
|
|
||||||
const SaveFileEEPROMAddresses* GetSaveFileEEPROMAddresses(u32);
|
const SaveFileEEPROMAddresses* GetSaveFileEEPROMAddresses(u32);
|
||||||
u32 sub_0807D008(u32, SaveFile*);
|
u32 DataDoubleReadWithStatus(u32, SaveFile* saveFile);
|
||||||
|
u32 DataDoubleWriteWithStatus(u32, SaveFile* saveFile);
|
||||||
u32 sub_0807D0A0(SaveFileStatus*, u16*, u32);
|
u32 sub_0807D0A0(SaveFileStatus*, u16*, u32);
|
||||||
u16 sub_0807D1A4(u16*, u32);
|
u16 CalculateChecksum(u16* data, u32);
|
||||||
|
u32 WriteSaveFile(u32 index, SaveFile* saveFile);
|
||||||
|
void SetFileStatusInit(u32 index);
|
||||||
|
|
||||||
u32 ReadSaveFileStatus(u32 address, SaveFileStatus* fileStatus);
|
u32 ReadSaveFileStatus(u32 address, SaveFileStatus* fileStatus);
|
||||||
u32 ParseSaveFileStatus(const SaveFileStatus* fileStatus);
|
u32 ParseSaveFileStatus(const SaveFileStatus* fileStatus);
|
||||||
|
@ -42,11 +45,9 @@ static SaveResult (*const sSaveHandlers[])(u32) = { HandleSaveInit, HandleSaveIn
|
||||||
static const char sSignatureLong[32] = "AGBZELDA:THE MINISH CAP:ZELDA 5";
|
static const char sSignatureLong[32] = "AGBZELDA:THE MINISH CAP:ZELDA 5";
|
||||||
|
|
||||||
// Save file is untouched
|
// Save file is untouched
|
||||||
static const char sSaveDescInit[8] = "\xFF\xFF\xFF\xFF"
|
static const SaveFileStatus sSaveDescInit = { 0xffff, 0xffff, 'TINI' };
|
||||||
"INIT";
|
|
||||||
// Save file is deleted
|
// Save file is deleted
|
||||||
static const char sSaveDescDeleted[8] = "\xFF\xFF\xFF\xFF"
|
static const SaveFileStatus sSaveDescDeleted = { 0xffff, 0xffff, 'FleD' };
|
||||||
"DelF";
|
|
||||||
|
|
||||||
const char gUnk_0811E4B4[8] = "DAMEDAME";
|
const char gUnk_0811E4B4[8] = "DAMEDAME";
|
||||||
const SaveFileEEPROMAddresses gSaveFileEEPROMAddresses[] = { { 0x500, 0x30, 0x1030, 0x80, 0x1080 },
|
const SaveFileEEPROMAddresses gSaveFileEEPROMAddresses[] = { { 0x500, 0x30, 0x1030, 0x80, 0x1080 },
|
||||||
|
@ -71,7 +72,7 @@ SaveResult HandleSaveInit(u32 arg0) {
|
||||||
gUnk_02021EE0[5] -= 8;
|
gUnk_02021EE0[5] -= 8;
|
||||||
if (gUnk_02021EE0[4] <= 0) {
|
if (gUnk_02021EE0[4] <= 0) {
|
||||||
gMenu.field_0xa = 8;
|
gMenu.field_0xa = 8;
|
||||||
gMenu.storyPanelIndex = 1;
|
gMenu.storyPanelIndex = SAVE_IN_PROGRESS;
|
||||||
}
|
}
|
||||||
return SAVE_BUSY;
|
return SAVE_BUSY;
|
||||||
}
|
}
|
||||||
|
@ -83,10 +84,10 @@ SaveResult HandleSaveInProgress(u32 arg0) {
|
||||||
InitDMA();
|
InitDMA();
|
||||||
switch (arg0) {
|
switch (arg0) {
|
||||||
case 0:
|
case 0:
|
||||||
temp = sub_0807CF08(gUnk_02000000->saveFileId, gSave.filler0);
|
temp = WriteSaveFile(gUnk_02000000->saveFileId, &gSave);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
sub_0807CF48(gUnk_02000000->saveFileId);
|
SetFileStatusDeleted(gUnk_02000000->saveFileId);
|
||||||
temp = 1;
|
temp = 1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -94,7 +95,7 @@ SaveResult HandleSaveInProgress(u32 arg0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gMenu.field_0xa = temp;
|
gMenu.field_0xa = temp;
|
||||||
gMenu.storyPanelIndex = 2;
|
gMenu.storyPanelIndex = SAVE_DONE;
|
||||||
sub_08056208();
|
sub_08056208();
|
||||||
} else {
|
} else {
|
||||||
gMenu.field_0xa--;
|
gMenu.field_0xa--;
|
||||||
|
@ -110,7 +111,7 @@ SaveResult HandleSaveDone(u32 arg0) {
|
||||||
if (gUnk_02021EE0[3] <= gUnk_02021EE0[5]) {
|
if (gUnk_02021EE0[3] <= gUnk_02021EE0[5]) {
|
||||||
gUnk_02021EE0[5] = gUnk_02021EE0[3];
|
gUnk_02021EE0[5] = gUnk_02021EE0[3];
|
||||||
sub_08050384();
|
sub_08050384();
|
||||||
gMenu.storyPanelIndex = 0;
|
gMenu.storyPanelIndex = SAVE_INIT;
|
||||||
if (gMenu.field_0xa == 1) {
|
if (gMenu.field_0xa == 1) {
|
||||||
result = SAVE_OK;
|
result = SAVE_OK;
|
||||||
} else {
|
} else {
|
||||||
|
@ -120,7 +121,7 @@ SaveResult HandleSaveDone(u32 arg0) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sub_0807CE90(void) {
|
u32 InitSaveData(void) {
|
||||||
const SaveFileEEPROMAddresses* eepromAddresses;
|
const SaveFileEEPROMAddresses* eepromAddresses;
|
||||||
int iVar3;
|
int iVar3;
|
||||||
|
|
||||||
|
@ -135,11 +136,11 @@ u32 sub_0807CE90(void) {
|
||||||
}
|
}
|
||||||
if (iVar3 != 0) {
|
if (iVar3 != 0) {
|
||||||
if (iVar3 == 3) {
|
if (iVar3 == 3) {
|
||||||
sub_0807CF68(5);
|
SetFileStatusInit(5);
|
||||||
sub_0807CF68(3);
|
SetFileStatusInit(3);
|
||||||
sub_0807CF68(2);
|
SetFileStatusInit(2);
|
||||||
sub_0807CF68(1);
|
SetFileStatusInit(1);
|
||||||
sub_0807CF68(0);
|
SetFileStatusInit(0);
|
||||||
}
|
}
|
||||||
DataWrite(eepromAddresses->address2, sSignatureLong, eepromAddresses->size);
|
DataWrite(eepromAddresses->address2, sSignatureLong, eepromAddresses->size);
|
||||||
DataWrite(eepromAddresses->address1, sSignatureLong, eepromAddresses->size);
|
DataWrite(eepromAddresses->address1, sSignatureLong, eepromAddresses->size);
|
||||||
|
@ -147,49 +148,49 @@ u32 sub_0807CE90(void) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sub_0807CF08(u32 arg0, u8* arg1) {
|
u32 WriteSaveFile(u32 index, SaveFile* saveFile) {
|
||||||
return sub_0807CF88(arg0, arg1);
|
return DataDoubleWriteWithStatus(index, saveFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sub_0807CF10(u8* arg0) {
|
u32 sub_0807CF10(u8* arg0) {
|
||||||
return sub_0807CF88(3, arg0);
|
return DataDoubleWriteWithStatus(3, (void*)arg0);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sub_0807CF1C(u8* arg0) {
|
u32 sub_0807CF1C(u8* arg0) {
|
||||||
return sub_0807CF88(5, arg0);
|
return DataDoubleWriteWithStatus(5, (void*)arg0);
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 sub_0807CF28(u32 arg0, SaveFile* arg1) {
|
s32 sub_0807CF28(u32 arg0, SaveFile* saveFile) {
|
||||||
return sub_0807D008(arg0, arg1);
|
return DataDoubleReadWithStatus(arg0, saveFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sub_0807CF30(SaveFile* arg0) {
|
u32 sub_0807CF30(SaveFile* arg0) {
|
||||||
return sub_0807D008(3, arg0);
|
return DataDoubleReadWithStatus(3, arg0);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sub_0807CF3C(SaveFile* arg0) {
|
u32 sub_0807CF3C(SaveFile* arg0) {
|
||||||
return sub_0807D008(5, arg0);
|
return DataDoubleReadWithStatus(5, arg0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sub_0807CF48(u32 arg0) {
|
void SetFileStatusDeleted(u32 index) {
|
||||||
const SaveFileEEPROMAddresses* eepromAddresses;
|
const SaveFileEEPROMAddresses* eepromAddresses;
|
||||||
|
|
||||||
eepromAddresses = GetSaveFileEEPROMAddresses(arg0);
|
eepromAddresses = GetSaveFileEEPROMAddresses(index);
|
||||||
WriteSaveFileStatus(eepromAddresses->checksum2, (const SaveFileStatus*)sSaveDescDeleted);
|
WriteSaveFileStatus(eepromAddresses->checksum2, &sSaveDescDeleted);
|
||||||
WriteSaveFileStatus(eepromAddresses->checksum1, (const SaveFileStatus*)sSaveDescDeleted);
|
WriteSaveFileStatus(eepromAddresses->checksum1, &sSaveDescDeleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sub_0807CF68(u32 arg0) {
|
void SetFileStatusInit(u32 index) {
|
||||||
const SaveFileEEPROMAddresses* eepromAddresses;
|
const SaveFileEEPROMAddresses* eepromAddresses;
|
||||||
const char* str;
|
const SaveFileStatus* fileStatus;
|
||||||
|
|
||||||
eepromAddresses = GetSaveFileEEPROMAddresses(arg0);
|
eepromAddresses = GetSaveFileEEPROMAddresses(index);
|
||||||
str = sSaveDescInit;
|
fileStatus = &sSaveDescInit;
|
||||||
WriteSaveFileStatus(eepromAddresses->checksum2, (const SaveFileStatus*)str);
|
WriteSaveFileStatus(eepromAddresses->checksum2, fileStatus);
|
||||||
WriteSaveFileStatus(eepromAddresses->checksum1, (const SaveFileStatus*)str);
|
WriteSaveFileStatus(eepromAddresses->checksum1, fileStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sub_0807CF88(u32 arg0, u8* arg1) {
|
u32 DataDoubleWriteWithStatus(u32 arg0, SaveFile* saveFile) {
|
||||||
SaveFileStatus fileStatus;
|
SaveFileStatus fileStatus;
|
||||||
|
|
||||||
u32 ret;
|
u32 ret;
|
||||||
|
@ -200,17 +201,17 @@ u32 sub_0807CF88(u32 arg0, u8* arg1) {
|
||||||
eepromAddresses = GetSaveFileEEPROMAddresses(arg0);
|
eepromAddresses = GetSaveFileEEPROMAddresses(arg0);
|
||||||
|
|
||||||
fileStatus.status = 'MCZ3';
|
fileStatus.status = 'MCZ3';
|
||||||
checksum = sub_0807D1A4((u16*)&fileStatus.status, 4);
|
checksum = CalculateChecksum((u16*)&fileStatus.status, 4);
|
||||||
checksum += sub_0807D1A4((u16*)arg1, eepromAddresses->size);
|
checksum += CalculateChecksum((u16*)saveFile, eepromAddresses->size);
|
||||||
fileStatus.checksum1 = checksum;
|
fileStatus.checksum1 = checksum;
|
||||||
fileStatus.checksum2 = -(u32)checksum;
|
fileStatus.checksum2 = -(u32)checksum;
|
||||||
write1success = DataWrite(eepromAddresses->address1, arg1, eepromAddresses->size);
|
write1success = DataWrite(eepromAddresses->address1, saveFile, eepromAddresses->size);
|
||||||
if (write1success) {
|
if (write1success) {
|
||||||
write1success = WriteSaveFileStatus(eepromAddresses->checksum1, (const SaveFileStatus*)&fileStatus.checksum1);
|
write1success = WriteSaveFileStatus(eepromAddresses->checksum1, &fileStatus);
|
||||||
}
|
}
|
||||||
write2success = DataWrite(eepromAddresses->address2, arg1, eepromAddresses->size);
|
write2success = DataWrite(eepromAddresses->address2, saveFile, eepromAddresses->size);
|
||||||
if (write2success) {
|
if (write2success) {
|
||||||
write2success = WriteSaveFileStatus(eepromAddresses->checksum2, (const SaveFileStatus*)&fileStatus.checksum1);
|
write2success = WriteSaveFileStatus(eepromAddresses->checksum2, &fileStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -220,40 +221,42 @@ u32 sub_0807CF88(u32 arg0, u8* arg1) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 sub_0807D008(u32 param_1, SaveFile* saveFile) {
|
u32 DataDoubleReadWithStatus(u32 param_1, SaveFile* saveFile) {
|
||||||
vu32 set_0;
|
vu32 set_0;
|
||||||
SaveFileStatus fileStatus;
|
SaveFileStatus fileStatus;
|
||||||
|
|
||||||
const SaveFileEEPROMAddresses* eepromAddresses;
|
const SaveFileEEPROMAddresses* eepromAddresses;
|
||||||
u32 t1;
|
u32 read1status;
|
||||||
u32 t2;
|
u32 read2status;
|
||||||
u32 ret;
|
u32 ret;
|
||||||
u32 temp;
|
u32 temp;
|
||||||
|
|
||||||
eepromAddresses = GetSaveFileEEPROMAddresses(param_1);
|
eepromAddresses = GetSaveFileEEPROMAddresses(param_1);
|
||||||
t1 = ReadSaveFileStatus(eepromAddresses->checksum1, &fileStatus);
|
read1status = ReadSaveFileStatus(eepromAddresses->checksum1, &fileStatus);
|
||||||
if (t1 == 2) {
|
if (read1status == 2) {
|
||||||
if ((DataRead(eepromAddresses->address1, (char*)saveFile, eepromAddresses->size) == 0) ||
|
if ((DataRead(eepromAddresses->address1, saveFile, eepromAddresses->size) == 0) ||
|
||||||
(sub_0807D0A0(&fileStatus, (u16*)saveFile, (u32)eepromAddresses->size) == 0)) {
|
(sub_0807D0A0(&fileStatus, (u16*)saveFile, (u32)eepromAddresses->size) == 0)) {
|
||||||
t1 = 0;
|
// read 1 failed
|
||||||
|
read1status = 0;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t2 = ReadSaveFileStatus(eepromAddresses->checksum2, &fileStatus);
|
read2status = ReadSaveFileStatus(eepromAddresses->checksum2, &fileStatus);
|
||||||
if (t2 == 2) {
|
if (read2status == 2) {
|
||||||
if ((DataRead(eepromAddresses->address2, (char*)saveFile, eepromAddresses->size) != 0) &&
|
if ((DataRead(eepromAddresses->address2, saveFile, eepromAddresses->size) != 0) &&
|
||||||
(sub_0807D0A0(&fileStatus, (u16*)saveFile, (u32)eepromAddresses->size) != 0)) {
|
(sub_0807D0A0(&fileStatus, (u16*)saveFile, (u32)eepromAddresses->size) != 0)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
t2 = 0;
|
// read 2 failed
|
||||||
|
read2status = 0;
|
||||||
}
|
}
|
||||||
set_0 = 0;
|
set_0 = 0;
|
||||||
CpuSet((u16*)&set_0, saveFile, eepromAddresses->size >> 2 | CPU_SET_SRC_FIXED | CPU_SET_32BIT);
|
CpuSet((u16*)&set_0, saveFile, eepromAddresses->size >> 2 | CPU_SET_SRC_FIXED | CPU_SET_32BIT);
|
||||||
temp = t1 | t2;
|
temp = read1status | read2status;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
if (temp == 0) {
|
if (temp == 0) {
|
||||||
ret = -1;
|
ret = -1; // both reads failed
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -263,8 +266,8 @@ NONMATCH("asm/non_matching/save/sub_0807D0A0.inc", u32 sub_0807D0A0(SaveFileStat
|
||||||
|
|
||||||
u16 u0;
|
u16 u0;
|
||||||
|
|
||||||
u0 = sub_0807D1A4((u16*)&unk_1->status, 4);
|
u0 = CalculateChecksum((u16*)&unk_1->status, 4);
|
||||||
u0 = u0 + sub_0807D1A4(unk_2, unk_3);
|
u0 = u0 + CalculateChecksum(unk_2, unk_3);
|
||||||
|
|
||||||
if (unk_1->checksum1 != u0) {
|
if (unk_1->checksum1 != u0) {
|
||||||
r0 = 0;
|
r0 = 0;
|
||||||
|
@ -338,16 +341,16 @@ bool32 WriteSaveFileStatus(u32 address, const struct SaveFileStatus* fileStatus)
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 sub_0807D1A4(u16* unk_1, u32 unk_2) {
|
u16 CalculateChecksum(u16* data, u32 size) {
|
||||||
u32 uVar1;
|
u32 checksum;
|
||||||
|
|
||||||
uVar1 = 0;
|
checksum = 0;
|
||||||
while (unk_2 != 0) {
|
while (size != 0) {
|
||||||
uVar1 = uVar1 + (*unk_1 ^ unk_2);
|
checksum = checksum + (*data ^ size);
|
||||||
unk_1 = unk_1 + 1;
|
data = data + 1;
|
||||||
unk_2 = unk_2 - 2;
|
size = size - 2;
|
||||||
}
|
}
|
||||||
return uVar1;
|
return checksum;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SaveFileEEPROMAddresses* GetSaveFileEEPROMAddresses(u32 unk_1) {
|
const SaveFileEEPROMAddresses* GetSaveFileEEPROMAddresses(u32 unk_1) {
|
||||||
|
|
Loading…
Reference in New Issue