From d93df41cba1b46f9ce2701da4717250f074dbb26 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Mon, 14 Feb 2022 20:22:08 +1000 Subject: [PATCH] Attempt to decompile texLoad --- src/game/bg.c | 4 +- src/game/bondgun.c | 4 +- src/game/game_013b80.c | 6 +- src/game/game_0b3350.c | 4 +- src/game/game_173520.c | 8 +- src/game/game_173a00.c | 4 +- src/game/game_1a7560.c | 2 +- src/game/texdecompress.c | 208 +++++++++++++++++++++++++++---- src/include/bss.h | 2 +- src/include/game/texdecompress.h | 15 +-- src/include/types.h | 32 ++++- 11 files changed, 234 insertions(+), 55 deletions(-) diff --git a/src/game/bg.c b/src/game/bg.c index 28ec90ff8..1af86ebbe 100644 --- a/src/game/bg.c +++ b/src/game/bg.c @@ -3954,7 +3954,7 @@ void bgInit(s32 stagenum) inflatedsize = (*(u16 *)&header[0] & 0x7fff) >> 1; for (i = 0; i != inflatedsize; i++) { - func0f1734e8(section2[i], NULL); + texLoadFromTextureNum(section2[i], NULL); } if (i); @@ -4147,7 +4147,7 @@ glabel bgInit /* f155f04: 8fa4005c */ lw $a0,0x5c($sp) .NB0f155f08: /* f155f08: 96240000 */ lhu $a0,0x0($s1) -/* f155f0c: 0fc5b860 */ jal func0f1734e8 +/* f155f0c: 0fc5b860 */ jal texLoadFromTextureNum /* f155f10: 00002825 */ or $a1,$zero,$zero /* f155f14: 26100001 */ addiu $s0,$s0,0x1 /* f155f18: 1612fffb */ bne $s0,$s2,.NB0f155f08 diff --git a/src/game/bondgun.c b/src/game/bondgun.c index bd43be460..ab7508594 100644 --- a/src/game/bondgun.c +++ b/src/game/bondgun.c @@ -9515,7 +9515,7 @@ glabel bgun0f09e144 /* f09e310: 5020000b */ beqzl $at,.L0f09e340 /* f09e314: 24e70001 */ addiu $a3,$a3,0x1 /* f09e318: afa3007c */ sw $v1,0x7c($sp) -/* f09e31c: 0fc5cc04 */ jal func0f173010 +/* f09e31c: 0fc5cc04 */ jal texLoad /* f09e320: afa70078 */ sw $a3,0x78($sp) /* f09e324: 8e2a0018 */ lw $t2,0x18($s1) /* f09e328: 8fa3007c */ lw $v1,0x7c($sp) @@ -9763,7 +9763,7 @@ glabel bgun0f09e144 /* f09c230: 29810daf */ slti $at,$t4,0xdaf /* f09c234: 50200007 */ beqzl $at,.NB0f09c254 /* f09c238: 26520001 */ addiu $s2,$s2,0x1 -/* f09c23c: 0fc5b72a */ jal func0f173010 +/* f09c23c: 0fc5b72a */ jal texLoad /* f09c240: 24060001 */ addiu $a2,$zero,0x1 /* f09c244: 8e6e0018 */ lw $t6,0x18($s3) /* f09c248: 01d0c021 */ addu $t8,$t6,$s0 diff --git a/src/game/game_013b80.c b/src/game/game_013b80.c index a2d2f3233..6a43bb9f1 100644 --- a/src/game/game_013b80.c +++ b/src/game/game_013b80.c @@ -8,9 +8,9 @@ void func0f013b80(void) { var800ab538 = 0; - var800aabc8[0] = 0; - var800aabc8[1] = 0; - var800aabc8[3] = 0; + var800aabc8.unk00 = NULL; + var800aabc8.unk04 = NULL; + var800aabc8.unk0c = NULL; } void func0f013ba0(void) diff --git a/src/game/game_0b3350.c b/src/game/game_0b3350.c index db18d0da3..686a6cf82 100644 --- a/src/game/game_0b3350.c +++ b/src/game/game_0b3350.c @@ -473,7 +473,7 @@ glabel func0f0b35b8 void func0f0b3988(struct textureconfig *config) { if ((u32)config->texturenum < 0xdaf) { - func0f173434(config, 1, 0, 0); + texLoadFromConfigs(config, 1, 0, 0); } } @@ -542,7 +542,7 @@ glabel func0f0b39c0 /* f0b3aa4: 10200004 */ beqz $at,.L0f0b3ab8 /* f0b3aa8: 03202025 */ or $a0,$t9,$zero /* f0b3aac: 8fa60188 */ lw $a2,0x188($sp) -/* f0b3ab0: 0fc5cd0d */ jal func0f173434 +/* f0b3ab0: 0fc5cd0d */ jal texLoadFromConfigs /* f0b3ab4: 00003825 */ or $a3,$zero,$zero .L0f0b3ab8: /* f0b3ab8: 8fae0174 */ lw $t6,0x174($sp) diff --git a/src/game/game_173520.c b/src/game/game_173520.c index 1eb7bb3de..e92bf3651 100644 --- a/src/game/game_173520.c +++ b/src/game/game_173520.c @@ -80,12 +80,12 @@ void texturesLoadConfigs(void) } for (i = 0; i < ARRAYCOUNT(g_TcExplosionTexturePairs); i++) { - func0f173010(&g_ExplosionTexturePairs[i].texturenum1, 0, 0); - func0f173010(&g_ExplosionTexturePairs[i].texturenum2, 0, 0); + texLoad(&g_ExplosionTexturePairs[i].texturenum1, 0, 0); + texLoad(&g_ExplosionTexturePairs[i].texturenum2, 0, 0); } - func0f172f5c(g_TexGdl1, 0, 0); - func0f172f5c(g_TexGdl3, 0, 0); + texLoadFromDisplayList(g_TexGdl1, 0, 0); + texLoadFromDisplayList(g_TexGdl3, 0, 0); stage = mainGetStageNum(); diff --git a/src/game/game_173a00.c b/src/game/game_173a00.c index 23e7a1c18..4db485ea3 100644 --- a/src/game/game_173a00.c +++ b/src/game/game_173a00.c @@ -2333,7 +2333,7 @@ glabel var7f1b7c80 /* f1757f4: 32440fff */ andi $a0,$s2,0xfff /* f1757f8: 326f0200 */ andi $t7,$s3,0x200 /* f1757fc: 00809025 */ or $s2,$a0,$zero -/* f175800: 0fc5cd3a */ jal func0f1734e8 +/* f175800: 0fc5cd3a */ jal texLoadFromTextureNum /* f175804: 01e09825 */ or $s3,$t7,$zero /* f175808: 02402025 */ or $a0,$s2,$zero /* f17580c: 0fc5cba3 */ jal func0f172e8c @@ -2396,7 +2396,7 @@ glabel var7f1b7c80 /* f1758e8: 8fa50144 */ lw $a1,0x144($sp) /* f1758ec: 00107b02 */ srl $t7,$s0,0xc /* f1758f0: 31e40fff */ andi $a0,$t7,0xfff -/* f1758f4: 0fc5cd3a */ jal func0f1734e8 +/* f1758f4: 0fc5cd3a */ jal texLoadFromTextureNum /* f1758f8: 00808025 */ or $s0,$a0,$zero /* f1758fc: 02002025 */ or $a0,$s0,$zero /* f175900: 0fc5cba3 */ jal func0f172e8c diff --git a/src/game/game_1a7560.c b/src/game/game_1a7560.c index 122483b6e..a92f4976f 100644 --- a/src/game/game_1a7560.c +++ b/src/game/game_1a7560.c @@ -154,7 +154,7 @@ glabel func0f1a7560 /* f1a7610: 8e640018 */ lw $a0,0x18($s3) /* f1a7614: 86650016 */ lh $a1,0x16($s3) /* f1a7618: 02323823 */ subu $a3,$s1,$s2 -/* f1a761c: 0fc5cd0d */ jal func0f173434 +/* f1a761c: 0fc5cd0d */ jal texLoadFromConfigs /* f1a7620: 03c03025 */ or $a2,$s8,$zero /* f1a7624: 8faa0074 */ lw $t2,0x74($sp) /* f1a7628: 5140002b */ beqzl $t2,.L0f1a76d8 diff --git a/src/game/texdecompress.c b/src/game/texdecompress.c index f44e10530..3c3b4c8bd 100644 --- a/src/game/texdecompress.c +++ b/src/game/texdecompress.c @@ -17,10 +17,10 @@ const char var7f1b2388nb[] = "texdecompress.c"; struct texture *g_Textures; u32 var800aabc4; -u32 var800aabc8[4]; +struct texturething var800aabc8; u8 var800aabd8[2400]; u32 var800ab538; -u32 var800ab53c; +s32 var800ab53c; u8 *var800ab540; u32 var800ab544; s32 var800ab548; @@ -154,7 +154,7 @@ void func0f16e810(u32 arg0) #if VERSION >= VERSION_NTSC_1_0 GLOBAL_ASM( -glabel func0f16e818 +glabel texLoadZlib /* f16e818: 27bde160 */ addiu $sp,$sp,-7840 /* f16e81c: afbf004c */ sw $ra,0x4c($sp) /* f16e820: afb60040 */ sw $s6,0x40($sp) @@ -545,7 +545,7 @@ glabel func0f16e818 ); #else GLOBAL_ASM( -glabel func0f16e818 +glabel texLoadZlib /* f1693c8: 27bde0a8 */ addiu $sp,$sp,-8024 /* f1693cc: afbf007c */ sw $ra,0x7c($sp) /* f1693d0: afb60070 */ sw $s6,0x70($sp) @@ -2133,28 +2133,28 @@ s32 func0f16fd50(u16 *arg0, s32 arg1, s32 arg2, s32 arg3) } GLOBAL_ASM( -glabel func0f16fde4 +glabel texLoadNonZlib .late_rodata glabel var7f1b7a50 -.word func0f16fde4+0x268 # f17004c +.word texLoadNonZlib+0x268 # f17004c glabel var7f1b7a54 -.word func0f16fde4+0x268 # f17004c +.word texLoadNonZlib+0x268 # f17004c glabel var7f1b7a58 -.word func0f16fde4+0x28c # f170070 +.word texLoadNonZlib+0x28c # f170070 glabel var7f1b7a5c -.word func0f16fde4+0x324 # f170108 +.word texLoadNonZlib+0x324 # f170108 glabel var7f1b7a60 -.word func0f16fde4+0x3d8 # f1701bc +.word texLoadNonZlib+0x3d8 # f1701bc glabel var7f1b7a64 -.word func0f16fde4+0x464 # f170248 +.word texLoadNonZlib+0x464 # f170248 glabel var7f1b7a68 -.word func0f16fde4+0x4b0 # f170294 +.word texLoadNonZlib+0x4b0 # f170294 glabel var7f1b7a6c -.word func0f16fde4+0x518 # f1702fc +.word texLoadNonZlib+0x518 # f1702fc glabel var7f1b7a70 -.word func0f16fde4+0x57c # f170360 +.word texLoadNonZlib+0x57c # f170360 glabel var7f1b7a74 -.word func0f16fde4+0x650 # f170434 +.word texLoadNonZlib+0x650 # f170434 .text /* f16fde4: 27bdcf58 */ addiu $sp,$sp,-12456 /* f16fde8: afbf004c */ sw $ra,0x4c($sp) @@ -5848,9 +5848,9 @@ glabel func0f172e8c /* f172f40: 00000000 */ nop ); -s32 func0f172f44(s32 *arg0) +s32 func0f172f44(struct texturething *arg0) { - return arg0[3] - arg0[2]; + return (u32)arg0->unk0c - (u32)arg0->unk08; } s32 func0f172f54(s32 *arg0) @@ -5858,14 +5858,14 @@ s32 func0f172f54(s32 *arg0) return arg0[2]; } -void func0f172f5c(Gfx *gdl, s32 arg1, s32 arg2) +void texLoadFromDisplayList(Gfx *gdl, struct texturething *arg1, s32 arg2) { u8 *bytes = (u8 *)gdl; while (bytes[0] != (u8)G_ENDDL) { // Look for GBI sequence: fd...... abcd.... if (bytes[0] == G_SETTIMG && bytes[4] == 0xab && bytes[5] == 0xcd) { - func0f173010((u32 *)((s32)bytes + 4), arg1, arg2); + texLoad((u32 *)((s32)bytes + 4), arg1, arg2); } bytes += 8; @@ -5873,7 +5873,7 @@ void func0f172f5c(Gfx *gdl, s32 arg1, s32 arg2) } GLOBAL_ASM( -glabel func0f173010 +glabel texLoad /* f173010: 27bddb10 */ addiu $sp,$sp,-9456 /* f173014: afb00020 */ sw $s0,0x20($sp) /* f173018: 00a08025 */ or $s0,$a1,$zero @@ -6063,7 +6063,7 @@ glabel func0f173010 /* f1732c4: afb00010 */ sw $s0,0x10($sp) /* f1732c8: 8fa414ac */ lw $a0,0x14ac($sp) /* f1732cc: 8fa614a8 */ lw $a2,0x14a8($sp) -/* f1732d0: 0fc5ba06 */ jal func0f16e818 +/* f1732d0: 0fc5ba06 */ jal texLoadZlib /* f1732d4: afaa0014 */ sw $t2,0x14($sp) /* f1732d8: 8fa31490 */ lw $v1,0x1490($sp) /* f1732dc: 1000000c */ b .L0f173310 @@ -6076,7 +6076,7 @@ glabel func0f173010 /* f1732f4: afb00010 */ sw $s0,0x10($sp) /* f1732f8: 8fa414ac */ lw $a0,0x14ac($sp) /* f1732fc: 8fa614a8 */ lw $a2,0x14a8($sp) -/* f173300: 0fc5bf79 */ jal func0f16fde4 +/* f173300: 0fc5bf79 */ jal texLoadNonZlib /* f173304: afad0014 */ sw $t5,0x14($sp) /* f173308: 8fa31490 */ lw $v1,0x1490($sp) /* f17330c: afa20038 */ sw $v0,0x38($sp) @@ -6162,13 +6162,167 @@ glabel func0f173010 /* f173430: 00000000 */ nop ); -void func0f173434(struct textureconfig *configs, s32 arg1, s32 arg2, s32 arg3) +//extern u8 _texturesdataSegmentRomStart; + +/** + * Load and decompress a texture from ROM. + * + * The given pointer points to a word which determines what to load. + * The formats of the word are: + * + * abcdxxxx -> load texture number xxxx + * 0000xxxx -> load texture number xxxx + * (memory address) -> the texture is already loaded, so do nothing + * + * After loading and decompressing the texture, the value that's pointed to is + * changed to be a pointer to... something. + */ +// Mismatch: Reordered instructions and regalloc. Is functionally identical. +//void texLoad(u32 *ptr, struct texturething *arg1, s32 arg2) +//{ +// s32 sp14b0[1040]; +// u8 *sp14ac_ptr; +// s32 sp14a8; +// s32 sp14a4_iszlib; +// s32 sp14a0_lod; +// struct texloadthing *sp149c; +// u32 freebytes; +// u32 stack; +// struct texloadthing *sp1490; +// u32 stack2; +// u8 sp148b_usingsharedstruct; +// s8 sp48[5187]; +// s32 sp44; +// s32 sp38; +// struct texloadthing *sp34; +// s32 sp30; +// u8 *sp2c; +// +// sp148b_usingsharedstruct = 0; +// +// if (arg1 == NULL) { +// arg1 = &var800aabc8; +// } +// +// if (arg1 == &var800aabc8) { +// sp148b_usingsharedstruct = 1; +// } +// +// if ((*ptr & 0xffff0000) == 0 || (*ptr & 0xffff0000) == 0xabcd0000) { +// var800ab53c = *ptr & 0xffff; +// +// sp149c = func0f172e8c(var800ab53c, arg1); +// +// if (sp149c == NULL && var800ab53c < 0xdaf) { +// sp2c = (void *)(((u32)sp14b0 + 0xf) >> 4 << 4); +// +// if (sp2c); +// +// osWritebackDCacheAll(); +// osInvalDCache(sp2c, DCACHE_SIZE); +// +// if (g_Textures[var800ab53c].dataoffset == g_Textures[var800ab53c + 1].dataoffset) { +// return; +// } +// +// sp44 = g_Textures[var800ab53c].dataoffset; +// +// dmaExec(sp2c, +// (u32)&_texturesdataSegmentRomStart + (sp44 & 0xfffffff8), +// (((g_Textures[var800ab53c + 1].dataoffset - sp44) + 0x1f) >> 4) * 0x10); +// +// if (sp148b_usingsharedstruct); +// sp14ac_ptr = sp2c + (sp44 & 7); +// sp14a8 = (*sp14ac_ptr & 0x80) >> 7; +// sp14a4_iszlib = (*sp14ac_ptr & 0x40) >> 6; +// sp14a0_lod = *sp14ac_ptr & 0x3f; +// +// if (sp14a0_lod > 5) { +// sp14a0_lod = 5; +// } +// +// sp14ac_ptr++; +// +// if (sp148b_usingsharedstruct) { +// freebytes = mempGetPoolFree(MEMPOOL_STAGE, MEMBANK_ONBOARD) + mempGetPoolFree(MEMPOOL_STAGE, MEMBANK_EXPANSION); +// } else { +// freebytes = func0f172f44(arg1); +// } +// +// if ((sp14a4_iszlib == 0 && freebytes < 4300) || (sp14a4_iszlib != 0 && freebytes < 2600)) { +// *ptr = osVirtualToPhysical(arg1->unk00); +// return; +// } +// +// if (sp148b_usingsharedstruct) { +// sp1490 = arg1->unk0c; +// arg1->unk0c = (struct texloadthing *)((((u32)sp48 + 0xf) >> 4 << 4) + 0x10); +// arg1->unk08 = arg1->unk0c + 1; +// +// while (sp1490) { +// if (sp1490->unk0c_04 == 0) { +// break; +// } +// +// sp1490 = (struct texloadthing *)PHYS_TO_K0(sp1490->unk0c_04); +// } +// } +// +// *(s16 *)(arg1->unk08) = var800ab53c; +// arg1->unk08 = (void *)((u32)arg1->unk08 + 8); +// sp149c = (struct texloadthing *)(arg1->unk0c - 1); +// arg1->unk0c = sp149c; +// sp149c->unk00_00 = var800ab53c; +// sp149c->unk04 = arg1->unk08; +// sp149c->unk0c_03 = false; +// +// if (sp14a4_iszlib) { +// sp38 = texLoadZlib(sp14ac_ptr, (u32 *)arg1->unk08, sp14a8, sp14a0_lod, arg1, arg2); +// } else { +// sp38 = texLoadNonZlib(sp14ac_ptr, (u32 *)arg1->unk08, sp14a8, sp14a0_lod, arg1, arg2); +// } +// +// if (sp148b_usingsharedstruct) { +// sp34 = mempAllocFromRight(ALIGN16(sp38 + 0x20), MEMPOOL_STAGE); +// arg1->unk0c = sp34; +// +// bcopy(sp149c, sp34, 0x10); +// +// sp149c = sp34; +// sp34++; +// +// bcopy((void *)((u32)arg1->unk08 - 8), sp34, sp38 + 8); +// +// arg1->unk0c->unk04 = (void *)((u32)sp34 + 8); +// arg1->unk0c->unk0c_04 = 0; +// +// if (sp1490 != NULL) { +// sp1490->unk0c_04 = (u32)arg1->unk0c & 0xffffff; +// } else { +// arg1->unk04 = arg1->unk0c; +// } +// +// arg1->unk00 = arg1->unk0c; +// } +// +// arg1->unk08 = (void *)((u32)arg1->unk08 + sp38); +// +// if (!sp148b_usingsharedstruct) { +// func0f172f44(arg1); +// } +// } +// } +// +// *ptr = osVirtualToPhysical(sp149c->unk04); +//} + +void texLoadFromConfigs(struct textureconfig *configs, s32 numconfigs, struct texturething *arg2, s32 arg3) { s32 i; - for (i = 0; i < arg1; i++) { + for (i = 0; i < numconfigs; i++) { if ((s32)configs[i].texturenum < 0xdaf) { - func0f173010(&configs[i].texturenum, arg2, 1); + texLoad(&configs[i].texturenum, arg2, 1); configs[i].unk0b = 1; } else { configs[i].texturenum += arg3; @@ -6176,11 +6330,11 @@ void func0f173434(struct textureconfig *configs, s32 arg1, s32 arg2, s32 arg3) } } -void func0f1734e8(u32 arg0, void *arg1) +void texLoadFromTextureNum(u32 arg0, struct texturething *arg1) { u32 sp1c = arg0; - func0f173010(&sp1c, (s32)arg1, 1); + texLoad(&sp1c, arg1, 1); } s32 func0f173510(s32 arg0, s32 arg1, s32 arg3) diff --git a/src/include/bss.h b/src/include/bss.h index 2087cfaf8..159f87b3f 100644 --- a/src/include/bss.h +++ b/src/include/bss.h @@ -254,7 +254,7 @@ extern u32 *g_LangBanks[69]; extern void *var800aabb4; extern struct var800aabb8 *var800aabb8; extern struct texture *g_Textures; -extern u32 var800aabc8[4]; +extern struct texturething var800aabc8; extern u8 var800aabd8[2400]; extern u32 var800ab538; extern u8 *var800ab540; diff --git a/src/include/game/texdecompress.h b/src/include/game/texdecompress.h index a719bcfab..4fa1fabdf 100644 --- a/src/include/game/texdecompress.h +++ b/src/include/game/texdecompress.h @@ -5,6 +5,7 @@ #include "types.h" void func0f16e810(u32 arg0); +s32 texLoadZlib(u8 *ptr, u32 *texturenum, s32 arg2, s32 lod, struct texturething *arg4, s32 arg5); u32 func0f16edac(void); u32 func0f16ee58(void); u32 func0f16eefc(void); @@ -13,7 +14,7 @@ u32 func0f16f044(void); u32 func0f16f0f4(void); u32 func0f16fc8c(void); s32 func0f16fd50(u16 *arg0, s32 arg1, s32 arg2, s32 arg3); -u32 func0f16fde4(void); +s32 texLoadNonZlib(u8 *ptr, u32 *texturenum, s32 arg2, s32 lod, struct texturething *arg4, s32 arg5); u32 func0f1706ec(void); u32 func0f1711b4(void); u32 func0f171558(void); @@ -27,13 +28,13 @@ u32 func0f172554(void); u32 func0f1729f8(void); u32 func0f172b5c(void); void func0f172e70(s32 *arg0, void *arg1, s32 arg2); -u32 func0f172e8c(void); -s32 func0f172f44(s32 *arg0); +struct texloadthing *func0f172e8c(s32 texturenum, struct texturething *arg1); +s32 func0f172f44(struct texturething *arg0); s32 func0f172f54(s32 *arg0); -void func0f172f5c(Gfx *gdl, s32 arg1, s32 arg2); -void func0f173010(u32 *texturenum, s32 arg1, s32 arg2); -void func0f173434(struct textureconfig *config, s32 arg1, s32 arg2, s32 arg3); -void func0f1734e8(u32 arg0, void *arg1); +void texLoadFromDisplayList(Gfx *gdl, struct texturething *arg1, s32 arg2); +void texLoad(u32 *texturenum, struct texturething *arg1, s32 arg2); +void texLoadFromConfigs(struct textureconfig *configs, s32 numconfigs, struct texturething *arg2, s32 arg3); +void texLoadFromTextureNum(u32 arg0, struct texturething *arg1); void func0f173520(u8 *arg0); s32 func0f17353c(s32 arg0); void texturesLoadConfigs(void); diff --git a/src/include/types.h b/src/include/types.h index fe0355838..701a4c690 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -5237,10 +5237,9 @@ struct weatherparticledata { }; struct texture { - u8 soundsurfacetype : 4; - u8 surfacetype : 4; - u8 unk01; - u16 dataoffset; + u32 soundsurfacetype : 4; + u32 surfacetype : 4; + u32 dataoffset : 24; u32 unk04; }; @@ -6757,4 +6756,29 @@ struct awardmetrics { /*0x38*/ f32 accuracyfrac; }; +struct texturething { + struct texloadthing *unk00; // void * - same as unk0c + struct texloadthing *unk04; + struct texloadthing *unk08; // texturenum + struct texloadthing *unk0c; // void * - same as unk00 +}; + +struct texloadthing { + u16 unk00_00 : 12; + u16 unk00_0c : 4; + void *unk04; + s16 unk08; + u16 unk0a; + union { + u32 unk0c; + struct { + u32 unk0c_00 : 1; + u32 unk0c_01 : 1; + u32 unk0c_02 : 1; + u32 unk0c_03 : 1; + u32 unk0c_04 : 24; + }; + }; +}; + #endif