mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-01 11:29:27 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
508 lines
16 KiB
Plaintext
508 lines
16 KiB
Plaintext
;
|
|
; File: SonyPatches.a
|
|
;
|
|
; Contains: patches for the Sony Driver
|
|
;
|
|
; A bit of history: Sony reportedly receives 8,000 800K drives/month for
|
|
; repair, 7,000 of these have head damage. By moving heads to the i.d. of
|
|
; the disk, head damage is vastly reduced (by SonyÕs studies).
|
|
;
|
|
; Also, a patch for Format on all Macs. Format used 'DskErr' as a completion flag
|
|
; for synchronous calls to DiskSel and Seek, but other drivers might mess
|
|
; with this (at interrupt level), causing Format to think the Sel/Seek was
|
|
; finished before it really was.
|
|
;
|
|
; Another problem is that Format saved an error code in DskErr around a call
|
|
; to toEmptyPD, then restored from it, but after interrupts were enabled.
|
|
; EmptyPD doesnÕt destroy d0, so restoring isnÕt necessary (and bad). This
|
|
; is fixed by patching jRdAddr.
|
|
;
|
|
; Written by: Gary Rensberger
|
|
;
|
|
; Copyright: © 1989-1991 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <3> 10/28/91 SAM/KSM Rolled in Regatta file.
|
|
;
|
|
; Regatta Change History:
|
|
;
|
|
; <3> 7/19/91 SAM (GMR) Added patch to fix Prime overpatch code bug in Terror ROM's.
|
|
; <2> 6/30/91 SAM (GMR) Added ReCal patch for Derringer's BuddyLite drive.
|
|
; <1> 6/24/91 SAM Split off from 7.0 GM sources.
|
|
;
|
|
; 7.0 Change History:
|
|
;
|
|
; <2> 8/30/91 DTY Define has3rdFloppy, onMac, onHcMac and onMacPP to make
|
|
; SonyEqu.a happy. (They got taken out of BBSStartup in an effort
|
|
; to make all the files in SysObj.make use {Defs}.)
|
|
; <1> 8/18/90 dba created by merging the eject patch and the format patch (viva la
|
|
; linked patches)
|
|
; Change History of the eject patch:
|
|
;
|
|
; <5> 8/6/90 GMR NEEDED FOR SixPack! Made ComeFrom addresses relative to ROMBase.
|
|
; <4> 7/19/90 GMR Now also patches SEfdhd, IIx, Portable, and IIci ROMS.
|
|
; <3> 7/11/90 gbm get rid of duplicate symbols
|
|
; <2> 12/28/89 dba changed PROC to MAIN to get dead code stripping
|
|
; <1.1> 8/18/89 CCH Removed definition of onMac32.
|
|
; <1.0> 7/25/89 GMR FOR 6.0.4!! Added to EASE for first time.
|
|
;
|
|
; Change History of the format patch:
|
|
;
|
|
; <6> 8/12/90 GMR Needed for SixPack!! Special cased the Erickson ROM because the
|
|
; Sony driver moved in this version of the Mac32 ROM.
|
|
; <5> 8/6/90 GMR Made ComeFrom addresses relative to ROMBase.
|
|
; <4> 7/21/90 GMR Fixed 24/32 bit JSR bug in one of the patches.
|
|
; <3> 7/11/90 gbm change to avoid assembly warnings
|
|
; <2> 12/28/89 dba change PROC to MAIN to get dead code stripping
|
|
; <1.0> 12/11/89 GMR Adding for first time to EASE
|
|
;
|
|
|
|
if (&type('onMac') = 'UNDEFINED') then ; <2>
|
|
onMac: equ 0 ; <2>
|
|
endif ; <2>
|
|
|
|
if (&type('onMacPP') = 'UNDEFINED') then ; <2>
|
|
onMacPP: equ 0 ; <2>
|
|
endif ; <2>
|
|
|
|
if (&type('onHcMac') = 'UNDEFINED') then ; <2>
|
|
onHcMac: equ 0 ; <2>
|
|
endif ; <2>
|
|
|
|
if (&type('has3rdFloppy') = 'UNDEFINED') then ; <2>
|
|
has3rdFloppy: equ 0 ; <2>
|
|
endif ; <2>
|
|
|
|
load 'StandardEqu.d'
|
|
include 'SonyEqu.a'
|
|
include 'LinkedPatchMacros.a'
|
|
|
|
SeekCk ROMBind (II,$2D9C2),(SE,$34986),(Portable,$2CFC0),(IIci,$6CC9C)
|
|
CkDrvNum ROMBind (Plus,$18040),(II,$2DA00),(SE,$349E2)
|
|
RWPowerUp ROMBind (Plus,$1890A),(II,$2E1B0),(SE,$352EC),(Portable,$2DAA6)
|
|
Seek ROMBind (Plus,$18718),(II,$2DFAC),(SE,$350DE)
|
|
SyncCallRtn ROMBind (Plus,$194CA),(II,$2EFFC),(SE,$363AA),(Portable,$2EADE),(IIci,$6EA7C)
|
|
FmtTrkRet ROMBind (Plus,$19230),(II,$2ED66),(SE,$36114),(Portable,$2E82C),(IIci,$6E7CE)
|
|
EmptyPD ROMBind (Plus,$194AE),(II,$2EFE0),(SE,$3638E),(Portable,$2EAC2),(IIci,$6EA60)
|
|
|
|
; second version of some ROM binds used by SE w/FDHD, II w/FDHD and IIci w/bad Erickson overpatch
|
|
|
|
SyncCallRtn2 ROMBind (SE,$3D86C),(II,$3231A),(IIci,$6EEBA)
|
|
FmtTrkRet2 ROMBind (SE,$3D5C4),(II,$3206C),(IIci,$6EC0C)
|
|
EmptyPD2 ROMBind (SE,$3D856),(II,$322FE),(IIci,$6EE9E)
|
|
|
|
|
|
; Used by the Recal Patch for BuddyLite drives
|
|
|
|
GetDrive ROMBind (Portable,$2D7C8)
|
|
InvalTrkCache ROMBind (Portable,$2DA92)
|
|
SetChipMode ROMBind (Portable,$2EB5A)
|
|
AdrAndStrb ROMBind (Portable,$2D85A)
|
|
AdrAndSense ROMBind (Portable,$2D838)
|
|
Pulse ROMBind (Portable,$2D85C)
|
|
Wait100 ROMBind (Portable,$2D902)
|
|
recalSlow ROMBind (Portable,$2D9F6)
|
|
|
|
; Used by the Prime Patch for the Terror overpatch ROM
|
|
|
|
PrimePC EQU $0086CEBE
|
|
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; JSeek Ñ patch to make the FDHD Sony driver seek to track 40 instead of track 79 when ejecting
|
|
|
|
ROMs SE,II,Portable,IIci,hasFDHDDriver,hasIWM,notAUX
|
|
|
|
SetupSeek40InsteadOf79Patch InstallProc
|
|
|
|
Import FromSeek0,FromSeek1
|
|
|
|
leaROM SeekCk,d0
|
|
and.l Lo3Bytes,d0
|
|
lea FromSeek0,a0
|
|
move.l d0,(a0) ; put stripped address into patch
|
|
add.l #$10,d0 ; advance to next address
|
|
lea FromSeek1,a0
|
|
move.l d0,(a0) ; put stripped address into patch
|
|
rts
|
|
|
|
EndProc
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
Seek40InsteadOf79Patch PatchProc JSeek
|
|
|
|
Entry FromSeek0,FromSeek1
|
|
|
|
move.l (sp),d0 ; get return address
|
|
and.l Lo3Bytes,d0 ; only check 24 bit part of address
|
|
|
|
FromSeek0 equ *+2
|
|
cmp.l #'GMR',d0 ; were we called by eject?
|
|
beq.s seekAlter ; yes, alter track #
|
|
FromSeek1 equ *+2
|
|
cmp.l #'GMR',d0 ; were we called by eject (2nd try case)?
|
|
bne.s callOld ; no, just call ROM based seek routine
|
|
seekAlter
|
|
moveq #40,d6 ; yes, alter track # from 79 to track 40 (half way out)
|
|
callOld
|
|
jmpOld ; call ROM based Seek routine
|
|
|
|
EndProc
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; JControl Ñ patch to make 800K floppy driver seek to track 40 when ejecting
|
|
|
|
; Seek to track 40 if itÕs an Eject call, valid drive, drive installed, not a DCD drive,
|
|
; and thereÕs a disk in the drive. Then jump back into the ROM to complete the eject.
|
|
|
|
ROMs Plus,SE,II,has800KDriver
|
|
|
|
SetupDCDDriveNumberForSE InstallProc (SE,has800KDriver)
|
|
|
|
Import pDCDNum
|
|
|
|
lea pDCDNum,a0 ; SE has 3 drives before the DCD
|
|
move.w #4,(a0) ; so the DCD drive number is 4, not 3
|
|
rts
|
|
|
|
EndProc
|
|
|
|
ControlSeek40OnEject PatchProc JControl
|
|
|
|
Entry pDCDNum
|
|
|
|
move.l a0,d4 ; save paramBlockPtr (donÕt use stack!)
|
|
|
|
cmpi.w #7,CSCode(a0) ; check for eject call
|
|
bne.s oldEject ; no, do old control call
|
|
|
|
jsrROM CkDrvNum ; check drive# validity
|
|
bne.s oldEject ; not valid, exit
|
|
|
|
tst.b Installed(a1,d1.w) ; check if drive actually installed
|
|
bmi.s oldEject ; no, let old control call handle it
|
|
|
|
pDCDNum equ *+2 ; drive number of the DCD drive
|
|
cmpi.w #3,Drive(a1) ; see if DCD drive
|
|
bge.s oldEject ; DCD drive, let old control call handle it
|
|
|
|
tst.b DiskInPlace(a1,d1.w) ; has disk been seen in drive?
|
|
ble.s oldEject ; no, skip seek
|
|
|
|
jsrROM RWPowerUp ; make sure the driveÕs powered up
|
|
moveq #40,d6 ; seek to track 40 to get away from shutter edge
|
|
jsrROM Seek
|
|
bgt.s oldEject ; (seek was successful)
|
|
beq.s reSeek ; (recalÕd)
|
|
|
|
pea @returnHere
|
|
move.l JRecal,-(sp) ; seek failed: recal first
|
|
rts
|
|
@returnHere
|
|
|
|
bmi.s oldEject
|
|
reSeek
|
|
moveq #40,d6
|
|
jsrROM Seek ; try seeking again
|
|
|
|
oldEject
|
|
movea.l d4,a0 ; restore paramBlockPtr
|
|
jmpOld ; call ROM based Control routine
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
|
|
ROMs Plus,SE,II,Portable,IIci,notAUX
|
|
|
|
SetupFormatPatchesCommon Proc
|
|
|
|
Import pSyncCallRtnInDiskSel,pSyncCallRtnInSeek,pFmtTrk
|
|
|
|
; pass SyncCallRtn in d0, FmtTrkRet in d1
|
|
|
|
and.l Lo3Bytes,d0 ; mask to get 24 bit compare address <4>
|
|
lea pSyncCallRtnInDiskSel,a0
|
|
move.l d0,(a0) ; stuff address into patch
|
|
lea pSyncCallRtnInSeek,a0
|
|
move.l d0,(a0) ; stuff address into patch
|
|
|
|
sub.l #$18,d1 ; address in ROM to jump back to
|
|
and.l Lo3Bytes,d1 ; mask to get 24 bit compare address <4>
|
|
lea pFmtTrk,a0
|
|
move.l d1,(a0) ; stuff in return check address into patch
|
|
|
|
rts
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
SetupFormatPatches1 Proc Export
|
|
|
|
leaROM SyncCallRtn,d0
|
|
leaROM FmtTrkRet,d1
|
|
|
|
jmp SetupFormatPatchesCommon
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
SetupFormatPatches2 Proc Export
|
|
|
|
Import pFmtTrkRet,pEmptyPD
|
|
|
|
leaROM SyncCallRtn2,d0
|
|
leaROM FmtTrkRet2,d1
|
|
leaROM EmptyPD2,d2
|
|
|
|
lea pFmtTrkRet,a0
|
|
move.l d1,(a0) ; stuff address into patch
|
|
|
|
lea pEmptyPD,a0
|
|
move.l d2,(a0)
|
|
|
|
jmp SetupFormatPatchesCommon
|
|
|
|
EndProc
|
|
|
|
MakeInstall SetupFormatPatches1,(Plus,SE,II,has800KDriver,notAUX)
|
|
MakeInstall SetupFormatPatches1,(Portable,IIci,notAUX)
|
|
|
|
MakeInstall SetupFormatPatches2,(SE,II,hasFDHDDriver,notAUX)
|
|
MakeInstall SetupFormatPatches2,(IIci,hasEricksonOverpatchMistake,notAUX)
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; This routine patches the DiskSelect routine. It first checks to see if
|
|
; we were called in the Format SyncCall routine. If we were, then we clear
|
|
; a new completion flag (instead of using diskErr). We also patch the two return
|
|
; addresses above the caller to this routine, one of which sets the new completion
|
|
; flag, the other which tests the flag. This quick and dirty, but works!
|
|
|
|
DiskSelectSyncCallPatch PatchProc JDiskSel
|
|
|
|
Entry pSyncCallRtnInDiskSel
|
|
Import WaitRtn,DoneRtn
|
|
|
|
nop ; Important..sync the instruction pipe
|
|
|
|
moveq #10,d0 ; return addresses should be 10 bytes apart
|
|
add.l 8(sp),d0 ; 3rd level return address + 10
|
|
sub.l 4(sp),d0 ; compare to 2nd level return address
|
|
bne.s Done ; no, not the one weÕre looking for, exit
|
|
|
|
move.l 4(sp),d0 ; yes, get 2nd level address again
|
|
and.l Lo3Bytes,d0 ; only check 24 bit part of address
|
|
pSyncCallRtnInDiskSel equ *+2
|
|
cmpi.l #'GMR',d0 ; were we called by Format SyncCall routine?
|
|
bne.s Done ; no, get out of here
|
|
|
|
move.l a0,d0 ; save a0
|
|
|
|
lea DoneRtn,a0 ; get address of our new Done routine
|
|
move.l a0,4(sp) ; replace old routine
|
|
lea WaitRtn,a0 ; get address of our new Wait routine
|
|
move.l a0,8(sp) ; replace old routine
|
|
|
|
movea.l d0,a0 ; restore a0
|
|
|
|
subq.b #1,Active(a1) ; signal that RWPowerUp isnÕt done yet.
|
|
Done
|
|
jmpOld ; go back to original jump vector
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; This routine patches the Seek routine. It first checks to see if
|
|
; we were called by the Format SyncCall routine. If we were, then we clear
|
|
; a new completion flag (instead of using diskErr). We also patch the two
|
|
; return addresses above this routine, one of which sets the new completion
|
|
; flag, the other which tests the flag.
|
|
|
|
SeekSyncCallPatch PatchProc JSeek
|
|
|
|
Entry WaitRtn,DoneRtn,pSyncCallRtnInSeek
|
|
|
|
moveq #10,d0 ; return addresses should be 10 bytes apart
|
|
add.l 4(sp),d0 ; 2nd level return address + 10
|
|
sub.l (sp),d0 ; compare to 1st level return address
|
|
bne.s Done ; no, not the one weÕre looking for, exit
|
|
|
|
move.l (sp),d0 ; get 2nd level return address
|
|
and.l Lo3Bytes,d0 ; only check 24 bit part of address
|
|
pSyncCallRtnInSeek equ *+2
|
|
cmpi.l #'GMR',d0 ; were we called by Format SyncCall?
|
|
bne.s Done ; no, get out of here
|
|
|
|
move.l a0,d0 ; save a0
|
|
|
|
lea DoneRtn,a0 ; get address of our new Done routine
|
|
move.l a0,(sp) ; replace old routine
|
|
lea WaitRtn,a0 ; get address of our new Wait routine
|
|
move.l a0,4(sp) ; replace old routine
|
|
|
|
movea.l d0,a0 ; restore a0
|
|
|
|
subq.b #1,Active(a1) ; signal that Seek isnÕt done yet.
|
|
Done
|
|
jmpOld ; go back to original jump vector
|
|
|
|
|
|
WaitRtn
|
|
cmpi.b #$FF,Active(a1) ; are we finished?
|
|
bne.s WaitRtn ; no, wait
|
|
rts ; exit
|
|
|
|
|
|
DoneRtn
|
|
st Active(a1) ; weÕre finished, set completion bit
|
|
rts
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
|
|
;----------------------------------------------------------------------------------
|
|
; Patch RdAddr to fix Format code, so format doesnÕt use DskErr lowmem
|
|
; for saving temporary error results, since an interrupt can get in and
|
|
; clobber this lowmem. The patch first checks to see if weÕre called from
|
|
; format, if so, patches in a new routine to return to on the stack. In either
|
|
; case, it continues by jumping to what jRdAddr pointed to.
|
|
|
|
RdAddrFormatPatch PatchProc JRdAddr
|
|
|
|
Entry pFmtTrk,pEmptyPD,pFmtTrkRet
|
|
|
|
move.l (sp),d0 ; get 1st level return address
|
|
and.l Lo3Bytes,d0 ; only check 24 bit part of address
|
|
pFmtTrk equ *+2
|
|
cmpi.l #'GMR',d0 ; were we called by Format FmtTrk1 rtn?
|
|
bne.s @dontPatch ; no, get out of here
|
|
|
|
move.l a0,d0 ; save a0
|
|
lea newFmtRtn,a0 ; get address of our new routine
|
|
move.l a0,(sp) ; replace old routine
|
|
movea.l d0,a0 ; restore a0
|
|
@dontPatch
|
|
jmpOld ; continue by jumping to RdAddr
|
|
|
|
;..................................................................................
|
|
|
|
newFmtRtn
|
|
bmi.s @dontChangeErr ; br if error
|
|
tst.b d2 ; should be sector 0
|
|
beq.s @dontChangeErr
|
|
moveq #Fmt1Err,d0 ; set "not sector 0" error otherwise
|
|
@dontChangeErr
|
|
|
|
pEmptyPD equ *+2
|
|
jsrROM EmptyPD ; get rid of poll data (saves D0 in DskErr)
|
|
andi #$F8FF,SR ; open up interrupts
|
|
lea GapSync(a1),a0 ; useful addr
|
|
tst.w d0 ; check error code
|
|
pFmtTrkRet equ *+2
|
|
jmpROM FmtTrkRet ; 'DecrSn1' back to ROM code...
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------- <2>
|
|
; Patch Recal to use fast (with handshake) step pulses for the
|
|
; new Buddy Lite SuperDrive on Derringer.
|
|
|
|
ROMs Portable
|
|
|
|
RecalPatch PatchProc jRecal
|
|
|
|
move.l (SP)+,A5 ; save return address
|
|
jsrROM GetDrive
|
|
jsrROM InvalTrkCache ; invalidate track cache
|
|
|
|
jsrROM SetChipMode ;Initialize appropriate register set
|
|
bne.s @RecalExit ; couldn't set IWM Mode
|
|
|
|
jsrROM RWPowerUp ;Re-enable the interface
|
|
moveq #80,D7 ; maximum number of steps needed
|
|
|
|
moveq #DirHAdr,D0 ;Set direction out (toward track 0)
|
|
jsrROM AdrAndStrb ;
|
|
|
|
move.w SeekTime(A1),D0 ; assume slow code
|
|
tst.b NewIntf(A1,D1) ; new drive interface?
|
|
bmi.s @fastRecal ; br if so (use fast code)
|
|
jmpROM recalSlow ; else, use slow code
|
|
|
|
;------
|
|
@fastRecal subq #1,D7 ;Adjust count for DBRA
|
|
@SeekLoop moveq #StepLAdr,D0 ;Make sure /STEP starts out high
|
|
jsrROM AdrAndSense ;
|
|
bpl.s @RecalFail ;-> it wasn't, so exit with error
|
|
jsrROM Pulse ;Then set it low
|
|
jsrROM Wait100 ;and wait a while for it to go high
|
|
dbra D7,@SeekLoop ;count track
|
|
|
|
moveq #0,D0 ; track 0
|
|
@RecalExit move.w D0,Track(A1,D1)
|
|
jmp (A5)
|
|
|
|
@RecalFail moveq #cantStepErr,D0 ; no track
|
|
bra.s @RecalExit
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
|
|
|
|
;---------------------------------------------------------------------------------- <3>
|
|
; The following patch applies to the Mac32 ROM's. It fixes a bug in the
|
|
; Terror ($67C) overpatch code for jPrime which had a stack problem.
|
|
;----------------------------------------------------------------------------------
|
|
|
|
ROMs IIci
|
|
|
|
instIODonePatch InstallProc (IIci)
|
|
|
|
IMPORT toOldIODone
|
|
leaResident toOldIODone,a0 ; get location of JMP to address
|
|
move.l jIODone,(a0) ; stuff old vector in JMP location
|
|
leaResident NewIODone,a0 ; get location of new IODone rtn
|
|
move.l a0,jIODone ; stuff in vector
|
|
rts
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
NewIODone Proc ; <3>
|
|
EXPORT toOldIODone
|
|
|
|
move.l (sp),d1 ; check return address
|
|
and.l Lo3Bytes,d1
|
|
cmpi.l #PrimePC,d1 ; are we comming from the Prime area?
|
|
bne.s NewExit ; no, normal exit
|
|
addq.w #4,sp ; yes, fix the stack
|
|
|
|
toOldIODone EQU *+2
|
|
NewExit jmp $40800000 ; exit
|
|
|
|
EndProc
|
|
|
|
|
|
|
|
;ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
|
|
End
|