ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее MBIOS3KPASM X  CENTR ASM  SCB ASM  MYKEYPADASM  PUTSYS ASM  Z80 LIB . FDC3KP ASM  LPTBL ASM ! SERIAL ASM "# WIN3KP ASM [$%&'() NDOS3 ASM O*+,-./0123456 CRT ASM 789:;<=>? TYPECR ASM @ RSXRM ASM A TR ASM 5BCDE MBIOS SUB F GETDP3KPASM >GHIJ NTPDATE ASM (KLM KEYBD ASM #NOP LDCPM3 ASM QR SNIOS3 ASM ST END ASM U GENCPM DAT VW NETSTAT ASM XY ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееvers equ '1a' ; March 10, 2017 17:11 drm "MBIOS3KP.ASM" ;**************************************************************** ; Main BIOS module for CP/M 3 (CP/M plus) on the KAYPRO computer* ; Copyright (c) 1985 Douglas Miller * ;**************************************************************** maclib Z80 true equ -1 false equ not true bnksiz equ 56 ;size of banks, in "K". Either 48 or 56. compag equ bnksiz*4 ; C0 or E0, for MMU common page select bnktop equ compag shl 8 ;C000 or E000 cr equ 13 lf equ 10 bell equ 7 cpm equ 0 bdos equ 5 ccp equ 0100h ; Console Command Processor gets loaded into the TPA ; SCB registers extrn @covec,@civec,@aovec,@aivec,@lovec,@ermde extrn @mxtpa,@sec,@min,@hour,@date extrn @lptbl ; External routines extrn ?getdp,?serdp ; Variables for use by other modules public @adrv,@pdrv,@rdrv,@side,@trk,@sect,@login public @dma,@dbnk,@cnt,@scrbf,@dtacb,@dircb public @dstat,@cmode,@dph,@rcnfg public @ctbl,@cbnk,bnkdos,resdos,wbtrap public @vect,sio1vec,sio2vec,piovec ; Routines for use by other modules public ?timot public ?dvtbl,?drtbl public ?bnksl,?stbnk ********************************************************* ** I/O port base addresses ********************************************************* sio1 equ 004h ;z80-sio/0 sio2 equ 00ch ; " pio equ 020h ;modem and rtc functions rtc equ 024h ;real-time clock fdc equ 010h ;floppy disk controller mmu equ 03fh ;memory management sysctl equ 014h ;system control (and floppy disk control bits) ********************************************************* ** SIO's ********************************************************* sio1datA equ sio1+0 sio1ctlA equ sio1datA+2 sio1datB equ sio1+1 sio1ctlB equ sio1datB+2 sio2datA equ sio2+0 sio2ctlA equ sio2datA+2 sio2datB equ sio2+1 sio2ctlB equ sio2datB+2 ********************************************************* ** PIO ********************************************************* pioAdat equ pio+0 pioActl equ pioAdat+2 pioBdat equ pio+1 pioBctl equ pioBdat+2 ********************************************************* ** RTC (MM58167 Real-Time Clock) ********************************************************* RTCDTA equ RTC RTCADR equ pioAdat RTCSEC equ 2 RTCMIN equ 3 RTCHRS equ 4 RTCDAY equ 5 RTCDAT equ 6 RTCMON equ 7 lastmon equ 10 ;month last accessed (used to detect year change) rtcyrs equ 8 ;years (decade) rtcent equ 9 ;century clrcnt equ 18 rtcsts equ 20 rtcis equ 16 ;interupt status rtcic equ 17 ;interupt control hbnk equ 2 ;bank to use for Hash tables. hstart equ 100h ;reserve page 0 for interupt vectors, etc. hsize equ (bnktop-hstart)/16 ;allocate space equally to each drive. ;-------- Start of Code-producing source ----------- cseg ; GENCPM puts CSEG stuff in common memory BIOS$0 equ $ bnkdos equ bios$0+0fc00h ;dummy values, reloc "Fxxx", GENCPM will resdos equ bios$0+0fd00h ; substitiute real values. jmp boot ; initial entry on cold start jmp wboot ; reentry on program exit, warm start jmp const ; return console input status jmp conin ; return console input character jmp conout ; send console output character jmp list ; send list output character jmp auxout ; send auxilliary output character jmp auxin ; return auxilliary input character jmp home ; set disks to logical home jmp seldsk ; select disk drive, return disk parameter info jmp settrk ; set disk track jmp setsec ; set disk sector jmp setdma ; set disk I/O memory address jmp read ; read physical block(s) jmp write ; write physical block(s) jmp listst ; return list device status jmp sectrn ; translate logical to physical sector jmp conost ; return console output status jmp auxist ; return aux input status jmp auxost ; return aux output status ?dvtbl: jmp devtbl ; return address of device def table jmp cinit ; change baud rate of device ?drtbl: jmp getdrv ; return address of disk drive table jmp multio ; set multiple record count for disk I/O jmp flush ; flush BIOS maintained disk caching movev: jmp move ; block move memory to memory jmp timex ; Signal Time and Date operation ?bnksl: jmp bnksel ; select bank for code execution and default DMA ?stbnk: jmp setbnk ; select different bank for disk I/O DMA operations. jmp xmove ; set source and destination banks for one operation jmp search ; reserved for OEM: search for module. jmp 0 ; reserved for future expansion jmp 0 ; reserved for future expansion @dstat: ds 1 dw @lptbl ;logical/physical drive table dw thread ;module thread dw ?serdp ;test mode validity, HL=memory address of ?serdp @adrv: ds 1 ; currently selected disk drive @pdrv: ds 1 ; physical drive number @rdrv: ds 1 ; module relative disk drive number curmdl: ds 2 ; currently selected Disk I/O module address @cmode: ds 2 @dph: ds 2 @dma: dw 0 wbtrap: dw 0 tmpdrv: db 0 defsrc: db 0,0ffh,0ffh,0ffh srctyp: db 000$00$000b ;only bits 3,4 are used (others ignored) icivec: dw 0100000000000000b icovec: dw 1000000000000000b iaivec: dw 0000000000000000b iaovec: dw 0000000000000000b ilovec: dw 0000001000000000b goccp: mvi a,1 ;select bank 1 (where CCP is) call bnksel jmp ccp ; then exit to ccp bdose: lhld @mxtpa call icall xra a call bnksel mov a,l mov b,h ret @@ set ($-BIOS$0) if (@@ and 0fh) ne 0 ds 16-(@@ and 0fh) endif ;put vectors on req. boundary, xxxxx000x for SIOs ; and xxxxxxx0 for PIO. @vect: sio1vec: dw nullsio ; chB TxE dw nullsio ; Ext/Sts dw nullsio ; RxA dw nullsio ; Spcl dw nullsio ; chA TxE dw nullsio ; Ext/Sts dw nullsio ; RxA dw nullsio ; Spcl sio2vec: dw nullsio ; chB TxE dw nullsio ; Ext/Sts dw nullsio ; RxA dw nullsio ; Spcl dw nullsio ; chA TxE dw nullsio ; Ext/Sts dw nullsio ; RxA dw nullsio ; Spcl piovec: dw nullpio ;ch A dw nullpio ;ch B @v set @vect-BIOS$0 @@ set $-BIOS$0 if (@v shr 8) ne (@@ shr 8) ds 'Vect X page bound' endif wboot: lxi sp,stack xra a call bnksel jmp wboot1 ds 64 stack equ $ ds 32 iostk equ $ iostkp: dw $-$ nullsio: nullpio: ei reti ds 16 ;8 levels of stack intstk: ds 0 istk: dw 0 tick: sspd istk lxi sp,intstk push psw push h push b lxi h,@sec inr m lxi h,tictbl mvi b,numtic to4: mov a,m inx h cpi true jz to3 mov a,m ora a jrz to5 dcr m jrnz to3 push b push d push h inx h mov a,m inx h mov h,m mov l,a call icall pop h pop d pop b mov a,m ora a jrnz to3 to5: dcx h mvi m,true inx h to3: inx h inx h inx h djnz to4 too3: mvi c,rtcadr inp b ;save existing rtcadr mvi a,rtcis ;clear rtc INT flag outp a ; in rtcdta ; outp b ;restore rtcadr pop b pop h pop psw lspd istk ei reti ;resets PIO interupt ; SEARCH for a module by device #. ; entry: C = device # (0-249) ; exit: [CY] = not found ; else HL=module address ("init" entry) ; A=device number (relative to module's #0) ; search: lxi d,thread ;C=device number snext: xchg mov e,m inx h mov d,m inx h mov a,d ora e sui 1 ;produce [CY] if DE=0000 rc ;return if device not found, DE=0000 mov a,c sub m jrc snext inx h cmp m jrnc snext inx h ;point to "init" vector ora a ;set [NC] condition ret devtbl: lxi h,@ctbl ret @ctbl: db 'nodev ',0,0 ;character table, filled at cold-start. db 'nodev ',0,0 db 'nodev ',0,0 db 'nodev ',0,0 db 'nodev ',0,0 db 'nodev ',0,0 db 'nodev ',0,0 db 'nodev ',0,0 db 0 ;table terminator cdtbl: rept 8 ;character device table, filled at cold-start. dw cnull endm cnull: jmp null ;init jmp nulli ;input status jmp nulli ;input jmp nulli ;output status jmp null ;output nulli: mvi a,1ah ;E.O.F. character, also [NZ] to be always ready. ora a ;sets [NZ] condition. null: ret cinit: mvi b,0 ;C=device number (0-11) bit 3,c ;devices 8-11? rnz ;cannot init those mvi b,0 ;C=device number (0-7) slar c ;*2 for table index lxi h,cdtbl dad b mov e,m inx h mov d,m mov b,c xchg pchl ;jump to modules "init" with B=device # const: lhld @civec ; get console input bit vector jr ist$scan0 auxist: lhld @aivec ; get aux input bit vector ist$scan0: call swtosys lxi d,xitusr push d ist$scan: lxi d,cdtbl mvi b,0 cis$next: slar h ; check next bit jnc is0 mvi a,3 ; assume device not ready call indjmp1 ; check status for this device ora a ! rnz ; if any ready, return true is0: inx d inx d inr b mov a,h ! ora a ; see if any more selected devices jrnz cis$next xra a ; all selected were not ready, return false ret conin: lhld @civec jr in$scan0 auxin: lhld @aivec in$scan0: call swtosys in$scan: push h call ist$scan ;see if there is a character ready pop h ora a jrz in$scan ;wait untill one is ready. mvi a,6 call indjmp ;get character jr xitusr conout: lhld @covec ; fetch console output bit vector jr out$scan0 auxout: lhld @aovec ; fetch aux output bit vector jr out$scan0 list: lhld @lovec ; fetch list output bit vector out$scan0: call swtosys out$scan: lxi d,cdtbl mvi b,0 co$next: slar h ; shift out next bit mvi a,12 cc indjmp1 inx d inx d inr b mov a,h ! ora a ; see if any devices left jrnz co$next ; and go find them... jr xitusr conost: lhld @covec ; get console output bit vector jr ost$scan0 auxost: lhld @aovec ; get aux output bit vector jr ost$scan0 listst: lhld @lovec ; get list output bit vector ost$scan0: call swtosys ost$scan: lxi d,cdtbl mvi b,0 ;B = device number cos$next: slar h ; check next bit mvi a,9 ; [NZ] will assume device ready (in case no call made) cc indjmp1 ; check status for this device ora a ; see if device ready jrz xitusr ; if any not ready, return false inx d inx d inr b mov a,h ! ora a ; see if any more selected devices jrnz cos$next ori true ; if all selected were ready, return true ; jr xitusr xitusr: mov b,a pop psw ora a jrz xu0 call bnksel ;preserves BC. lspd iostkp xu0: mov a,b ora a ret swtosys: pop d ;routine return address lda @cbnk ora a jrz sw0 sspd iostkp lxi sp,iostk push psw xra a call bnksel pop psw sw0: push psw push d ret indjmp1: push h push d push b call indjmp pop b pop d pop h ret indjmp: xchg add m ;a=0,3,6,9,12,... mov e,a mvi a,0 inx h adc m mov d,a xchg pchl ;indirect call addjmp: add l ;a=0,3,6,9,... mov l,a mvi a,0 adc h mov h,a icall: pchl ;indirect call bnksel: sta @cbnk ; remember current bank push b mov b,a add a add a ora b ori compag out mmu pop b ret timex: ;time get/set. sded savede call swtosys ;destroys DE push h call gett pop h lded savede jmp xitusr savede: ds 2 xmove: mov a,b ;WR bnk add a add a ora c ;RD bnk ori compag sta xmbnk ret xmbnk: ds 1 move: lda xmbnk ora a jrz xxm0 out mmu xxm0: xchg ldir xchg ora a ;test xmbnk again lda @cbnk cnz bnksel xra a sta xmbnk ret @cbnk: db 0 ; bank for processor operations signon: db 13,10,7,'KAYPRO CP/M 3.10' dw vers db ' (c) 1985 DRI and DRM',13,10,'$' ccp$msg db 13,10,7,'No CCP$' ccprecs db 0 ccp$com db 1,'CCP COM',0,0,0,0 ds 16 fcb$nr db 0,0,0,0 tictbl: db true,0 dw $-$ db true,0 dw $-$ numtic equ ($-tictbl)/4 ;must be at end of all "cseg" code. thread equ $ dseg ; this part can be banked @login: ds 2 ;position is assumed by special BNKBDOS3.SPR... ; must be first item in DSEG. hlast: dw hstart hleft: dw bnktop-hstart boot: lxi sp,stack lxi h,@vect mov a,h stai im2 ; Verify that we have banked RAM... ; init PIO,RTC and tick interupt call clrpio ;reset any PIO interupts pending mvi a,11$001111b ;bit control mode out pioActl mvi a,11000000b ;7,6 inputs out pioActl lxi h,piovec+0 ;bit-0 of vector must be 0 mov a,l out pioActl mvi a,1011$0111b ;EI, OR, HI, mask follows out pioActl ; mvi a,10111111b ;bit 6 only out pioActl lxi h,tick shld piovec+0 mvi a,rtcis out rtcadr in rtcdta mvi a,rtcic out rtcadr mvi a,00000100b ;enable INT on 1-second interval out rtcdta ; mvi a,01$001111b ;input mode out pioBctl mvi a,0000$0111b ;no interupts out pioBctl mvi a,01001010b out pioBdat lxi h,piovec+2 mov a,l out pioBctl ; mvi a,2 out sio1ctlB out sio2ctlB lxi h,sio1vec mov a,l out sio1ctlB lxi h,sio2vec mov a,l out sio2ctlB ei ; Initialize all modules and build tables. lxi h,thread ;thread our way through the modules, in0: mov e,m ;initializing as we go. inx h mov d,m ;next module, or "0000" if we're past the end. inx h mov a,d ora e jz init$done mov a,m ;device base number inx h inx h ;thread+4 = init entry (JMP) sui 200 ;if Char I/O module, build entry(s) in tables. jc notchr push d ;save NEXT module address mov c,a mvi b,0 dcx h mov a,m ;number of devices inx h xchg ;DE=init entry point lxi h,cdtbl dad b dad b mov b,a mov a,c in1: cpi 12 jnc in4 ;if device # overflows, adjust next step. mov m,e ; inx h ; mov m,d ; inx h ; inr a djnz in1 dcx d ldax d ;number of devices in3: mov b,a mov a,c ;DE=module address, C=device base add a ; *2 add a ; *4 add a ; *8 mov c,a mov a,b ;number of devices mvi b,0 lxi h,@ctbl dad b xchg ;DE=@ctbl indexed by device base mvi c,17+1 ;B=0 still, point to CHRTBL vector dad b ;point to chrtbl location mov c,m inx h mov h,m mov l,c ;HL=chrtbl add a add a add a ;num.dev * 8 = number of bytes in module's table. mov c,a ;B=0 still ldir ;copy modules chrtbl into system table. in2: pop h jmp in0 in4: sub c ;compute number of devices that will fit. jnz in3 ;continue with initialization of tables jmp in2 notchr: ;HL point to init entry push d call icall ;"call" (HL) pop h jmp in0 clrpio: call twice twice: reti init$done: ;all Disk I/O modules are initialized. mvi c,11 in5: push b call cinit pop b dcr c jp in5 lhld icovec shld @covec ;set console I/O lhld icivec shld @civec ; lhld ilovec shld @lovec ;set list output device lhld iaovec shld @aovec ;set auxiliary I/O device lhld iaivec shld @aivec ; lxi h,defsrc lxi d,@ermde+1 ;location of default search chain in SCB lxi b,5 ldir lda srctyp ani 000$11$000b mov c,a lda @civec-10 ;location of search type flags in CCP section ani 111$00$111b ora c sta @civec-10 lxi d,signon mvi c,9 call bdose ; was there enough RAM? call set$jumps ;setup system jumps and put in all banks ; fetch CCP for first time, system will put it in bank 1. mvi a,0feh ;don't try warm boot on error... sta @ermde ; lxi d,ccp$com mvi c,15 ;open file call bdose inr a jz noccp xra a sta fcb$nr lxi d,ccp mvi c,26 ;set DMA address call bdose mvi e,64 ;read upto 64 records (8K) mvi c,44 ;set multi-sector count call bdose lxi d,ccp$com mvi c,20 ;read record(s) call bdose mov a,h ;H=number of records actually read sta ccprecs xra a ;back to sta @ermde ;default mode for user lxi b,0001h ; save CCP in bank 0 for warm boots. call xmovccp ;NOTE: this restricts banked OS size. jmp goccp ; (allowing 8K for "CCP" and reserving page 0) wboot1: call set$jumps ; initialize page zero, selects bank 0 lxi b,0100h call xmovccp lhld wbtrap ; allow I/O modules to partake in the warm$boot. mov a,h ; ora l ; cnz icall ; jmp goccp xmovccp: call xmove lda ccprecs mov b,a mvi c,0 srlr b rarr c ;BC=number of bytes in CCP lxi h,ccp lxi d,ccp jmp move set$jumps: mvi a,(JMP) sta cpm ! sta bdos ; set up jumps in page zero lxi h,BIOS$0+3 ! shld cpm+1 ; BIOS warm start entry lhld @mxtpa ! shld bdos+1 ; BDOS system call entry lxi b,0100h ;source bank 0, dest bank 1 call xmove lxi h,0 lxi d,0 lxi b,64 call move lxi b,0200h ;source bank 0, dest bank 2 call xmove lxi h,0 lxi d,0 lxi b,64 call move lxi b,0300h ;source bank 0, dest bank 3 call xmove lxi h,0 lxi d,0 lxi b,64 jmp move ?timot: ; (B)=I.D. (C)=count, (DE)=routine address push d to1: mvi e,numtic lxi h,tictbl di to0: mov a,m cpi true jrz to2 cmp b jrz to2 inx h inx h inx h inx h dcr e jrnz to0 ei mov a,c ;don't wait if all it wants is to clear a possible ora a ;existing entry, since none exists for that module. jrnz to1 ;-- maybe we should "ei hlt" and then jump -- pop d ret to2: pop d mov m,b inx h mov m,c inx h mov m,e inx h mov m,d ei ret noccp: lxi d,ccp$msg errx: mvi c,9 call bdose di ! hlt gett: inr c ;test for "FF" jz sett ;FF=set time ti0: lxi d,rtcsts+(numrtc shl 8) lxi h,time lxi b,rtcadr+(rtcsec shl 8) ti1: outp b ;select reg inr b in rtcdta mov m,a inx h outp e ;select status reg in rtcdta ora a jrnz ti0 dcr d jrnz ti1 lda timemon ;if last accessed month is greater lxi h,lstmnth ;than current month, the year must be cmp m ;changed. cc setyear$1 ;assumes 1 year elapsed lda timesec sta @sec lda timemin sta @min lda timehrs sta @hour mvi a,28 sta mondays+1 ;set February=28 lda timeyrs call bcdbin mov b,a lda timecnt sui 19h mov a,b jrz ti1@0 adi 100 ;adjust for century ti1@0: sui 78 ;years since 1978 (base year) mov b,a ; inr a ;adjustment for leap year calc. mov c,a ; srlr c ; srlr c ;divide by 4 = number of leap years (exclusive) ani 11b cpi 11b ;is this year a leap year? jrnz ti2 mvi a,29 sta mondays+1 ;set february=29 ti2: lxi h,0 lxi d,365 ti3: dad d ;find number of days since 1978 djnz ti3 dad b ;(B=0) add in 1 day for each leap year lda timedat call bcdbin mov c,a mvi b,0 dad b ;add in days of this month lda timemon call bcdbin dcr a ;if January, nothing left to add. jrz ti4 mov b,a lxi d,mondays ;add in days of each month upto this. ti5: ldax d inx d add l mov l,a mvi a,0 adc h mov h,a djnz ti5 ti4: shld @date lda @sec ret sett: lda @hour sta timehrs lda @min sta timemin lda @sec sta timesec lhld @date lxi d,365 mvi a,28 sta mondays+1 ;set february=28 mvi b,0 ;start counting years since 1978 ti6: mov a,b ; check for leap year ani 11b ;every 4 years, xri 10b ;starting with 1980 jrnz ti7 stc ;one extra day for leap years ti7: dsbc d ;does this year fit in @date? inr b ;count a year. jrnc ti6 ;yes, keep taking out more days (by years) mov a,b ;is this year a leap year? ani 11b xri 10b jrnz ti8 mvi a,29 sta mondays+1 ;February=29 stc ti8: dadc d ;normalize @date (we subtracted one too many) dcr b mov a,b adi 78 ;adjust year to 1900 mvi b,19 ;century cpi 100 jrc ti8@0 inr b sui 100 ti8@0: call binbcd sta timeyrs mov a,b call binbcd sta timecnt xchg ;remainder into DE mvi b,1 ;start taking out months. lxi h,mondays ti9: mov a,e sub m mov c,a mov a,d sbi 0 jrc ti10 mov e,c mov d,a inx h inr b mov a,b cpi 13 jrc ti9 ti10: mov a,b call binbcd sta timemon sta lstmnth ;also set last accessed month mov a,e ;left-over must be date of month call binbcd sta timedat ; set day-of-week using Zeller's congruence: lda timeyrs ;E=([2.6m-.2]+K+D+[D/4]+[C/4]-2C) mod 7 call bcdbin ;0=sunday mov d,a lda timemon call bcdbin mov b,d sui 2 jrz ti11 jrnc ti12 ti11: adi 12 dcr b ti12: mov c,a add a add c ;*3 add a add a ;*12 add c ;*13 dcr a mvi c,0 ti13: inr c sui 5 jrnc ti13 dcr c lda timedat push b call bcdbin pop b add c ;[2.6m-.2]+K add b ;+D srlr b srlr b ; [D/4] add b ;+[D/4] mov c,a lda timecnt ;century call bcdbin mov b,a slar b ; 2*C srlr a ;; srlr a ; [C/4] add c ;+[C/4] sub b ;-2*C mov c,a jp ti14 neg ti14: mvi b,0 ti15: inr b sui 7 jrz ti16 jrnc ti15 bit 7,c jrnz ti16 dcr b ti16: mov a,b add a add b ;*3 add a add b ;*7 bit 7,c jrz ti17 neg ti17: mov b,a mov a,c sub b inr a sta timeday mvi a,clrcnt ; out rtcadr ; mvi a,00000011b ;reset fractional seconds out rtcdta ;we now have one second to set time mvi d,numrtc lxi h,time lxi b,rtcadr+(rtcsec shl 8) ti18: outp b ;select reg inr b mov a,m out rtcdta inx h dcr d jrnz ti18 ret setyear$1: mov m,a ;set last-month dcx h dcx h mov a,m adi 1 daa mov m,a jrnc sy0 inx h mov a,m adi 1 daa mov m,a dcx h sy0: mvi d,3 ;3 registers to update lxi b,rtcadr+(rtcyrs shl 8) jr ti18 bcdbin: mov b,a ani 00001111b mov c,a mov a,b ani 11110000b rrc mov b,a rrc rrc add b add c ret binbcd: sui 100 jrnc binbcd adi 100 mvi c,0 bb0: sui 10 inr c jrnc bb0 adi 10 dcr c slar c slar c slar c slar c ora c ret mondays: db 31,28,31,30,31,30,31,31,30,31,30,31 time: timesec: db 0 timemin: db 0 timehrs: db 0 timeday: db 0 timedat: db 0 timemon: db 0 db 0 ;thousandths of seconds, 4 bits only timeyrs: db 0 timecnt: db 0 lstmnth: db 0 numrtc equ $-time getdrv: lxi h,@dtbl ! ret @dtbl: dw dnull,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 dnull: dw 0,0,0,0,0,0,0,0,0,@dircb,@dtacb,0 db 0 seldsk: mov a,c ! sta @adrv ; save drive select code lxi h,@lptbl mvi b,0 ! dad b ; create index from drive code mov a,m cpi 255 jrz selerr sta @pdrv mov c,a mov b,e ;save login flag thru "search" routine call search jrc selerr sta @rdrv shld curmdl push b ;save login bit lxi d,14 dad d ;point to dphtbl mov e,m ;DE=dphtbl inx h mov d,m inx h mov c,m ;BC=modtbl inx h mov b,m lda @rdrv add a add a add a ;*8 mov l,a mvi h,0 dad b ;select mode bytes shld @cmode ;set current mode pointer pop b ;get login bit back. bit 0,b ;test for initial select. jrnz notlgi xchg ;DE=modes mov c,a mvi b,0 dad b ;+*8 dad b ;+*16 dad b ;+*24 lda @rdrv mov c,a dad b ;+*1 = +*25 shld @dph call setup$dph jrc selerr xra a sta @rcnfg mvi a,3 call calmod ;call module's "login" routine. ora a ;see if an error occured. jrnz selerr lda @rcnfg ora a cnz setup$dph jrc selerr lda @adrv add a mov c,a mvi b,0 lxi h,@dtbl dad b lded @dph mov m,e ;set current DPH in @dtbl inx h mov m,d jr selcom ;DE=dph selerr: lxi h,0 ret notlgi: lda @adrv add a mov c,a mvi b,0 lxi h,@dtbl dad b mov e,m ;get current DPH from @dtbl inx h mov d,m ;DE=dph sded @dph selcom: lhld @cmode lxi b,0 ; bit 7,m ;Tracks-per-side not valid for Hard disks. jrnz selxit inx h ; ; bit 1,m ;unless its Z17... ; ; jrz sc0 ; ; mvi b,4 ;then side 1 has 4 less tracks (8 on DT) sc0: mvi a,40 ;assume 5" ST inx h bit 7,m ;check 5" drive jrz sc1 mvi a,77 ;8" drives have 77 tracks sc1: mov c,a ;set side 0 tracks sub b mov b,a inx h ;fix for HT bug bit 5,m ;check for DT jrz selxit slar b ;multiply # of tracks by 2 if DT slar c ; selxit: sbcd @tps lded @dph lxi h,+12 dad d ;point to DPB entry mov c,m inx h mov b,m push b ;save DPB ldax b ;sectors-per-track, byte value lxi h,+15 dad b mov b,m ;psh inr b gh2: dcr b jz gh3 srlr a jr gh2 gh3: sta @pspt ;physical sectors per track lxi h,+22 ; HASH dad d mov a,m inx h ora m jnz ghz ; already have HASH pop b push b lxi h,+7 ; DRM dad b mov a,m inx h mov h,m mov l,a inx h ; HL = num dir ent dad h dad h ; for Kaypro there should always be enough space... mov c,l mov b,h ; BC = size of HASH needed lhld hleft ora a dsbc b jrc nohash shld hleft lhld hlast push h dad b shld hlast pop b ; HASH alloc'd for this drive gh0: lxi h,+22 dad d ;point to hash address mov m,c ;set hash buffer address for this drive. inx h mov m,b inx h mvi m,hbnk ;set hash bank also. ghz: xchg ;put DPH in (HL) for BDOS mov e,m inx h mov d,m ;DE=sectrn dcx h pop b ;BC=dpb ret nohash: lxi b,0ffffh jr gh0 setup$dph: ora a ;reset [CY] lhld @cmode ;HL=modes bit 7,m ;check for hard-disk drive (modes not standard) rnz call ?getdp stc rnz lhld @dph ;restore dph mov m,c ;set XLAT table inx h mov m,b lxi b,12-1 dad b ;point to dpb mov c,m ;get DPB addr inx h mov h,m ;(HL=dpb) mov l,c xchg lxi b,17 ldir ora a ;reset [CY] ret home: lxi b,0 ; same as set track zero settrk: sbcd trk ret setsec: sbcd sect ret setdma: sbcd @dma lda @cbnk ; default DMA bank is current bank setbnk: sta @dbnk ret sectrn: mov l,c ! mov h,b mov a,d ! ora e ! rz xchg ! dad b ! mov l,m ! mvi h,0 dcx h ;sectors numbered 0 - (n-1) ret read: mvi e,6 ;read entry is +6 jmp rw$common ; use common code write: mvi e,9 ;write entry is +9 rw$common: ;do any track/sector/side conversion... xra a sta @side lhld trk shld @trk lhld sect shld @sect lhld @cmode bit 7,m ;floppy or hard-disk? jrnz rw0 inx h inx h inx h bit 6,m ;DS jrz rw0 mov a,m ani 01110b ;DSALG lxi h,dstbl mov c,a mvi b,0 dad b mov c,m inx h mov h,m mov l,c call icall rw0: mov a,e calmod: lhld curmdl jmp addjmp ; leap to driver ;; 0 1 2 3 4 5 6 7 dstbl: dw wrap,alt1,cont1,cont2,alt2,dsret,dsret,dsret cont2: lda @pspt ;as done by Gnat srlr a ;SPT must be EVEN mov c,a lxi h,@sect mov a,m sub c ;don't change the sector number on side 1 rc mov c,a ;save for cont1 jr side1 cont1: call cont2 rc mov m,c ret ;side1 already set alt1: lxi h,@trk rarr m mvi a,0 ral jr sside alt2: call alt1 ;Kaypro ora a ;side 0? rz ;yes, done. lxi h,@sect ;for KAYPRO, sectors on side 1 lda @pspt ;are numbered PSPT+1 to PSPT*2. add m ; mov m,a ret wrap: lbcd @tps ;B=tracks on side 1, C=tracks on side 0 lda @trk ;(for all except Z17, B=C) cmp c rc neg add c add b dcr a sta @trk side1: mvi a,1 sside: sta @side dsret: ret multio: sta @cnt ! ret flush: xra a ! ret ; return with no error @side: ds 1 ; current side of media (floppy only) @trk: ds 2 ; current track number @sect: ds 2 ; current sector number @cnt: db 0 ; record count for multisector transfer @dbnk: db 0 ; bank for disk DMA operations @pspt: ds 1 @tps: ds 2 @rcnfg: ds 1 trk: ds 2 sect: ds 2 @dtacb: dw dtacb1 @dircb: dw dircb1 dircb1: db 0ffh ;drive db 0,0,0,0,0 dw 0,0,2100h ;directly after CCP image (max 8K CCP) db 0 dw dircb2 dircb2: db 0ffh ;drive db 0,0,0,0,0 dw 0,0,2500h db 0 dw dircb3 dircb3: db 0ffh ;drive db 0,0,0,0,0 dw 0,0,2900h db 0 dw dircb4 dircb4: db 0ffh ;drive db 0,0,0,0,0 dw 0,0,2d00h ;dir buffers: 2100-3100 db 0 dw 0000 ;end of DIR buffers dtacb1: db 0ffh ;drive db 0,0,0,0,0 dw 0,0,3100h db 0 dw dtacb2 dtacb2: db 0ffh ;drive db 0,0,0,0,0 dw 0,0,3500h db 0 dw dtacb3 dtacb3: db 0ffh ;drive db 0,0,0,0,0 dw 0,0,3900h db 0 dw dtacb4 dtacb4: db 0ffh ;drive db 0,0,0,0,0 dw 0,0,3d00h ;data buffers: 3100-4100 db 0 dw 0000 ;end of data buffers @scrbf dw 4100h ;scratch buffer 4100-4500 ; Max. system space: 4500h to "bnktop", 38K if 8K common. end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееvers equ '0c' ; December 21, 1985 15:57 drm "CENTR.ASM" ;******************************************************** ; Centronics Printer module for the KAYPRO * ; Copyright (C) 1985 Douglas Miller * ;******************************************************** maclib Z80 false equ 0 true equ not false dev0 equ 206 ndev equ 1 port equ 018h ;parallel printer port sysctl equ 014h ;status/ctrl bits extrn @ctbl,@vect cseg ;common memory, other parts in banked. dw thread db dev0,ndev jmp init jmp nullst jmp nullin jmp outst jmp output dw strcnt dw tblcnt dw modcnt strcnt: db 'KAYPRO ',0,'Parallel Printer ',0,'v3.10' dw vers db '$' modcnt: db 00000000b,00000000b,10000000b,port thread equ $ dseg ;banked memory. tblcnt: ;initial value only, copied by BIOS to its table. db 'LPT ',00000010b,0 ;Output, no baud, no protocal init: ret nullin: mvi a,1ah ret output: outp0: call outst jrz outp0 ; wait for not busy mov a,c out port ; send data di in sysctl ani 10110111b out sysctl ori 00001000b out sysctl ei ret outst: in sysctl xri 01000000b ani 01000000b rz nullst: ori true ret ; return true if ready end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; System Control Block definitions public @civec,@covec,@aivec,@aovec,@lovec public @mxtpa,@ermde,@date,@hour,@min,@sec scb equ 0fb9ch @civec equ scb+22h @covec equ scb+24h @aivec equ scb+26h @aovec equ scb+28h @lovec equ scb+2ah @ermde equ scb+4bh @date equ scb+58h @hour equ scb+5ah @min equ scb+5bh @sec equ scb+5ch @mxtpa equ scb+62h end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее maclib z80 numeric equ 1 ; Numeric Keypad codes standard equ 0 ; 81-292a ROM codes ; else: return raw code from keyboard ; TODO: use commandline options to select keypad codes org 0100h lxi sp,stack ; TODO: check for CP/M 3? mvi c,201 ; keyboard device call search jc nokbd ; double check sanity ora a jnz nokbd ; TODO: more sanity checks? ; HL -> jmp init lxi d,5*3+4 dada d mov e,m inx h mov d,m ; DE = modes table lxi h,4 dad d ; HL = keycnv xchg lxi h,keypad lxi b,kplen ldir jmp cpm search: lhld cpm+1 lxi d,31*3 dad d pchl bs eq 8 lf equ 10 vt equ 11 ff equ 12 cr equ 13 keypad: if numeric ; Number Pad conversion db 0, '0', '.', 0, 0 db '1', '2', '3', cr, 0 db '4', '5', '6', ',', 0 db 0, '7', '8', '9', '-' db 0, vt, lf, bs, ff else if standard ; As returned by ROM 81-292a db 0, 084h, 091h, 0, 0 db 085h, 086h, 087h, 090h, 0 db 088h, 089h, 08ah, 08fh, 0 db 0, 08bh, 08ch, 08dh, 08eh db 0, 080h, 081h, 082h, 083h else ; "neutral" - same as raw code from keyboard db 0, 0b1h, 0b2h, 0, 0 db 0c0h, 0c1h, 0c2h, 0c3h, 0 db 0d0h, 0d1h, 0d2h, 0d3h, 0 db 0, 0e1h, 0e2h, 0e3h, 0e4h db 0, 0f1h, 0f2h, 0f3h, 0f4h endif endif kplen equ $-keypad ds 64 stack: ds 0 end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; PUTSYS for WD1002 with ST412, CP/M 2.2u and "Universal" ROM series 2.0 ; DO NOT USE for older ROM! (maybe it will work...) ; TODO: check ROM and abort... bdos equ 5 ; BDOS functions msgout equ 9 org 00100h start: mvi c,msgout lxi d,signon call bdos lda sysimg cpi 018h ; JR opcode jnz error lda sysimg+1 cpi 0feh ; "JR $" operand jnz error lhld nrec lxi d,003ch ora a dsbc d jnc error call setcks lhld nrec lxi d,3 dad d srlr h rarr l srlr h rarr l ; /4 128->512 blocks inx h ; +1 for boot params sector shld nsec call home lxi h,0 xra a shld track sta sector lxi h,sysimg mvi a,0 trk0: shld bufptr sta sector push psw call write lda nsec dcr a sta nsec jrz done lhld bufptr lxi d,512 dad d pop psw inr a jr trk0 ; finish track done: ret setcks: lxi h,sysimg lxi d,0 lxi b,510 setck0: mov a,e add m mov e,a mod a,d aci 0 mov d,a inx h dcx b mov a,b ora c jrnz setck0 xchg shld cksum ret write: call setlba call wrsec rz mvi c,msgout lxi d,l016dh ; write fault call bdos die: jmp die l016dh: db 13,10,'DISK WRITE FAULT',13,10,'$' setlba: lda track mvi c,a call setcyl lda sector mvi c,a call setsec ret home: call setsdh mvi a,011h ; RESTORE out 087h call getbsy xra a out 084h out 085h mvi a,070h ; SEEK out 087h getbsy: in 087h bit 7,a jrnz getbsy ret setcyl: lhld track ; track srlr h rarr l mvi a,l out 084h mvi a,h out 085h ret setsec: mvi a,c out 083h ; sector ret setsdh: in 014h ani 11111101b ; RESET ori 000h out 014h lda track ; head (track LSB) ani 001h ori 0a8h out 086h ; SDH ret wrsec: call setsdh in 084h out 084h lxi b,0080h ; '00' for 256, '80' for data port lhld bufptr mvi a,030h ; WRITE out 087h otir otir call getbsy ani 001h ret signon: db 13,10,'PUTSYS VER 2.0u',13,10,'$' track: dw 0 sector: dw 0 bufptr: dw 0 nsec: dw 0 org 0900h ; This is where MOVCPM, SYSGEN, etc. ; leave the system image. sysimg: ds 2 ; "JR $" ccp: ds 2 entry: ds 2 nrec: ds 2 ds 502 ; cksum: ds 2 ; end of 512-byte sector ; rest of system image follows... end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее@CHK MACRO ?DD ;; USED FOR CHECKING RANGE OF 8-BIT DISP.S IF (?DD GT 7FH) AND (?DD LT 0FF80H) 'DISPLACEMENT RANGE ERROR - Z80 LIB' ENDIF ENDM @CHKR MACRO ?NN,?DD @CHK ?DD DB ?NN,?DD ENDM LDX MACRO ?R,?D @CHK ?D DB 0DDH,?R*8+46H,?D ENDM LDY MACRO ?R,?D @CHK ?D DB 0FDH,?R*8+46H,?D ENDM STX MACRO ?R,?D @CHK ?D DB 0DDH,70H+?R,?D ENDM STY MACRO ?R,?D @CHK ?D DB 0FDH,70H+?R,?D ENDM MVIX MACRO ?N,?D @CHK ?D DB 0DDH,36H,?D,?N ENDM MVIY MACRO ?N,?D @CHK ?D DB 0FDH,36H,?D,?N ENDM LDAI MACRO DB 0EDH,57H ENDM LDAR MACRO DB 0EDH,5FH ENDM STAI MACRO DB 0EDH,47H ENDM STAR MACRO DB 0EDH,4FH ENDM LXIX MACRO ?NNNN DB 0DDH,21H DW ?NNNN ENDM LXIY MACRO ?NNNN DB 0FDH,21H DW ?NNNN ENDM LDED MACRO ?NNNN DB 0EDH,5BH DW ?NNNN ENDM LBCD MACRO ?NNNN DB 0EDH,4BH DW ?NNNN ENDM LSPD MACRO ?NNNN DB 0EDH,07BH DW ?NNNN ENDM LIXD MACRO ?NNNN DB 0DDH,2AH DW ?NNNN ENDM LIYD MACRO ?NNNN DB 0FDH,2AH DW ?NNNN ENDM SBCD MACRO ?NNNN DB 0EDH,43H DW ?NNNN ENDM SDED MACRO ?NNNN DB 0EDH,53H DW ?NNNN ENDM SSPD MACRO ?NNNN DB 0EDH,73H DW ?NNNN ENDM SIXD MACRO ?NNNN DB 0DDH,22H DW ?NNNN ENDM SIYD MACRO ?NNNN DB 0FDH,22H DW ?NNNN ENDM SPIX MACRO DB 0DDH,0F9H ENDM SPIY MACRO DB 0FDH,0F9H ENDM PUSHIX MACRO DB 0DDH,0E5H ENDM PUSHIY MACRO DB 0FDH,0E5H ENDM POPIX MACRO DB 0DDH,0E1H ENDM POPIY MACRO DB 0FDH,0E1H ENDM EXAF MACRO DB 08H ENDM EXX MACRO DB 0D9H ENDM XTIX MACRO DB 0DDH,0E3H ENDM XTIY MACRO DB 0FDH,0E3H ENDM LDI MACRO DB 0EDH,0A0H ENDM LDIR MACRO DB 0EDH,0B0H ENDM LDD MACRO DB 0EDH,0A8H ENDM LDDR MACRO DB 0EDH,0B8H ENDM CCI MACRO DB 0EDH,0A1H ENDM CCIR MACRO DB 0EDH,0B1H ENDM CCD MACRO DB 0EDH,0A9H ENDM CCDR MACRO DB 0EDH,0B9H ENDM ADDX MACRO ?D @CHK ?D DB 0DDH,86H,?D ENDM ADDY MACRO ?D @CHK ?D DB 0FDH,86H,?D ENDM ADCX MACRO ?D @CHK ?D DB 0DDH,8EH,?D ENDM ADCY MACRO ?D @CHK ?D DB 0FDH,8EH,?D ENDM SUBX MACRO ?D @CHK ?D DB 0DDH,96H,?D ENDM SUBY MACRO ?D @CHK ?D DB 0FDH,96H,?D ENDM SBBX MACRO ?D @CHK ?D DB 0DDH,9EH,?D ENDM SBBY MACRO ?D @CHK ?D DB 0FDH,9EH,?D ENDM ANAX MACRO ?D @CHK ?D DB 0DDH,0A6H,?D ENDM ANAY MACRO ?D @CHK ?D DB 0FDH,0A6H,?D ENDM XRAX MACRO ?D @CHK ?D DB 0DDH,0AEH,?D ENDM XRAY MACRO ?D @CHK ?D DB 0FDH,0AEH,?D ENDM ORAX MACRO ?D @CHK ?D DB 0DDH,0B6H,?D ENDM ORAY MACRO ?D @CHK ?D DB 0FDH,0B6H,?D ENDM CMPX MACRO ?D @CHK ?D DB 0DDH,0BEH,?D ENDM CMPY MACRO ?D @CHK ?D DB 0FDH,0BEH,?D ENDM INRX MACRO ?D @CHK ?D DB 0DDH,34H,?D ENDM INRY MACRO ?D @CHK ?D DB 0FDH,34H,?D ENDM DCRX MACRO ?D @CHK ?D DB 0DDH,035H,?D ENDM DCRY MACRO ?D @CHK ?D DB 0FDH,35H,?D ENDM NEG MACRO DB 0EDH,44H ENDM IM0 MACRO DB 0EDH,46H ENDM IM1 MACRO DB 0EDH,56H ENDM IM2 MACRO DB 0EDH,5EH ENDM BC EQU 0 DE EQU 2 HL EQU 4 IX EQU 4 IY EQU 4 DADC MACRO ?R DB 0EDH,?R*8+4AH ENDM DSBC MACRO ?R DB 0EDH,?R*8+42H ENDM DADX MACRO ?R DB 0DDH,?R*8+09H ENDM DADY MACRO ?R DB 0FDH,?R*8+09H ENDM INXIX MACRO DB 0DDH,23H ENDM INXIY MACRO DB 0FDH,23H ENDM DCXIX MACRO DB 0DDH,2BH ENDM DCXIY MACRO DB 0FDH,2BH ENDM BIT MACRO ?N,?R DB 0CBH,?N*8+?R+40H ENDM SETB MACRO ?N,?R DB 0CBH,?N*8+?R+0C0H ENDM RES MACRO ?N,?R DB 0CBH,?N*8+?R+80H ENDM BITX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+46H ENDM BITY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+46H ENDM SETX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+0C6H ENDM SETY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+0C6H ENDM RESX MACRO ?N,?D @CHK ?D DB 0DDH,0CBH,?D,?N*8+86H ENDM RESY MACRO ?N,?D @CHK ?D DB 0FDH,0CBH,?D,?N*8+86H ENDM JR MACRO ?N @CHKR 18H,?N-$-1 ENDM JRC MACRO ?N @CHKR 38H,?N-$-1 ENDM JRNC MACRO ?N @CHKR 30H,?N-$-1 ENDM JRZ MACRO ?N @CHKR 28H,?N-$-1 ENDM JRNZ MACRO ?N @CHKR 20H,?N-$-1 ENDM DJNZ MACRO ?N @CHKR 10H,?N-$-1 ENDM PCIX MACRO DB 0DDH,0E9H ENDM PCIY MACRO DB 0FDH,0E9H ENDM RETI MACRO DB 0EDH,4DH ENDM RETN MACRO DB 0EDH,45H ENDM INP MACRO ?R DB 0EDH,?R*8+40H ENDM OUTP MACRO ?R DB 0EDH,?R*8+41H ENDM INI MACRO DB 0EDH,0A2H ENDM INIR MACRO DB 0EDH,0B2H ENDM IND MACRO DB 0EDH,0AAH ENDM INDR MACRO DB 0EDH,0BAH ENDM OUTI MACRO DB 0EDH,0A3H ENDM OUTIR MACRO DB 0EDH,0B3H ENDM OUTD MACRO DB 0EDH,0ABH ENDM OUTDR MACRO DB 0EDH,0BBH ENDM RLCR MACRO ?R DB 0CBH,00H+?R ENDM RLCX MACRO ?D @CHK ?D DB 0DDH,0CBH,?D,06H ENDM RLCY MACRO ?D @CHK ?D DB 0FDH,0CBH,?D,06H ENDM RALR MACRO ?R DB 0CBH,10H+?R ENDM RALX MACRO ?D @CHK ?D DB 0DDH,0CBH,?D,16H ENDM RALY MACRO ?D @CHK ?D DB 0FDH,0CBH,?D,16H ENDM RRCR MACRO ?R DB 0CBH,08H+?R ENDM RRCX MACRO ?D @CHK ?D DB 0DDH,0CBH,?D,0EH ENDM RRCY MACRO ?D @CHK ?D DB 0FDH,0CBH,?D,0EH ENDM RARR MACRO ?R DB 0CBH,18H+?R ENDM RARX MACRO ?D @CHK ?D DB 0DDH,0CBH,?D,1EH ENDM RARY MACRO ?D @CHK ?D DB 0FDH,0CBH,?D,1EH ENDM SLAR MACRO ?R DB 0CBH,20H+?R ENDM SLAX MACRO ?D @CHK ?D DB 0DDH,0CBH,?D,26H ENDM SLAY MACRO ?D @CHK ?D DB 0FDH,0CBH,?D,26H ENDM SRAR MACRO ?R DB 0CBH,28H+?R ENDM SRAX MACRO ?D @CHK ?D DB 0DDH,0CBH,?D,2EH ENDM SRAY MACRO ?D @CHK ?D DB 0FDH,0CBH,?D,2EH ENDM SRLR MACRO ?R DB 0CBH,38H+?R ENDM SRLX MACRO ?D @CHK ?D DB 0DDH,0CBH,?D,3EH ENDM SRLY MACRO ?D @CHK ?D DB 0FDH,0CBH,?D,3EH ENDM RLD MACRO DB 0EDH,6FH ENDM RRD MACRO DB 0EDH,67H ENDM ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееvers equ '0c' ; March 6, 2017 17:26 drm "FDC3KP.ASM" ;********************************************************* ; Floppy Disk I/O module for CP/M 3.1 on KAYPRO ; Copyright (c) 1986 Douglas Miller ;********************************************************* MACLIB Z80 extrn @dph,@rdrv,@side,@trk,@sect,@dma,@dbnk,@dstat extrn @dtacb,@dircb,@scrbf,@rcnfg,@cmode extrn ?bnksl,?timot,?getdp false equ 0 true equ not false ; Ports and Constants fdc equ 010h ;floppy disk controller sysctl equ 014h ;floppy disk control bits ********************************************************* ** FDC (WD1793-02 Floppy Disk Controller) ********************************************************* FDCSTAT equ FDC+0 FDCCOMD equ FDC+0 FDCTRK equ FDC+1 FDCSEC equ FDC+2 FDCDATA equ FDC+3 dev0 equ 33 ; first drive in system ndev equ 3 ; # of drives is system LABLEN EQU 19H ; LENGTH OF Z37 DISK LABEL LABEL EQU 04H ; POSITION OF LABEL IN SECTOR 0 LABHTH EQU 05H ; START OF "HEATH EXTENSION" IN SECTOR 0 MODE2S EQU 00000001H ; DOUBLE SIDED LABDPB EQU 0DH ; START OF DPB IN SECTOR 0 LABVER EQU 00 ; LABEL VERSION NUMBER DPEH37 EQU 60H ; I.D. ;--------- Start of Code-producing Source -------------- cseg ;put only whats necessary in common memory... dw thread db dev0,ndev jmp init jmp login jmp read$fdc jmp write$fdc dw string dw dphtbl,modtbl string: DB 'KAYPRO ',0,'Floppy Disk Controller ',0,'3.10' dw vers db '$' modtbl: DB 00000000b,00000001b,01010000B,01011000B ; drive 33 kaypro,DS,ST,5" db 10000000b,00000000b,11110000b,00000000b DB 00000000b,00000001b,01010000B,01011000B ; drive 34 kaypro,DS,ST,5" db 10000000b,00000000b,11110000b,00000000b DB 00000000b,00000001b,01010000B,01011000B ; drive 35 kaypro,DS,ST,5" db 10000000b,00000000b,11110000b,00000000b motor$off: db 0 ;must be directly after MODTBL motoff: lda motor$off cpi true rz in sysctl ani 10101111b out sysctl mvi a,true sta motor$off ret dpb0: ds 17 ;disks may have labels. dpb1: ds 17 ; dpb2: ds 17 ; savNMI: ds 1 savSTK: ds 2 ds 8 rwSTK: ds 0 type$II$ext: lda @dbnk call ?bnksl lxi h,0066h mov a,m mvi m,(RET) sta savNMI lhld @dma mov a,e mov e,c mvi c,fdcdata di out fdccomd ret ;jump to appropriate routine rd4: hlt rd42: INI ; or OUTI jnz rd4 rd3: hlt rd32: INI ; or OUTI jnz rd3 rd2: hlt rd22: INI ; or OUTI jnz rd2 rd1: hlt rd12: INI ; or OUTI jnz rd1 ei hlt rd0: in fdcstat rrc jrc rd0 rlc ana d push psw mvi a,11010000b ;reset 1797 to TYPE$I status out fdccomd ; in fdcstat ; lda savNMI sta 0066h mvi a,0 call ?bnksl pop psw lspd savSTK ret thread equ $ ;must be last statement in "cseg" dseg ;put most everything in banked memory... dphtbl: dw 0,0,0,0,0,0,dpb0,csv0,alv0,@dircb,@dtacb,0 ;hash buffers db 0 ;(hash buffer bank number) ;are allocated dw 0,0,0,0,0,0,dpb1,csv1,alv1,@dircb,@dtacb,0 ;by main BIOS db 0 ;during LOGIN. dw 0,0,0,0,0,0,dpb2,csv2,alv2,@dircb,@dtacb,0 db 0 csv0: ds (256)/4 ;max dir entries: 256 csv1: ds (256)/4 csv2: ds (256)/4 alv0: ds (400)/4 ;max dsk blocks: 400 alv1: ds (400)/4 alv2: ds (400)/4 init: IN fdcstat ; CLEAR WD-1793 from power-on (or whatever) push psw jmp setmot ; set timeout in case no more activity ; RET login: pushix ;save IX lixd @cmode inxix inxix sixd cmode ;save cmode+2 for faster access to modes xra a sta selerr ; NO SELECT ERROR (YET) bitx 7,+1 ; SHOULD WE READ TRACK 0 SECTOR 0 ? cnz physel bitx 7,+0 ; IS IT A 5.25" DISK ? jrnz login1 lda selerr ora a ; was there a select error cz physel3 ; CHECK FOR HALF TRACK: must update DPB. login1: popix lda selerr ;return error code, error during configuration. ora a ret physel: lxi h,0 ; shld @trk ; TRACK 0 shld @sect ; SECTOR 0 lhld @scrbf ;use BIOS scratch buffer to read Z37 label. shld @dma ;we must also make sure that bank 0 is selected. xra a sta @dbnk ;set disk bank=0 (the bank we're in now) sta @side ;side=0 STA MODFLG ; RESET CHANGED MODE FLAG mvi a,true ; flag a select operation sta selop MVI A,5 ; 5 RETRYS FOR A SELECT OPERATION STA RETRYS CALL READ ; TRY READING LABEL AT DENSITY ; CURRENTLY INDICATED IN TABLES JZ PHYSEL1 ; BR IF SUCCESSFUL bitx 7,+0 jnz physel6 ; if 8" error out MVI A,5 ; RESET RETRYS TO 5 STA RETRYS STA MODFLG ; SET CHANGED MODE FLAG ; IX=mode bytes ldx a,+1 ; TRY OTHER DENSITY XRI 00010000b stx a,+1 CALL READ ; TRY TO READ LABEL jrz physel1 ldx a,+1 xri 00010000b ; return mode bytes to former state stx a,+1 jmp physel6 ; jmp to error PHYSEL1:XRA A ; ZERO ACCUM. MVI B,LABLEN ; GET LENGTH OF LABEL lhld @scrbf LXI d,LABEL dad d CHKLAB1:ADD M INX H DJNZ CHKLAB1 INR A JRZ PHYSEL2 ; BR IF CORRECT CHECKSUM LDA MODFLG ORA A ; MODE BEEN CHANGED ? jz physel7 ; NO KEEPING OLD MODE BYTES ldx a,+1 xri 00010000b ; return mode bytes to former state stx a,+1 jmp physel6 ; jmp to error ; ; EXTRACT MODE INFORMATION FROM LABEL ; physel2: lhld @scrbf lxi d,LABHTH dad d ; HL POINTS TO HEATH EXTENSION IN LABEL ldx b,-1 ; keep old format ldx c,-2 mvix 0,-1 mvix 0,-2 mov a,m ani 111$00000b cpi 001$00000b ; z100 formats jrnz nf1 setx 5,-1; ; set mode byte jr setmode nf1: cpi 011$00000b ; z37 jrnz nf2 bit 2,m ; check for extended density jrz gf1 setx 4,-1 ; z37x jr setmode gf1: liyd @scrbf ; get cpm sectors per physical sector ldy a,+labhth+2 cpi 4 ; see if 512 byte sectors - if so set to z100 jrnz gf0 ; this is in here because the Z100 puts the setx 5,-1 ; device type code in the label on 5" jr setmode gf0: setx 3,-1 ; z37 jr setmode ;; currently no 8" support in this module nf2: ; cpi 100$00000b ; z47 ; jrnz nf3 ; bit 2,m ; check for extended density ; jrz gf2 ; setx 6,-1 ; z47x ; jr setmode ;gf2: setx 5,-1 ; jr setmode nf3: ; cpi 110$00000b ; z67 ; jrz f1 ; keep old mode if device type not valid stx b,-1 stx c,-2 jmp physel7 ;f1: setx 7,-1 ; z67 setmode: mov a,m ; get flag byte bit 3,a ; track density bit jrz gs0 setx 5,+0 ; set drive and media to dt setx 5,+1 jr gs2 gs0: resx 5,+0 resx 5,+1 gs2: bit 1,a ; density bit jrz gs1 setx 4,+1 jr gs3 gs1: resx 4,+1 gs3: bit 0,a ; sides bit jrz gs4 setx 6,+1 jr gs6 gs4: resx 6,+1 gs6: lhld @cmode call ?getdp ; setup mode bytes jnz physel6 ; error if format doesnt exists liyd @dph ; set dpb addr in dph sty c,+0 ; store XLAT address in DPH sty b,+1 ldy l,+12 ; get DPB address in DPH ldy h,+13 xchg lhld @scrbf lxi b,labdpb dad b lxi b,15 ldir ; move dpb xchg ; hl points to psh byte (15) liyd @scrbf ldy a,+labhth+2 mov b,a ; save CP/M sectors per physical sector mvi c,0 pshlp srlr a ; rolate LSB into [cy] jc psh1 inr c jr pshlp psh1 mov m,c ; set PSH byte inx h ; mode pointer to PSM dcr b mov m,b ; put in dpb JR PHYSEL7 PHYSEL6:MVI A,1 STA SELERR ; FLAG A SELECT ERROR PHYSEL7: call done ; setup motor turn-off lxi h,selop mvi m,false ; SELECT OPERATION IS OVER ret PHYSEL3: CALL SELECT JRC PHYSEL6 ; ERROR IF NOT READY CALL HOME ;RESTORE HEAD TO TRACK 0 JRC PHYSEL6 MVI B,01001000B ;STEP IN, NO UPDATE CALL TYPE$I CALL TYPE$I ;STEP IN TWICE call read$addr ; READ ADDRESS lda @dstat ANI 00011000B SHL 1 ;check for FDC error. JRNZ PHYSEL6 in fdcsec ;track number, from read-addr CPI 2 JRZ PHYSEL4 CPI 1 JRNZ PHYSEL6 lhld cmode setb 5,m ;make drive "DT" inx h bit 5,m ;test for 40 track already jz physel4 res 5,m ;make disk "ST" and reconfigure mvi a,0ffh sta @rcnfg ;set "re-configure" flag so BIOS will get new DPB/XLAT PHYSEL4: CALL HOME JRC PHYSEL6 JR PHYSEL7 setup$rw: MVI A,21 ; 21 RETRYS FOR A READ/WRITE OPERATION STA RETRYS lhld @cmode inx h inx h shld cmode ret read$fdc: call setup$rw READ: CALL ACCESS$R ; START DRIVE AND STEP TO PROPER TRACK JRC ERROR lxi d,10011111$10001000B ; status mask + read command JR TYPE$II error: xra a ; [NZ] to indicate error inr a done: push psw lda selop ora a jrnz retrn mvi a,false ;motor off false sta motor$off setmot: lxi d,motoff mvi c,15 ;15 seconds mvi b,dev0 ;I.D. call ?timot retrn: pop psw ret write$fdc: call setup$rw WRITE: LHLD CMODE ; CHECK FOR HALF TRACK R/O bit 5,m ;see if drive is DT. jrz ht0 inx h bit 5,m ;see if media is not DT. jrz ERROR ; R/O ERROR ht0: CALL ACCESS$R ; ACCESS DRIVE FOR WRITE JRC ERROR in fdcstat sta @dstat ; save DISK STATUS BYTE ani 01000000b ; WRITE PROTECT BIT jrnz ERROR ; WRITE PROTECT ERROR lxi d,11111111$10101000B ; status mask + write command TYPE$II: lhld cmode inx h mov a,m ani 1 ;sector offset lxi h,@sect ; GET SECTOR NUMBER add m ;others use sectors 1-n OUT fdcsec ; give to controller RETRY: PUSH d ; save registers CALL TYPE$II$COM ; execute disk transfer routine. STA @dstat ; save status of transfer XRA A ; CLEAR CARRY FOR DSBC lded @dma DSBC D ; HL NOW CONTAINS # OF BYTES TRANSFERRED LDA @dstat ; check for successful transfer ANI 11111111B ; WP is 0 for any read command. JRNZ IOERR ; RETRY IF ERROR LDA SELOP ; IS THIS A SELECT OPERATION ? ORA A jrnz POPRET ; THEN DON'T CHECK SECTOR SIZE LDA BLCODE ; CHECK IF CORRECT NUMBER OF BYTES TRANSFERRED CPI 3 JRNZ NOTED ; BLCODE=3 => 1024 BYTE SECTOR EXPECTED INR A ; INCREMENT BECAUSE (H) FOR 1024 IS 4 NOTED: CMP H ; COMPARE TO EXPECTED SIZE POPRET: POP d mvi a,0 ;signal "no error" to BDOS. jrz done ; RETURN IF CORRECT JR TRYAGN ; RETRY IF INCORRECT IOERR: POP B JM ERROR ; ERROR IF NO READY SIGNAL TRYAGN: LXI H,RETRYS ; decrement retry count DCR M JZ ERROR ; NO MORE RETRIES MOV A,M CPI 10 JNC RETRY ; LESS THAN TEN RETRYS LEFT => STEP HEAD LDA SELOP ORA A jnz RETRY ; DO NOT STEP HEAD IF SELECT OPERATION PUSH d ; SAVE REGISTERS CALL STEPIN ; STEP IN COMMAND CALL SEEK ; SEEK WILL REPOSITION HEAD POP d JMP RETRY ; TRY AGAIN rtbl: db 128 ;128 bytes dw rd1 db 0 ;256 bytes dw rd1 db 0 ;512 bytes dw rd2 db 0 ;1024 bytes dw rd4 type$II$com: ;command in E mov a,e ani 00100000b ; 1 if write rlc! rlc! rlc ; 0000000w ori 0a2h ;A2/A3 for INI/OUTI sta rd12+1 sta rd22+1 sta rd32+1 sta rd42+1 call setside sspd savSTK ; lxi sp,rwSTK ; lda blcode mov c,a add a ; *2 add c ; *3 lxi h,rtbl mov c,a mvi b,0 dad b mov b,m inx h mov c,m inx h mov h,m mov l,c push h jmp type$II$ext SELECT: mvi c,0 mvi b,dev0 call ?timot ;clear any pending "motor off" LDA @rdrv ; get the RELATIVE drive number MOV C,A ; relative drive number in (C) (rel. to driv0) lhld cmode INX H ; POINT TO MODE BYTE 2 inr a ; 1,2,3,4 cma ; 111111xx ani 00000011b ; 2,1,0,3 bit 4,m ;single density ? jrnz se1 ori 00100000b ;select single density data rate. se1: ori 00010000b ;motor on, also mov e,a di in sysctl ; ani 10011100b ora e ; out sysctl ; ei dcx h MOV A,M ANI 00001100B ; setup steprate bits for seek-restore commands rrc rrc STA STEPRA ; RATE FOR SUBSEQUENT SEEK/RESTORE LXI H,LOGDSK ; save position (track) of current drive MOV E,M ; in 'trks' array addressed by contents of MOV M,C ; location 'logdsk'. MVI B,0 MOV D,B LXI H,TRKS DAD D IN fdctrk MOV M,A ; SAVE CURRENT TRACK # LXI H,TRKS ; identify position (track) of requested drive DAD B ; from 'trks' array addressed by new 'logdsk'. MOV A,M OUT fdctrk ; set track number mov a,c sub e ;same drive as last time? sui 1 ! sbb a ;.true. if same drive cma di lxi h,motor$off ;if diff. drive, must check ready. ora m ;if same but motor off, must check ready. mvi m,true ;this prevents the motor from being turned off sta mtflg ; test drive for ready. cma ! ora a ;[NC] jrnz fb3 ;[NZ] if motor still on. ; mvi a,11010000b out fdccomd in fdcstat mvi b,10 ;must be ready within 10 rev. fb1: call find$NE lxi d,IP$count fb2: in fdcstat ani 00000010b jrnz got$IP dcx d mov a,e ora d jrnz fb2 djnz fb1 stc fb3: ei ret IP$count equ 17250 ; 200mS +10%, timed to "fb2" loop got$IP: xra a ei ret find$NE: in fdcstat ani 00000010b mov c,a mvi h,4 ;wait even longer... (3.67 sec) fb00: lxi d,0 ;wait a long time for any edge fb01: in fdcstat ani 00000010b cmp c jrnz got$edge dcx d mov a,e ora d jrnz fb01 dcr h jrnz fb00 pop d ;discard address from "fb1" loop stc ei ret got$edge ora a rz mov c,a ;if not NE, go find another jr fb00 ACCESS$R: lhld @dph lxi d,12 dad d mvi a,15 ;PSH add m mov e,a inx h mvi a,0 adc m mov d,a ldax d sta blcode ;get physical sector size lhld cmode mov c,m ; mode byte 2 inx h mov a,m ; mode byte 3 cma ; get "NOT MDT... ana c ; ... AND DDT" ani 00100000b ; flag is in bit 5 sta htflag ; half track flag CALL SELECT rc SEEK: lda @trk ora a ;see if we're on physical track 0 jrnz xf0 lhld cmode lda @side ora a ;see which side we're on. jrnz xf1 bit 0,m ;check TRK-0,SID-0 density bit. jrz xf0 xra a sta blcode ;select 128 bytes/sector di in sysctl ani 10111111b ori 00100000b ;select SD media out sysctl ei jr xf0 xf1: bit 1,m ;check TRK-0,SID-1 format (may be 256 bytes/sector) jrz xf0 mvi a,1 sta blcode ;select 256 bytes/sector ;leave DD as is. xf0: LXI H,SEKERR ; initialize seek error counters MVI M,4 ; 4 ERRORS ON SEEK IS FATAL INX H MVI M,10 ; RESTORE once, then 9 errors are fatal call setside lda @trk mov c,a RETRS: MOV A,C ; get track number back ORA A ; FORCES "RESTORE" IF "seek to track 0" jz HOME ;RESTORE HEAD TO TRACK 0 lda htflag mov h,a ; get half-track flag in h IN fdctrk ;CURRENT HEAD POSITION, SUB C ;SEE HOW FAR WE WANT TO GO. RZ ;IF ZERO TRACKS TO STEP, WERE FINISHED MVI B,01111000B ;ASSUME STEP-OUT + UPDATE + HEADLOAD JRNC STOUT ;ASSUMPTION WAS CORRECT... MVI B,01011000B ;ELSE MUST BE STEP-IN NEG ;AND NUMBER OF TRACKS WOULD BE NEGATIVE STOUT: MOV L,A ;COUNTER FOR STEPING SEEK5: BIT 5,H ; CHECK FOR 48 TPI DISK IN 96 TPI DRIVE JRZ NOTHT RES 4,B ;SELECT NO-UPDATE CALL TYPE$I ;STEP HEAD ANI 00000100B SHL 1 ;DID THIS STEP PUT US AT TRACK 0 ? JRNZ TRK0ERR SETB 4,B ;SELECT UPDATE TO TRACK-REG notht: CALL TYPE$I ;STEP HEAD ANI 00000100B SHL 1 ;DID THIS STEP PUT US AT TRACK 0 ? JRNZ TRK0ERR DCR L JRNZ SEEK5 IN fdcsec ;SAVE CURRENT SECTOR NUMBER MOV L,A CALL READ$ADDR ; GET ACTUAL TRACK UNDER HEAD (IN SECTOR REG) in fdcsec ;GET TRACK NUMBER FROM MEDIA MOV H,A MOV A,L OUT fdcsec ;RESTORE SECTOR NUMBER LDA @dstat ;GET TRUE ERROR STATUS OF READ-ADDRESS RLC RC ;DRIVE NOT READY ANI 00011000B SHL 1 ; CRC ERROR + REC-NOT-FOUND MOV A,H ; ACTUAL TRACK FROM READ-ADDRESS LXI H,SEKERR ;POINT TO ERROR COUNTERS JRNZ RESTR0 CMP C ; (C) MUST STILL BE VALID DEST. TRACK RZ ;NO ERRORS RTS00: DCR M ; SHOULD WE KEEP TRYING ? STC RZ ;NO, WE'VE TRYED TOO MUCH OUT fdctrk ; re-define head position accordingly JR RETRS ; RETRY SEEK TRK0ERR: XRA A LXI H,SEKERR JR RTS00 RESTR0: INX H ; RESTORE ERROR COUNT DCR M STC RZ ; If count 0, return with Carry set. MOV A,M CPI 9 JRNC RESTR1 ; RESTORE ONLY FIRST TIME CALL STEPIN ; OTHERWISE STEP HEAD IN 1 TRACK JR RETRS RESTR1: ; RESTORE HEAD TO TRACK 0 MVI A,00000011B STA STEPRA ; RETRY WITH MAXIMUM STEP RATE CALL HOME JR RETRS ; RETRY SEEK STEPIN: lda htflag ora a ; CHECK HALF TRACK mode MVI B,01001000B ; STEP IN WITHOUT UPDATE CNZ TYPE$I ; STEP A SECOND TIME (W/O UPDATE) FOR HALF-TRK MVI B,01011000B ; STEP IN AND UPDATE TRACK REGISTER JR TYPE$I HOME: ;POSITION HEAD AT TRACK ZERO... mvi a,11010000b ;force TYPE$I status out fdccomd in fdcstat ANI 00000100B ;TEST TRACK ZERO SENSOR, JRNZ @TRK0 ;SKIP ROUTINE IF WE'RE ALREADY AT TRACK 0. IN fdctrk ;DOES THE SYSTEM THINK WE'RE AT TRACK 0 ?? ORA A JRNZ HOME1 ;IF IT DOESN'T, ITS PROBEBLY ALRIGHT TO GIVE "RESTORE" MVI L,6 ;(6 TRKS) ;ELSE WE COULD BE IN "NEGATIVE TRACKS" SO... MVI B,01001000B ;WE MUST STEP-IN A FEW TRACKS, LOOKING FOR THE HOME0: CALL TYPE$I ;TRACK ZERO SIGNAL. ANI 00000100B SHL 1 ;"SHL 1" BECAUSE TYPE$I DOES AN "RLC" JRNZ @TRK0 DCR L JRNZ HOME0 HOME1: MVI B,00001000B ;RESTORE COMMAND, WITH HEADLOAD CALL TYPE$I XRI 00000100B SHL 1 ;TEST TRACK-0 SIGNAL RAR RAR RAR RAR ;[CY] = 1 IF NOT AT TRACK 0 @TRK0: MVI A,0 OUT fdctrk ;MAKE SURE EVERYONE KNOWS WERE AT TRACK 0 RET ; READ$ADDR: mvi a,11000100B ; READ-ADDRESS COMMAND WITH SETTLE DELAY jr PUT$I TYPE$I: LDA STEPRA ; STEP-RATE BITS ORA B ; MERGE COMMAND PUT$I: OUT fdccomd ; SEND command TO CONTROLLER WB: IN fdcstat ; WAIT FOR BUSY SIGNAL RAR ; TO COME UP JRNC WB WNB: IN fdcstat ; poll controller for function-complete RAR ; Busy? JRC WNB ; wait until not busy. RAL STA @dstat ;SAVE TYPE II (III) STATUS FOR ERROR DETECTION. MVI A,11010000B ;TERMINATE COMMAND (RESET STATUS TO TYPE 1) OUT fdccomd IN fdcdata ; in fdcstat ; rlc ret setside: lda @side xri 00000001b rlc ! rlc mov c,a di in sysctl ani 10111011b ora c out sysctl ei ret STEPRA DB 0 ; STEP RATE CODE RETRYS DB 0 SEKERR DB 0,0 ; SEEK,RESTORE ERROR COUNTS CMODE DW 0 ; POINTER TO MODE BYTE LOGDSK DB 2 ; CURRENT DRIVE SELECTED BY THIS MODULE BLCODE DB 0 SELERR: DB 0 SELOP: DB false MODFLG: DB 0 TRKS: DB 255,255,0 htflag: db 0 mtflg: db 0 END ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее public @lptbl cseg @lptbl: db 50, 51, 33,255 db 255,255,255,255 db 255,255,255,255 db 255,255,255,255 end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееvers equ '0e' ; December 23, 1985 21:38 drm "SERIAL.ASM" ;******************************************************** ; Z80-SIO I/O module for CP/M plus on the KAYPRO * ; Copyright (C) 1985 Douglas Miller * ;******************************************************** maclib Z80 false equ 0 true equ not false dbase equ 200 ;base for all char I/O devices dev0 equ 002 ;first device, rel. to base ndev equ 3 sio1 equ 004h ;z80-sio/0 sio2 equ 00ch ;another sio dce equ sio2+0 ;auxiliary printer dte equ sio1+0 ;terminal equip. modem equ sio2+1 ;modem cseg ;common memory, other parts in banked. dw thread db dbase+dev0,ndev jmp intsio jmp instsio jmp inputsio jmp outstsio jmp outputsio dw strsio dw tblsio dw modsio strsio: db 'KAYPRO ',0,'Z80-SIO handler ',0,'v3.10' dw vers db '$' ; 7=DTR, 6=, 5=CTS, 4=sync 3=DCD : 2=, 1=RTS, 0= modsio: db 00100000b,10100010b,00110100b,dce db 00101000b,10101010b,00110100b,dte db 00101000b,10101010b,00110100b,modem thread equ $ dseg ;banked memory. tblsio: ;initial values only, copied by BIOS to its table. db 'DCE ',00001111b,14 ;I/O, soft-baud, no protocal, 9600 db 'DTE ',00001111b,14 ;I/O, soft-baud, no protocal, 9600 db 'MODEM ',00001011b,6 ;I/O, hard-baud, no protocal, 300 ; all serial vector: mov a,b ;device number sui dev0 add a add a ;*4 mov c,a add a ;*8 mov e,a mvi b,0 mov d,b lxi h,tblsio+6 dad d xchg lxi h,modsio+3 dad b ret intsio: call vector dcx h is1: bit 7,m rnz push d mov a,m ani 00110000b ; bits per char rlc ; -bb----- mov e,a ; Tx image setb 3,e ; Tx Enable rlc ; bb------ ori 00000001b ; Rx Enable mov d,a ; Rx image mov a,m ani 00001111b ori 01000000b ; 16x clock mov b,a ; WR4 image dcx h mov a,m ; ani 10000010b ; DTR, RTS ora e mov e,a ; Tx control, with RTS/DTR inx h inx h mov c,m inr c inr c mvi a,4 outp a outp b ; WR4 inr a outp a outp e ; WR5 mvi a,3 outp a outp d ; WR3 ; init baud rate mov c,m res 2,c ; baud rate port pop h bit 2,m ; soft baud? rz mov a,m ; 0; 1,2,3..15 ora a rz cpi 10 ; 1,2,3..15 jrnc is0 dcr a ; 0,1,2,3,4,5,6,7,8,10,11,12,13,14,15 is0: outp a ret inputsio: inp0: call instsio jrz inp0 ; wait for character ready mov c,m inp a ; get data ani 7Fh ; mask parity ret instsio: call vector ins0: mov c,m inr c inr c xra a outp a inp a ; read from status port ani 1 ; isolate RxRdy rz ; return with zero ori true ret outputsio: mov a,c push psw outp0: call outstsio jrz outp0 ; wait for TxEmpty, HL->port pop psw mov c,m outp a ; send data ret outstsio: call vector os0: mov c,m dcx h dcx h inr c inr c mvi a,00010000b ;reset ext/status change outp a inp a xra m dcx h ; ana m ; [ZR] = ready ani 00111000b jrnz nrdy inp a ani 04h ; test xmit holding register empty rz ; ori true ret ; return true if ready nrdy: xra a ret ;speed$table: ; DTE,DCE ;0 db 00h ;no baud rate ;1 db 0 ;50 ;2 db 1 ;75 ;3 db 2 ;110 ;4 db 3 ;134.5 ;5 db 4 ;150 ;6 db 5 ;300 ;7 db 6 ;600 ;8 db 7 ;1200 ;9 db 8 ;1800 ;10 db 10 ;2400 ;11 db 11 ;3600 ;12 db 12 ;4800 ;13 db 13 ;7200 ;14 db 14 ;9600 ;15 db 15 ;19200 end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееvers equ '0c' ; March 10, 2017 17:18 drm "WIN3KP.ASM" ;********************************************************* ; Winchester Disk I/O module for CP/M 3.1 on KAYPRO ; Copyright (c) 2017 Douglas Miller ;********************************************************* MACLIB Z80 extrn @dph,@rdrv,@side,@trk,@sect,@dma,@dbnk,@dstat extrn @dtacb,@dircb,@scrbf,@rcnfg,@cmode extrn ?bnksl,?timot,?getdp false equ 0 true equ not false ; Ports and Constants sysctl equ 014h ;winchester disk control bits dev0 equ 50 ; first drive in system ndev equ 2 ; # of drives is system ; ********************************************************* ; * * ; * D a t a D e f i n i t i o n s * ; * * ; ********************************************************* ; windta equ 80h ;1002 data port winpcmp equ 81h ;1002 precomp port winerr equ 81h ;1002 error port winsc equ 82h ;1002 sector count port winsec equ 83h ;1002 sector number port winlsb equ 84h ;1002 lsb of cylinder port winmsb equ 85h ;1002 msb of cylinder port winsdh equ 86h ;1002 size/drive/head port winstat equ 87h ;1002 status port wincmd equ 87h ;1002 command port ; rstcmd equ 10h ;1002 restore command seekcmd equ 70h ;1002 seek command rdcmd equ 20h ;1002 read command wrcmd equ 30h ;1002 write command ; wincfg equ 10100000b ;ecc and sector size bits nosel equ 10111000b ;winchester de-select ; TODO: abstract all this to allow other drive types ; ST412 drive parameters (as used by Kaypro): ncyl equ 306 ; total number of cylinders lcyl equ ncyl-1 ; last cylinder number pcmpcyl equ ncyl/2 ;starting precomp cylinder number nhed equ 4 nsec equ 17 zsec equ 512 fsec equ zsec/128 ;--------- Start of Code-producing Source -------------- cseg ;put only whats necessary in common memory... dw thread db dev0,ndev jmp init$win jmp login$win jmp read$win jmp write$win dw string dw dphtbl,modtbl string: DB 'KAYPRO ',0,'Winchester Disk Interface ',0,'3.10' dw vers db '$' winlun equ 00001000b ; Kaypro convention winpt0 equ 00000000b winpt1 equ 00000010b winpt2 equ 00000100b winpt3 equ 00000110b ; Both partitions use cyls 0-305, but different heads. ; head = (PTN << 1) + (track & 1) ; track >>= 1 modtbl: ; -PTN cfg-byte-template ---not-used-------- DB 10000000b,wincfg+winlun+winpt0,00000000B,00000000B db 11111111b,11111111b,11111111b,11111111b DB 10000001b,wincfg+winlun+winpt1,00000000B,00000000B db 11111111b,11111111b,11111111b,11111111b ; currently, both (all) partitions are identical, ; due to head-slice algorithm for partitioning. ; But, Universal ROM pulls DSM from partition info on disk, ; So each could be different... Also, ROM version selects OFF... dpb0: dw nsec*fsec ; SPT db 5,01fh,1 ; BSH,BSM,EXM dw 1125,1023 ; DSM,DRM db 0ffh,000h ; ALV0 dw 08000h,4 ; CKS,OFF db 2,003h ; PSH, PSM dpb1: dw nsec*fsec ; SPT db 5,01fh,1 ; BSH,BSM,EXM dw 1125,1023 ; DSM,DRM db 0ffh,000h ; ALV0 dw 08000h,4 ; CKS,OFF db 2,003h ; PSH, PSM ; Controller is already done by now win$rw: lda cmdbuf ani 010h mvi a,0b2h ; inir jrz nread mvi a,0b3h ; outir nread: sta here+1 lda @dbnk call ?bnksl lhld @dma lxi b,windta mvi e,2 here: inir dcr e jrnz here xra a call ?bnksl ret offline db 0 ; fatal error prevents use cmdbuf db 0 romid db 0 thread equ $ dseg ; HASH/HBANK is set by main bios... dphtbl: dw 0,0,0,0,0,0,dpb0,0,alv0,@dircb,@dtacb,0 db 0 ; HBANK dw 0,0,0,0,0,0,dpb1,0,alv1,@dircb,@dtacb,0 db 0 ; HBANK alv0: ds 512 ; really only need about 283 alv1: ds 512 ; ptnoff equ 302 ; offset in sector of ptn tbl partns: d0dsm: dw 0 d0cyl: dw 0 d1dsm: dw 0 d1cyl: dw 0 partnz equ $-partns ptnend equ zsec-ptnoff-partnz curptn: dw 0 ; cyl offset of current partition ; driver init init$win: xra a sta offline lda 0050h ; gift from loader: ROM id sta romid ; TODO: move to login code, for each LUN... call winrest ; TODO: Universal ROM uses track xlat (spares) table... ; For virtual hardware it should not matter. ; But, partition info is also stored there. Need that now. lda romid cpi 'U' rnz ; done if not Universal ROM lxi h,2 ; new OFF shld dpb0+13 shld dpb1+13 lda modtbl+1 ; spares must be on "drive 0" out winsdh call winrdy jz disable xra a out winlsb out winmsb ; Cyl 0 inr a out winsc ; 1 sector mvi a,nsec-1 out winsec ; last sector on track mvi a,rdcmd out wincmd call winbusy jz disable ; TODO: checksum verification... ; surgically read partition info from buffer... lxi b,ptnoff initw0: in windta dcx b mov a,b ora c jrnz initw0 mvi b,partnz mvi c,windta lxi h,partns inir mvi b,ptnend ; rest of sector initw1: in windta dcr b jrnz initw1 lhld d0dsm shld dpb0+5 lhld d1dsm shld dpb1+5 ret login$win: lda offline ora a rnz ; This should prevent read/write from ; ever being called ; TODO: check init flag (per LUN, not partition) ; and call winrest (anything else?). ; Could always select LUN and test READY. lda romid cpi 'U' mvi a,0 rnz lhld @cmode mov a,m ani 00000011b ; ptn add a add a ; 4 bytes per drive inr a inr a ; +2 for cyl offset mov e,a mvi d,0 lxi h,partns dad d mov a,m inx h mov h,m mov l,a shld curptn ; cyl offset of current partition xra a ret setup$win: lhld @cmode inx h mov b,m ; SDH template eSSDDHH- lda @trk ani 1 ora b ; eSSDDHHH out winsdh call winrdy rz ; timeout mvi a,pcmpcyl out winpcmp ; This is horrible, but since 302C ROM does it ; we also must to keep compatible on disk: ; if (trk > 7) trk += 4; ; else if (trk >= 4) trk += (trk - 4); ; For universal ROM: ; if (trk > 1 || ptn > 0) trk += 12; ; All: ; putHd((trk & 1) | (ptn << 1)); ; putCyl(trk >> 1); lhld @trk lda romid cpi '3' jrnz setup2 mov a,l ani 11111000b ora h jrz setup1 lxi d,4 dad d jr setup2 setup1: mov a,l cpi 4 jrc setup2 sui 4 add l ; CARRY not possible mov l,a setup2: srlr h rarr l ; from here on, use cyl lda romid cpi 'U' jrnz setup3 ; probably wrong, but should not have WD1002 ; B is still eSSDDHH- from above lded curptn ; cyl offset dad d mov a,l ora h ; cyl 0 is special case jrnz setup4 mov a,b ani 00000110b jz setup3 ; partition 0 no xlat setup4: lxi d,6 dad d setup3: mov a,l out winlsb mov a,h out winmsb lda @sect out winsec mvi a,1 out winsc ora a ret read$win: mvi a,rdcmd sta cmdbuf call setup$win jrz error ; timeout on READY lda cmdbuf out wincmd call winbusy jrz error ; timeout on BUSY in winstat bit 0,a jrnz error ; ERROR set bit 3,a jrz error ; no DRQ ; no more errors from here on... call win$rw ; xfer from common memory... xra a ret write$win: mvi a,wrcmd sta cmdbuf call setup$win jrz error ; timeout on READY lda cmdbuf out wincmd lxi d,0 mvi h,3 write1: in winstat bit 3,a ; DRQ jrnz write2 call timer jrnz write1 ; timeout - no failure here? we'll get error from winbusy? write2: call win$rw ; xfer from common memory... call winbusy jrz error in winstat bit 0,a ; ERROR jrnz error xra a ret error: ; possible retry... ; possible recovery - step, restore, etc. xra a inr a ret ; ; WD 1002 interface routines. ; ; Written by: T. Hayes ; ; These routines provide the physical interface between the system ; and the WD 1002 winchester controller. ; winrest: ; ; Reset and restore the winchester disk ; ; On entry: ; B contains the configuration byte of the drive to be accessed ; ; On exit: ; A and B contain the configuration byte altered as follows: ; Bits 2 and 3 will be set if the drive is off line ; or reset if the controller is ready ; ; in sysctl ;first issue a controller reset setb 1,a out sysctl push psw ; mvi h,1 ;hold reset for > 50 ms lxi d,0 winrest1: call timer jrnz winrest1 pop psw ; res 1,a ;select controller (MR off) out sysctl ; mvi h,3 lxi d,6000h winrest11: in winstat ;Check busy bit 7,a ; jrz winrest3 ;go on if not busy call timer ;else count down jrnz winrest11 ; disable: xra a dcr a sta offline ; disable drive... ret ;and return that status to caller winrest3: in winerr ;check for diagnostic errors cpi 1 ;if error jrz winrest31 ;ignore "diagnostic only" errrors ; ana a ;believe all others jrnz disable ;abort if an error shown winrest31: call winpsel ; call winrdy ;ready wait jrnz winrest32 call winrdy ;wait for device ready (again?) jrz disable ;abort if timed out (twice) ; winrest32: mvi a,rstcmd ;issue the restore command out wincmd ; call winbusy ;wait for not busy jrz disable ;abort if timed out ; in winstat ;get device status ; bit 0,a ;if there was an error jrnz disable ;abort winrest6: xra a sta offline ret ;return that status to caller ; winpsel: ; ; WD 1002 physical select routine ; ; for now, assume "drive 0" has valid LUN ; lda modtbl+1 ; fully-formed SDH byte from "drive 0" ; out winsdh ;and issue the select ret ;return to caller timer: ; ; General down counter routine ; ; On entry: ; HDE are a 24 bit counter ; On exit: ; The counter will have been decremented ; zero is set if the counter is done ; zero is reset if the counter is not at 000000h ; ; Typical timings are 25 t states in the loop with an additional ; overhead of 29 t states in the calling routine. This assumes ; that the calling routine is using a call xxx and jr nz,xxxx. ; This gives a time of 13.5 usec for each iteration of the loop. ; Times when de goes 0 will be marginally longer but should not ; be significant. ; dcx d mov a,d ora e rnz dcr h ret ; TODO: make use of this somehow... winoff: ; ; If the 1002 is not at 305, seek track ; 305 then select physical unit 3. It is assumed that ; the host buffer has been flushed. ; in winlsb ;see if the drive is at 305 already cpi high lcyl jrnz winoff1 in winmsb cpi low lcyl jrz winoff2 winoff1: ; mvi a,high lcyl out winmsb mvi a,low lcyl out winlsb ; mvi a,seekcmd ;now issue a seek to that cylinder out wincmd ; ret ;return to caller winoff2: mvi a,nosel ;now deselect the drive out winsdh ; ret ;and return to caller winrdy: ; ; Wait for device ready ; mvi h,5 lxi d,0 winrdy1: in winstat ;check for ready bit 6,a rnz ;return if it is ; call timer ;else count down rz ;return if timed out jr winrdy1 ;else try again ; ; winbusy: ; ; Wait for device not busy ; mvi h,7 ;set up dead man counter lxi d,0 winbusy1: in winstat ;get status cma bit 7,a ;if not busy rnz ;return call timer ;else count down rz ;and return if timed out jr winbusy1 ; end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; NETWORK DISK OPERATING SYSTEM FOR CP/NET on CP/M Plus v3 ; ; 1982.12.31. exact date unknown ; 2016.05.20. adapted for RSX on CP/M Plus ; Dropped support for remote console/list, due to BIOS intercept issues. ; BIOS intercept is a problem because of the transient nature of RSXs. ; Could add back support for "well-behaved" LIST OUTPUT users, ; provided BIOS intercept is not required. ; ;TITLE NETWORK DISK OPERATING SYSTEM FOR CP/NET SLAVE maclib z80 extrn NTWKIN, NTWKST, CNFTBL, SNDMSG, RCVMSG, NTWKBT, CFGTBL ; ; ; EQUATIONS OF DATA ; LF EQU 0AH ;LINE FEED CR EQU 0DH ;CARRIAGE RETURN EOF EQU 1AH ;CTRL-Z IS END OF FILE LEOF EQU 0ffh ;-1 is logical end of file ; TOP equ 0000h CDISK equ 0004h BDOS equ 0005h SYSDMA equ 0080h TPA equ 0100h SCTLNG equ 128 ;ONE SECTOR LENGTH ; ; EQUATIONS OF DOS FUNCTION ; CCNDIN EQU 3 ;CONSOLE INPUT WITH DEVICE CODE CCNDOT EQU 4 ;CONSOLE OUTPUT WITH DEVICE CODE CBUFPR EQU 9 ;BUFFER PRINT CRDBUF EQU 10 ;READ BUFFER CCONST EQU 11 ;GET CONSOLE STATUS CGETVR EQU 12 ;GET VERSION NUMBER CRSDSK EQU 13 ;RESET DISK COPEN EQU 15 ;OPEN FILE CCLOSE EQU 16 ;CLOSE FILE CSRFST EQU 17 ;SEARCH FIRST CSRNXT EQU 18 ;SEARCH NEXT DIRECTORY CREAD EQU 20 ;READ SEQ CWRITE EQU 21 ;WRITE SEQ CSTDMA EQU 26 ;SET DMA ADDRESS CGTALL EQU 27 ;get alloc vector addr CGTDPB EQU 31 ;get DPB addr CSTUSC EQU 32 ;SET USER CODE CRREAD EQU 33 ;READ SEQ CRWRIT EQU 34 ;WRITE SEQ CRSDSN EQU 37 ;RESET DISK BY DISK VERCTOR CFRSP equ 46 ; get disk free space scbf equ 49 ; get/set SCB CBIOS equ 50 ; direct BIOS call COVLY equ 59 ; load overlay CRSX equ 60 ; call RSX function CDEFPW EQU 106 ;set default password CLSBLK equ 112 ; List Block - does not fit in table... CBMAX EQU 50 ;MAX OF BDOS FUNCTION - CXMIN.. collapsed here CXMIN EQU 98 ;extended bdos functions base - collapse into CBMAX ; CNMIN EQU 64 ;MIN OF NDOS FUNCTION CLOGIN EQU 64 ;LOGIN CLOGOF EQU 65 ;LOGOFF CNMAX EQU 72 ;MAX OF NDOS FUNCTION ; ; SLAVE CONFIGRATION TABLE ; ; -1 NETWORK STATUS ; 0 SLAVE PROCESSOR ID ; 1-32 A - P DISK DEVICE CODE ; 33-34 CONSOLE DEVICE ; 35-36 LIST DEVICE ; 37 LIST BUFFER COUNTER ; 38-42 MESSAGE HEADER FOR LIST OUT ; 43 LISTER DEVICE NUMBER ; 44-171 LIST OUT DATA BUFFER ; ; EACH DEVICE DATA USED 2 BYTES ; IN 1-36 ; 1B:BIT 7 H ON NETWORK ; BIT 6 H SET UP IN DISK ; BIT 0-3 DEVICE NUMBER IN MASTER ; 2B:MASTER ID ; ; BIAS TO DATA IN CONFIGRATION TABLE ; BSRID equ 1 ;client ID BSDSKS equ 2 ;first byte in disk table BSDSKE equ 33 ;last byte in disk table BSCONS EQU 34 ;BIAS TO CONSOLE DATA BSLIST EQU 36 ;BIAS TO LISTER DATA FCBRR0 equ 33 ; offset of RR0 field in FCB (not FCB in MSG) scbase equ 09ch ; base address of SCB within page org 0 ; RSX Prefix serial: db 0,0,0,0,0,0 start: jmp COLDST next: jmp 0 prev: dw 0 remove: db 0 ; 0ffh for remove nonbank: db 0 rsxnam: db 'NDOS3 ' loader: db 0,0,0 db 'COPYRIGHT (C) 1980-82, DIGITAL RESEARCH ' db 0,0,0,0,0,0 NDERRM: db CR,LF,'NDOS Err $' NDERR2: db ', Func $' BDOSE: dw 0 CURSID: db 0 scbadr: dw 0 MSGTOP: db 0 MSGID: db 0 db 0 ; We assume network hw/sw sets this. MSGFUN: db 0 MSGSIZ: db 0 MSGDAT: ds 256 db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h db 0c7h,0c7h,0c7h,0c7h,0c7h,0c7h STACK: ds 0 USTACK: dw 0 FUNCOD: db 0 PARAMT: dw 0 RETCOD: db 0 MCRPNT: dw 0 LSTUNT: db 0 F5SETF: db 0 FNTMPF: db 0 ORGBIO: dw 0 HEXMSG: db 0,0,'$' CLDERR: db 'Init err$' COLDSE: ; BC and DE are pushed... lxi d,CLDERR mvi c,CBUFPR call next lxi h,next shld start+1 ; only until remove takes place... mvi a,0ffh sta remove pop b pop d jmp next ; pass to BDOS and hope for the best... ; Not a true cold start - we are in context of a valid BDOS call... COLDST: push d push b call NTWKIN ora a jnz COLDSE lxi h,NDOSE shld start+1 xra a ; sta remove ; is the required? lxi h,MSGDAT shld MCRPNT ; Apparently, it is passe to use BDOS calls for certain things... lxi d,scbadd mvi c,scbf call next shld scbadr lxi d,CSTUP mvi c,CBUFPR call next pop b pop d jmp next scbadd: db 03ah, 0 BDERMD: lhld scbadr mvi l,scbase+4bh mov a,m ret SYSMSC: lhld scbadr mvi l,scbase+4ah mov a,m ret CURUSR: lhld scbadr mvi l,scbase+44h mov a,m ret ; Some sneaky programs, like ERASE.COM, use the "saved search address" from the SCB. ; so we must put the address there if the BDOS does not (i.e. networked drive). SETSRA: lhld PARAMT xchg lhld scbadr mvi l,scbase+47h mov m,e inx h mov m,d ret SETDSK: lhld scbadr mvi l,scbase+3eh lda PARAMT mov m,a ret CURDSK: lhld scbadr mvi l,scbase+3eh mov a,m ret DMAADD: lhld scbadr mvi l,scbase+3ch mov a,m inx h mov h,m mov l,a ret CSTUP: DB 'NDOS3 Started.',CR,LF,'$' CSTDN: DB 'NDOS3 Ending.',CR,LF,'$' ;wbmsg: DB 'NDOS3 Warm-boot.',CR,LF,'$' NDOSE: mov a,c ; must save REAL function code! sta FUNCOD sta MSGFUN ora a jz WARMST cpi COVLY jz LDOVLY ; LOAD OVERLAY (RSX SCRUB) - indication of warm boot cpi CRSX jz CALRSX ; used to unload CP/Net cpi CBIOS jz next ; DIRECT BIOS CALL - might need to trap for LIST OUT lxi h,FUNTBS NDOSE1: mov a,c sub m jc next inx h cmp m inx h jc NDOSE2 inx h inx h mov a,m ora a jnz NDOSE1 jmp next NDOSE2: sspd USTACK lxi sp,STACK mov c,a ; modified func code! mov a,m inx h mov h,m mov l,a ; HL = func table push h xchg shld PARAMT call DMAADD shld DMAADR ; cache DMA address for this call... lxi h,MSGSIZ mvi m,0 ; assume 1-byte payload inx h shld MCRPNT ; MSGDAT xra a mov b,a mov d,a pop h ; specific func table in HL dad b mov e,m ; don't need HL anymore sub e ; assumes A=0 jz tnextp ; code 0 = not handled by CP/Net NDOSE4: lxi h,NDENDR push h lxi h,FUNTB2 dad d push h NDOSE5: pop b ldax b mov d,a ani 07fh ; strip off EOP bit mov e,a mov a,d mvi d,0 lxi h,FUNTB3 dad d mov e,m inx h mov d,m inx b ral jc NDOSE6 push b lxi h,NDOSE5 push h NDOSE6: xchg pchl FUNTB3: dw 0 ; 0 000h 080h - never called dw SNDHDR ; 2 002h 082h dw RCVPAR ; 4 004h 084h dw SNDFCB ; 6 006h 086h dw CKSFCB ; 8 008h 088h dw RENTMP ; 10 00ah 08ah dw WTDTC2 ; 12 00ch 08ch dw WTDTC8 ; 14 00eh 08eh dw WTDTCP ; 16 010h 090h dw CKSTDK ; 18 012h 092h dw BCSTFN ; 20 014h 094h dw BCSTVC ; 22 016h 096h dw RCVEC ; 24 018h 098h dw GTFCB ; 26 01ah 09ah dw GTFCCR ; 28 01ch 09ch dw GTFCRR ; 30 01eh 09eh dw GTDIRE ; 32 020h 0a0h dw GTOSCT ; 34 022h 0a2h dw GTMISC ; 36 024h 0a4h dw GTLOGV ; 38 026h 0a6h dw LIST1 ; 40 028h 0a8h dw SELDSK ; 42 02ah 0aah dw LSTBLK ; 44 02ch 0ach dw GETVER ; 46 02eh 0aeh dw 0 ; 48 030h 0b0h - to be removed dw RESET ; 50 032h 0b2h dw NWSTAT ; 52 034h 0b4h dw NWCFTB ; 54 036h 0b6h dw SDMSGU ; 56 038h 0b8h dw RVMSGU ; 58 03ah 0bah dw LOGIN ; 60 03ch 0bch dw LOGOFF ; 62 03eh 0beh dw STSF ; 64 040h 0c0h dw STSN ; 66 042h 0c2h dw 0 ; 68 044h 0c4h - to be removed dw CKSTDP ; 046h 0c6h dw CHKMSC ; 048h 0c8h ; hi bit is "end" signal, else keep executing routines in list... ; byte & 07fh is index into FUNTB3, routine to call. FUNTB2: db 080h ; - never called fgtvr equ $-FUNTB2 db 0aeh ; frssy equ $-FUNTB2 db 0b2h ; frsvc equ $-FUNTB2 db 096h ; fsldk equ $-FUNTB2 db 0aah ; fopfi equ $-FUNTB2 db 008h, 00eh, 018h, 09ah ; fdlfi equ $-FUNTB2 db 006h, 098h ; fsrfs equ $-FUNTB2 db 040h, 018h, 0a0h ; fsrnx equ $-FUNTB2 db 042h, 018h, 0a0h ; frdsq equ $-FUNTB2 db 048h, 006h, 018h, 01ch, 0a2h ; READ SEQ fwrsq equ $-FUNTB2 db 048h, 008h, 010h, 018h, 09ch ; WRITE SEQ frefi equ $-FUNTB2 db 008h, 00ah, 002h, 098h ; flgvc equ $-FUNTB2 db 0a6h ; fgtal equ $-FUNTB2 db 012h, 002h, 018h, 0a4h ; fwrpr equ $-FUNTB2 db 012h, 002h, 098h ; fstfi equ $-FUNTB2 db 006h, 018h, 09ch ; frdrr equ $-FUNTB2 db 048h, 006h, 018h, 01eh, 0a2h ; READ RAND fwrrr equ $-FUNTB2 db 048h, 008h, 010h, 018h, 09eh ; WRITE RAND [ZEROFIL] fgtsz equ $-FUNTB2 db 006h, 018h, 09eh ; flkrc equ $-FUNTB2 db 008h, 00ch, 018h, 09eh ; fstpw equ $-FUNTB2 db 094h ; flgin equ $-FUNTB2 db 03ch, 098h ; flgof equ $-FUNTB2 db 03eh, 098h ; fsdnw equ $-FUNTB2 db 0b8h ; frvnw equ $-FUNTB2 db 0bah ; fnwst equ $-FUNTB2 db 0b4h ; fnwcf equ $-FUNTB2 db 0b6h ; fstcp equ $-FUNTB2 ; ***** DUPLICATE of fstpw ***** db 094h ; fsvcf equ $-FUNTB2 db 03eh, 018h, 0a4h ; fgtdl equ $-FUNTB2 db 046h, 098h ; fdkms equ $-FUNTB2 db 046h, 002h, 018h, 0a4h ; flst1 equ $-FUNTB2 db 0a8h flstbk equ $-FUNTB2 db 0ach ; table of message handlers? per BDOS func? ; -1 = ERROR, 0 = PASSTHRU, else index into FUNTB2 FUNTB1: db 0 ; 0 - db 0 ; 1 - db 0 ; 2 - db 0 ; 3 - db 0 ; 4 - db flst1 ; 5 - db 0 ; 6 - db 0 ; 7 - db 0 ; 8 - db 0 ; 9 - db 0 ; 10 - db 0 ; 11 - db fgtvr ; 12 - GET VERSION db frssy ; 13 - RESET DISK SYSTEM db fsldk ; 14 - SELECT DISK db fopfi ; 15 - OPEN FILE db fopfi ; 16 - CLOSE FILE db fsrfs ; 17 - SEARCH FIRST db fsrnx ; 18 - SEARCH NEXT db fdlfi ; 19 - DELETE FILE db frdsq ; 20 - READ SEQUENTIAL db fwrsq ; 21 - WRITE SEQUENTIAL db fopfi ; 22 - MAKE FILE db frefi ; 23 - RENAME FILE db flgvc ; 24 - GET LOGIN VECTOR db 0 ; 25 - GET CURRENT DISK db 0 ; 26 - SET DMA ADDR db fgtal ; 27 - GET ALLOC ADDR db fwrpr ; 28 - WRITE PROTECT DISK db flgvc ; 29 - GET R/O VECTOR db fstfi ; 30 - SET FILE ATTR db fgtal ; 31 - GET DPB ADDR db 0 ; 32 - GET/SET USER CODE db frdrr ; 33 - READ RANDOM db fwrrr ; 34 - WRITE RANDOM db fgtsz ; 35 - GET FILE SIZE db fgtsz ; 36 - SET RAND RECORD db frsvc ; 37 - RESET DRIVE db frsvc ; 38 - ACCESS DRIVE db frsvc ; 39 - FREE DRIVE db fwrrr ; 40 - WRITE RAND ZERO FILL db 0 ; 41 - TEST & WRITE RECORD db flkrc ; 42 - LOCK RECORD db flkrc ; 43 - UNLOCK RECORD db 0 ; 44 - SET MULTISECTOR COUNT db 0 ; 45 - SET BDOS ERR MODE db fdkms ; 46 - GET DISK FREE SPACE db 0 ; 47 - CHAIN TO PROGRAM (***? can't chain to remote program) db fstcp ; 48 - FLUSH BUFFERS db 0 ; 49 - GET/SET SCB ; 50..63 - handled by special case NFTB1 equ $-FUNTB1 ; if any are passed to server, must preserve FUNCOD as real code FUNTBX: db fstcp ; 98 - FREE BLOCKS db fopfi ; 99 - TRUNCATE FILE db 0 ; 100 - SET DIR LABEL ****support?**** db fgtdl ; 101 - GET DIR LABEL BYTE db fgtdl ; 102 - READ FILE DATE-PWD MODE db 0 ; 103 - WRITE FILE XFCB ****support?**** db 0 ; 104 - SET DATE & TIME db 0 ; 105 - GET DATE & TIME - can't support here, use SEND NW MESG db fstpw ; 106 - SET DEF PASSWORD db 0 ; 107 - GET SERIAL NUMBER db 0 ; 108 - GET/SET PGM RET CODE db 0 ; 109 - GET/SET CONS MODE db 0 ; 110 - GET/SET OUT DELIM db 0 ; 111 - PRINT BLOCK db flstbk ; 112 - LIST BLOCK NFTBX equ $-FUNTBX ; CP/Net functions, not known to BDOS FUNTBN: db flgin ; 64 - LOGIN db flgof ; 65 - LOGOFF db fsdnw ; 66 - SEND NW MESG db frvnw ; 67 - RECV NW MESG db fnwst ; 68 - GET NW STATUS db fnwcf ; 69 - GET NW CFG db fstcp ; 70 - SET COMP ATTR db fsvcf ; 71 - GET SERVER CFG NFTBN equ $-FUNTBN FUNTBS: db 0,NFTB1 dw FUNTB1 db CNMIN,NFTBN dw FUNTBN db CXMIN,NFTBX dw FUNTBX dw 0 SNDHDR: lxi h,MSGTOP mvi m,0 ; FMT = CP/Net inx h ; DID (server ID) already set inx h ; SID, our node ID, will be set by SNIOS inx h inx h inx h xchg ; DE = MSGDAT lhld MCRPNT xra a ; negate DE sub e mov c,a mvi a,0 sbb d mov b,a dad b ; HL -= DE mov a,l ora h jz SNDHD1 ; size set already dcx h xchg dcx h mov m,e ; SIZ = length - 1 SNDHD1: lxi b,MSGTOP SDMSGE: call SNDMSG inr a rnz jmp NERROR RVMSGE: call RCVMSG inr a rnz NERROR: lxi h,-1 mov a,h jmp NDEND NDENDR: lda RETCOD NDEND: xchg lhld USTACK sphl xchg mov l,a mov b,h ret RCVPAR: lxi b,MSGTOP call RVMSGE lxi h,MSGDAT shld MCRPNT ret tnextp: ; abandon call to real BDOS lhld USTACK sphl TBDOSP: lhld PARAMT xchg lda FUNCOD mov c,a jmp next CKFCBD: lhld PARAMT mov a,m dcr a jp CKFCB1 call CURDSK CKFCB1: mov e,a mvi d,0 call CHKDSK cpi 0ffh rnz call TBDOSP jmp NDEND CHKDSK: lxi h,CFGTBL+BSDSKS dad d dad d mov a,m ral jc CHKDS1 ; remote disk mvi a,0ffh ret CHKDS1: rar ani 00fh ; remote server disk number inr a mov c,a inx h mov a,m ; remote server node ID sta MSGID ret SNDFCB: call CKSFCB jmp SNDHDR CKSFCB: call CKFCBD ; check FCB disk for local/remote (local does not return) STFCB: call CURUSR lhld MCRPNT mov m,a ; put USR in msg buf inx h mov m,c ; put DSK in msg buf inx h xchg lhld PARAMT inx h xchg mvi b,35 call MCPYTS ; copy FCB to msg buf xra a sta FNTMPF sta F5SETF lhld MCRPNT lxi d,-35 dad d ; point to start of FCB name in msg buf SUBTMP: call CKDOL ; substitute $NN for $$$ at start of name mvi b,0 dad b ; skip rest of 3 chars inx h mov a,m ani 080h ; check f5' attr - partial close/delete XFCBs only inx h jz SUBTM1 mov a,m ani 080h ; check f6' attr - assign passwd/set byte count jnz SUBTM1 dcr a sta F5SETF SUBTM1: lda FNTMPF add a sta FNTMPF inx h inx h inx h CKDOL: mvi c,3 mvi a,'$' CKDOL1: cmp m rnz inx h dcr c jnz CKDOL1 xchg lxi h,FNTMPF inr m dcx d lda CFGTBL+BSRID ; client (slave) ID mov b,a call HEXDIG dcx d mov a,b rar rar rar rar call HEXDIG inx d inx d xchg ret HEXDIG: ani 00fh cpi 10 jnc HEXDG1 adi '0' stax d ret HEXDG1: adi 'A'-10 stax d ret RENTMP: lhld MCRPNT lxi d,-19 dad d jmp SUBTMP MCPYTS: ldax d mov m,a inx h inx d dcr b jnz MCPYTS shld MCRPNT ret WTDTC2: mvi b,2 jmp WTDTCS WTDTC8: mvi b,8 jmp WTDTCS WTDTCP: mvi b,SCTLNG WTDTCS: lhld DMAADR xchg lhld MCRPNT call MCPYTS jmp SNDHDR CKSTDP: lda PARAMT jmp STDSK0 CKSTDK: call CURDSK STDSK0: mov e,a mvi d,000h call CHKDSK cpi 0ffh jnz STDSK1 call TBDOSP jmp NDEND STDSK1: sta MSGID lhld MCRPNT dcr c mov m,c inx h shld MCRPNT ret ; Handle multi-sector count CHKMSC: call CKFCBD ; does not return if disk is local ; From here on, we know the disk is remote call SYSMSC cpi 1 ; skip multi-sector handling if count == 1 rz ; returns to NDOSE5, goto next opcode. sta CURMSC pop h ; NDOSE5 ret addr shld MSCRET pop h ; FUNTB2 pointer (past CHKMSC) shld MSCTBP lda FUNCOD cpi CRREAD jc CKMSC2 ; save rand rec position lhld PARAMT ; FCB lxi b,FCBRR0 dad b mov e,m inx h mov d,m inx h mov a,m sta SAVRR+2 xchg shld SAVRR jmp CKMSC2 CKMSC0: lda RETCOD ora a jnz CKMSC1 lda CURMSC dcr a sta CURMSC jz CKMSC1 lxi h,MSGDAT shld MCRPNT lhld DMAADR lxi b,128 dad b shld DMAADR lda FUNCOD cpi CRREAD jc CKMSC2 ; advance random record number... lhld PARAMT ; FCB lxi b,FCBRR0 dad b inr m jnz CKMSC2 inx h inr m jnz CKMSC2 inx h inr m CKMSC2: lxi h,CKMSC0 push h lhld MSCTBP push h lhld MSCRET pchl ; jmp NDOSE5 - do next opcode. Returns to CKMSC0 when done. ; done with multi-sec read/write, restore everything. CKMSC1: ; could be EOF, or some physical error lda FUNCOD cpi CRREAD jc CKMSC3 ; restore file position... lda SAVRR+2 lhld SAVRR xchg lhld PARAMT ; FCB lxi b,FCBRR0 dad b mov m,e inx h mov m,d inx h mov m,a ; If the program's next op is random read/write, then we are ; finished now. But, if the next op is sequential then ; we must set the file position back to where it started. ; Use READ RAND to set file position. Response is ignored. mvi a,CRREAD sta MSGFUN lxi h,MSGDAT shld MCRPNT call SNDFCB call RCVPAR ; ignore data/error returned by CRREAD CKMSC3: lda CURMSC ; if error ended us early, need num sec completed. mov e,a ; save where SYSMSC won't destroy it call SYSMSC sub e mov h,a ret ; NDENDR BCSTFN: ; broadcast func (set default password, set compat attrs) lxi d,0 call FORALL mov a,c inr c jz RSTALL ; no (more) servers, reset and return sta MSGID lhld PARAMT xchg lhld MCRPNT lda FUNCOD cpi CDEFPW-CBMAX ; a.k.a. 106 - set def password jz BCST1 ; fn 70 - set compat attr mov m,e jmp BCST2 BCST1: mvi b,8 call MCPYTS BCST2: call SNDHDR call RCVPAR jmp BCSTFN BCSTVC: ; broadcast "drive vector" funcs to all servers lhld PARAMT xchg BCSTV1: call FORALL push h mov a,c inr c jnz BCSTV2 ; some remote drives to do call RSTALL pop d lda FUNCOD cpi CRSDSN ; reset drive rnz ; only reset drive is passed to local mov c,a call next sta RETCOD ret BCSTV2: sta MSGID lxi h,MSGDAT mov m,e inx h mov m,d inx h shld MCRPNT call SNDHDR lda FUNCOD sui 38 ; access drive jz BCSTV3 push psw call RCVPAR pop psw pop d dcr a jz BCSTV1 lda MSGDAT sta RETCOD inr a jz RSTALL jmp BCSTV1 BCSTV3: call RCVEC pop d jmp BCSTV1 ; Returns vector of all disks for given server, ; each call skips servers already reported. FORALL: lxi h,CFGTBL+BSDSKS push d lxi d,0 lxi b,010ffh FORAL1: mov a,m ral jnc FORAL6 ; local ral jc FORAL6 ; "already did" flag inx h mov a,c cpi 0ffh jz FORAL2 cmp m jz FORAL3 dcx h jmp FORAL6 FORAL2: mov c,m FORAL3: dcx h mov a,m ori 040h ; mark this one done... mov m,a xthl call RHLR0 jnc FORAL7 xthl mov a,m ani 00fh inr a push h lxi h,1 FORAL4: dcr a jz FORAL5 dad h jmp FORAL4 FORAL5: mov a,e ora l mov e,a mov a,d ora h mov d,a pop h jmp FORAL8 FORAL6: xthl call RHLR0 jnc FORAL7 mov a,h ori 080h mov h,a FORAL7: xthl FORAL8: inx h inx h dcr b jnz FORAL1 pop h ret RHLR0: ora a mov a,h rar mov h,a mov a,l rar mov l,a ret ; Reset from FORALL RSTALL: lxi h,CFGTBL+BSDSKS mvi b,16 RSTAL1: mov a,m ani 08fh ; clear FORALL iterator flag(s) mov m,a inx h inx h dcr b jnz RSTAL1 ret STSF: ; setup Search First mvi a,0ffh sta CURSID ; assume local lhld PARAMT mov a,m cpi '?' jnz STSF1 call CKSTDK mvi c,'?'+080h ; "drive" code with CP/M3 flag call STFCB jmp STSF2 STSF1: lhld MCRPNT inx h shld MCRPNT call CKSFCB ; if remote, set FCB in msg STSF2: lda MSGID sta CURSID call SETSRA jmp SNDHDR STSN: ; setup Search Next lda CURSID cpi 0ffh ; was Search First a local op? jnz STSN1 call TBDOSP jmp NDEND STSN1: sta MSGID call CURUSR lhld MCRPNT inx h mov m,a inx h shld MCRPNT jmp SNDHDR RCVEC: call RCVPAR lxi h,MSGDAT+1 shld MCRPNT mov d,m ; D = ext err code dcx h mov a,m sta RETCOD dcx h mov a,m ; SIZ dcr a mvi h,0 ; ensure H=0 to avoid confusion with extended errors rnz ; not extended error - skip rest call BDERMD inr a jnz NDERR xchg jmp NDENDR NDERR: push d lxi d,NDERRM call PRMSG pop psw ; A = (D), ext err code push psw ; Fix bug in NDOS.ASM call HEXOUT lxi d,NDERR2 call PRMSG lda FUNCOD call HEXOUT call BDERMD pop h ; H = ext err code cpi 0feh jz NDENDR jmp TOP ; abort program HEXOUT: lxi d,HEXMSG+1 ; do low nibble first push psw call HEXDIG pop psw rar rar rar rar dcx d ; back to hi nibble call HEXDIG PRMSG: mvi c,CBUFPR jmp next GTFCB: lda F5SETF inr a jnz GTFCCR GTFCRR: mvi b,35 ; FCB+CR+RR (-drive) jmp GTFC1 GTFCCR: mvi b,32 ; FCB+CR, not RR GTFC1: call RSTMP ; un-do temp file subst lhld MCRPNT inx h xchg lhld PARAMT inx h call MCPYFS mvi h,0 ; ensure H=0 to avoid confusion with extended errors ret MCPYFS: ldax d mov m,a inx d inx h dcr b jnz MCPYFS xchg shld MCRPNT ret RSTMP: ; restore TMP filename lda FNTMPF rar rar jnc RSTMP1 lhld MCRPNT inx h inx h mvi m,'$' inx h mvi m,'$' RSTMP1: ral rnc lhld MCRPNT lxi d,10 dad d mvi m,'$' inx h mvi m,'$' ret GTDIRE: lda RETCOD inr a mvi h,0 ; ensure H=0 to avoid confusion with extended errors rz lhld MCRPNT ; Special case for CP/M3 full search, although really ; any SEARCH that wants to be fully compatible with CP/M ; neuances - specifically that the DMA buffer contains the ; full directory sector after a search. ; ; CP/Net breaks SEARCH funcs 17/18 by only returning ; one DIRENT at a time, while the local BDOS calls ; actually fill the DMA buffer with the directory sector. ; DIR.COM depends on this for getting timestamps. lda MSGSIZ ora a ; 00 = 1 byte, dir code only, DMA buf implied rz ; NDENDR will return dir code to user cpi 32+4 ; anything 1 < x < 128 really, pick a number (expect 32). jnc STOSC0 ; assume 128 bytes, copy all to DMA buffer. ; single DIRENT returned, copy to correct location. xchg lhld DMAADR lda RETCOD inr a lxi b,32 GTDIR1: dcr a jz GTDIR2 dad b jmp GTDIR1 GTDIR2: mov b,c call MCPYFS ret GTOSCT: lda RETCOD ora a rnz lxi h,MSGDAT+37 STOSC0: xchg lhld DMAADR mvi b,SCTLNG call MCPYFS mvi h,0 ; ensure H=0 to avoid confusion with extended errors ret GTMISC: lhld MCRPNT dcx h ; drop error byte lda FUNCOD cpi CGTALL ; get alloc addr jz GTMSC3 ; for alloc vec, just leave in message buffer xchg cpi CFRSP ; get disk free space jz GTMSC4 cpi CGTDPB ; get DPB addr jnz GTMSC1 ; fn 31 - get DPB lxi h,CURDPB push h mvi b,16 ; should be 15 for CP/M 2.2, 17 for CP/M 3 jmp GTMSC2 GTMSC4: lxi h,0 push h lhld DMAADR mvi b,3 jmp GTMSC2 GTMSC1: ; fn 71 - get server config lxi h,CURSCF push h mvi b,23 GTMSC2: call MCPYFS pop h GTMSC3: mov a,l sta RETCOD ret GTLOGV: lxi d,CFGTBL+BSDSKE lxi h,0 mvi b,16 GTLGV1: ldax d dcx d mov c,a ldax d dcx d dad h call DRVSTS dcr b jnz GTLGV1 mov a,l sta RETCOD ret ; Get a drive's status (i.e. GET LOGIN VECTOR) ; B = local drive num ; A = net cfg byte, bit-7 = remote, bit-0:3 = remote drive num ; Returns DE bit-0 = drive's status DRVSTS: push d push b push h ral jc DRVST1 ; drive is local push b call TBDOSP pop b dcr b xchg jmp DRVST2 DRVST1: ; drive is remote rar ani 00fh mov b,a ; remote drive number mov a,c ; server ID sta MSGID lxi h,MSGDAT shld MCRPNT push b call SNDHDR call RCVPAR pop b lhld MCRPNT mov e,m inx h mov d,m DRVST2: ; DE = vector of active drives mov a,b ora a jz DRVST4 DRVST3: ; get drive 'B' bit to LSB mov a,d rar mov d,a mov a,e rar mov e,a dcr b jnz DRVST3 DRVST4: mvi d,000h mov a,e ani 001h mov e,a pop h dad d pop b pop d ret SELDSK: lda PARAMT mvi d,000h mov e,a call CHKDSK cpi 0ffh ; local disk jz TBDOSP ; let BDOS handle call SETDSK lhld MCRPNT dcr c mov m,c inx h shld MCRPNT call SNDHDR jmp RCVEC RESET: ; anything to do? BDOS will be called... but BDOS does not call 0005 (us)? lxi h,MSGDAT shld MCRPNT ; A: cannot be remote... jmp next LIST1: lxi d,PARAMT lxi b,1 jmp lstbk2 LSTBLK: lhld PARAMT mov e,m inx h mov d,m ; address of data inx h mov c,m inx h mov b,m ; length mov a,c ora b rz lstbk2: lxix CFGTBL+BSLIST bitx 7,+0 jz tnextp lxi h,CFGTBL+BSLIST+9 push d ldx e,+7 mvi d,0 dad d pop d lstbk0: ldax d inx d mov m,a inx h inrx +7 ; dirty == not-zero jm lstbk3 ; send data cpi 0ffh ; stop at 0ffh? or need to continue if more? jz lstbk3 ; this will continue if more chars exist... lstbk1: dcx b mov a,b ora c jnz lstbk0 ret lstbk3: ; must send buffer ldx a,+0 ani 0fh stx a,+8 ; SIZ already len-1, incl LST unit ldx a,+1 ; LST server stx a,+4 ; DID push d push b pushix lxi b,CFGTBL+BSLIST+3 ; MSG buffer call SNDMSG popix pushix mvix 0,+7 ; clear dirty flag, setup for next char inr a jz NERROR lxi b,MSGTOP call RVMSGE popix pop b pop d lxi h,CFGTBL+BSLIST+9 jmp lstbk1 GETVER: lhld scbadr mvi l,scbase+05h mov l,m mvi h,002h mov a,l sta RETCOD ret NWSTAT: call NTWKST sta RETCOD ret NWCFTB: call CNFTBL mov a,l sta RETCOD ret LOGIN: lhld PARAMT mov a,m sta MSGID inx h xchg lhld MCRPNT mvi b,8 call MCPYTS jmp SNDHDR LOGOFF: lda PARAMT sta MSGID jmp SNDHDR SDMSGU: lhld PARAMT mov b,h mov c,l call SNDMSG sta RETCOD ret RVMSGU: lhld PARAMT mov b,h mov c,l call RCVMSG sta RETCOD ret LDERR: mvi a,-1 pop h ret SAVDMA: dw 0 SAVRR: db 0,0,0 MSCRET: dw 0 MSCTBP: dw 0 CURMSC: db 0 DMAADR: dw 0 CURDPB: ds 15 CURSCF: ds 23 ; this is used to do warm boot initialization, since most ; programs do not call BDOS Function 0 but instead just ; JMP 0. The CCP then makes this call, either upon startup ; and/or immediately prior to running a program. ; Perportedly, the CPP calls this with DE=NULL in order ; to scrub RSXs on warm boot. LDOVLY: WARMST: push d push b call NTWKBT ; TODO: any other re-init? reset some context? ; lxi d,wbmsg ; mvi c,CBUFPR ; call next pop b pop d jmp next ; An example of how to process BDOS Func 60 RSX Func 113 ; and remove one's self. CALRSX: mov l,e mov h,d mov a,m inx h cpi 113 ; Check for RSX Func 113 jnz next mov a,m inx h cpi 1 ; Check param count to be sure jnz next push d mov e,m inx h mov d,m lxi h,rsxnam mvi b,8 rsxf0: ; Compare paramter to our name ldax d cmp m jnz rsxf1 inx d inx h dcr b jnz rsxf0 rsxf1: pop d jnz next lxi d,CSTDN mvi c,CBUFPR call next lxi h,next shld start+1 ; only until remove takes place... mvi a,0ffh sta remove lxi h,0 mov a,l ret end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееvers equ '0g' ; January 20, 1986 11:06 drm "CRT.ASM" ;******************************************************** ; CRT module for the KAYPRO * ; Copyright (C) 1985 Douglas Miller * ;******************************************************** maclib Z80 false equ 0 true equ not false external equ false ;actual driver in EPROM? dev0 equ 200 ndev equ 1 sysctl equ 014h ;status/ctrl bits if not external line25n equ 00100000b crtadr equ 1ch vidctl equ crtadr crtreg equ 1dh viddat equ 1fh sio1 equ 4 keyb equ sio1+1 ; CRTC register addresses curst equ 10 curen equ 11 startH equ 12 startL equ 13 cursrH equ 14 cursrL equ 15 ramioH equ 18 ramioL equ 19 nulla equ 31 ctrlD equ 4 bell equ 7 bs equ 8 lf equ 10 ctrlK equ 11 ff equ 12 cr equ 13 ctrlW equ 23 ctrlX equ 24 ctrlZ equ 26 esc equ 27 rs equ 30 endif extrn @ctbl,@vect cseg ;common memory, other parts in banked. dw thread db dev0,ndev jmp init jmp nullst jmp nullin jmp nullst jmp output dw strcrt dw tblcrt dw modcrt strcrt: db 'KAYPRO ',0,'CRT driver ',0,'v3.10' dw vers db '$' modcrt: db 00000000b,00000000b,10000000b,0 thread equ $ dseg ;banked memory. tblcrt: ;initial value only, copied by BIOS to its table. db 'CRT ',00000010b,0 ;Output, no baud, no protocal init: if not external LXI H,escflg MVI B,12 XRA A L06E0 MOV M,A INX H DJNZ L06E0 lhld 0041h ;gifts from the loader... shld line lhld 0044h ; shld curpos lhld 0046h ; shld starta endif ret nullin: mvi a,1ah ret nullst: ori true ret ; return true if ready if external output: di in sysctl ani 10111111b ori 10000000b out sysctl call 0045h in sysctl ani 00111111b out sysctl ei ret else ;internal CRT driver code: ;CTR controlling code output: LDA escflg ORA A JNZ L09CB ;ESC codes MOV A,C ORA A RZ ;ignore nulls JM L07AE ;Block graphics CPI ' ' JC L0A44 ;CTRL codes ;Displayable char L078F MOV A,C LDED curpos CALL L0998 CALL L09A4 ;advance cursor L079A LDA column INR A CPI 80 JNC L07F7 ;wrap STA column LDED curpos INX D JMP L0815 ;Block graphics codes L07AE LDA attrib ANI 00010000b JRZ L078F ;normal char LDA LFD8C ANI 01000000b JRZ L07C3 MOV A,C ANI 00000001b STA LFD8C RET L07C3 LDA LFD8C ORA A MOV A,C JRZ L07CB CMA L07CB ORI 10000000b LDED curpos CALL L0998 LDA LFD8C MOV C,A LDA attrib ORA C CALL L09A7 MVI A,01000000b STA LFD8C JR L079A ;advance cursor pos L07E6 LHLD curpos LDA column MOV E,A XRA A MOV D,A STA column DSBC D XCHG JR L0815 ;wrap to next line L07F7 CALL L07E6 ; L07FA LDA line CPI 23 JRC L0809 L0801 CPI 24 RZ CALL L088A JR L080D L0809 INR A STA line L080D LHLD curpos LXI D,80 DAD D XCHG L0815 MOV A,D ANI 00000111b MOV D,A XCHG SHLD curpos LBCD starta DSBC B JRNC L0829 LXI D,2048 DAD D L0829 DAD B XCHG LXI B,crtadr + (cursrH shl 8) JMP L0981 L0831 LDA line CPI 24 RZ ORA A RZ DCR A STA line LHLD curpos LXI D,80 DSBC D XCHG JR L0815 L0848 LDA column ORA A JRNZ L085D LDA line ORA A RZ CPI 24 JRZ L0868 DCR A STA line MVI A,80 L085D DCR A STA column LDED curpos DCX D JR L0815 L0868 MVI A,79 STA column LHLD curpos LXI D,79 DAD D XCHG JR L0815 L0877 LDA column CPI 79 JNC L07F7 LDED curpos INX D INR A STA column JR L0815 L088A JMP L0A8C ;set modes L088D LXI H,attrib MOV A,C SUI '0' JRZ L08AB DCR A JRZ L08B0 DCR A JRZ L08B5 DCR A JRZ L08BA DCR A JRZ L08BF DCR A JRZ L08C9 DCR A JRZ L08D7 DCR A JRZ L08DE RET ;Rev Vid L08AB MOV A,M ORI 00000001b MOV M,A RET L08B0 MOV A,M ORI 00000010b MOV M,A RET L08B5 MOV A,M ORI 00000100b MOV M,A RET L08BA MOV A,M ORI 00001000b MOV M,A RET ;Cursor on L08BF MVI C,01100000b ; L08C1 MVI A,curst OUT crtadr MOV A,C OUT viddat RET ;Vid Mode L08C9 LDA attrib ORI 00010000b STA attrib MVI A,01000000b STA LFD8C RET L08D7 LHLD line SHLD LFD7D RET L08DE LDA attrib ORI 00100000b STA attrib RET ;reset mode L08E7 LXI H,attrib MOV A,C SUI '0' JRZ L0905 DCR A JRZ L090A DCR A JRZ L090F DCR A JRZ L0914 DCR A JRZ L0919 DCR A JRZ L091D DCR A JRZ L0922 DCR A JRZ L0934 RET L0905 MOV A,M ANI 11111110b MOV M,A RET L090A MOV A,M ANI 11111101b MOV M,A RET L090F MOV A,M ANI 11111011b MOV M,A RET L0914 MOV A,M ANI 11110111b MOV M,A RET ;Cursor off L0919 MVI C,00100000b JR L08C1 L091D MOV A,M ANI 11101111b MOV M,A RET ;restore cursor pos L0922 LHLD LFD7D MOV A,H ADI ' ' STA LFD7F MOV A,L ADI ' ' STA LFD81 JMP L093D L0934 LDA attrib ANI 11011111b STA attrib RET ;direct cursor control L093D LXI H,0 MOV C,L LDA LFD81 SUI ' ' RC MOV B,A JRZ L0953 CPI 25 RNC LXI D,80 L0950 DAD D DJNZ L0950 L0953 MOV E,A LDA LFD7F SUI ' ' RC CPI 80 RNC MOV C,A STA column MOV A,E STA line DAD B LDED starta DAD D XCHG JMP L0815 L096F LXI B,crtadr + (ramioH shl 8) CALL L0981 DCR C MVI A,nulla OUTP A L097A INP A ORA A JP L097A RET L0981 OUTP B INR C OUTP D DCR C INR B OUTP B INR C OUTP E RET L0992 CALL L096F IN viddat RET L0998 PUSH PSW MOV A,D ANI 7 MOV D,A CALL L096F POP PSW OUT viddat RET L09A4 LDA attrib L09A7 PUSH H PUSH PSW CALL L09BF CALL L096F POP PSW OUT viddat XCHG POP H RET PUSH H CALL L09BF CALL L0992 XCHG POP H RET L09BF LXI H,0801h DAD D MOV A,H ANI 7 ORI 8 MOV H,A XCHG RET ;ESC sequences L09CB LXI H,escflg MVI M,0 CPI 1 JRNZ L09ED MOV A,C ANI 01111111b CPI 'R' JZ L0C06 CPI 'E' JZ L0C9D CPI 'A' RZ CPI 'G' RZ STA LFD7C MVI M,2 RET ;more than 1 in sequence L09ED CPI 2 JRNZ L0A05 LDA LFD7C CPI 'B' JZ L088D CPI 'C' JZ L08E7 MOV A,C STA LFD81 MVI M,3 RET ;more than 2 in sequence L0A05 CPI 3 JRNZ L0A22 MOV A,C STA LFD7F LDA LFD7C CPI '=' JZ L093D CPI '*' JZ L0DA1 CPI ' ' JZ L0DA8 MVI M,4 RET ;more than 3 L0A22 CPI 4 JRNZ L0A2D MOV A,C STA LFD82 MVI M,5 RET ;5 sequential char L0A2D MOV A,C STA LFD80 LDA LFD7C CPI 'L' JZ L0F41 CPI 'D' JZ L0F48 RET L0A3F in keyb+2 ani 00000100b jrz L0A3F mvi a,ctrlD out keyb ret ;CTRL codes L0A44 CPI cr JZ L07E6 CPI lf JZ L07FA CPI bell JRZ L0A3F CPI ctrlX JZ L06A1 CPI ctrlW JZ L06A6 CPI ctrlZ JZ L06F8 CPI bs JZ L0848 CPI ff JZ L0877 CPI ctrlK JZ L0831 CPI rs JZ L075F CPI esc JNZ L078F MVI A,1 STA escflg RET L0A8C LDA attrib ANI 00100000b JRZ L0AC9 L0A93 LHLD starta LXI D,1920 LXI B,80 DAD D MOV A,H ANI 00000111b MOV H,A MOV D,H MOV E,L DAD B MOV A,H ANI 00000111b MOV H,A XCHG PUSH H CALL L0AF0 POP D LXI H,80 CALL L0711 LHLD starta LXI D,80 DAD D MOV A,H ANI 00000111b MOV H,A SHLD starta XCHG LXI B,crtadr + (startH shl 8) JMP L0981 L0AC9 LHLD starta LXI D,80 DAD D MOV A,H ANI 00000111b MOV H,A SHLD starta XCHG LXI B,crtadr + (startH shl 8) CALL L0981 LHLD starta LXI D,1920 DAD D MOV A,H ANI 00000111b MOV H,A XCHG LXI H,80 JMP L0711 L0AF0 MOV A,B ANI 00000111b ORA C RZ L0AF5 PUSH B L0AF6 IN vidctl ORA A JP L0AF6 LXI B,ramioL + (ramioH shl 8) MOV A,B OUT crtadr MOV A,H OUT crtreg MOV A,C OUT crtadr MOV A,L OUT crtreg MVI A,nulla OUT crtadr L0B0F IN vidctl ORA A JP L0B0F IN viddat EXAF MOV A,B OUT crtadr MOV A,D OUT crtreg MOV A,C OUT crtadr MOV A,E OUT crtreg MVI A,nulla OUT crtadr EXAF OUT viddat INX D INX H MOV A,D ANI 00000111b MOV D,A MOV A,H ANI 00000111b MOV H,A L0B35 IN vidctl ORA A JP L0B35 MOV A,B OUT crtadr MOV A,H ORI 00001000b OUT crtreg MOV A,C OUT crtadr MOV A,L OUT crtreg MVI A,nulla OUT crtadr L0B4D IN vidctl ORA A JP L0B4D IN viddat EXAF MOV A,B OUT crtadr MOV A,D ORI 00001000b OUT crtreg MOV A,C OUT crtadr MOV A,E OUT crtreg MVI A,nulla OUT crtadr EXAF OUT viddat POP B DCX B MOV A,B ORA C JNZ L0AF5 JMP L0BFF L0B75 MOV A,B ANI 00000111b ORA C RZ L0B7A PUSH B L0B7B IN vidctl ORA A JP L0B7B LXI B,ramioL + (ramioH shl 8) MOV A,B OUT crtadr MOV A,H ANI 00000111b OUT crtreg MOV A,C OUT crtadr MOV A,L OUT crtreg MVI A,nulla OUT crtadr L0B96 IN vidctl ORA A JP L0B96 IN viddat EXAF MOV A,B OUT crtadr MOV A,D ANI 00000111b OUT crtreg MOV A,C OUT crtadr MOV A,E OUT crtreg MVI A,nulla OUT crtadr EXAF OUT viddat INX D INX H MOV A,D ANI 00000111b MOV D,A MOV A,H ANI 00000111b MOV H,A L0BBE IN vidctl ORA A JP L0BBE MOV A,B OUT crtadr MOV A,H ORI 8 OUT crtreg MOV A,C OUT crtadr MOV A,L OUT crtreg MVI A,nulla OUT crtadr L0BD6 IN vidctl ORA A JP L0BD6 IN viddat EXAF MOV A,B OUT crtadr MOV A,D ORI 00001000b OUT crtreg MOV A,C OUT crtadr MOV A,E OUT crtreg MVI A,nulla OUT crtadr EXAF OUT viddat POP B DCX H DCX H DCX D DCX D DCX B MOV A,B ORA C JNZ L0B7A L0BFF IN vidctl ORA A JP L0BFF RET L0C06 CALL L07E6 LDA line ORA A JZ L0C4F LDED curpos LXI H,80 CPI 23 JNC L0711 CPI 11 JRNC L0C64 XCHG LXI B,79 DAD B MOV A,H ANI 00000111b MOV H,A MOV B,H MOV C,L DSBC D MOV A,H ANI 00000111b MOV H,A PUSH H LDED starta DSBC D JRNC L0C5D LXI H,2048 ORA A DSBC D POP D DAD D MOV A,H ANI 00000111b MOV H,B MOV B,A MOV A,L MOV L,C MOV C,A XCHG L0C4B INX B CALL L0B75 L0C4F CALL L0A93 LHLD curpos LXI D,80 DAD D XCHG JMP L0815 L0C5D MOV D,B MOV E,C MOV B,H MOV C,L POP H JR L0C4B L0C64 DAD D MOV A,H ANI 00000111b MOV D,A MOV E,L LHLD starta LXI B,1920 DAD B MOV A,H ANI 00000111b MOV H,A MOV B,A MOV C,L DSBC D JRNC L0C82 LXI H,2048 ORA A DSBC D DAD B L0C82 MOV B,H MOV C,L LHLD curpos XCHG CALL L0AF0 LHLD starta LXI D,1840 DAD D MOV A,H ANI 00000111b MOV D,A MOV E,L LXI H,80 JMP L0711 L0C9D LDA line CPI 12 JNC L0D4E LHLD starta LXI D,80 ORA A DSBC D MOV A,H ANI 00000111b MOV H,A XCHG LXI B,crtadr + (startH shl 8) CALL L0981 LHLD curpos LBCD starta ORA A DSBC B JRNC L0CD4 LXI H,2048 ORA A DSBC B MOV A,H ANI 00000111b MOV H,A LBCD curpos DAD B L0CD4 MOV A,H ANI 00000111b MOV B,A MOV C,L LXI H,128 DAD B MOV A,H ANI 00000111b MOV B,A MOV C,L LHLD starta LXI D,1840 DAD D MOV A,H ANI 00000111b MOV H,A XCHG LXI H,80 DAD D MOV A,H ANI 00000111b MOV H,A CALL L0AF0 LHLD curpos LXI B,80 ORA A DSBC B MOV A,H ANI 00000111b MOV H,A XCHG LDA column MOV C,A MVI B,0 LXI H,80 DSBC B PUSH D PUSH H CALL L0711 POP B PUSH B LHLD curpos LDA column MOV E,A MVI D,0 ORA A DSBC D MOV A,H ANI 00000111b MOV D,A MOV E,L LHLD curpos CALL L0AF0 POP B LXI H,80 ORA A DSBC B CNZ L0711 LHLD starta LXI B,80 ORA A DSBC B MOV A,H ANI 00000111b MOV H,A SHLD starta POP D JMP L0815 L0D4E SUI 22 JRZ L0D7C JNC L06A1 NEG PUSH PSW LHLD starta LXI D,1839 LXI B,80 DAD D MOV A,H ANI 00000111b MOV D,A MOV E,L DAD B MOV A,H ANI 00000111b MOV H,A XCHG POP PSW PUSH H LXI H,0 L0D72 DAD B DCR A JRNZ L0D72 MOV B,H MOV C,L POP H CALL L0B75 L0D7C LHLD curpos MOV D,H MOV E,L LDA column MOV C,A MVI A,80 SUB C MOV C,A MVI B,0 DAD B MOV A,H ANI 00000111b MOV H,A XCHG CALL L0AF0 LDA column MOV L,A MVI H,0 ORA A CNZ L0711 JMP L06A1 L0DA1 MVI A,0 STA LFD83 JR L0DAD L0DA8 MVI A,-1 STA LFD83 L0DAD LDA LFD7F SUI ' ' MOV E,A LDA LFD81 SUI ' ' MOV D,A L0DB9 MOV A,D CPI 100 RNC ANI 0011b MOV B,A srlr d srlr d MOV A,E CPI 160 RNC RRC MOV E,A MVI A,1 JRC L0DD1 ADD A L0DD1 INR B DCR B JRZ L0DDA L0DD5 ADD A ADD A djnz L0DD5 L0DDA STA LFD85 MOV A,E ANI 01111111b MOV E,A LHLD starta MOV B,D MOV C,E LXI D,80 INR B JR L0DED L0DEC DAD D L0DED DJNZ L0DEC MVI D,0 MOV E,C DAD D MOV A,H ANI 00000111b MOV D,A MOV E,L SDED LFD86 CALL L0E93 ORA A JM L0E08 CPI ' ' RNZ MVI A,128 L0E08 STA LFD84 LDA LFD85 ORA A JP L0E4A LDED LFD86 CALL L0ED9 STA LFD7C ANI 00000001b JRZ L0E37 LDA LFD83 ORA A RZ LDA LFD7C ANI 11111110b LDED LFD86 CALL L0ECB LDA LFD84 CMA JR L0E6E L0E37 LDA LFD83 ORA A RNZ LDA LFD7C ORI 00000001b CALL L0ECB LDA LFD84 CMA JR L0E6E L0E4A LDED LFD86 CALL L0ED9 ANI 00000001b JRNZ L0E78 LDA LFD83 ORA A JRZ L0E66 LDA LFD85 CMA MOV B,A LDA LFD84 ANA B JR L0E6E L0E66 LDA LFD84 MOV B,A LDA LFD85 ORA B L0E6E ORI 10000000b LDED LFD86 CALL L0E9D RET L0E78 LDA LFD83 ORA A JRZ L0E88 LDA LFD85 MOV B,A LDA LFD84 ORA B JR L0E6E L0E88 LDA LFD85 CMA MOV B,A LDA LFD84 ANA B JR L0E6E L0E93 MOV A,D ANI 00000111b MOV D,A L0E97 CALL L0EA9 IN viddat RET L0E9D PUSH PSW MOV A,D ANI 00000111b MOV D,A CALL L0EA9 POP PSW OUT viddat RET L0EA9 LXI B,crtadr + (ramioH shl 8) CALL L0EBB DCR C MVI A,nulla OUTP A L0EB4 INP A ORA A JP L0EB4 RET L0EBB OUTP B INR C OUTP D DCR C INR B OUTP B INR C OUTP E RET L0ECB PUSH H PUSH PSW CALL L0EE3 CALL L0EA9 POP PSW OUT viddat XCHG POP H RET L0ED9 PUSH H CALL L0EE3 CALL L0E97 XCHG POP H RET L0EE3 LXI H,L0801 DAD D MOV A,H ANI 00000111b ORI 00001000b MOV H,A XCHG RET L0EF1 MOV A,E SUI ' ' MOV E,A MOV A,D SUI ' ' MOV D,A SUB E RZ JRNC L0EFF NEG L0EFF INR A RET L0F01 LXI H,0 MOV A,D ORA A RZ MOV A,E ORA A RZ INX H CMP D JRC L0F10 MOV A,D MOV D,E L0F10 MVI E,0 L0F12 MOV B,H MOV C,L ADD A JRNC L0F18 INR E L0F18 DAD B JRC L0F2F SUB D JRNC L0F2C PUSH PSW MOV A,E ORA A JRZ L0F28 POP PSW MVI E,0 JR L0F2C L0F28 POP PSW ADD D JR L0F12 L0F2C INX H JR L0F12 L0F2F SUB D JRNC L0F35 MOV A,E ORA A RZ L0F35 INX H RET L0F37 PUSH H PUSH D PUSH B CALL L0DB9 POP B POP D POP H RET L0F41 MVI A,0 STA LFD83 JR L0F4F L0F48 MVI A,-1 STA LFD83 JR L0F4F L0F4F LDED LFD81 CALL L0EF1 SDED LFD81 STA LFD8A LDED LFD7F CALL L0EF1 SDED LFD7F STA LFD8B MOV D,A LDA LFD8A MOV E,A CALL L0F01 LDA LFD81 MOV D,A LDA LFD82 CMP D MVI A,-1 JRC L0F81 MVI A,1 L0F81 STA LFD88 LDA LFD7F MOV E,A LDA LFD80 CMP E MVI A,-1 JRC L0F92 MVI A,1 L0F92 STA LFD89 LDA LFD8A MOV C,A LDA LFD8B CMP C MOV B,H MOV C,L LXI H,0 JRC L0FBD JRZ L0FD4 L0FA6 CALL L0F37 LDA LFD80 CMP E RZ LDA LFD89 ADD E MOV E,A DAD B JRNC L0FA6 LDA LFD88 ADD D MOV D,A JR L0FA6 L0FBD CALL L0F37 LDA LFD82 CMP D RZ LDA LFD88 ADD D MOV D,A DAD B JRNC L0FBD LDA LFD89 ADD E MOV E,A JR L0FBD L0FD4 CALL L0F37 LDA LFD82 CMP D RZ LDA LFD88 ADD D MOV D,A LDA LFD89 ADD E MOV E,A JR L0FD4 L06A1 CALL L06CA JR L0711 L06A6 MVI C,23 LDA attrib ANI line25n JRNZ L06B0 INR C L06B0 LDA line SUB C JRNC L06A1 NEG MOV B,A LXI D,80 LXI H,0 L06BF DAD D DJNZ L06BF PUSH H CALL L06CA POP B DAD B JR L0711 L06CA LXI H,80 LDED curpos LDA column MOV C,A XRA A MOV B,A DSBC B RET L06F8 CALL L075F LDA attrib ;reset attributes ANI 11110000b STA attrib ; ; clear rest of screen LDED curpos LXI H,80*25 ANI line25n ;test 25th line JRZ L0711 LXI H,80*24 L0711 LXI B,ramioL + (ramioH shl 8) ; L0714 IN vidctl ;wait for ??? ORA A ; JP L0714 ; MOV A,B OUT crtadr MOV A,D ANI 00000111b MOV D,A OUT crtreg MOV A,C OUT crtadr MOV A,E OUT crtreg MVI A,nulla OUT crtadr L072D IN vidctl ORA A JP L072D MVI A,' ' OUT viddat INX D L0738 IN vidctl ORA A JP L0738 MOV A,B OUT crtadr MOV A,D ORI 00001000b OUT crtreg MOV A,C OUT crtadr MOV A,E OUT crtreg MVI A,nulla OUT crtadr L0750 IN vidctl ORA A JP L0750 XRA A OUT viddat DCX H MOV A,H ORA L JRNZ L0714 RET L075F XRA A STA column STA line LHLD starta XCHG JMP L0815 escflg db 0 line db 0 column db 0 attrib db 0 curpos dw 0 starta dw 0 LFD7C db 0 LFD7D dw 0 LFD7F db 0 LFD80 db 0 LFD81 db 0 LFD82 db 0 LFD83 db 0 LFD84 db 0 LFD85 db 0 LFD86 dw 0 LFD88 db 0 LFD89 db 0 LFD8A db 0 LFD8B db 0 LFD8C db 0 endif end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее org 0100h mvi a,23 sta lcount lxi d,005ch mvi c,0fh call 0005h inr a jz error lxi d,0080h mvi c,01ah call 0005h rdloop: lxi d,005ch mvi c,014h call 0005h ora a jnz done lxi h,0080h mvi d,080h outloop: mov a,m inx h cpi 01ah jz done push h push d cpi 00ah jnz notlf mvi e,00dh mvi c,002h call 0005h mvi e,00ah mvi c,02h call 0005h lda lcount dcr a sta lcount cz more jmp waslf notlf: mov e,a mvi c,002h call 0005h waslf: pop d pop h dcr d jnz outloop jmp rdloop done0: pop h ; discard return addr done: lxi d,005ch mvi c,010h call 0005h ret error: lxi d,errmsg mvi c,09h call 0005h ret more: mvi a,23 sta lcount lxi d,moremsg mvi c,09h call 0005h mvi c,01h call 0005h cpi 0003h; Ctrl C jnz clearmsg pop h ; ret addr pop h ; saved DE pop h ; saved HL lxi d,crlf mvi c,09h call 0005h jmp done clearmsg: lxi d,clrmsg mvi c,09h call 0005h ret lcount: db 23 errmsg: db 'No File' crlf: db 13, 10, '$' moremsg: db 'MORE:$' clrmsg: db 13, ' ',13,'$' end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; This program can be used to remove an RSX that is persistent. ; The RSX must trap function 60 (CALL RSX) and honor sub function 113. ; The RSXPB is defined as: ; ; rsxpb: db 113 ; function code ; db 1 ; num params ; db name ; param: name of RSX to remove ; ; name: db 'TOREMOVE' ; must be 8 chars, blank padded ; ; This program expects the CCP to format the single commandline ; parameter into the default FCB, which will produce an 8-char ; (actually, 11) blank padded field. ; ; Usage: RSXRM ; Example: RSXRM RSXTEST ; ; A compatible RSX must accept BDOS Function 60 RSX Function 113, ; compare it's name to the parameter, and if matching then set ; it's own REMOVE flag. ; ; See RSXTEST.ASM for an example, in the RSXFUN routine. ; org 100h start: lxi d,rsxpb mvi c,60 call 5 jmp 0 rsxpb: db 113 db 1 dw 005dh end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; Translate text file between CP/M and Unix line-ends maclib z80 WBOOT equ 0000h BDOS equ 0005h CMDLINE equ 0080h CR equ 13 LF equ 10 EOF equ 26 CONOUT equ 2 PRINT equ 9 OPEN equ 15 CLOSE equ 16 SERFST equ 17 SERNXT equ 18 DELETE equ 19 READ equ 20 WRITE equ 21 MAKE equ 22 RENAME equ 23 SETDMA equ 26 SETATR equ 30 PARSE equ 152 BUFLEN equ 128 org 0100h jmp start infile: ds 36 outfile: ds 36 tmpfile: ds 36 sawcr: db 0 conv: db 0 bytcnt: db 0 flptr: dw 0 flcnt: db 0 pfcb: dw 0 ; text to parse dw 0 ; output FCB ; TODO: support things like A:=B:*.asm[u] start: lxi sp,stack lxi d,CMDLINE ldax d inx d ora a jz help mov l,a mvi h,0 dad d mvi m,0 ; ensure NUL terminated xchg shld pfcb lxi h,outfile shld pfcb+2 lxi d,pfcb mvi c,PARSE call BDOS mov a,h ana l cpi 0ffh jz parerr mov a,m ; HL point to next, unparsed, char cpi '=' jnz parerr inx h shld pfcb lxi h,infile shld pfcb+2 lxi d,pfcb mvi c,PARSE call BDOS mov a,h ana l cpi 0ffh jz parerr mov a,m ; HL point to next, unparsed, char cpi '[' jnz parerr ; make this optional, default is no conversion? inx h mov a,m ani 0dfh ; toupper cpi 'U' jz convok cpi 'C' jnz parerr convok: ani 010h ; 0=to-cp/m, ~0=to-unix sta conv inx h mov a,m cpi ']' jnz parerr inx h mov a,m ora a jnz parerr lxi h,infile call chkafn jnc multcp lda outfile+1 cpi ' ' jnz noblank lxi d,outfile+1 lxi h,infile+1 lxi b,11 ldir lda outfile+1 cpi ' ' jz parerr noblank: lxi h,outfile call chkafn jnc parerr call trfile ; errors abort, do not return here jmp WBOOT multcp: lda outfile+1 cpi ' ' jnz parerr ; make list of matching files, then ; translate each one... lxi h,flist shld flptr xra a sta flcnt lxi d,inbuf mvi c,SETDMA call BDOS lxi d,infile mvi c,SERFST call BDOS cpi 0ffh jz inofile serloop: rlc rlc rlc rlc rlc ; * 32 mov e,a mvi d,0 lxi h,inbuf dad d inx h xchg lhld flptr xchg lxi b,11 ldir xchg mvi m,'$' inx h shld flptr lda flcnt inr a sta flcnt lxi d,0 mvi c,SERNXT call BDOS cpi 0ffh jnz serloop ; got list of 'flcnt' files at 'flist' ; There must be at least one if we get here... lxi d,cpying mvi c,PRINT call BDOS lxi h,flist lda flcnt floop: push psw push h lxi d,fprefx mvi c,PRINT call BDOS pop d push d mvi c,PRINT call BDOS pop h push h lxi d,infile+1 lxi b,11 ldir lxi h,infile+1 lxi d,outfile+1 lxi b,11 ldir call trfile pop h pop psw lxi b,12 dad b dcr a jnz floop jmp WBOOT ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Translate file infile => outfile trfile: xra a sta infile+12 sta outfile+12 lxi h,outfile lxi d,tmpfile lxi b,16 ldir lxi h,tmpfile+9 mvi m,'$' inx h mvi m,'$' inx h mvi m,'$' ; FCBs all setup. lxi d,infile mvi c,OPEN call BDOS cpi 0ffh jz inofile xra a sta infile+32 lxi d,tmpfile mvi c,DELETE call BDOS lxi d,tmpfile mvi c,MAKE call BDOS cpi 0ffh jz mkerr sta sawcr call infill call outinit chrloop: call getchr cpi EOF jz ineof mvi d,0 cpi CR jnz notcr lda conv ora a jnz chrloop ; to-unix: drop all CR inr d mvi a,CR notcr: cpi LF jnz notlf lda conv ora a jnz crlfok ; to-unix: do not add back CR lda sawcr ora a jnz crlfok mvi a,CR call putchr mvi d,0 crlfok: mvi a,LF notlf: push d call putchr pop d mov a,d sta sawcr jmp chrloop ineof: lda conv ora a jnz done0 ; Unix file, set byte count instead... ineof0: mvi a,EOF call putchr ; fill buffer and force flush... lda outcnt ora a ; zero means next putchr will flush... jnz ineof0 done0: lda outcnt mov c,a mvi a,BUFLEN sub c sta bytcnt ; 0..128 call outflush ; flushes full 128 byte record done: ; close all and rename tmpfile... call closeall lda conv ora a jz iscpm lda bytcnt sta tmpfile+32 lxi h,tmpfile+6 mov a,m ori 80h mov m,a lxi d,tmpfile mvi c,SETATR call BDOS ; trim file back to exact byte count ; check error? aborting doesn't help iscpm: lxi d,outfile mvi c,DELETE call BDOS ; check error? do anything different? lxi h,outfile lxi d,tmpfile+16 lxi b,16 ldir lxi d,tmpfile mvi c,RENAME call BDOS cpi 0ffh jz renerr ret getchr: lda incnt ora a cz infill lda incnt dcr a sta incnt lhld inptr mov a,m inx h shld inptr ret putchr: push psw lda outcnt ora a cz outflush lda outcnt dcr a sta outcnt pop psw lhld outptr mov m,a inx h shld outptr ret outflush: lxi d,outbuf mvi c,SETDMA call BDOS lxi d,tmpfile mvi c,WRITE call BDOS ora a jnz outerr outinit: lxi h,outbuf shld outptr mvi a,BUFLEN sta outcnt ret infill: lxi d,inbuf mvi c,SETDMA call BDOS lxi d,infile mvi c,READ call BDOS ora a jz inok cpi 1 jnz inerr mvi a,EOF ; should never happen for text files, but handle anyway sta inbuf inok: lxi h,inbuf shld inptr mvi a,BUFLEN sta incnt ret closeall: lxi d,tmpfile mvi c,CLOSE call BDOS lxi d,infile mvi c,CLOSE call BDOS ret parerr: lxi d,perrm mvi c,PRINT call BDOS lxi d,CMDLINE ldax d inx d mov l,a mvi h,0 dad d mvi m,'$' mvi c,PRINT call BDOS help: lxi d,usage mvi c,PRINT call BDOS jmp WBOOT mkerr: ; infile open, partial cleanup lxi d,merrm jmp abort inerr: ; both files open lxi d,ierrm jmp abort outerr: ; both files open lxi d,oerrm abort: push d call closeall lxi d,tmpfile mvi c,DELETE call BDOS pop d jmp errmsg renerr: ; files are all closed, no cleanup lxi d,rerrm jmp errmsg inofile: ; files not open yet, no cleanup lxi d,nerrm errmsg: push d lda flcnt ora a jz nocrlf mvi e,CR mvi c,CONOUT call BDOS mvi e,LF mvi c,CONOUT call BDOS nocrlf: pop d mvi c,PRINT call BDOS jmp WBOOT ; Check for '?' (ambiguous file name) in FCB HL ; Return CY set if unambiguous chkafn: mvi b,13 qchk: mov a,m cpi '?' rz inx h dcr b jnz qchk stc ret perrm: db 'Invalid: $' ierrm: db 'Error reading input$' oerrm: db 'Error writing output$' nerrm: db 'No file found for input$' merrm: db 'Error creating temp$' rerrm: db 'Error renaming temp$' usage: db CR,LF,'Usage: TR A:{outfile}=B:infile[U|C]$' cpying: db 'Copying -$' fprefx: db CR,LF,' $' outcnt: db 0 outptr: dw 0 incnt: db 0 inptr: dw 0 stack equ $+64 outbuf equ stack inbuf equ outbuf+BUFLEN flist equ inbuf+BUFLEN end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееLINK BNKBIOS3=MBIOS3KP,WIN3KP,FDC3KP,CRT,KEYBD,SERIAL,CENTR,END,LPTBL,GETDP3KP,SCB[B,OS,$$SZ] ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; December 21, 1985 10:46 drm "GETDP3KP.ASM" maclib Z80 ; $-MACRO @ equ -1 ; CP/M 3.0 system routine to select a DPB and sector translation table ; given the mode bytes (4) **************************************************** * label: calcdpb spt,spb,bpd,dpd,nst,pss,exd[,flg] * * spt = Sectors per Track * spb = Sectors per allocation Block * bpd = allocation Blocks per Disk (max (DS)) * dpd = Directory entries per Disk * nst = Number of System Tracks * pss = Physical Sector Size (bytes) * exd = Extra Directory entries reserved * [flg]= optional flag to intentionally produce incorrect EXM * (used to maintain compatability with previous formats) * calcdpb macro ?spt0,?spb0,?dsm0,?drm0,?off0,?pss0,?exd0,?flg ?bsm set ?spb0-1 ?exm set ?bsm shr 3 if ?dsm0 gt 256 ?exm set ?exm shr 1 endif if not NUL ?flg ?exm set ?exm shr 1 endif ?cks set ?drm0/4 ?exs set ?exd0/4 ?bsh set 0 ?@ set ?spb0 rept 8 ?@ set ?@ shr 1 if ?@ eq 0 exitm endif ?bsh set ?bsh+1 endm ?al0 set 0 rept (?cks+?exs+?bsm)/?spb0 ?al0 set (?al0 shr 1) or 10000000$00000000b endm ?al1 set low ?al0 ?al0 set high ?al0 ?psh set 0 ?psm set 0 ?@ set high ?pss0 rept 8 if ?@ eq 0 exitm endif ?psh set ?psh+1 ?psm set (?psm shl 1) or 1 ?@ set ?@ shr 1 endm dw ?spt0 db ?bsh,?bsm,?exm dw ?dsm0-1,?drm0-1 db ?al0,?al1 dw ?cks,?off0 db ?psh,?psm endm ; Entry: HL = points to Mode bytes ; Exit: A = error code (0 if DPs found) ; DE = points to DPB ; BC = points to sector translation table (or BC=0) ; HL = offset from ?serdp to beginning of format string table ; Uses 2 levels of stack. ; public ?getdp,?serdp cseg ;for now we'll put it all in common memory. ?serdp: ;user has to tell us where we are. lxi b,PTRTBL-?serdp ;HL=memory address of "?serdp" dad b ;DE=mode bytes xchg jr gd1 ?GETDP: lxi d,ptrtbl gd1: PUSH H ; save mode byte pointer push d ;save parameter table address mov c,m ;no need to mask format origin code. inx h mov b,m inx h MOV A,M ; get first mode byte ani srm0 ; mask FIRST BYTE MOV E,A INX H ; and point to the second MOV A,M ani srm1 ; mask SECOND BYTE MOV D,A pop h ; table lookup... NXDPB: MOV A,M ; format origin code. inx h ana c ;compare it: if the format requested matches jrnz got1 ;(if the bit is set in both DPB and requested mov a,m ; mode ([NZ] condition) then we have a match.) ana b ;check for possible extend format origin jrz nxd1 ;... got1: inx h MOV A,M ; get first byte INX H ani srm0 ;mask it also CMP E ;compare to target mode jrnz NXD3 MOV A,M ; and the second ani srm1 ;mask it CMP D ;compare it jrnz NXD3 inx h mov e,m ;pick up DPB inx h mov d,m inx h mov c,m ;pick up XLAT also inx h mov b,m xchg ;DE=table pointer, HL=DPB xthl ;put DPB on stack, get HL=requested mode inx h inx h ;point past "format origin" push b ;put XLAT on stack. xchg lxi b,-5 dad b ;point back to table's modes xchg ; ldax d ;get "excess" mode bits. ani xsm0 ;mask in bits to give caller. mov c,a mvi a,(not xsm0) and 0ffh ana m ;clear callers bits prior to setting again ora c ;complete callers mode bytes mov m,a inx h inx d ldax d ;get "excess" mode bits. ani xsm1 ;mask in bits to give caller. mov c,a mvi a,(not xsm1) and 0ffh ana m ;clear callers bits prior to setting again ora c ;complete callers mode bytes mov m,a pop b ;restore XLAT pop d ;restore DPB lxi h,strtbl-?serdp ; load address of string table XRA A ; and clear the accumulator RET ; as this is the successful return NXD1: INX H NXD2: INX H nxd3: inx h inx h inx h inx h inx h MOV A,M CPI 11111111B jrnz NXDPB ; loop if more entries in table POP H ; restore mode byte pointer lxi h,strtbl-?serdp ; load address of string table xra a ! dcr a ; return [NZ] if DPs not found. RET ; as this is the error return ; ; (10-256 byte) ; Format string name table - all formats must have a entry here ; strtbl db 'KAYPRO ' ;bit 0 - must be 8 characters wide db 'KAYPROX ' ;bit 1 db 'MMS ' ; 2 db 'Z37 ' ; 3 db 'Z37X ' ; 4 db 'Z100 ' ; 5 db 'EPSON ' ; 6 db 'ASSOC ' ; 7 db 'FMT8 ' ; 8 db 'FMT9 ' ; 9 db 'FMT10 ' ; 10 db 'FMT11 ' ; 11 db 'FMT12 ' ; 12 db 'FMT13 ' ; 13 db 'FMT14 ' ; 14 ; ;---------------------------------------------------------------------- ; ; ;---------------------------------------------------------------------- ; ; SRM0: equ 10000000B ; SRM1: equ 01110000B ;SEARCH MODES MASKS XSM0: equ 00000011B ; XSM1: equ 10001111B ;EXCESS MODES MASKS PTRTBL: DB 00000000b,00000100B,00000000B,00010001B ; 5" mms,dd,ss,st dw mms0,0 DB 00000000b,00000100B,00000000B,01010001B ; 5" mms,dd,ds,st dw mms1,0 DB 00000000b,00000100B,00000000B,00110001B ; 5" mms,dd,ss,dt dw mms2,0 DB 00000000b,00000100B,00000000B,01110001B ; 5" mms,dd,ds,dt dw mms3,0 DB 00000000b,00001000B,00000000B,10000001B ; z37,sd,ss,st dw z370,0 DB 00000000b,00001000B,00000000B,10010001B ; z37,dd,ss,st dw z371,0 DB 00000000b,00010000B,00000000B,10010001B ; z37x,dd,ss,st dw z372,0 DB 00000000b,00001000B,00000000B,11000011B ; z37,sd,ds,st dw z373,0 DB 00000000b,00001000B,00000000B,11010011B ; z37,dd,ds,st dw z374,0 DB 00000000b,00010000B,00000000B,11010011B ; z37x,dd,ds,st dw z375,0 DB 00000000b,00001000B,00000000B,10100001B ; z37,sd,ss,dt dw z376,0 DB 00000000b,00001000B,00000000B,10110001B ; z37,dd,ss,dt dw z377,0 DB 00000000b,00010000B,00000000B,10110001B ; z37x,dd,ss,dt dw z378,0 DB 00000000b,00001000B,00000000B,11100011B ; z37,sd,ds,dt dw z379,0 DB 00000000b,00001000B,00000000B,11110011B ; z37,dd,ds,dt dw z37a,0 DB 00000000b,00010000B,00000000B,11110011B ; z37x,dd,ds,dt dw z37b,0 DB 00000000b,00100000B,00000000B,10010001B ; z100,dd,ss,st dw z100a,0 DB 00000000b,00100000B,00000000B,11010011B ; z100,dd,ds,st dw z100b,0 DB 00000000b,00100000B,00000000B,10110001B ; z100,dd,ss,dt dw z100c,0 DB 00000000b,00100000B,00000000B,11110011B ; z100,dd,ds,dt dw z100d,0 DB 00000000b,01000000B,00000000B,01010101B ; 5" EPSON,dd,ds,st dw epson,0 DB 00000000b,10000000B,00000000B,01010111B ; 5" GNAT,dd,ds,st dw gnat,0 DB 00000000b,00000001B,00000000B,00011000B ; 5" KAYPRO ss,st dw kaypro0,0 DB 00000000b,00000001B,00000000B,01011000B ; 5" KAYPRO ds,st dw kaypro1,0 DB 00000000b,00000010b,00000000b,01011000b ; 5" KAYPROX ds,st dw kaypro2,0 DB 11111111B ;FLAG FOR END OF TABLE $*MACRO dseg ;DPBs and SECTRN tables in banked mem MMS0: calcdpb 36,16, 83, 96,3,512,0 MMS1: calcdpb 36,16,173, 96,3,512,0 MMS2: calcdpb 36,32, 86,128,3,512,0 MMS3: calcdpb 36,32,176,128,3,512,0 Z370: calcdpb 20, 8, 92, 64,3,256,0 Z371: calcdpb 32, 8,152,128,2,256,0 Z372: calcdpb 40, 8,186,128,2,1024,0 Z373: calcdpb 20, 8,188,128,3,256,0 Z374: calcdpb 32,16,156,256,2,256,0,@ Z375: calcdpb 40,16,195,256,2,1024,0,@ Z376: calcdpb 20, 8,192, 64,3,256,0 Z377: calcdpb 32,16,156,128,2,256,0 Z378: calcdpb 40,16,195,128,2,1024,0 Z379: calcdpb 20,16,196,128,3,256,0 Z37A: calcdpb 32,16,316,256,2,256,0 Z37B: calcdpb 40,16,395,256,2,1024,0 Z100a: calcdpb 32, 8,152,128,2,512,0 ;; 5" disks Z100b: calcdpb 32,16,156,256,2,512,0,@ Z100c: calcdpb 32,16,156,128,2,512,0 Z100d: calcdpb 32,16,316,256,2,512,0 epson: calcdpb 80,16,190,128,2,512,0 gnat: calcdpb 80,16,169,128,1,512,0,@ kaypro0: calcdpb 40,8,195,64,1,512,64 kaypro1: calcdpb 40,16,197,64,1,512,64 kaypro2: calcdpb 40,16,197,128,1,512,0 ; ; NOTE: skew tables are for physical sector numbers. ; end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; ntpdate program for Kaypro CP/M 3 maclib z80 BDOS equ 0005h CMDLN equ 0080h ; BDOS functions CONOUT equ 2 PRINT equ 9 GETVER equ 12 SGSCB equ 49 ; CP/NET NDOS functions NSEND equ 66 NRECV equ 67 org 0100h jmp start ioport: db 038h vers: dw 0 scbadr: dw 0 gettime: db 0, 0, 2, 105, 0, 0 gottime: db 1, 2, 0, 105, 4, 0, 0, 0, 0, 0 ; just prediction of what will be received scbpb: db 03ah ; offset of SCB address (reserved area) db 0 ; get word, (SCB address) dw 0 ; assume < 100 decout: mvi b,'0' decot0: sui 10 jc decot1 inr b jmp decot0 decot1: adi 10 adi '0' push psw mov a,b call prout pop psw jmp prout ; Keeps number in HL - caller must preserve/init ; Returns CY for invalid hexnum: sui '0' rc cpi 9+1 jnc hexnm1 hexnm2: dad h dad h dad h dad h ora l mov l,a ret hexnm1: sui 'A'-'9' rc cpi 5+1 cmc rc adi 10 jmp hexnm2 hexout: push psw rrc rrc rrc rrc call hexdig pop psw hexdig: call tohex prout: mov e,a mvi c,CONOUT jmp BDOS tohex: ani 0fh adi 90h daa aci 40h daa ret ; HL = CP/M Date-time field, w/o seconds ; Print date and time to console. prdate: mov e,m inx h mov d,m inx h push h ; compute year mvi c,78 ; base year, epoch, binary mvi b,078h ; year, BCD ; special-case date=0... mov a,e ora d jnz prdat0 inx d prdat0: lxi h,365 mov a,c ani 03h ; Not strictly true, but works until year 2100... jnz prdat1 inx h prdat1: push h ora a dsbc d pop h jnc prdat2 ; done computing year... xchg ora a dsbc d xchg inr c mov a,b adi 1 daa mov b,a jmp prdat0 prdat2: ; DE = days within year 'C' push b ; save (2-digit) year, B = BCD, C = binary (until 2155) lxi h,month0+24 mov a,c ani 03h jnz prdat3 lxi h,month1+24 prdat3: ; compute month, DE = days in year,HL = mon-yr-days table adj for leap mvi b,12 prdat4: dcx h dcx h dcr b jm prdat5 ; should never happen... push h push d mov a,m inx h mov h,m mov l,a ; DE = days in year, HL = ytd[month] ora a dsbc d mov a,l ; potential remainder (neg) pop d pop h jnc prdat4 prdat5: ; B = month, 0-11; A = -dom neg push psw inr b mov a,b call decout mvi e,'/' mvi c,CONOUT call BDOS pop psw call decout mvi e,'/' mvi c,CONOUT call BDOS pop b mov a,b ; already BCD call hexout mvi e,' ' mvi c,CONOUT call BDOS pop h ; -> BCD hours mov a,m inx h push h call hexout mvi e,':' mvi c,CONOUT call BDOS pop h ; -> BCD minutes mov a,m inx h push h call hexout mvi e,':' mvi c,CONOUT call BDOS pop h ; -> BCD seconds mov a,m jmp hexout ; J F M A M J J A S O N D month0: dw 0, 31, 59, 90,120,151,181,212,243,273,304,334 month1: dw 0, 31, 60, 91,121,152,182,213,244,274,305,335 start: mvi c,GETVER call BDOS shld vers mov a,l cpi 30 jc badvers lxi h,CMDLN mov c,m inx h sid1: mov a,m cpi ' ' jnz sid0 inx h dcr c jnz sid1 jmp start1 ; no params, use defaults sid0: ; scan hex number as server ID xchg lxi h,0 sid2: ldax d inx d call hexnum jc sid3 dcr c jnz sid2 sid3: mov a,l sta gettime+1 start1: ; TODO: handle MP/M... lxi d,scbpb mvi c,SGSCB call BDOS shld scbadr lhld vers mvi a,2 ; bit for CP/Net ana h jz nocpnet lxi d,gettime mvi c,NSEND call BDOS ora a jnz error lxi d,gottime mvi c,NRECV call BDOS ora a jnz error jmp settime nocpnet: call netinit lxi b, gettime call sendmsg ora a jnz error lxi b, gottime call receivemsg ora a jnz error settime: lhld scbadr lxi d,058h ; date/time dad d xchg lxi h,gottime+5 lxi b,5 ; length of date/time di ldir ei lxi d,done mvi c,PRINT call BDOS lxi h,gottime+5 call prdate ret error: lxi d,errmsg mvi c,PRINT call BDOS ret badvers: lxi d,vermsg mvi c,PRINT call BDOS ret done: db 'Time was set to: $' errmsg: db 7,'Error retrieving network time.$' vermsg: db 7,'This program requires BDOS >= 3.0.$' ; These are only used if CP/Net is not running. netinit: lda ioport mov c,a inr c outp a inp a sta gettime+2 ret ; Send Message on Network sendmsg: ; BC = message addr mov h,b mov l,c ; HL = message address push h popix lda ioport mov c,a mvi b,5 ; length of header outir ldx b,4 ; msg siz field (-1) inr b ; might be 0, but that means 256 outir inr c ; status port inp a ; ani 02h ; cmd overrun rz mvi a,0ffh ret ; Receive Message from Network receivemsg: ; BC = message addr mov h,b mov l,c ; HL = message address push h popix lda ioport mov c,a inr c ; status port rcvwait: inp a ani 01h ; data ready jz rcvwait dcr c mvi b,5 ; header length inir ldx b,4 ; msg siz inr b inir inr c inp a ani 04h ; rsp overrun rz mvi a,0ffh ret end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееvers equ '0e' ; December 23, 1985 21:40 drm "KEYBD.ASM" ;******************************************************** ; KEYBOARD module for CP/M plus on the KAYPRO * ; Copyright (C) 1985 Douglas Miller * ;******************************************************** maclib Z80 false equ 0 true equ not false dbase equ 200 ;base for all char I/O devices dev0 equ 001 ;first device, rel. to base ndev equ 1 int equ false ;Keyboard input via interupts? bufsiz equ 16 ;use only 2,4,8,16,32,64,128,256. bufmsk equ bufsiz-1 sio1 equ 004h ;z80-sio/0 keyb equ sio1+1 ;CONSOLE keyboard ctrlA equ 1 ctrlB equ 2 ctrlD equ 4 ctrlE equ 5 ctrlF equ 6 ctrlG equ 7 lf equ 10 cr equ 13 ctrlN equ 14 ctrlO equ 15 ctrlP equ 16 ctrlQ equ 17 ctrlR equ 18 ctrlS equ 19 ctrlT equ 20 ctrlU equ 21 ctrlV equ 22 ctrlW equ 23 ctrlX equ 24 ctrlY equ 25 cls equ 26 extrn sio1vec cseg ;common memory, other parts in banked. dw thread db dbase+dev0,ndev jmp intkey jmp instkey jmp inputkey jmp outstkey jmp outputkey dw strkey dw tblkey dw modkey strkey: db 'KAYPRO ',0,'Keyboard handler ',0,'v3.10' dw vers db '$' modkey: db 00000000b,10000010b,00110100b,keyb ;primary conversion table for cursor and numberpad keys ; --0-- --1-- --2-- --3-- --4-- keycnv: db 0,ctrlP,ctrlU, 0, 0 ; B db ctrlV,ctrlW,ctrlY,ctrlQ, 0 ; C db ctrlR,ctrlO,ctrlF,ctrlB, 0 ; D db 0,ctrlA,ctrlN,ctrlG,ctrlT ; E db 0,ctrlE,ctrlX,ctrlS,ctrlD ; F ; ; * 0 . * * e = enter ; 1 2 3 e * u = up arrow ; 4 5 6 , * d = down ; * 7 8 9 - l = left ; * u d l r r = right ; if int index: lxi d,keybd mov a,e add m mov e,a push psw mov a,m inr a ani bufmsk mov m,a pop psw rnc inr d ret spclRx: sspd ustk lxi sp,istk push psw mvi a,00110000b ;error reset out keyb+2 pop psw lspd ustk ei reti interupt: sspd ustk lxi sp,istk push psw push b push d push h xra a out keyb+2 in keyb+2 bit 7,a jnz break rrc jnc exit lxi h,keypt0 lda keypt1 dcr a ani bufmsk cmp m push psw call index in keyb ani 01111111b stax d pop psw jnz exit gobl: mov a,m dcr a ani bufmsk mov m,a exit: pop h pop d pop b pop psw lspd ustk ei reti break: mvi a,00010000b ;reset ext/status (& break) out keyb+2 in keyb xra a sta keybd sta keypt1 inr a sta keypt0 jmp exit ustk: dw 0 dw 0,0,0,0,0,0,0,0 istk: ds 0 keypt0: db 0 keypt1: db 0 keybd: ds bufsiz endif thread equ $ dseg ;banked memory. tblkey: ;initial values only, copied by BIOS to its table. if int db 'IKEYBD',00001011b,6 ;I/O, hard-baud, no protocal, 300 else ;serial db 'KEYBD ',00001011b,6 ;I/O, hard-baud, no protocal, 300 endif ;serial intkey: if int call is1 lxi h,interupt shld sio1vec+4 lxi h,spclRx shld sio1vec+6 xra a sta keypt0 sta keypt1 mvi a,1 out keyb+2 mvi a,00011100b ;int on receive character, sts eff vect. out keyb+2 ret endif is1: lxi h,modkey+2 bit 7,m rnz mov a,m ani 00110000b ; --bb---- bits per char rlc ; -bb----- mov e,a ; Tx image setb 3,e ; Tx Enable rlc ; bb------ ori 00000001b ; Rx Enable mov d,a ; Rx image mov a,m ani 00001111b ori 01000000b ; 16x clock mov b,a ; WR4 image dcx h mov a,m ; ani 10000010b ; DTR, RTS ora e mov e,a ; Tx control, with RTS/DTR inx h inx h mov c,m inr c inr c mvi a,4 outp a outp b ; WR4 inr a outp a outp e ; WR5 mvi a,3 outp a outp d ; WR3 ret inputkey: inp1: call instkey jz inp1 if int lxi h,keypt1 call index ldax d else in keyb ; get data endif ora a rp sui 0B0H lxi h,keycnv ; first loc. is not used mov m,a xra a rrd mov c,m add c add c add c add c add c mov c,a mvi b,0 dad b mov a,m ret instkey: if int lxi h,keypt0 lda keypt1 sub m else xra a out keyb+2 in keyb+2 ; read from status port ani 1 ; isolate RxRdy endif rz ; return with zero ori true ret outputkey: outp0: call outstkey jrz outp0 ; wait for TxEmpty, HL->port mov a,c out keyb ; send data ret outstkey: mvi a,00010000b ;reset ext/status change out keyb+2 in keyb+2 ani 00000100b ; test xmit holding register empty rz ; ori true ret ; return true if ready end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееvers equ '0c' ; March 5, 2017 08:39 drm "LDCPM3.ASM" maclib Z80 cpm equ 0 bdos equ 5 tbuff equ 80h msgout equ 9 reset equ 13 openf equ 15 read equ 20 sdma equ 26 lf equ 10 cr equ 13 org 100h LOADER: ; ***** this should be part of COLD BOOT in CPM3LDRK ; lxi h,0fd74h ; lxi d,00040h ; lxi b,16 ; ldir ; ***** ; ROM 81-292 uses 0fd74h ; U-ROM 81-478 uses 0fe9ah ; ROM 81-302 uses 0fd5ch ; Identify ROM by... ; we can't map ROM in, we are in low memory. ; can't call ROM, either. ; U-ROM places '2.01' in 0fff8h... ; 81-292 places copyout in 0fde5h (DB 14 CB BF D3 14 ED B0 DB 14 CB FF D3 14 C9) ; 81-302 places copyout in 0f919h (DB 14 CB BF D3 14 ED B0 DB 14 CB FF D3 14 C9) call chkuni lxi h,0fe9ah mvi a,'U' jrz gotrom lxi h,0f919h call chksig lxi h,0fd5ch mvi a,'3' jrz gotrom lxi h,0fde5h call chksig lxi h,0fd74h mvi a,'2' jrz gotrom lxi d,badrom mvi c,msgout call bdos jmp cpm gotrom: shld romcrt sta romid lxi d,rommsg mvi c,msgout call bdos mvi c,reset call bdos MVI C,openf LXI D,cpm3$sys CALL bdos CPI 255 LXI D,nofile JZ errmsg LXI D,tbuff CALL dmaset CALL readfile LXI H,tbuff LXI D,topres lxi b,6 ldir CALL readfile MVI C,msgout LXI D,tbuff CALL bdos LDA reslen MOV d,A ; LDA topres mvi e,0 lxi h,buffer dad d shld resend xchg call loadf LDA bnklen ORA A JZ nobnk MOV d,A ; LDA topbnk mvi e,0 lhld resend dad d shld bnkend xchg CALL loadf nobnk: di ; ***** this should be part of COLD BOOT in CPM3LDRK lhld romcrt lxi d,00040h lxi b,16 ldir lda romid stax d ; ROM identifer char at 0050h ; ***** lda reslen mov b,a ;B=reslen mvi c,0 lhld resend dcx h lda topres mov d,a mvi e,0 dcx d lddr lda bnklen ora a jz nobnk0 mov b,a mvi c,0 lhld bnkend dcx h lda topbnk mov d,a mvi e,0 dcx d lddr nobnk0: lhld cstart pchl loadf: ;ORA A ;DE = top address (max+1) ;MOV D,A ;MVI E,0 MOV A,H RAL MOV H,A read0: XCHG LXI B,-128 DAD B XCHG PUSH D PUSH H CALL dmaset CALL readfile POP H POP D DCR H JNZ read0 RET dmaset: MVI C,sdma CALL bdos RET readfile: MVI C,read LXI D,cpm3$sys CALL bdos ORA A LXI D,rderr RZ errmsg: MVI C,msgout CALL bdos jmp cpm chkuni: lxi h,0fff8h mov a,m inx h cpi '2' rnz mov a,m inx h cpi '.' rnz mov a,m inx h cpi '0' rnz mov a,m inx h cpi '1' ret ; HL = prospective location chksig: lxi d,signature mvi b,siglen chk0: ldax d cmp m rnz inx h inx d djnz chk0 xra a ret cpm3$sys: DB 0,'CPM3 SYS',0,0,0,0 DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 DB 0,0,0,0 nofile: DB cr,lf,'error: File not found: CPM3.SYS',cr,lf,'$' rderr: DB cr,lf,'error: Read failure: CPM3.SYS',cr,lf,'$' topres: db 0 reslen: db 0 topbnk: db 0 bnklen: db 0 cstart: dw 0 resend: dw 0 bnkend: dw 0 signature: in 014h res 7,a out 014h ldir in 014h setb 7,a out 014h ret siglen equ $-signature badrom: db cr,lf,7,'Unknown ROM version!',cr,lf,'$' rommsg: db cr,lf,'Got ROM id ' romid db '.',cr,lf,'$' romcrt dw 0 buffer: ds 0 end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; SNIOS for fictitious CPNetDevice ; maclib z80 public NTWKIN, NTWKST, CNFTBL, SNDMSG, RCVMSG, NTWKER, NTWKBT, CFGTBL cseg ; Slave Configuration Table CFGTBL: ds 1 ; network status byte ds 1 ; slave processor ID number ds 2 ; A: Disk device +2 ds 2 ; B: " ds 2 ; C: " ds 2 ; D: " ds 2 ; E: " ds 2 ; F: " ds 2 ; G: " ds 2 ; H: " ds 2 ; I: " ds 2 ; J: " ds 2 ; K: " ds 2 ; L: " ds 2 ; M: " ds 2 ; N: " ds 2 ; O: " ds 2 ; P: " ds 2 ; console device +34 ds 2 ; list device: +36... ds 1 ; buffer index +2 db 0 ; FMT +3 db 0 ; DID +4 db 0ffh ; SID (CP/NOS must still initialize) db 5 ; FNC +6 db 0 ; SIZ +7 ds 1 ; MSG(0) List number +8 ds 128 ; MSG(1) ... MSG(128) +9... ioport: db 038h ; possibly configured here... ; Network Status Byte Equates ; active equ 0001$0000b ; slave logged in on network rcverr equ 0000$0010b ; error in received message senderr equ 0000$0001b ; unable to send message ; Utility Procedures ; ; Network Initialization NTWKIN: lxix CFGTBL mvi a,active stx a,+0 ; network status byte lda ioport mov c,a inr c ; status port xra a outp a dcr c inp a stx a,+1 ; our slave (client) ID xra a sta CFGTBL+36+7 ret ; Network Status NTWKST: lda CFGTBL+0 mov b,a ani not (rcverr+senderr) sta CFGTBL+0 mov a,b ret ; Return Configuration Table Address ; Still need this for BDOS func 69 CNFTBL: lxi h,CFGTBL ret ; Send Message on Network SNDMSG: ; BC = message addr mov h,b mov l,c ; HL = message address push h popix lda CFGTBL+1 stx a,+2 ; Set Slave ID in header lda ioport mov c,a mvi b,5 ; length of header outir ldx b,+4 ; msg siz field (-1) inr b ; might be 0, but that means 256 outir inr c ; status port inp a ; ani 02h ; cmd overrun rz mvi a,0ffh ret ; Receive Message from Network RCVMSG: ; BC = message addr mov h,b mov l,c ; HL = message address push h popix lda ioport mov c,a inr c ; status port rcvwait: inp a ani 01h ; data ready jz rcvwait dcr c ; data port mvi b,5 ; header length inir ; Could compare SLVID with "LDX r,1" and ignore messages. ; But this "hardware" is point-to-point (connection oriented) ; so the only messages we see are intended for us. ldx b,+4 ; msg siz inr b inir inr c ; status port inp a ani 04h ; rsp overrun rz mvi a,0ffh NTWKER: ret NTWKBT: ; NETWORK WARM START lda ioport mov c,a xra a ; Future hardware might expect data outp a inp a ; this is our Slave ID, but we already have it ret end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; Thread terminator for CP/M 3 I/O modules. cseg ;common memory dw 0 ;terminate thread end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееPRTMSG = Y PAGWID = 4F PAGLEN = 17 BACKSPC = N RUBOUT = Y BOOTDRV = A MEMTOP = FF BNKSWT = Y COMBAS = E0 LERROR = Y NUMSEGS = 03 MEMSEG00 = 00,80,00 MEMSEG01 = 00,C0,02 MEMSEG02 = 00,C0,03 MEMSEG03 = 00,C0,04 MEMSEG04 = 00,C0,05 MEMSEG05 = 00,C0,06 MEMSEG06 = 00,C0,07 MEMSEG07 = 00,C0,08 MEMSEG08 = 00,C0,09 MEMSEG09 = 00,C0,0A MEMSEG0A = 00,C0,0B MEMSEG0B = 00,C0,0C MEMSEG0C = 00,C0,0D MEMSEG0D = 00,C0,0E MEMSEG0E = 00,C0,0F MEMSEG0F = 00,C0,10 HASHDRVA = Y HASHDRVB = Y HASHDRVC = Y HASHDRVD = Y HASHDRVE = Y HASHDRVF = Y HASHDRVG = Y HASHDRVH = Y HASHDRVI = Y HASHDRVJ = Y HASHDRVK = Y HASHDRVL = Y HASHDRVM = Y HASHDRVN = Y HASHDRVO = Y HASHDRVP = Y ALTBNKSA = N ALTBNKSB = N ALTBNKSC = N ALTBNKSD = N ALTBNKSE = N ALTBNKSF = N ALTBNKSG = N ALTBNKSH = N ALTBNKSI = N ALTBNKSJ = N ALTBNKSK = N ALTBNKSL = N ALTBNKSM = N ALTBNKSN = N ALTBNKSO = N ALTBNKSP = N NDIRRECA = 01 NDIRRECB = 01 NDIRRECC = 01 NDIRRECD = 01 NDIRRECE = 01 NDIRRECF = 01 NDIRRECG = 01 NDIRRECH = 01 NDIRRECI = 01 NDIRRECJ = 01 NDIRRECK = 01 NDIRRECL = 01 NDIRRECM = 01 NDIRRECN = 01 NDIRRECO = 01 NDIRRECP = 01 NDTARECA = 01 NDTARECB = 01 NDTARECC = 01 NDTARECD = 01 NDTARECE = 01 NDTARECF = 01 NDTARECG = 01 NDTARECH = 01 NDTARECI = 01 NDTARECJ = 01 NDTARECK = 01 NDTARECL = 01 NDTARECM = 01 NDTARECN = 01 NDTARECO = 01 NDTARECP = 01 ODIRDRVA = A ODIRDRVB = A ODIRDRVC = A ODIRDRVD = A ODIRDRVE = A ODIRDRVF = A ODIRDRVG = A ODIRDRVH = A ODIRDRVI = A ODIRDRVJ = A ODIRDRVK = A ODIRDRVL = A ODIRDRVM = A ODIRDRVN = A ODIRDRVO = A ODIRDRVP = A ODTADRVA = A ODTADRVB = A ODTADRVC = A ODTADRVD = A ODTADRVE = A ODTADRVF = A ODTADRVG = A ODTADRVH = A ODTADRVI = A ODTADRVJ = A ODTADRVK = A ODTADRVL = A ODTADRVM = A ODTADRVN = A ODTADRVO = A ODTADRVP = A OVLYDIRA = Y OVLYDIRB = Y OVLYDIRC = Y OVLYDIRD = Y OVLYDIRE = Y OVLYDIRF = Y OVLYDIRG = Y OVLYDIRH = Y OVLYDIRI = Y OVLYDIRJ = Y OVLYDIRK = Y OVLYDIRL = Y OVLYDIRM = Y OVLYDIRN = Y OVLYDIRO = Y OVLYDIRP = Y OVLYDTAA = Y OVLYDTAB = Y OVLYDTAC = Y OVLYDTAD = Y OVLYDTAE = Y OVLYDTAF = Y OVLYDTAG = Y OVLYDTAH = Y OVLYDTAI = Y OVLYDTAJ = Y OVLYDTAK = Y OVLYDTAL = Y OVLYDTAM = Y OVLYDTAN = Y OVLYDTAO = Y OVLYDTAP = Y CRDATAF = N DBLALV = Y ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее; A version of CPNETSTS that minimizes output org 00100h jmp start l0103h: db 13,10,'CP/NET Status' db 13,10,'=============' db 13,10,'$' l012ch: db 'Requester ID = $' l013ch: db 13,10,'Network Status Byte = $' l0155h: db 13,10,'Device status:' db 13,10,'$' l016dh: db ' Drive $' l0176h: db ' = Drive $' l0180h: db ' on Network Server ID = $' l01a2h: db ' Console Device = $' l01b4h: db 'Console #$' l01ddh: db ' List Device = $' l01ech: db 'List #$' l01hhh: db ' All LOCAL$' l0212h: db 13,10,'CP/NET has not been loaded.$' start: lxi h,0 dad sp shld usrstk lxi sp,stack call getver mov a,h ani 02h jz nocpnt lxi b,l0103h ; Intro call msgout call getcfg shld nettbl lxi b,l012ch ; Req ID (client ID) call msgout lhld nettbl inx h mov c,m call hexout lxi b,l013ch ; Net Sts Byte call msgout call getsts mov c,a call hexout lxi b,l0155h ; Disk device status: call msgout xra a sta count sta curdrv drvlup: lda curdrv cpi 16 jnc trycon ; Done with drives A-P... mov l,a mvi h,0 dad h ; *2 - 2 bytes per drive inx h inx h ; +2 - 2 bytes before drives xchg lhld nettbl dad d mov a,m ani 080h jz locdrv ; drive is local... push h lda count ora a cnz crlf lxi h,count inr m lxi b,l016dh ; Drive... call msgout lda curdrv adi 'A' mov c,a call chrout mvi c,':' call chrout lxi b,l0176h ; = Drive... i.e. REMOTE call msgout pop h push h mov a,m ani 00fh ; remote drive number adi 'A' mov c,a call chrout mvi c,':' call chrout lxi b,l0180h ; on server... call msgout pop h inx h mov a,m ; server ID mov c,a call hexout locdrv: ; Drive is LOCAL... lxi h,curdrv inr m jmp drvlup trycon: lxi b,00022h lhld nettbl dad b mov a,m ani 080h jz trylst push h lda count ora a cnz crlf lxi h,count inr m lxi b,l01a2h ; Console Device = ... call msgout lxi b,l01b4h ; Console # call msgout pop h push h mov a,m call hexdig lxi b,l0180h ; on Network Server ID = call msgout pop h inx h mov a,m mov c,a call hexout trylst: lxi b,00024h lhld nettbl dad b mov a,m ani 080h jz done push h lda count ora a cnz crlf lxi h,count inr m lxi b,l01ddh ; List Device = call msgout lxi b,l01ech ; List # call msgout pop h push h mov a,m call hexdig lxi b,l0180h ; on Network Server ID = call msgout pop h inx h mov a,m mov c,a call hexout done: lda count ora a jnz exit lxi b,l01hhh call msgout jmp exit nocpnt: lxi b,l0212h ; CP/NET has not been loaded call msgout exit: lhld usrstk sphl ret chrout: mov e,c mvi c,002h call 00005h ret msgout: mov d,b mov e,c mvi c,009h call 00005h ret getver: mvi c,12 call 00005h ret getsts: mvi c,044h call 00005h ret getcfg: mvi c,045h call 00005h ret crlf: mvi c,13 call chrout mvi c,10 call chrout ret hexout: push b mov a,c rrc rrc rrc rrc call hexdig pop b mov a,c call hexdig mvi c,'H' call chrout ret hexdig: ani 0fh adi 90h daa aci 40h daa mov c,a jmp chrout ds 40 stack: ds 0 usrstk: dw 0 count: db 0 curdrv: db 0 nettbl: dw 0 end ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее5m512z10p2s40t1d2i1l0h