diff --git a/trunk/Apps/apps-bins/access.com b/trunk/Apps/apps-bins/access.com new file mode 100644 index 00000000..e91cb0ee Binary files /dev/null and b/trunk/Apps/apps-bins/access.com differ diff --git a/trunk/Apps/apps-bins/banker.com b/trunk/Apps/apps-bins/banker.com new file mode 100644 index 00000000..a697c5e6 Binary files /dev/null and b/trunk/Apps/apps-bins/banker.com differ diff --git a/trunk/Apps/apps-bins/chars.com b/trunk/Apps/apps-bins/chars.com new file mode 100644 index 00000000..ae60fa6b Binary files /dev/null and b/trunk/Apps/apps-bins/chars.com differ diff --git a/trunk/Apps/apps-bins/cls.com b/trunk/Apps/apps-bins/cls.com new file mode 100644 index 00000000..66132e66 Binary files /dev/null and b/trunk/Apps/apps-bins/cls.com differ diff --git a/trunk/Apps/apps-bins/cpmname.com b/trunk/Apps/apps-bins/cpmname.com new file mode 100644 index 00000000..cdbda3ca Binary files /dev/null and b/trunk/Apps/apps-bins/cpmname.com differ diff --git a/trunk/Apps/apps-bins/diskcopy.com b/trunk/Apps/apps-bins/diskcopy.com new file mode 100644 index 00000000..6436ee4b Binary files /dev/null and b/trunk/Apps/apps-bins/diskcopy.com differ diff --git a/trunk/Apps/apps-bins/findfile.com b/trunk/Apps/apps-bins/findfile.com new file mode 100644 index 00000000..b7b9d4b3 Binary files /dev/null and b/trunk/Apps/apps-bins/findfile.com differ diff --git a/trunk/Apps/apps-bins/label.com b/trunk/Apps/apps-bins/label.com new file mode 100644 index 00000000..606e57a8 Binary files /dev/null and b/trunk/Apps/apps-bins/label.com differ diff --git a/trunk/Apps/apps-bins/ls.com b/trunk/Apps/apps-bins/ls.com new file mode 100644 index 00000000..d3d5b417 Binary files /dev/null and b/trunk/Apps/apps-bins/ls.com differ diff --git a/trunk/Apps/apps-bins/map.com b/trunk/Apps/apps-bins/map.com new file mode 100644 index 00000000..3545f259 Binary files /dev/null and b/trunk/Apps/apps-bins/map.com differ diff --git a/trunk/Apps/apps-bins/meta.com b/trunk/Apps/apps-bins/meta.com new file mode 100644 index 00000000..f65eb4b4 Binary files /dev/null and b/trunk/Apps/apps-bins/meta.com differ diff --git a/trunk/Apps/apps-bins/multifmt.com b/trunk/Apps/apps-bins/multifmt.com new file mode 100644 index 00000000..7bf0a506 Binary files /dev/null and b/trunk/Apps/apps-bins/multifmt.com differ diff --git a/trunk/Apps/apps-bins/noaccess.com b/trunk/Apps/apps-bins/noaccess.com new file mode 100644 index 00000000..5c2d55ef Binary files /dev/null and b/trunk/Apps/apps-bins/noaccess.com differ diff --git a/trunk/Apps/apps-bins/rem.com b/trunk/Apps/apps-bins/rem.com new file mode 100644 index 00000000..a0546cb9 Binary files /dev/null and b/trunk/Apps/apps-bins/rem.com differ diff --git a/trunk/Apps/apps-bins/setlabel.com b/trunk/Apps/apps-bins/setlabel.com new file mode 100644 index 00000000..410e5cf5 Binary files /dev/null and b/trunk/Apps/apps-bins/setlabel.com differ diff --git a/trunk/Apps/apps-bins/stop.com b/trunk/Apps/apps-bins/stop.com new file mode 100644 index 00000000..dc5959f2 Binary files /dev/null and b/trunk/Apps/apps-bins/stop.com differ diff --git a/trunk/Apps/apps-bins/sysgen.com b/trunk/Apps/apps-bins/sysgen.com new file mode 100644 index 00000000..1c7ea1cb Binary files /dev/null and b/trunk/Apps/apps-bins/sysgen.com differ diff --git a/trunk/Apps/apps-bins/termtype.com b/trunk/Apps/apps-bins/termtype.com new file mode 100644 index 00000000..f7df8dd8 Binary files /dev/null and b/trunk/Apps/apps-bins/termtype.com differ diff --git a/trunk/Apps/apps-bins/view.com b/trunk/Apps/apps-bins/view.com new file mode 100644 index 00000000..74fb3053 Binary files /dev/null and b/trunk/Apps/apps-bins/view.com differ diff --git a/trunk/Apps/apps-srcs/sources.lbr b/trunk/Apps/apps-srcs/sources.lbr new file mode 100644 index 00000000..d8275f66 Binary files /dev/null and b/trunk/Apps/apps-srcs/sources.lbr differ diff --git a/trunk/Apps/core/access.com b/trunk/Apps/core/access.com new file mode 100644 index 00000000..7700ab6a Binary files /dev/null and b/trunk/Apps/core/access.com differ diff --git a/trunk/Apps/core/cpmname.com b/trunk/Apps/core/cpmname.com new file mode 100644 index 00000000..240a82bb Binary files /dev/null and b/trunk/Apps/core/cpmname.com differ diff --git a/trunk/Apps/core/findfile.com b/trunk/Apps/core/findfile.com new file mode 100644 index 00000000..0cd5b976 Binary files /dev/null and b/trunk/Apps/core/findfile.com differ diff --git a/trunk/Apps/core/map.com b/trunk/Apps/core/map.com new file mode 100644 index 00000000..46f5f4b7 Binary files /dev/null and b/trunk/Apps/core/map.com differ diff --git a/trunk/Apps/core/meta.com b/trunk/Apps/core/meta.com new file mode 100644 index 00000000..e66dd712 Binary files /dev/null and b/trunk/Apps/core/meta.com differ diff --git a/trunk/Apps/core/multifmt.com b/trunk/Apps/core/multifmt.com new file mode 100644 index 00000000..ccb19da7 Binary files /dev/null and b/trunk/Apps/core/multifmt.com differ diff --git a/trunk/Apps/core/noaccess.com b/trunk/Apps/core/noaccess.com new file mode 100644 index 00000000..383a22df Binary files /dev/null and b/trunk/Apps/core/noaccess.com differ diff --git a/trunk/Apps/core/rem.com b/trunk/Apps/core/rem.com new file mode 100644 index 00000000..a0546cb9 Binary files /dev/null and b/trunk/Apps/core/rem.com differ diff --git a/trunk/Apps/core/setlabel.com b/trunk/Apps/core/setlabel.com new file mode 100644 index 00000000..c3a3a967 Binary files /dev/null and b/trunk/Apps/core/setlabel.com differ diff --git a/trunk/Apps/core/sysgen.com b/trunk/Apps/core/sysgen.com new file mode 100644 index 00000000..35de2b79 Binary files /dev/null and b/trunk/Apps/core/sysgen.com differ diff --git a/trunk/Apps/core/termtype.com b/trunk/Apps/core/termtype.com new file mode 100644 index 00000000..de88a748 Binary files /dev/null and b/trunk/Apps/core/termtype.com differ diff --git a/trunk/Apps/core/view.com b/trunk/Apps/core/view.com new file mode 100644 index 00000000..e9ac2db8 Binary files /dev/null and b/trunk/Apps/core/view.com differ diff --git a/trunk/Apps/crossdev/APPLVERS.H b/trunk/Apps/crossdev/APPLVERS.H new file mode 100644 index 00000000..06d9aa5f --- /dev/null +++ b/trunk/Apps/crossdev/APPLVERS.H @@ -0,0 +1,20 @@ +/****************************/ +/* applvers.h dwg - 2.0.0.0 */ +/****************************/ + +#define A_RMJ 2 +#define A_RMN 0 +#define A_RUP 0 +#define A_RTP 0 + +#define A_MONTH 6 +#define A_DAY 10 +#define A_YEAR 2012 +#define A_YR 12 + +/********************/ +/* eof - applvers.h */ +/********************/ + + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/ASMIFACE.ASM b/trunk/Apps/crossdev/ASMIFACE.ASM new file mode 100644 index 00000000..fd84186c --- /dev/null +++ b/trunk/Apps/crossdev/ASMIFACE.ASM @@ -0,0 +1,67 @@ +; asmiface.asm 6/4/2012 dwg - + + extrn .begin,.chl,.swt + extrn csave,cret,.move + + global xrega_,1 + global xregbc_,2 + global xregde_,2 + global xreghl_,2 + + PUBLIC asmif_ +asmif_: lxi d,.2 + call csave + + LXI H,8-.2 ; pick up 1st parm "function address" + DAD SP + MOV E,M + INX H + MOV D,M + xchg + shld callad+1 + + LXI H,10-.2 + DAD SP + MOV E,M + INX H + MOV D,M ; DE = parm + xchg + shld xregbc_ + + LXI H,12-.2 + DAD SP + MOV E,M + INX H + MOV D,M + xchg + shld xregde_ + + LXI H,14-.2 + DAD SP + MOV E,M + INX H + MOV D,M + xchg + shld xreghl_ + + lhld xregbc_ + mov b,h + mov c,l ; setup B&C + lhld xregde_ + xchg ; setup D&E + lhld xreghl_ ; setup H&L + +callad: call 0e639h ; setlu + + sta xrega_ + shld xreghl_ + xchg + shld xregde_ + mov l,c + mov h,b + shld xregbc_ + RET ; HL has return value + +.2 EQU 0 + END + \ No newline at end of file diff --git a/trunk/Apps/crossdev/ASMIFACE.H b/trunk/Apps/crossdev/ASMIFACE.H new file mode 100644 index 00000000..5b39e406 --- /dev/null +++ b/trunk/Apps/crossdev/ASMIFACE.H @@ -0,0 +1,14 @@ +/*****************************/ +/* asmiface.H 6/4/2012 dwg - */ +/*****************************/ + + extern char xrega; + extern unsigned int xregbc; + extern unsigned int xregde; + extern unsigned int xreghl; + extern asmif(); /* asmif(0xe60,bc,de,hl); */ + +/********************/ +/* eof - asmiface.h */ +/********************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/BANNER.H b/trunk/Apps/crossdev/BANNER.H new file mode 100644 index 00000000..447ec6a3 --- /dev/null +++ b/trunk/Apps/crossdev/BANNER.H @@ -0,0 +1,4 @@ +/* banner.h */ +extern sbanner(); +extern banner(); + \ No newline at end of file diff --git a/trunk/Apps/crossdev/BDOSCALL.ASM b/trunk/Apps/crossdev/BDOSCALL.ASM new file mode 100644 index 00000000..07850d39 --- /dev/null +++ b/trunk/Apps/crossdev/BDOSCALL.ASM @@ -0,0 +1,71 @@ +; bdoscall.asm 3/10/2012 dwg - bdos binding for Aztec C + + global drega_,1 + global dregbc_,2 + global dregde_,2 + global dreghl_,2 + + PUBLIC lurst_ +lurst_: + + push b + push d + push h + push psw + + mvi c,37 + lxi d,127 + lxi b,127 + call 5 + + pop psw + pop h + pop d + pop b + + RET + + + PUBLIC bdoscall_ +bdoscall_: + + push b + push d + push h + push psw + + lhld dregbc_ + mov b,h + mov c,l + + lhld dregde_ + mov d,h + mov e,l + + lhld dreghl_ + + lda drega_ + + call 5 + + sta drega_ + + shld dreghl_ + + mov l,e + mov h,d + shld dregde_ + + mov l,c + mov h,b + shld dregbc_ + + pop psw + pop h + pop d + pop b + + RET + + END + \ No newline at end of file diff --git a/trunk/Apps/crossdev/BDOSCALL.H b/trunk/Apps/crossdev/BDOSCALL.H new file mode 100644 index 00000000..b816e90a --- /dev/null +++ b/trunk/Apps/crossdev/BDOSCALL.H @@ -0,0 +1,8 @@ +/* bdoscall.h 3/10/2012 dwg - header file for bdoscall */ + + extern char drega; + extern unsigned int dregbc; + extern unsigned int dregde; + extern unsigned int dreghl; + extern bdoscall(); + \ No newline at end of file diff --git a/trunk/Apps/crossdev/BIN/AS80.EXE b/trunk/Apps/crossdev/BIN/AS80.EXE new file mode 100644 index 00000000..66dd9ba0 Binary files /dev/null and b/trunk/Apps/crossdev/BIN/AS80.EXE differ diff --git a/trunk/Apps/crossdev/BIN/CCZ.EXE b/trunk/Apps/crossdev/BIN/CCZ.EXE new file mode 100644 index 00000000..4fdb418e Binary files /dev/null and b/trunk/Apps/crossdev/BIN/CCZ.EXE differ diff --git a/trunk/Apps/crossdev/BIN/HEX80.EXE b/trunk/Apps/crossdev/BIN/HEX80.EXE new file mode 100644 index 00000000..f1c2bf1a Binary files /dev/null and b/trunk/Apps/crossdev/BIN/HEX80.EXE differ diff --git a/trunk/Apps/crossdev/BIN/LIBUTIL.EXE b/trunk/Apps/crossdev/BIN/LIBUTIL.EXE new file mode 100644 index 00000000..57db8a9d Binary files /dev/null and b/trunk/Apps/crossdev/BIN/LIBUTIL.EXE differ diff --git a/trunk/Apps/crossdev/BIN/LN80.EXE b/trunk/Apps/crossdev/BIN/LN80.EXE new file mode 100644 index 00000000..2213e719 Binary files /dev/null and b/trunk/Apps/crossdev/BIN/LN80.EXE differ diff --git a/trunk/Apps/crossdev/BIN/MAKE.EXE b/trunk/Apps/crossdev/BIN/MAKE.EXE new file mode 100644 index 00000000..a541a8b3 Binary files /dev/null and b/trunk/Apps/crossdev/BIN/MAKE.EXE differ diff --git a/trunk/Apps/crossdev/BIOSCALL.ASM b/trunk/Apps/crossdev/BIOSCALL.ASM new file mode 100644 index 00000000..f3a501de --- /dev/null +++ b/trunk/Apps/crossdev/BIOSCALL.ASM @@ -0,0 +1,80 @@ +; bioscall.asm 3/10/2012 dwg - bios binding for Aztec C + + global irega_,1 + global iregbc_,2 + global iregde_,2 + global ireghl_,2 + + + public getmeta_ +getmeta_: + push psw + push b + push d + push h + + lxi b,4 + lxi d,0 + call 0e61bh + + lxi d,0 + call 0e61eh + + lxi d,11 + call 0e621h + + lxi d,80h + call 0e624h + + call 0e627h + + pop h + pop d + pop b + pop psw + ret + + PUBLIC bioscall_ +bioscall_: + + push b + push d + push h + push psw + + lhld iregbc_ + mov b,h + mov c,l + + lhld iregde_ + mov d,h + mov e,l + + lhld ireghl_ + shld mycall+1 + + lda irega_ + +mycall: call 5 + + sta irega_ + + shld ireghl_ + + mov l,e + mov h,d + shld iregde_ + + mov l,c + mov h,b + shld iregbc_ + + pop psw + pop h + pop d + pop b + + RET + + END + \ No newline at end of file diff --git a/trunk/Apps/crossdev/BIOSCALL.H b/trunk/Apps/crossdev/BIOSCALL.H new file mode 100644 index 00000000..a563b075 --- /dev/null +++ b/trunk/Apps/crossdev/BIOSCALL.H @@ -0,0 +1,8 @@ +/* bioscall.h 3/10/2012 dwg - header file for bdoscall */ + + extern char irega; + extern unsigned int iregbc; + extern unsigned int iregde; + extern unsigned int ireghl; + extern bioscall(); + \ No newline at end of file diff --git a/trunk/Apps/crossdev/C.LIB b/trunk/Apps/crossdev/C.LIB new file mode 100644 index 00000000..2ca5ab78 Binary files /dev/null and b/trunk/Apps/crossdev/C.LIB differ diff --git a/trunk/Apps/crossdev/CBANNER.C b/trunk/Apps/crossdev/CBANNER.C new file mode 100644 index 00000000..0735bee5 --- /dev/null +++ b/trunk/Apps/crossdev/CBANNER.C @@ -0,0 +1,41 @@ +/* cbanner.c 3/12/2012 dwg - */ + +#include "portab.h" +#include "globals.h" +#include "applvers.h" + +char * lines = "----------------------------------------"; +char * line1 = "12345678.123 mm/dd/yyyy Version x.x.x.x"; +char * line2 = "S/N CPM80-DWG-654321 Licensed under GPL3"; +char * line3 = "Copyright (C) 2011-12 Douglas W. Goodall"; + +sbanner(program) + char *program; +{ + char szTemp[128]; + + printf("%s ",program); + printf("%2d/%2d/%4d ",A_MONTH,A_DAY,A_YEAR); + printf("Version %d.%d.%d.%d ",A_RMJ,A_RMN,A_RUP,A_RTP); + printf("COPR Douglas Goodall Licensed w/GPLv3\n"); +} + +banner(program) + char *program; +{ + char szTemp[128]; + + printf("%s\n",lines); + strcpy(szTemp,program); + while(12 > strlen(szTemp)) { + strcat(szTemp," "); + } + printf("%s ",szTemp); + printf("%2d/%2d/%4d ",A_MONTH,A_DAY,A_YEAR); + printf("Version %d.%d.%d.%d\n",A_RMJ,A_RMN,A_RUP,A_RTP); + printf("%s\n",line2); + printf("%s\n",line3); + printf("%s\n",lines); +} + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CBANNER.H b/trunk/Apps/crossdev/CBANNER.H new file mode 100644 index 00000000..43c1908a --- /dev/null +++ b/trunk/Apps/crossdev/CBANNER.H @@ -0,0 +1 @@ +ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ \ No newline at end of file diff --git a/trunk/Apps/crossdev/CHARS.C b/trunk/Apps/crossdev/CHARS.C new file mode 100644 index 00000000..242fd5c4 --- /dev/null +++ b/trunk/Apps/crossdev/CHARS.C @@ -0,0 +1,133 @@ +/* chars.c 6/7/2012 dwg - test command line arguments */ + +#include "stdio.h" + +#include "portab.h" +#include "globals.h" +#include "std.h" +#include "cpm80.h" +#include "cpmappl.h" +#include "applvers.h" + +#define TOP 0 +#define LEFT 4 + +char map[256] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3 0 - 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4 A - O */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5 P - Z */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 6 a - o */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 7 p - z */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 8 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B 0 - 9 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C A - O */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D P - Z */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E a - o */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F p - z */ +}; + +char attroff[] = { 27, '[', 'm', 0 }; +char attrbold[] = { 27, '[', '1', 'm', 0 }; +char attrlow[] = { 27, '[', '2', 'm', 0 }; +char attrundr[] = { 27, '[', '4', 'm', 0 }; +char attrblnk[] = { 27, '[', '5', 'm', 0 }; +char attrrevs[] = { 27, '[', '7', 'm', 0 }; +char attrinvs[] = { 27, '[', '8', 'm', 0 }; +char graphon[] = { 27, 'F', 0 }; +char graphoff[] = { 27, 'G', 0 }; + + +char atreset[] = "0"; +char atbold[] = "1"; +char atdim[] = "2"; +char atundrscr[] = "4"; +char atblink[] = "5"; +char atrevs[] = "7"; +char athidden[] = "8"; + +char fgblack[] = "30"; +char fgred[] = "31"; +char fggreen[] = "32"; +char fgyellow[] = "33"; +char fgblue[] = "34"; +char fgmagenta[] = "35"; +char fgcyan[] = "36"; +char fgwhite[] = "37"; + +char bgblack[] = "40"; +char bgred[] = "41"; +char bggreen[] = "42"; +char bgyellow[] = "43"; +char bgblue[] = "44"; +char bgmagenta[] = "45"; +char bgcyan[] = "46"; +char bgwhite[] = "47"; + +dispattr(attr,fg,bg) + char * attr; + char * fg; + char * bg; +{ + printf("%c[%s;%s;%sm",27,attr,fg,bg); +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i,j,k; + int x,y; + + if(1 < argc) { + for(i=1;i>8; +} + +luscur(drive,lunum) +{ + asmif(pGETLU,drive,0,0); + /* A = Result 0=OK */ + /* B = devunit */ + /* DE = current */ + /* HL = numlu */ + + /* BC = devunit*256+drive */ + /* DE = current */ + /* HL = numlu */ + asmif(pSETLU,xregbc,lunum,xreghl); +} + +lusnum(drive,numlu) +{ + asmif(pGETLU,drive,0,0); + /* A = Result 0=OK */ + /* B = devunit */ + /* DE = current */ + /* HL = numlu */ + + /* BC = devunit*256+drive */ + /* DE = current */ + /* HL = numlu */ + asmif(pSETLU,xregbc,xregde,numlu); +} + + +/********************/ +/* eof - clogical.c */ +/********************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CLOGICAL.H b/trunk/Apps/crossdev/CLOGICAL.H new file mode 100644 index 00000000..37385b8e --- /dev/null +++ b/trunk/Apps/crossdev/CLOGICAL.H @@ -0,0 +1,18 @@ + +/*****************************/ +/* clogical.H 6/4/2012 dwg - */ +/*****************************/ + +#define METATRK 0 +#define METASEC 11 + +extern lugdu(); +extern lugcur(); +extern luscur(); +extern lugnum(); +extern lusnum(); + +/********************/ +/* eof - clogical.h */ +/********************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CMEMORY.C b/trunk/Apps/crossdev/CMEMORY.C new file mode 100644 index 00000000..ba33be0e --- /dev/null +++ b/trunk/Apps/crossdev/CMEMORY.C @@ -0,0 +1,53 @@ +/* cmemory.c 3/13/2012 dwg - */ + +#include "portab.h" +/* #include "cpmbind.h" */ + +memcmp(xptr,yptr,count) + u8 * xptr; + u8 * yptr; + int count; +{ + u8 * x; + u8 * y; + int i; + + x = xptr; + y = yptr; + for(i=0;icnfgdata"); + + printf("syscfg->jmp jp 0%04xh",syscfg->jmp.address); + pager(); + + printf("syscfg->cnfloc .dw 0%04xh",syscfg->cnfloc); + pager(); + + printf("syscfg->tstloc .dw 0%04xh",syscfg->tstloc); + pager(); + + printf("syscfg->varloc .dw 0%04xh",syscfg->varloc); + pager(); + + printf("%s.rmj = %d",cache,syscfg->cnfgdata.rmj); + pager(); + + printf("%s.rmn = %d",cache,syscfg->cnfgdata.rmn); + pager(); + + printf("%s.rup = %d",cache,syscfg->cnfgdata.rup); + pager(); + + printf("%s.rtp = %d",cache,syscfg->cnfgdata.rtp); + pager(); + + printf("%s.diskboot = ",cache); + switch(syscfg->cnfgdata.diskboot) { + case TRUE: printf("TRUE"); break; + case FALSE: printf("FALSE"); break; + } + pager(); + + printf("%s.devunit = 0x%02x",cache, + syscfg->cnfgdata.devunit); + pager(); + + printf("%s.bootlu = 0x%04x",cache, + syscfg->cnfgdata.bootlu); + pager(); + + printf("%s.freq = %dMHz",cache,syscfg->cnfgdata.freq); + pager(); + + printf("%s.platform = ",cache); + switch(syscfg->cnfgdata.platform) { + case PLT_N8VEM: printf("N8VEM"); break; + case PLT_ZETA: printf("ZETA"); break; + case PLT_N8: printf("N8"); break; + } + pager(); + + printf("%s.dioplat = ",cache); + switch(syscfg->cnfgdata.dioplat) { + case DPNONE: printf("DIOPLT_NONE"); break; + case DPDIO: printf("DIOPLT_DISKIO"); break; + case DPZETA: printf("DIOPLT_ZETA"); break; + case DPDIDE: printf("DIOPLT_DIDE"); break; + case DPN8: printf("DIOPLT_N8"); break; + case DPDIO3: printf("DIOPLT_DISKIO3"); break; + default: printf("Unknown"); break; + } + pager(); + + printf("%s.vdumode = ",cache); + switch(syscfg->cnfgdata.vdumode) { + case VPNONE: printf("VDUPLT_NONE"); break; + case VPVDU: printf("VDUPLT_VDU"); break; + case VPVDUC: printf("VDUPLT_VDUC"); break; + case VPPROPIO: printf("VDUPLT_PROPIO"); break; + case VPN8: printf("VDUPLT_VPN8"); break; + default: printf("Unknown!!"); break; + } + pager(); + + printf("%s.romsize = %d",cache, + syscfg->cnfgdata.romsize); + pager(); + + printf("%s.ramsize = %d",cache, + syscfg->cnfgdata.ramsize); + pager(); + +} + + +/********************/ +/* eof - cnamecp1.c */ +/********************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CNAMEPT2.C b/trunk/Apps/crossdev/CNAMEPT2.C new file mode 100644 index 00000000..fb76a21d --- /dev/null +++ b/trunk/Apps/crossdev/CNAMEPT2.C @@ -0,0 +1,113 @@ +/* cnamept2.c 5/24/2012 dwg - */ + +#include "stdio.h" +#include "stdlib.h" + +#include "portab.h" +#include "std.h" + +#include "cnfgdata.h" +#include "syscfg.h" + +extern pager(); + +char cache[17]; + +cnamept2(syscfg) + struct SYSCFG * syscfg; +{ + strcpy(cache,"syscfg->cnfgdata"); + + printf("%s.clrramdk = ",cache); + switch(syscfg->cnfgdata.clrramdk) { + case CLRNEV: printf("CLR_NEVER"); break; + case CLRAUTO: printf("CLR_AUTO"); break; + case CLRALLW: printf("CLR_ALLWAYS"); break; + } + pager(); + + printf("%s.dskyenable = ",cache); + switch(syscfg->cnfgdata.dskyenable) { + case TRUE: printf("TRUE"); break; + case FALSE: printf("FALSE"); break; + } + pager(); + + printf("%s.uartenable = ",cache); + switch(syscfg->cnfgdata.uartenable) { + case TRUE: printf("TRUE"); break; + case FALSE: printf("FALSE"); break; + } + pager(); + + printf("%s.vduenable = ",cache); + switch(syscfg->cnfgdata.vduenable) { + case TRUE: printf("TRUE"); break; + case FALSE: printf("FALSE"); break; + } + pager(); + + printf("%s.fdenable = ",cache); + switch(syscfg->cnfgdata.fdenable) { + case TRUE: printf("TRUE"); break; + case FALSE: printf("FALSE"); break; + } + pager(); + + if(TRUE == syscfg->cnfgdata.fdenable) { + + printf("%s.fdtrace = ",cache); + switch(syscfg->cnfgdata.fdtrace) { + case 0: printf("Silent"); break; + case 1: printf("Fatal Errors"); break; + case 2: printf("All Errors"); break; + case 3: printf("Everything"); break; + default: printf("Unknown!!"); break; + } + pager(); + + printf("%s.fdmedia = ",cache); + switch(syscfg->cnfgdata.fdmedia) { + case FDM720: printf("FDM720"); + printf(" 3.5 720KB 2-sided 80 Trks 9 Sectors"); + break; + case FDM144: printf("FDM144"); + printf(" 3.5 1.44MB 2-sided 80 Trks 18 Sectors"); + break; + case FDM360: printf("FDM360"); + printf(" 5.25 360KB 2-sided 40 Trks 9 Sectors"); + break; + case FDM120: printf("FDM120"); + printf(" 3.5 1.2MB 2-sided 80 Trks 15 Sectors"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + printf("%s.fdmediaalt = ",cache); + switch(syscfg->cnfgdata.fdmediaalt) { + case FDM720: printf("FDM720"); + printf(" 3.5 720KB 2-sided 80 Trks 9 Sectors"); + break; + case FDM144: printf("FDM144"); + printf(" 3.5 1.44MB 2-sided 80 Trks 18 Sectors"); + break; + case FDM360: printf("FDM360"); + printf(" 5.25 360KB 2-sided 40 Trks 9 Sectors"); + break; + case FDM120: printf("FDM120"); + printf(" 3.5 1.2MB 2-sided 80 Trks 15 Sectors"); + break; + } + pager(); + + } +} + + +/********************/ +/* eof - cnamept2.c */ +/********************/ + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CNAMEPT3.C b/trunk/Apps/crossdev/CNAMEPT3.C new file mode 100644 index 00000000..26284b2c --- /dev/null +++ b/trunk/Apps/crossdev/CNAMEPT3.C @@ -0,0 +1,216 @@ +/* cnamept2.c 5/24/2012 dwg - */ + +#include "stdio.h" +#include "stdlib.h" + +#include "portab.h" +#include "std.h" + +#include "cnfgdata.h" +#include "syscfg.h" + +extern pager(); + +char cache[17]; + +cnamept3(syscfg) + struct SYSCFG * syscfg; +{ + strcpy(cache,"syscfg->cnfgdata"); + + printf("%s.fdmauto = ",cache); + switch(syscfg->cnfgdata.fdmauto) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + } + pager(); + + printf("%s.ideenable = ",cache); + switch(syscfg->cnfgdata.ideenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + } + pager(); + + if(TRUE == syscfg->cnfgdata.ideenable) { + + printf("%s.idetrace = ",cache); + switch(syscfg->cnfgdata.idetrace) { + case 0: printf("SILENT"); + break; + case 1: printf("ERRORS"); + break; + case 2: printf("EVERYTHING"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + printf("%s.de8bit = ",cache); + switch(syscfg->cnfgdata.ide8bit) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + printf("%s.idecapacity = %dMB",cache, + syscfg->cnfgdata.idecapacity); + pager(); + + } + + printf("%s.ppideenable = ",cache); + switch(syscfg->cnfgdata.ppideenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + } + pager(); + + if(TRUE == syscfg->cnfgdata.ppideenable) { + + printf("%s.ppidetrace = ",cache); + switch(syscfg->cnfgdata.ppidetrace) { + case 0: printf("SILENT"); + break; + case 1: printf("ERRORS"); + break; + case 2: printf("EVERYTHING"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + + printf("%s.ppide8bit = ",cache); + switch(syscfg->cnfgdata.ppide8bit) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + printf("%s.ppidecapacity = %dKB",cache, + syscfg->cnfgdata.ppidecapacity); + pager(); + + printf("%s.ppideslow = ",cache); + switch(syscfg->cnfgdata.ppideslow) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + } + + printf("%s.boottype = ",cache); + switch(syscfg->cnfgdata.boottype) { + case BTMENU: printf("BT_MENU"); + break; + case BTAUTO: printf("BT_AUTO"); + break; + } + pager(); + + printf("%s.boottimeout = %d seconds",cache, + syscfg->cnfgdata.boottimeout); + pager(); + + printf("%s.bootdefault = %c:",cache, + syscfg->cnfgdata.bootdefault); + pager(); + + printf("%s.baudrate = %u (0x%04x) Baud",cache, + syscfg->cnfgdata.baudrate,syscfg->cnfgdata.baudrate); + pager(); + + if(PLT_N8 == syscfg->cnfgdata.platform) { + + printf("%s.ckdiv = %d",cache, + syscfg->cnfgdata.ckdiv); + pager(); + + printf("%s.memwait = 0x%02x",cache, + syscfg->cnfgdata.memwait); + pager(); + + printf("%s.iowait = 0x%02x",cache,syscfg->cnfgdata.iowait); + pager(); + + printf("%s.cntlb0 = 0x%02x",cache,syscfg->cnfgdata.cntlb0); + pager(); + + printf("%s.cntlb1 = 0x%02x",cache,syscfg->cnfgdata.cntlb1); + pager(); + + + printf("%s.sdenable = ",cache); + switch(syscfg->cnfgdata.sdenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + printf("%s.sdtrace = ",cache); + switch(syscfg->cnfgdata.sdtrace) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + } +} + + +/********************/ +/* eof - cnamept3.c */ +/********************/ + +/* + unsigned char ckdiv; + unsigned char memwait; + + unsigned char iowait; + unsigned char cntlb0; + unsigned char cntlb1; + unsigned char sdenable; + unsigned char sdtrace; + unsigned int sdcapacity; + unsigned char sdcsio; + unsigned char sdcsiofast; + unsigned char defiobyte; + unsigned char termtype; + unsigned int revision; + unsigned char prpsdenable; + unsigned char prpsdtrace; + unsigned int prpsdcapacity; + unsigned char prpconenable; + unsigned int biossize; +*/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CNAMEPT4.C b/trunk/Apps/crossdev/CNAMEPT4.C new file mode 100644 index 00000000..9e0b9e92 --- /dev/null +++ b/trunk/Apps/crossdev/CNAMEPT4.C @@ -0,0 +1,198 @@ +/* cnamept2.c 5/24/2012 dwg - */ + +#include "stdio.h" +#include "stdlib.h" + +#include "portab.h" +#include "std.h" + +#include "cnfgdata.h" +#include "syscfg.h" + +extern pager(); + +char cache[17]; + +cnamept4(syscfg) + struct SYSCFG * syscfg; +{ + strcpy(cache,"syscfg->cnfgdata"); + + if(PLT_N8 == syscfg->cnfgdata.platform) { + + printf("%s.sdcapacity = %uKB",cache, + syscfg->cnfgdata.sdcapacity); + pager(); + + + printf("%s.sdcsio = ",cache); + switch(syscfg->cnfgdata.sdcsio) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: + printf("Unknown!!"); + break; + } + pager(); + + printf("%s.sdcsiofast = ",cache); + switch(syscfg->cnfgdata.sdcsiofast) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + } + + printf("%s.defiobyte = 0x%02x",cache, + syscfg->cnfgdata.defiobyte); + pager(); + + printf("%s.termtype = ",cache); + switch(syscfg->cnfgdata.termtype) { + case TERM_TTY: printf("TERM_TTY"); + break; + case TERM_ANSI: printf("TERM_ANSI"); + break; + case TERM_WYSE: printf("TERM_WYSE"); + break; + case TERM_VT52: printf("TERM_VT52"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + printf("%s.revision = %d",cache, + syscfg->cnfgdata.revision); + pager(); + + printf("%s.prpenable = ",cache); + switch(syscfg->cnfgdata.prpenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + if(TRUE == syscfg->cnfgdata.prpenable) { + + printf("%s.prpsdenable = "); + switch(syscfg->cnfgdata.prpsdenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + if(TRUE == syscfg->cnfgdata.prpsdenable) { + + printf("%s.prpsdtrace = ",cache); + switch(syscfg->cnfgdata.prpsdtrace) { + case 0: printf("SILENT"); + break; + case 1: printf("ERRORS"); + break; + case 2: printf("EVERYTHING"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + printf("%s.prpsdcapacity = ",cache); + pager(); + + printf("%s.prpconenable = ",cache); + switch(syscfg->cnfgdata.prpconenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + } + + } + + printf("%s.biossize = %d",cache, + syscfg->cnfgdata.biossize); + pager(); + + + printf("%s.pppenable = ",cache); + switch(syscfg->cnfgdata.pppenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + if(TRUE == syscfg->cnfgdata.pppenable) { + + printf("%s.pppsdenable = ",cache); + switch(syscfg->cnfgdata.pppsdenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + printf("%s.pppsdtrace = ",cache); + switch(syscfg->cnfgdata.pppsdtrace) { + case 0: printf("SILENT"); + break; + case 1: printf("ERRORS"); + break; + case 2: printf("EVERYTHING"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + + printf("%s.pppcapacity = %d",cache, + syscfg->cnfgdata.prpsdcapacity); + pager(); + + printf("%s.pppconenable = ",cache); + switch(syscfg->cnfgdata.pppconenable) { + case TRUE: printf("TRUE"); + break; + case FALSE: printf("FALSE"); + break; + default: printf("Unknown!!"); + break; + } + pager(); + + } + +} + +/********************/ +/* eof - cnamept4.c */ +/********************/ + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CNFGDATA.H b/trunk/Apps/crossdev/CNFGDATA.H new file mode 100644 index 00000000..5b365015 --- /dev/null +++ b/trunk/Apps/crossdev/CNFGDATA.H @@ -0,0 +1,73 @@ +/* cnfgdata.h 6/04/2012 dwg - */ + +struct CNFGDATA { + unsigned char rmj; + unsigned char rmn; + unsigned char rup; + unsigned char rtp; + unsigned char diskboot; + unsigned char devunit; + unsigned int bootlu; + unsigned char hour; + unsigned char minute; + unsigned char second; + unsigned char month; + unsigned char day; + unsigned char year; + unsigned char freq; + unsigned char platform; + unsigned char dioplat; + unsigned char vdumode; + unsigned int romsize; + unsigned int ramsize; + unsigned char clrramdk; + unsigned char dskyenable; + unsigned char uartenable; + unsigned char vduenable; + unsigned char fdenable; + unsigned char fdtrace; + unsigned char fdmedia; + unsigned char fdmediaalt; + unsigned char fdmauto; + unsigned char ideenable; + unsigned char idetrace; + unsigned char ide8bit; + unsigned int idecapacity; + unsigned char ppideenable; + unsigned char ppidetrace; + unsigned char ppide8bit; + unsigned int ppidecapacity; + unsigned char ppideslow; + unsigned char boottype; + unsigned char boottimeout; + unsigned char bootdefault; + unsigned int baudrate; + unsigned char ckdiv; + unsigned char memwait; + unsigned char iowait; + unsigned char cntlb0; + unsigned char cntlb1; + unsigned char sdenable; + unsigned char sdtrace; + unsigned int sdcapacity; + unsigned char sdcsio; + unsigned char sdcsiofast; + unsigned char defiobyte; + unsigned char termtype; + unsigned int revision; + unsigned char prpsdenable; + unsigned char prpsdtrace; + unsigned int prpsdcapacity; + unsigned char prpconenable; + unsigned int biossize; + unsigned char pppenable; + unsigned char pppsdenable; + unsigned char pppsdtrace; + unsigned int pppsdcapacity; + unsigned char pppconenable; + unsigned char prpenable; +}; + +/********************/ +/* eof - cnfgdata.h */ +/********************/ \ No newline at end of file diff --git a/trunk/Apps/crossdev/CPM80.H b/trunk/Apps/crossdev/CPM80.H new file mode 100644 index 00000000..f7ed0bac --- /dev/null +++ b/trunk/Apps/crossdev/CPM80.H @@ -0,0 +1,196 @@ +/* cpmbios.h 3/11/2012 dwg - added CURDRV */ + +/*************************/ +/* BIOS Memory Locations */ +/*************************/ + +#define CURDRV 0x00004 +#define BIOSAD 0x0e600 + +#define pBOOT 0x0E600 +#define pWBOOT 0x0E603 +#define pCONST 0x0E606 +#define pCONIN 0x0E609 +#define pCONOUT 0x0E60C +#define pLIST 0x0E60F +#define pPUNCH 0x0E612 +#define pREADER 0x0E615 +#define pHOME 0x0E618 +#define pSELDSK 0x0E61B +#define pSETTRK 0x0E61E +#define pSETSEC 0x0E621 +#define pSETDMA 0x0E624 +#define pREAD 0x0E627 +#define pWRITE 0x0E62A +#define pLISTST 0x0E62D +#define pSECTRN 0x0E630 +#define pBNKSEL 0x0E633 +#define pGETLU 0x0E636 +#define pSETLU 0x0E639 +#define pGETINFO 0x0E63C + +struct JMP { + unsigned char opcode; + unsigned int address; +}; + +struct BIOS { + struct JMP boot; + struct JMP wboot; + struct JMP const; + struct JMP conin; + struct JMP conout; + struct JMP list; + struct JMP punch; + struct JMP reader; + struct JMP home; + struct JMP seldsk; + struct JMP settrk; + struct JMP setsec; + struct JMP setdma; + struct JMP read; + struct JMP write; + struct JMP listst; + struct JMP sectrn; + struct JMP bnksel; + struct JMP getlu; + struct JMP setlu; + struct JMP getinfo; + struct JMP rsvd1; + struct JMP rsvd2; + struct JMP rsvd3; + struct JMP rsvd4; + + char diskboot; + char bootdrive; + char devunit; + + char rmj; + char rmn; + char rup; + char rtp; +}; + + +struct DPH { + unsigned int xlt; + unsigned int rv1; + unsigned int rv2; + unsigned int rv3; + unsigned int dbf; + unsigned int dpb; + unsigned int csv; + unsigned int alv; + unsigned char sigl; + unsigned char sigu; + unsigned int current; + unsigned int number; +}; + +struct DPB { + unsigned int spt; + unsigned char bsh; + unsigned char blm; + unsigned char exm; + unsigned int dsm; + unsigned int drm; + unsigned char al0; + unsigned char al1; + unsigned int cks; + unsigned int off; +}; + +/* bioscall.h 3/10/2012 dwg - header file for bdoscall */ + + extern char irega; + extern unsigned int iregbc; + extern unsigned int iregde; + extern unsigned int ireghl; + extern bioscall(); + + +/* bdoscall.h 3/10/2012 dwg - header file for bdoscall */ + + extern char drega; + extern unsigned int dregbc; + extern unsigned int dregde; + extern unsigned int dreghl; + extern bdoscall(); + +/* diagnose.h 5/23/2012 dwg - */ + + extern char hrega; + extern unsigned int hregbc; + extern unsigned int hregde; + extern unsigned int hreghl; + +extern diagnose(); + +/* ctermcap.h 3/11/2012 dwg - declarations for termal capability */ + +extern crtinit(); +extern crtclr(); +extern crtlc(); + +/* cpmbdos.h */ +#define TERMCPM 0 +#define CONIN 1 +#define CWRITE 2 +#define DIRCONIO 6 +#define PRINTSTR 9 +#define RDCONBUF 10 +#define GETCONST 11 +#define RETVERNUM 12 +#define RESDISKSYS 13 +#define SELECTDISK 14 +#define FOPEN 15 +#define FCLOSE 16 +#define SEARCHFIRST 17 +#define SEARCHNEXT 18 +#define FDELETE 19 +#define FREADSEQ 20 +#define FWRITESEQ 21 +#define FMAKEFILE 22 +#define FRENAME 23 +#define RETLOGINVEC 24 +#define RETCURRDISK 25 +#define SETDMAADDR 26 +#define GETALLOCVEC 27 +#define WRPROTDISK 28 +#define GETROVECTOR 29 +#define FSETATTRIB 30 +#define GETDPBADDR 31 +#define SETGETUSER 32 +#define FREADRANDOM 33 +#define FWRITERAND 34 +#define FCOMPSIZE 35 +#define SETRANDREC 36 +#define RESETDRIVE 37 +#define WRRANDFILL 38 + +#define DRIVEA 0 + +/* dphmap.h 5/29/2012 dwg - declaration of DPH MAP structure */ + +struct DPHMAP { + struct DPH * drivea; + struct DPH * driveb; + struct DPH * drivec; + struct DPH * drived; + struct DPH * drivee; + struct DPH * drivef; + struct DPH * driveg; + struct DPH * driveh; +} * pDPHMAP; + +struct DPHMAP * pDPHVEC[MAXDRIVE]; + + +/******************/ +/* eof - dphmap.h */ +/******************/ + +/*****************/ +/* eof - cpm80.h */ +/*****************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CPM86/AME86.EXE b/trunk/Apps/crossdev/CPM86/AME86.EXE new file mode 100644 index 00000000..663b7bd5 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/AME86.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/AME86DOS.EXE b/trunk/Apps/crossdev/CPM86/AME86DOS.EXE new file mode 100644 index 00000000..99b32591 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/AME86DOS.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/ARCV.COM b/trunk/Apps/crossdev/CPM86/ARCV.COM new file mode 100644 index 00000000..2dccca48 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/ARCV.COM differ diff --git a/trunk/Apps/crossdev/CPM86/AS.EXE b/trunk/Apps/crossdev/CPM86/AS.EXE new file mode 100644 index 00000000..40e27101 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/AS.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/ASSERT.H b/trunk/Apps/crossdev/CPM86/ASSERT.H new file mode 100644 index 00000000..a03a1015 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/ASSERT.H @@ -0,0 +1,8 @@ +#ifndef NDEBUG +#ifndef stderr +#include +#endif +#define assert(x) if (!(x)) {fprintf(stderr,"Assertion failed: x, file %s, line %d\n",__FILE__,__LINE__); exit(1);} +#else +#define assert(x) +#endif diff --git a/trunk/Apps/crossdev/CPM86/C.LIB b/trunk/Apps/crossdev/CPM86/C.LIB new file mode 100644 index 00000000..5337a8b3 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/C.LIB differ diff --git a/trunk/Apps/crossdev/CPM86/CC.EXE b/trunk/Apps/crossdev/CPM86/CC.EXE new file mode 100644 index 00000000..b78e091b Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/CC.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/CCB.EXE b/trunk/Apps/crossdev/CPM86/CCB.EXE new file mode 100644 index 00000000..8f0b5a25 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/CCB.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/CNM.EXE b/trunk/Apps/crossdev/CPM86/CNM.EXE new file mode 100644 index 00000000..2bf71d82 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/CNM.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/CPM.EXE b/trunk/Apps/crossdev/CPM86/CPM.EXE new file mode 100644 index 00000000..df873a9f Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/CPM.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/CRC.EXE b/trunk/Apps/crossdev/CPM86/CRC.EXE new file mode 100644 index 00000000..f010c3e2 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/CRC.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/CTYPE.H b/trunk/Apps/crossdev/CPM86/CTYPE.H new file mode 100644 index 00000000..390ffb31 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/CTYPE.H @@ -0,0 +1,20 @@ +/* Copyright (C) 1984 by Manx Software Systems */ + +extern char ctp_[]; + +#define isalpha(x) (ctp_[(x)+1]&0x03) +#define isupper(x) (ctp_[(x)+1]&0x01) +#define islower(x) (ctp_[(x)+1]&0x02) +#define isdigit(x) (ctp_[(x)+1]&0x04) +#define isxdigit(x) (ctp_[(x)+1]&0x08) +#define isalnum(x) (ctp_[(x)+1]&0x07) +#define isspace(x) (ctp_[(x)+1]&0x10) +#define ispunct(x) (ctp_[(x)+1]&0x40) +#define iscntrl(x) (ctp_[(x)+1]&0x20) +#define isprint(x) (ctp_[(x)+1]&0xc7) +#define isgraph(x) (ctp_[(x)+1]&0x47) +#define isascii(x) (((x)&0x80)==0) + +#define toascii(x) ((x)&127) +#define _tolower(x) ((x)|0x20) +#define _toupper(x) ((x)&0x5f) diff --git a/trunk/Apps/crossdev/CPM86/D11.LIB b/trunk/Apps/crossdev/CPM86/D11.LIB new file mode 100644 index 00000000..a4e2fac7 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/D11.LIB differ diff --git a/trunk/Apps/crossdev/CPM86/D20.LIB b/trunk/Apps/crossdev/CPM86/D20.LIB new file mode 100644 index 00000000..bc64a01d Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/D20.LIB differ diff --git a/trunk/Apps/crossdev/CPM86/DIFF.EXE b/trunk/Apps/crossdev/CPM86/DIFF.EXE new file mode 100644 index 00000000..f25fb626 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/DIFF.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/DIOCTL.H b/trunk/Apps/crossdev/CPM86/DIOCTL.H new file mode 100644 index 00000000..092740d1 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/DIOCTL.H @@ -0,0 +1,26 @@ +/* Copyright (C) 1983 by Manx Software Systems */ + +#define TIOCGETP 0 /* read contents of tty control structure */ +#define TIOCSETP 1 /* set contents of tty control structure */ +#define TIOCSETN 1 /* ditto only don't wait for output to flush */ + +/* special codes for MSDOS 2.x only */ +#define TIOCREAD 2 /* read control info from device */ +#define TIOCWRITE 3 /* write control info to device */ +#define TIOCDREAD 4 /* same as 2 but for drives */ +#define TIOCDWRITE 5 /* same as 3 but for drives */ +#define GETISTATUS 6 /* get input status */ +#define GETOSTATUS 7 /* get output status */ + +struct sgttyb { + short sg_flags; /* control flags */ + char sg_erase; /* ignored */ + char sg_kill; /* ignored */ +}; + +/* settings for flags */ +#define RAW 0x20 /* no echo or mapping of input/output BDOS(6) */ + +/* Refer to the MSDOS technical reference for detailed information on + * the remaining flags. + */ diff --git a/trunk/Apps/crossdev/CPM86/ERRNO.H b/trunk/Apps/crossdev/CPM86/ERRNO.H new file mode 100644 index 00000000..2ab0591c --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/ERRNO.H @@ -0,0 +1,29 @@ +extern int errno; +extern char *sys_errlist[]; +extern int sys_nerr; + +/* MsDos return codes */ +#define EINVAL 1 +#define ENOENT 2 +#define ENOTDIR 3 +#define EMFILE 4 +#define EACCES 5 +#define EBADF 6 +#define EARENA 7 +#define ENOMEM 8 +#define EFAULT 9 +#define EINVENV 10 +#define EBADFMT 11 +#define EINVACC 12 +#define EINVDAT 13 +#define ENODEV 15 +#define ERMCD 16 +#define EXDEV 17 +#define ENOMORE 18 + +/* additional codes used by Aztec C */ +#define EEXIST 19 +#define ENOTTY 20 +/* used by the math library */ +#define ERANGE 21 +#define EDOM 22 diff --git a/trunk/Apps/crossdev/CPM86/FCNTL.H b/trunk/Apps/crossdev/CPM86/FCNTL.H new file mode 100644 index 00000000..e9d60acb --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/FCNTL.H @@ -0,0 +1,7 @@ +#define O_RDONLY 0 +#define O_WRONLY 1 +#define O_RDWR 2 +#define O_CREAT 0x0100 +#define O_TRUNC 0x0200 +#define O_EXCL 0x0400 +#define O_APPEND 0x0800 diff --git a/trunk/Apps/crossdev/CPM86/G.LIB b/trunk/Apps/crossdev/CPM86/G.LIB new file mode 100644 index 00000000..6c5fe3e0 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/G.LIB differ diff --git a/trunk/Apps/crossdev/CPM86/GRAPH.C b/trunk/Apps/crossdev/CPM86/GRAPH.C new file mode 100644 index 00000000..3f80a80e --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/GRAPH.C @@ -0,0 +1,16 @@ +main() +{ + char buffer[100]; + + /* set to 25 row x 80 column monochrome mode 6 (HIRES) */ + mode('H'); + printf("Please enter your name: "); + gets(buffer); + /* set to 25 row x 40 column 4-color mode 4 (MEDRES) */ + mode('M'); + printf("Hello %s!\nWelcome to the growing family of\nAZTEC C users...\n", + buffer); + getchar(); + /* set to 25 row x 80 column color text mode 3 (LOWRES) */ + mode('L'); +} diff --git a/trunk/Apps/crossdev/CPM86/GRAPH.EXE b/trunk/Apps/crossdev/CPM86/GRAPH.EXE new file mode 100644 index 00000000..eee18462 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/GRAPH.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/GRAPH.O b/trunk/Apps/crossdev/CPM86/GRAPH.O new file mode 100644 index 00000000..a247de10 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/GRAPH.O differ diff --git a/trunk/Apps/crossdev/CPM86/HELLO.C b/trunk/Apps/crossdev/CPM86/HELLO.C new file mode 100644 index 00000000..daab2005 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/HELLO.C @@ -0,0 +1,4 @@ +main() +{ + printf("Hello Woprd!!"); +} diff --git a/trunk/Apps/crossdev/CPM86/HELLO.CMD b/trunk/Apps/crossdev/CPM86/HELLO.CMD new file mode 100644 index 00000000..4444d964 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/HELLO.CMD differ diff --git a/trunk/Apps/crossdev/CPM86/HELLO.EXE b/trunk/Apps/crossdev/CPM86/HELLO.EXE new file mode 100644 index 00000000..58027d8f Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/HELLO.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/HELLO.O b/trunk/Apps/crossdev/CPM86/HELLO.O new file mode 100644 index 00000000..7529c4ec Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/HELLO.O differ diff --git a/trunk/Apps/crossdev/CPM86/HEX86.EXE b/trunk/Apps/crossdev/CPM86/HEX86.EXE new file mode 100644 index 00000000..84b75110 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/HEX86.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/IO.H b/trunk/Apps/crossdev/CPM86/IO.H new file mode 100644 index 00000000..d78d6a3c --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/IO.H @@ -0,0 +1,82 @@ +/* Copyright (C) 1982 by Manx Software Systems */ +/* + * if MAXCHAN is changed then the initialization of chantab in croot.c + * should be adjusted so that it initializes EXACTLY MAXCHAN elements of + * the array. If this is not done, the I/O library may exhibit + * strange behavior. + */ +#define MAXCHAN 11 /* maximum number of I/O channels */ + +/* + * argument to device routines. + * this is a typedef to allow future redeclaration to guarantee + * enough space to store either a pointer or an integer. + */ +typedef char *_arg; + +/* + * device control structure + */ +struct device { + char d_read; + char d_write; + char d_ioctl; /* used by character special devices (eg CON:) */ + char d_seek; /* used by random I/O devices (eg: a file) */ + int (*d_open)(); /* for special open handling */ +}; + +/* + * device table, contains names and pointers to device entries + */ +struct devtabl { + char *d_name; + struct device *d_dev; + _arg d_arg; +}; + +/* + * channel table: relates fd's to devices + */ +struct channel { + char c_read; + char c_write; + char c_ioctl; + char c_seek; + int (*c_close)(); + _arg c_arg; +} ; +extern struct channel chantab[MAXCHAN]; + +struct fcb { + char f_driv; + char f_name[8]; + char f_type[3]; + char f_ext; + char f_resv[2]; + char f_rc; + char f_sydx[16]; + char f_cr; + unsigned f_record; char f_overfl; +}; + +struct fcbtab { + struct fcb fcb; + char offset; + char flags; + char user; +}; + +#define OPNFIL 15 +#define CLSFIL 16 +#define DELFIL 19 +#define READSQ 20 +#define WRITSQ 21 +#define MAKFIL 22 +#define SETDMA 26 +#define GETUSR 32 +#define READRN 33 +#define WRITRN 34 +#define FILSIZ 35 +#define SETREC 36 + +#define Wrkbuf ((char *)0x80) diff --git a/trunk/Apps/crossdev/CPM86/LIBC.H b/trunk/Apps/crossdev/CPM86/LIBC.H new file mode 100644 index 00000000..1251d336 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/LIBC.H @@ -0,0 +1,41 @@ +/* Copyright (C) 1981, 1982 by Manx Software Systems */ + +extern int errno; +#define FLT_FAULT 0 /* vector for floating-point faults */ +extern int (*Sysvec[])(); + +#define NULL 0 +#define EOF -1 +#define BUFSIZ 1024 + +#define _BUSY 0x01 +#define _ALLBUF 0x02 +#define _DIRTY 0x04 +#define _EOF 0x08 +#define _IOERR 0x10 +#define _TEMP 0x20 /* temporary file (delete on close) */ + +typedef struct { + char *_bp; /* current position in buffer */ + char *_bend; /* last character in buffer + 1 */ + char *_buff; /* address of buffer */ + char _flags; /* open mode, etc. */ + char _unit; /* token returned by open */ + char _bytbuf; /* single byte buffer for unbuffer streams */ + int _buflen; /* length of buffer */ + char *_tmpname; /* name of file for temporaries */ +} FILE; + +extern FILE Cbuffs[]; +extern char *Stdbufs; /* free list of buffers */ +long ftell(); + +#define stdin (&Cbuffs[0]) +#define stdout (&Cbuffs[1]) +#define stderr (&Cbuffs[2]) +#define getchar() agetc(stdin) +#define putchar(c) aputc(c, stdout) +#define feof(fp) (((fp)->_flags&_EOF)!=0) +#define ferror(fp) (((fp)->_flags&_IOERR)!=0) +#define clearerr(fp) ((fp)->_flags &= ~(_IOERR|_EOF)) +#define fileno(fp) ((fp)->_unit) diff --git a/trunk/Apps/crossdev/CPM86/LMACROS.H b/trunk/Apps/crossdev/CPM86/LMACROS.H new file mode 100644 index 00000000..c3686de2 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/LMACROS.H @@ -0,0 +1,210 @@ + nlist +; Copyright (C) 1985 by Manx Software Systems, Inc. +; :ts=8 + ifndef MODEL +MODEL equ 0 + endif + if MODEL and 1 + largecode +FARPROC equ 1 +FPTRSIZE equ 4 + else +FPTRSIZE equ 2 + endif + if MODEL and 2 +LONGPTR equ 1 + endif + +;this macro to be used on returning +;restores bp and registers +pret macro +if havbp + pop bp +endif + ret + endm + +internal macro pname + public pname +pname proc + endm + +intrdef macro pname + public pname +ifdef FARPROC + pname label far +else + pname label near +endif + endm + +procdef macro pname, args + public pname&_ +ifdef FARPROC + _arg = 6 + pname&_ proc far +else + _arg = 4 + pname&_ proc near +endif +ifnb + push bp + mov bp,sp + havbp = 1 + decll +else + havbp = 0 +endif + endm + +entrdef macro pname, args + public pname&_ +ifdef FARPROC + _arg = 6 + pname&_: +else + _arg = 4 + pname&_: +endif +ifnb +if havbp + push bp + mov bp,sp +else + error must declare main proc with args, if entry has args +endif + decll +endif + endm + +;this macro equates 'aname' to arg on stack +decl macro aname, type +;;'byte' or anything else +havtyp = 0 +ifidn , + aname equ byte ptr _arg[bp] + _arg = _arg + 2 + havtyp = 1 +endif +ifidn , + aname equ dword ptr _arg[bp] + _arg = _arg + 4 + havtyp = 1 +endif +ifidn , + aname equ qword ptr _arg[bp] + _arg = _arg + 8 + havtyp = 1 +endif +ifidn , + ifdef LONGPTR + aname equ dword ptr _arg[bp] + _arg = _arg + 4 + else + aname equ word ptr _arg[bp] + _arg = _arg + 2 + endif + havtyp = 1 +endif +ifidn , + ifdef FARPROC + aname equ dword ptr _arg[bp] + _arg = _arg + 4 + else + aname equ word ptr _arg[bp] + _arg = _arg + 2 + endif + havtyp = 1 +endif +ifidn , + aname equ word ptr _arg[bp] + _arg = _arg + 2 + havtyp = 1 +endif +ife havtyp + error -- type is unknown. +endif + endm + +;this macro loads an arg pointer into DEST, with optional SEGment +ldptr macro dest, argname, seg +ifdef LONGPTR + ifnb ;;get segment if specified + ifidn , + les dest,argname + else + ifidn , + lds dest,argname + else + mov dest, word ptr argname + mov seg, word ptr argname[2] + endif + endif + else + ifidn , ;;si gets seg in ds + lds si, argname + else + ifidn , ;;or, es:di + les di, argname + else + garbage error: no seg for long pointer + endif + endif + endif +else + mov dest, word ptr argname ;;get the pointer +ENDIF + ENDM + +decll macro list + IRP i, + decl i + ENDM + ENDM + +pend macro pname +pname&_ endp + endm + +retptrm macro src,seg +mov ax, word ptr src +ifdef LONGPTR + mov dx, word ptr src+2 +endif + endm + +retptrr macro src,seg +mov ax,src +ifdef LONGPTR + ifnb + mov dx, seg + endif +endif + endm + +retnull macro +ifdef LONGPTR + sub dx,dx +endif + sub ax,ax + endm + +pushds macro + ifdef LONGPTR + push ds + endif + endm + +popds macro + ifdef LONGPTR + pop ds + endif + endm + +finish macro +codeseg ends + endm + + list +codeseg segment byte public 'code' + assume cs:codeseg diff --git a/trunk/Apps/crossdev/CPM86/LN.EXE b/trunk/Apps/crossdev/CPM86/LN.EXE new file mode 100644 index 00000000..a8a38c53 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/LN.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/M.LIB b/trunk/Apps/crossdev/CPM86/M.LIB new file mode 100644 index 00000000..776dafa6 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/M.LIB differ diff --git a/trunk/Apps/crossdev/CPM86/M87.LIB b/trunk/Apps/crossdev/CPM86/M87.LIB new file mode 100644 index 00000000..73c30bca Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/M87.LIB differ diff --git a/trunk/Apps/crossdev/CPM86/M87S.LIB b/trunk/Apps/crossdev/CPM86/M87S.LIB new file mode 100644 index 00000000..edb56309 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/M87S.LIB differ diff --git a/trunk/Apps/crossdev/CPM86/MAKE.EXE b/trunk/Apps/crossdev/CPM86/MAKE.EXE new file mode 100644 index 00000000..de7a09a5 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/MAKE.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/MAKEFILE b/trunk/Apps/crossdev/CPM86/MAKEFILE new file mode 100644 index 00000000..18140338 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/MAKEFILE @@ -0,0 +1,8 @@ + + +hello.cmd: hello.c + cc hello + ln -o hello.cmd hello.o -lc + +clean: + erase hello.cmd diff --git a/trunk/Apps/crossdev/CPM86/MAP.BAT b/trunk/Apps/crossdev/CPM86/MAP.BAT new file mode 100644 index 00000000..9b2a2117 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/MAP.BAT @@ -0,0 +1 @@ +z:mount i /Users/doug/Downloads/azcpm32d diff --git a/trunk/Apps/crossdev/CPM86/MATH.H b/trunk/Apps/crossdev/CPM86/MATH.H new file mode 100644 index 00000000..bc2ebd77 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/MATH.H @@ -0,0 +1,11 @@ +double sin(), cos(), tan(), cotan(); +double asin(), acos(), atan(), atan2(); +double ldexp(), frexp(), modf(); +double floor(), ceil(), fabs(); +double log(), log10(), exp(), sqrt(), pow(); +double sinh(), cosh(), tanh(); + +#define HUGE_VAL 1.79e+308 +#define LOGHUGE 709.778 +#define TINY_VAL 2.2e-308 +#define LOGTINY -708.396 diff --git a/trunk/Apps/crossdev/CPM86/MEMORY.H b/trunk/Apps/crossdev/CPM86/MEMORY.H new file mode 100644 index 00000000..85cc4c88 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/MEMORY.H @@ -0,0 +1,2 @@ +extern char *memcpy(), *memchr(), *memcpy(), memset(); +extern int memcmp(); diff --git a/trunk/Apps/crossdev/CPM86/OBD.EXE b/trunk/Apps/crossdev/CPM86/OBD.EXE new file mode 100644 index 00000000..95006b9d Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/OBD.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/ORD.EXE b/trunk/Apps/crossdev/CPM86/ORD.EXE new file mode 100644 index 00000000..939b095a Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/ORD.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/REGS.H b/trunk/Apps/crossdev/CPM86/REGS.H new file mode 100644 index 00000000..f7395c80 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/REGS.H @@ -0,0 +1,55 @@ +/* regs.h for aztec.c (C) Copyright Bill Buckels 2008. All rights reserved. */ + +#ifndef REGS_DEFINED + +/* word registers */ +/* different than M$oft so don't mix the two */ +struct WORDREGS { + unsigned int ax; + unsigned int bx; + unsigned int cx; + unsigned int dx; + unsigned int si; + unsigned int di; + unsigned int ds; + unsigned int es; + }; + +/* byte registers */ +/* I made these the same as M$oft since + the first 6 word regs are the same between the two */ +struct BYTEREGS { + unsigned char al, ah; + unsigned char bl, bh; + unsigned char cl, ch; + unsigned char dl, dh; + }; + +/* general purpose registers union - + * overlays the corresponding word and byte registers. + */ + +union REGS { + struct WORDREGS x; + struct BYTEREGS h; + }; + + +/* segment registers */ +/* different than M$oft so don't mix the two */ +struct SREGS { + unsigned int cs; + unsigned int ss; + unsigned int ds; + unsigned int es; + }; + + +/* the following makes it a little easier + to port code from M$soft and Turbo C + over to Aztec C unless you want to be + an Aztec C purist */ +#define int86(x,y,z) sysint(x,y,z) + +#define REGS_DEFINED 1 +#endif \ No newline at end of file diff --git a/trunk/Apps/crossdev/CPM86/S.LIB b/trunk/Apps/crossdev/CPM86/S.LIB new file mode 100644 index 00000000..36906898 Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/S.LIB differ diff --git a/trunk/Apps/crossdev/CPM86/SEARCH.H b/trunk/Apps/crossdev/CPM86/SEARCH.H new file mode 100644 index 00000000..a32fdf35 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/SEARCH.H @@ -0,0 +1,5 @@ +typedef int VISIT; +#define preorder 1 +#define postorder 2 +#define endorder 3 +#define leaf 4 diff --git a/trunk/Apps/crossdev/CPM86/SETJMP.H b/trunk/Apps/crossdev/CPM86/SETJMP.H new file mode 100644 index 00000000..0205583d --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/SETJMP.H @@ -0,0 +1,4 @@ +/* Copyright (C) 1983 by Manx Software Systems */ +#define JBUFSIZE (6*sizeof(int)) + +typedef char jmp_buf[JBUFSIZE]; diff --git a/trunk/Apps/crossdev/CPM86/SGTTY.H b/trunk/Apps/crossdev/CPM86/SGTTY.H new file mode 100644 index 00000000..a2a5cad3 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/SGTTY.H @@ -0,0 +1,19 @@ +/* Copyright (C) 1983 by Manx Software Systems */ + +#define TIOCGETP 0 /* read contents of tty control structure */ +#define TIOCSETP 1 /* set contents of tty control structure */ +#define TIOCSETN 1 /* ditto only don't wait for output to flush */ + +struct sgttyb { + char sg_erase; /* ignored */ + char sg_kill; /* ignored */ + short sg_flags; /* control flags */ +}; + +/* settings for flags */ +#define _VALID 0x3a +#define RAW 0x20 /* no echo or mapping of input/output BDOS(6) */ +#define CRMOD 0x10 /* map input CR to NL, output NL to CR LF */ +#define ECHO 0x08 /* ignored unless CBREAK is set */ +#define CBREAK 0x02 /* input using BDOS(1), unless echo off then */ + /* same as RAW */ diff --git a/trunk/Apps/crossdev/CPM86/SIGNAL.H b/trunk/Apps/crossdev/CPM86/SIGNAL.H new file mode 100644 index 00000000..2bea52f2 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/SIGNAL.H @@ -0,0 +1,15 @@ +/* Copyright (C) 1985 by Manx Software Systems, Inc. */ + +#define SIG_DFL ((void (*)())0) +#define SIG_IGN ((void (*)())1) +#define SIG_ERR ((void (*)())-1) + +#define SIGINT 1 +#define SIGTERM 2 +#define SIGABRT 3 +#define SIGFPE 4 +#define SIGILL 5 +#define SIGSEGV 6 + +#define _NUMSIG 6 +#define _FSTSIG 1 diff --git a/trunk/Apps/crossdev/CPM86/SQZ.EXE b/trunk/Apps/crossdev/CPM86/SQZ.EXE new file mode 100644 index 00000000..b4a27ffe Binary files /dev/null and b/trunk/Apps/crossdev/CPM86/SQZ.EXE differ diff --git a/trunk/Apps/crossdev/CPM86/STAT.H b/trunk/Apps/crossdev/CPM86/STAT.H new file mode 100644 index 00000000..5e10dbaf --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/STAT.H @@ -0,0 +1,29 @@ +/* Copyright (C) 1984 by Manx Software Systems */ + +struct stat { + char st_attr; + long st_mtime; + long st_size; +}; + +/* settings of the st_attr field */ +#define ST_RDONLY 0x01 /* read only file */ +#define ST_HIDDEN 0x02 /* hidden file */ +#define ST_SYSTEM 0x04 /* system file */ +#define ST_VLABEL 0x08 /* volume label */ +#define ST_DIRECT 0x10 /* file is a sub-directory */ +#define ST_ARCHIV 0x20 /* set when file has been written and closed */ + +/* the format of the st_mtime field is: + < year > < month> < day > < hours > < minutes > < sec/2 > + 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +where: + year is from 0-119 for 1980-2099 + month is 1-12 + day is 1-31 + hours is 0-23 + minutes is 0-59 + sec/2 is 0-29 +*/ diff --git a/trunk/Apps/crossdev/CPM86/STDIO.H b/trunk/Apps/crossdev/CPM86/STDIO.H new file mode 100644 index 00000000..aa5bec1e --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/STDIO.H @@ -0,0 +1,45 @@ +/* Copyright (C) 1982, 1984 by Manx Software Systems */ +#define fgetc getc +#define fputc putc +#define NULL (void *)0 +#define EOF -1 + + +#define BUFSIZ 1024 +#define MAXSTREAM 20 + +#define _BUSY 0x01 +#define _ALLBUF 0x02 +#define _DIRTY 0x04 +#define _EOF 0x08 +#define _IOERR 0x10 +#define _TEMP 0x20 /* temporary file (delete on close) */ + +typedef struct { + char *_bp; /* current position in buffer */ + char *_bend; /* last character in buffer + 1 */ + char *_buff; /* address of buffer */ + char _flags; /* open mode, etc. */ + char _unit; /* token returned by open */ + char _bytbuf; /* single byte buffer for unbuffer streams */ + int _buflen; /* length of buffer */ + char *_tmpname; /* name of file for temporaries */ +} FILE; + +extern FILE Cbuffs[]; +FILE *fopen(); +long ftell(); + +#define stdin (&Cbuffs[0]) +#define stdout (&Cbuffs[1]) +#define stderr (&Cbuffs[2]) +#define getchar() agetc(stdin) +#define putchar(c) aputc(c, stdout) +#define feof(fp) (((fp)->_flags&_EOF)!=0) +#define ferror(fp) (((fp)->_flags&_IOERR)!=0) +#define clearerr(fp) ((fp)->_flags &= ~(_IOERR|_EOF)) +#define fileno(fp) ((fp)->_unit) +#define fflush(fp) flsh_(fp,-1) + +#define P_tmpdir "" +#define L_tmpnam 40 diff --git a/trunk/Apps/crossdev/CPM86/TIME.H b/trunk/Apps/crossdev/CPM86/TIME.H new file mode 100644 index 00000000..07c73a42 --- /dev/null +++ b/trunk/Apps/crossdev/CPM86/TIME.H @@ -0,0 +1,22 @@ +/* Copyright (C) 1984, 1985 by Manx Software Systems */ + +#define CLK_TCK 100 +typedef long time_t; +typedef long clock_t; + +struct tm { + short tm_sec; + short tm_min; + short tm_hour; + short tm_mday; + short tm_mon; + short tm_year; + short tm_wday; + short tm_yday; + short tm_isdst; + short tm_hsec; +}; + +struct tm *gmtime(), *localtime(); +char *asctime(), *ctime(); +time_t time(); diff --git a/trunk/Apps/crossdev/CPMAPPL.H b/trunk/Apps/crossdev/CPMAPPL.H new file mode 100644 index 00000000..a68ac9f2 --- /dev/null +++ b/trunk/Apps/crossdev/CPMAPPL.H @@ -0,0 +1,8 @@ +/* cpmappl.h */ + +extern banner(); + +/*******************/ +/* eof - cpmappl.h */ +/*******************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CPMBDOS.H b/trunk/Apps/crossdev/CPMBDOS.H new file mode 100644 index 00000000..cc941b65 --- /dev/null +++ b/trunk/Apps/crossdev/CPMBDOS.H @@ -0,0 +1,53 @@ +/* cpmbdos.h 6/11/2012 dwg - */ + +#define TERMCPM 0 +#define CONIN 1 +#define CWRITE 2 +#define DIRCONIO 6 +#define PRINTSTR 9 +#define RDCONBUF 10 +#define GETCONST 11 +#define RETVERNUM 12 +#define RESDISKSYS 13 +#define SELECTDISK 14 +#define FOPEN 15 +#define FCLOSE 16 +#define SEARCHFIRST 17 +#define SEARCHNEXT 18 +#define FDELETE 19 +#define FREADSEQ 20 +#define FWRITESEQ 21 +#define FMAKEFILE 22 +#define FRENAME 23 +#define RETLOGINVEC 24 +#define RETCURRDISK 25 +#define SETDMAADDR 26 +#define GETALLOCVEC 27 +#define WRPROTDISK 28 +#define GETROVECTOR 29 +#define FSETATTRIB 30 +#define GETDPBADDR 31 +#define SETGETUSER 32 +#define FREADRANDOM 33 +#define FWRITERAND 34 +#define FCOMPSIZE 35 +#define SETRANDREC 36 +#define RESETDRIVE 37 +#define WRRANDFILL 38 + +#define BDOSDRA 1 +#define BDOSDRB 2 +#define BDOSDRC 3 +#define BDOSDRD 4 +#define BDOSDRE 5 +#define BDOSDRF 6 +#define BDOSDRG 7 +#define BDOSDRH 8 + +struct FCB { + char drive; + char filename[8]; + char filetype[3]; + char filler[24]; +}; + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CPMBIND.H b/trunk/Apps/crossdev/CPMBIND.H new file mode 100644 index 00000000..0a0dfcf7 --- /dev/null +++ b/trunk/Apps/crossdev/CPMBIND.H @@ -0,0 +1,682 @@ +/* cpmbind.h 5/21/2012 dwg - added b1f0peek and b1f0poke */ +/* cpmbind.h 3/16/2012 dgw - created */ + + +#define CR 0x0d +#define LF 0x0a +#define ESC 27 + +#define BIOSAD 0x0e600 +#define pTermType 0x0E679 + +/*************************/ +/* BIOS Memory Locations */ +/*************************/ + +#define CURDRV 0x00004 +#define BIOSAD 0x0e600 + +#define pBOOT 0x0E600 +#define pWBOOT 0x0E603 +#define pCONST 0x0E606 +#define pCONIN 0x0E609 +#define pCONOUT 0x0E60C +#define pLIST 0x0E60F +#define pPUNCH 0x0E612 +#define pREADER 0x0E615 +#define pHOME 0x0E618 +#define pSELDSK 0x0E61B +#define pSETTRK 0x0E61E +#define pSETSEC 0x0E621 +#define pSETDMA 0x0E624 +#define pREAD 0x0E627 +#define pWRITE 0x0E62A +#define pLISTST 0x0E62D +#define pSECTRN 0x0E630 +#define pBNKSEL 0x0E633 +#define pGETLU 0x0E636 +#define pSETLU 0x0E639 +#define pGETINFO 0x0E63C +#define pB1F0PEEK 0x0E63F +#define pB1F0POKE 0x0E642 + +/* + +struct JMP { + unsigned char opcode; + unsigned int address; +}; + +struct BIOS { + struct JMP boot; + struct JMP wboot; + struct JMP const; + struct JMP conin; + struct JMP conout; + struct JMP list; + struct JMP punch; + struct JMP reader; + struct JMP home; + struct JMP seldsk; + struct JMP settrk; + struct JMP setsec; + struct JMP setdma; + struct JMP read; + struct JMP write; + struct JMP listst; + struct JMP sectrn; + struct JMP bnksel; + struct JMP getlu; + struct JMP setlu; + struct JMP getinfo; + struct JMP b1f0peek; + struct JMP b1f0poke; + struct JMP res1; + struct JMP res2; + + char rmj; + char rmn; + char rup; + char rtp; + char diskboot; + char bootdrive; + char timedate[6]; + char cpufreq; + char platform; + char dioplat; + char vduplt; + unsigned int romsize; + unsigned int ramsize; + char clrramdisk; + char dskyenable; + char uartenable; + char vduenable; + char fdenable; + char fdtrace; + char fdmedia; + char fdmediaalt; + char fdmauto; + char ideenable; + char idetrace; + char ide8bit; + unsigned int idecapacity; + char ppideenable; + char ppidetrace; + char ppide8bit; + unsigned int ppidecapacity; + char ppideslow; + char boottype; + char boot_timeout; + char boot_default; + unsigned int baudrate; + char clkdiv; + char memwait; + char iowait; + char cntlb0; + char cntlb1; + char sdenable; + char sdtrace; + unsigned int sdcapacity; + char sdcsio; + char sdcsiofast; + char defiobyte; + char termtype; + unsigned int revision; + char prpsdenable; + char prpsdtrace; + char prpsdcapacity; + char prpconenable; + unsigned int biossize; +}; + +*/ + +/* + + +*/ + +/* bioscall.h 3/10/2012 dwg - header file for bdoscall */ + + extern char irega; + extern unsigned int iregbc; + extern unsigned int iregde; + extern unsigned int ireghl; + extern bioscall(); + + +/*********************/ +/* BDOS Declarations */ +/*********************/ + +#define TERMCPM 0 +#define CONIN 1 +#define CWRITE 2 +#define DIRCONIO 6 +#define PRINTSTR 9 +#define RDCONBUF 10 +#define GETCONST 11 +#define RETVERNUM 12 +#define RESDISKSYS 13 +#define SELECTDISK 14 +#define FOPEN 15 +#define FCLOSE 16 +#define SEARCHFIRST 17 +#define SEARCHNEXT 18 +#define FDELETE 19 +#define FREADSEQ 20 +#define FWRITESEQ 21 +#define FMAKEFILE 22 +#define FRENAME 23 +#define RETLOGINVEC 24 +#define RETCURRDISK 25 +#define SETDMAADDR 26 +#define GETALLOCVEC 27 +#define WRPROTDISK 28 +#define GETROVECTOR 29 +#define FSETATTRIB 30 +#define GETDPBADDR 31 +#define SETGETUSER 32 +#define FREADRANDOM 33 +#define FWRITERAND 34 +#define FCOMPSIZE 35 +#define SETRANDREC 36 +#define RESETDRIVE 37 +#define WRRANDFILL 38 + +#define DRIVEA 0 + +/* bdoscall.h 3/10/2012 dwg - header file for bdoscall */ + + extern char drega; + extern unsigned int dregbc; + extern unsigned int dregde; + extern unsigned int dreghl; + extern bdoscall(); + +/* std.h 3/11/2012 dwg - c version of std.asm */ + +#define TERM_TTY 0 +#define TERM_ANSI 1 +#define TERM_WYSE 2 +#define TERM_VT52 3 + +#define DEV_MD 0x00 +#define DEV_FD 0x10 +#define DEV_IDE 0x20 +#define DEV_ATAPI 0x30 +#define DEV_PPIDE 0x40 +#define DEV_SD 0x50 +#define DEV_PRPSD 0x60 + +#define PLT_N8VEM 1 +#define PLT_ZETA 2 +#define PLT_N8 3 + + +/* + + +; std.lib 2/21/2012 dwg - added TERM$VT52 + +; TRUE equ 1 +; FALSE equ 00 +; +; PRIMARY HARDWARE PLATFORMS +; PLT$N8VEM equ 1 ; N8VEM ECB Z80 SBC +; PLT$ZETA equ 2 ; ZETA Z80 SBC +; PLT$N8 equ 3 ; N8 (HOME COMPUTER) Z180 SBC +; +; BOOT STYLE +; BT$MENU equ 1 ; WAIT FOR MENU SELECTION AT LOADER PROMPT +; BT$AUTO equ 2 ; AUTO SELECT BOOT$DEFAULT AFTER BOOT$TIMEOUT +; +; VDU PLATFORM SELECTIONS +; +; +; VDUPLT$NONE equ 0 ; NO VDU +; VDUPLT$VDU equ 1 ; ORIGINAL ECB VDU (6545 CHIP) +; VDUPLT$VDUC equ 2 ; ECB VDU COLOR (PENDING HARDWARE DEVELOPMENT) +; VDUPLT$PROPIO equ 3 ; ECB PROPIO (NOT IMPLEMENTED) +; VDUPLT$N8 equ 4 ; N8 ONBOARD VIDEO SUBSYSTEM (NOT IMPLEMENTED) +; +; RAM DISK INITIALIZATION OPTIONS +; CLR$NEVER equ 0 ; NEVER CLEAR RAM DISK +; CLR$AUTO equ 1 ; CLEAR RAM DISK IF INVALID DIR ENTRIES +; CLR$ALWAYS equ 2 ; ALWAYS CLEAR RAM DISK +; +; +; ; DISK MAP SELECTION OPTIONS +; +; DM$ROM equ 1 ; ROM DRIVE PRIORITY +; DM$RAM equ 2 ; RAM DRIVE PRIORITY +; DM$FD equ 3 ; FLOPPY DRIVE PRIORITY +; DM$IDE equ 4 ; IDE DRIVE PRIORITY +; DM$PPIDE equ 5 ; PPIDE DRIVE PRIORITY +; DM$SD equ 6 ; SD DRIVE PRIORITY +; DM$PRPSD equ 7 ; PROPIO SD DRIVE PRIORITY +; +; +; ; FLOPPY DISK MEDIA SELECTIONS (ID'S MUST BE INDEX OF ENTRY IN FCD$TBL) +; +; +; FDM720 equ 0 ; 3.5" FLOPPY, 720KB, 2 SIDES, 80 TRKS, 9 SECTORS +; FDM144 equ 1 ; 3.5" FLOPPY, 1.44MB, 2 SIDES, 80 TRKS, 18 SECTORS +; FDM360 equ 2 ; 5.25" FLOPPY, 360KB, 2 SIDES, 40 TRKS, 9 SECTORS +; FDM120 equ 3 ; 3.5" FLOPPY, 1.2MB, 2 SIDES, 80 TRKS, 15 SECTORS +; +; +; ; DISK PLATFORM SELECTIONS +; +; DIOPLT$NONE equ 0 ; NO DISK IO HARDWARE +; DIOPLT$DISKIO equ 1 ; N8VEM ECB DISK IO BOARD +; DIOPLT$ZETA equ 2 ; ZETA BUILT-IN DISK IO SECTION +; DIOPLT$DIDE equ 3 ; N8VEM ECB DUAL IDE W/ FLOPPY BOARD +; DIOPLT$N8 equ 4 ; N8 BUILT-IN DISK IO SECTION +; DIOPLT$DISKIO3 equ 5 ; N8VEM ECB DISK IO V3 BOARD +; +; CONSOLE DEVICE CHOICES FOR LDRCON AND DBGCON IN CONFIG SETTINGS +; +; CON$UART equ 1 +; CON$VDU equ 2 +; CON$PRP equ 3 +; +; CONSOLE TERMINAL TYPE CHOICES +; +TERM$TTY equ 0 +TERM$ANSI equ 1 +TERM$WYSE equ 2 +TERM$VT52 equ 3 +; +; +; ; SYSTEM GENERATION SETTINGS +; +; SYS$CPM equ 1 ; CPM (IMPLIES BDOS + CCP) +; SYS$ZSYS equ 2 ; ZSYSTEM OS (IMPLIES ZSDOS + ZCPR) +; +; DOS$BDOS equ 1 ; BDOS +; DOS$ZDDOS equ 2 ; ZDDOS VARIANT OF ZSDOS +; DOS$ZSDOS equ 3 ; ZSDOS +; +; CP$CCP equ 1 ; CCP COMMAND PROCESSOR +; CP$ZCPR equ 2 ; ZCPR COMMAND PROCESSOR +; +; CONFIGURE DOS (DOS) AND COMMAND PROCESSOR (CP) BASED ON SYSTEM SETTING (SYS) +; +; +; #IFNDEF BLD$SYS +; SYS equ SYS$CPM +; #ELSE +; SYS equ BLD$SYS +; #ENDIF +; +; #IF (SYS == SYS$CPM) +; DOS equ DOS$BDOS +; CP equ CP$CCP +; #DEFINE OSLBL "CP/M-80 2.2C" +; #ENDIF +; +; #IF (SYS == SYS$ZSYS) +; DOS equ DOS$ZSDOS +; CP equ CP$ZCPR +; #DEFINE OSLBL "ZSYSTEM (ZSDOS 1.2, ZCPR 1.0)" +; #ENDIF +; +; +; ; INCLUDE VERSION AND BUILD SETTINGS +; +; #INCLUDE "ver.inc" ; ADD BIOSVER +; +; +; #INCLUDE "build.inc" ; INCLUDE USER CONFIG, ADD VARIANT, TIMESTAMP, & ROMSIZE +; +; +; #IF (PLATFORM NE PLT$N8) +; +; +; ; N8VEM HARDWARE IO PORT ADDRESSES AND MEMORY LOCATIONS +; MPCL$RAM equ 78H ; BASE IO ADDRESS OF RAM MEMORY PAGER CONFIGURATION LATCH +; MPCL$ROM equ 7CH ; BASE IO ADDRESS OF ROM MEMORY PAGER CONFIGURATION LATCH +; +; +; ; HARDWARE INTERFACES +; +; PIO 82C55 I/O IS DECODED TO PORT 60-67 +; PIOA equ 60H ; PORT A +; PIOB equ 61H ; PORT B +; PIOC equ 62H ; PORT C +; PIOX equ 63H ; PIO CONTROL PORT +; +; 16C550 SERIAL LINE UART +; +; SIO$BASE equ 68H +; SIO$RBR equ SIO$BASE + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY) +; SIO$THR equ SIO$BASE + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY) +; SIO$IER equ SIO$BASE + 1 ; DLAB=0: INT ENABLE REG +; SIO$IIR equ SIO$BASE + 2 ; INT IDENT REGISTER (READ ONLY) +; SIO$FCR equ SIO$BASE + 2 ; FIFO CONTROL REG (WRITE ONLY) +; SIO$LCR equ SIO$BASE + 3 ; LINE CONTROL REG +; SIO$MCR equ SIO$BASE + 4 ; MODEM CONTROL REG +; SIO$LSR equ SIO$BASE + 5 ; LINE STATUS REG +; SIO$MSR equ SIO$BASE + 6 ; MODEM STATUS REG +; SIO$SCR equ SIO$BASE + 7 ; SCRATCH REGISTER +; SIO$DLL equ SIO$BASE + 0 ; DLAB=1: DIVISOR LATCH (LS) +; SIO$DLM equ SIO$BASE + 1 ; DLAB=1: DIVISOR LATCH (MS) +; #ENDIF ; (PLATFORM NE PLT$N8) +; +; +; #IF (PLATFORM NE PLT$N8) +; +; +; ; Z180 REGISTERS +; +; +; CPU$IOBASE equ 40H ; ONLY RELEVANT FOR Z180 +; CPU$CNTLA0 equ CPU$IOBASE+$00 ;ASCI0 control A +; CPU$CNTLA1 equ CPU$IOBASE+$01 ;ASCI1 control A +; CPU$CNTLB0 equ CPU$IOBASE+$02 ;ASCI0 control B +; CPU$CNTLB1 equ CPU$IOBASE+$03 ;ASCI1 control B +; CPU$STAT0 equ CPU$IOBASE+$04 ;ASCI0 status +; CPU$STAT1 equ CPU$IOBASE+$05 ;ASCI1 status +; CPU$TDR0 equ CPU$IOBASE+$06 ;ASCI0 transmit +; CPU$TDR1 equ CPU$IOBASE+$07 ;ASCI1 transmit +; CPU$RDR0 equ CPU$IOBASE+$08 ;ASCI0 receive +; CPU$RDR1 equ CPU$IOBASE+$09 ;ASCI1 receive +; CPU$CNTR equ CPU$IOBASE+$0A ;CSI/O control +; CPU$TRDR equ CPU$IOBASE+$0B ;CSI/O transmit/receive +; CPU$TMDR0L equ CPU$IOBASE+$0C ;Timer 0 data lo +; CPU$TMDR0H equ CPU$IOBASE+$0D ;Timer 0 data hi +; CPU$RLDR0L equ CPU$IOBASE+$0E ;Timer 0 reload lo +; CPU$RLDR0H equ CPU$IOBASE+$0F ;Timer 0 reload hi +; CPU$TCR equ CPU$IOBASE+$10 ;Timer control +; CPU$ASEXT0 equ CPU$IOBASE+$12 ;ASCI0 extension control (Z8S180) +; CPU$ASEXT1 equ CPU$IOBASE+$13 ;ASCI1 extension control (Z8S180) +; CPU$TMDR1L equ CPU$IOBASE+$14 ;Timer 1 data lo +; CPU$TMDR1H equ CPU$IOBASE+$15 ;Timer 1 data hi +; CPU$RLDR1L equ CPU$IOBASE+$16 ;Timer 1 reload lo +; CPU$RLDR1H equ CPU$IOBASE+$17 ;Timer 1 reload hi +; CPU$FRC equ CPU$IOBASE+$18 ;Free running counter +; CPU$ASTC0L equ CPU$IOBASE+$1A ;ASCI0 Time constant lo (Z8S180) +; CPU$ASTC0H equ CPU$IOBASE+$1B ;ASCI0 Time constant hi (Z8S180) +; CPU$ASTC1L equ CPU$IOBASE+$1C ;ASCI1 Time constant lo (Z8S180) +; CPU$ASTC1H equ CPU$IOBASE+$1D ;ASCI1 Time constant hi (Z8S180) +; CPU$CMR equ CPU$IOBASE+$1E ;Clock multiplier (latest Z8S180) +; CPU$CCR equ CPU$IOBASE+$1F ;CPU control (Z8S180) +; CPU$SAR0L equ CPU$IOBASE+$20 ;DMA0 source addr lo +; CPU$SAR0H equ CPU$IOBASE+$21 ;DMA0 source addr hi +; CPU$SAR0B equ CPU$IOBASE+$22 ;DMA0 source addr bank +; CPU$DAR0L equ CPU$IOBASE+$23 ;DMA0 dest addr lo +; CPU$DAR0H equ CPU$IOBASE+$24 ;DMA0 dest addr hi +; CPU$DAR0B equ CPU$IOBASE+$25 ;DMA0 dest addr bank +; CPU$BCR0L equ CPU$IOBASE+$26 ;DMA0 byte count lo +; CPU$BCR0H equ CPU$IOBASE+$27 ;DMA0 byte count hi +; CPU$MAR1L equ CPU$IOBASE+$28 ;DMA1 memory addr lo +; CPU$MAR1H equ CPU$IOBASE+$29 ;DMA1 memory addr hi +; CPU$MAR1B equ CPU$IOBASE+$2A ;DMA1 memory addr bank +; CPU$IAR1L equ CPU$IOBASE+$2B ;DMA1 I/O addr lo +; CPU$IAR1H equ CPU$IOBASE+$2C ;DMA1 I/O addr hi +; CPU$IAR1B equ CPU$IOBASE+$2D ;DMA1 I/O addr bank (Z8S180) +; CPU$BCR1L equ CPU$IOBASE+$2E ;DMA1 byte count lo +; CPU$BCR1H equ CPU$IOBASE+$2F ;DMA1 byte count hi +; CPU$DSTAT equ CPU$IOBASE+$30 ;DMA status +; CPU$DMODE equ CPU$IOBASE+$31 ;DMA mode +; CPU$DCNTL equ CPU$IOBASE+$32 ;DMA/WAIT control +; CPU$IL equ CPU$IOBASE+$33 ;Interrupt vector load +; CPU$ITC equ CPU$IOBASE+$34 ;INT/TRAP control +; CPU$RCR equ CPU$IOBASE+$36 ;Refresh control +; CPU$CBR equ CPU$IOBASE+$38 ;MMU common base register +; CPU$BBR equ CPU$IOBASE+$39 ;MMU bank base register +; CPU$CBAR equ CPU$IOBASE+$3A ;MMU common/bank area register +; CPU$OMCR equ CPU$IOBASE+$3E ;Operation mode control +; CPU$ICR equ $3F ;I/O control register (not relocated) +; +; N8 ONBOARD I/O REGISTERS +; N8$IOBASE equ $80 +; PIO equ N8$IOBASE+$00 +; PIOA equ PIO+$00 ; PORT A +; PIOB equ PIO+$01 ; PORT B +; PIOC equ PIO+$02 ; PORT C +; PIOX equ PIO+$03 ; PIO CONTROL PORT +; PIO2 equ N8$IOBASE+$04 +; PIO2A equ PIO2+$00 ; PORT A +; PIO2B equ PIO2+$01 ; PORT B +; PIO2C equ PIO2+$02 ; PORT C +; PIO2X equ PIO2+$03 ; PIO CONTROL PORT +; +; RTC equ N8$IOBASE+$08 ;RTC latch and buffer +; FDC equ N8$IOBASE+$0C ;Floppy disk controller +; UTIL equ N8$IOBASE+$10 ;Floppy disk utility +; ACR equ N8$IOBASE+$14 ;auxillary control register +; RMAP equ N8$IOBASE+$16 ;ROM page register +; VDP equ N8$IOBASE+$18 ;Video Display Processor (TMS9918A) +; PSG equ N8$IOBASE+$1C ;Programmable Sound Generator (AY-3-8910) +; +; DEFACR equ $1B +; +; #ENDIF +; +; +; ; CHARACTER DEVICE FUNCTIONS +; +; +; CF$INIT equ 0 +; CF$IN equ 1 +; CF$IST equ 2 +; CF$OUT equ 3 +; CF$OST equ 4 +; +; DISK OPERATIONS +; DOP$READ equ 0 ; READ OPERATION +; DOP$WRITE equ 1 ; WRITE OPERATION +; DOP$FORMAT equ 2 ; FORMAT OPERATION +; DOP$READID equ 3 ; READ ID OPERATION +; +; DISK DRIVER FUNCTIONS +; DF$READY equ 1 +; DF$SELECT equ 2 +; DF$READ equ 3 +; DF$WRITE equ 4 +; DF$FORMAT equ 5 +; +; DISK DEVICES (ONLY FIRST NIBBLE RELEVANT, SECOND NIBBLE MUST BE ZERO) +; DEV$MD equ 000H +; DEV$FD equ 010H +; DEV$IDE equ 020H +; DEV$ATAPI equ 030H +; DEV$PPIDE equ 040H +; DEV$SD equ 050H +; DEV$PRPSD equ 060H +; +; IMG$START equ 00000H ; IMMUTABLE: ROM IMAGE AREA START +; IMG$END equ 08000H ; IMMUTABLE: ROM IMAGE AREA END +; +; PG0$LOC equ 00000H ; IMMUTABLE +; PG0$SIZ equ 00100H ; IMMUTABLE +; PG0$END equ PG0$LOC + PG0$SIZ +; PG0$IMG equ IMG$START ; IMMUTABLE +; LDR$LOC equ PG0$END +; LDR$SIZ equ 02000H - PG0$SIZ ; CONFIGURABLE +; LDR$END equ LDR$LOC + LDR$SIZ +; LDR$IMG equ PG0$IMG + PG0$SIZ +; CPM$LOC equ 0D000H ; CONFIGURABLE: LOCATION OF CPM FOR RUNNING SYSTEM +; CPM$END equ 10000H ; IMMUTABLE: TOP OF MEMORY +; CPM$SIZ equ CPM$END - CPM$LOC ; SIZE OF CPM IMAGE (CCP + BDOS + CBIOS (INCLUDING DATA)) +; CPM$ENT equ CPM$LOC + 01600H ; IMMUTABLE: CPM ENTRY POINT +; CPM$IMG equ LDR$IMG + LDR$SIZ ; START OF CONCATENATED CPM IMAGE +; DAT$SIZ equ DATASIZE ; FROM CONFIG FILE +; DAT$END equ CPM$END +; DAT$LOC equ DAT$END - DAT$SIZ +; BIOS$LOC equ CPM$ENT +; BIOS$END equ DAT$LOC +; BIOS$SIZ equ DAT$LOC - CPM$ENT +; MON$IMG equ CPM$IMG + CPM$SIZ ; LOCATION OF MONITOR BINARY IMAGE IN ROM +; MON$LOC equ 08000H ; LOCATION OF MONITOR FOR RUNNING SYSTEM +; MON$SIZ equ 01000H ; SIZE OF MONITOR BINARY IMAGE +; MON$END equ MON$LOC + MON$SIZ +; MON$DSKY equ MON$LOC ; MONITOR ENTRY (DSKY) +; MON$UART equ MON$LOC + 3 ; MONITOR ENTRY (UART) +; ROMX$LOC equ MON$IMG + MON$SIZ ; LOCATION OF ROM EXTENSION CODE +; +; +; ROMX$SIZ equ 02000H ; FIXED +; ROMX$END equ ROMX$LOC + ROMX$SIZ +; +; +; VDU$LOC equ ROMX$LOC + 0 ; LOCATION OF ROM VDU DRIVER +; +; +; CBIOS$BOOT equ BIOS$LOC + 0 +; CBIOS$WBOOT equ BIOS$LOC + 3 +; CBIOS$CONST equ BIOS$LOC + 6 +; CBIOS$CONIN equ BIOS$LOC + 9 +; CBIOS$CONOUT equ BIOS$LOC + 12 +; CBIOS$LIST equ BIOS$LOC + 15 +; CBIOS$PUNCH equ BIOS$LOC + 18 +; CBIOS$READER equ BIOS$LOC + 21 +; CBIOS$HOME equ BIOS$LOC + 24 +; CBIOS$SELDSK equ BIOS$LOC + 27 +; CBIOS$SETTRK equ BIOS$LOC + 30 +; CBIOS$SETSEC equ BIOS$LOC + 33 +; CBIOS$SETDMA equ BIOS$LOC + 36 +; CBIOS$READ equ BIOS$LOC + 39 +; CBIOS$WRITE equ BIOS$LOC + 42 +; CBIOS$LISTST equ BIOS$LOC + 45 +; CBIOS$SECTRN equ BIOS$LOC + 48 +; +; MEMORY CONFIGURATION +; +; MSIZE equ 59 ; CP/M VERSION MEMORY SIZE IN KILOBYTES +; +; "BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS +; ; THAN 16K (REFERRED TO AS "B" THROUGHOUT THE TEXT) +; +; BIAS equ (MSIZE-20)*1024 +; CCP equ 3400H+BIAS ; BASE OF CCP +; BDOS equ CCP+806H ; BASE OF BDOS +; BIOS equ CCP+1600H ; BASE OF BIOS +; CCPSIZ equ 00800H +; +; #IF (PLATFORM == PLT$N8VEM) +; +; +; ; #DEFINE PLATFORM$NAME "N8VEM Z80 SBC" +; +; +; ; #ENDIF +; +; +; ; #IF (PLATFORM == PLT$ZETA) +; ; #DEFINE PLATFORM$NAME "ZETA Z80 SBC" +; ; #ENDIF +; +; +; ; #IF (PLATFORM == PLT$N8) +; ; #DEFINE PLATFORM$NAME "N8 Z180 SBC" +; ; #ENDIF +; +; #IF (DSKYENABLE) +; ; #DEFINE DSKYLBL ", DSKY" +; ; #ELSE +; ; #DEFINE DSKYLBL "" +; ; #ENDIF +; +; #IF (VDUENABLE) +; #DEFINE VDULBL ", VDU" +; #ELSE +; #DEFINE VDULBL "" +; #ENDIF +; +; #IF (DIOPLT NE DIOPLT$NONE) +; +; +; #IF (DIOPLT EQ DIOPLT$DISKIO) +; #DEFINE DIOLBL ", DISKIO" +; #ENDIF +; +; +; #IF (DIOPLT EQ DIOPLT$ZETA) +; #DEFINE DIOLBL "" +; #ENDIF +; +; +; #IF (DIOPLT EQ DIOPLT$DIDE) +; #DEFINE DIOLBL ", DUALIDE" +; #ENDIF +; +; +; #IF (DIOPLT EQ DIOPLT$N8) +; #DEFINE DIOLBL "" +; #ENDIF +; +; #IF (DIOPLT EQ DIOPLT$DISKIO3) +; #DEFINE DIOLBL ", DISKIO-V3" +; #ENDIF +; +; #ELSE +; #DEFINE DIOLBL "" +; #ENDIF +; +; +; ; #ENDIF +; +; +; #IF (FDENABLE) +; #IF (FDMAUTO) +; #DEFINE FDLBL ", FLOPPY (AUTOSIZE)" +; #ELSE +; #IF (FDMEDIA == FDM720) +; #DEFINE FDLBL ", FLOPPY (720KB)" +; #ENDIF +; #IF (FDMEDIA == FDM144) +; #DEFINE FDLBL ", FLOPPY (1.44MB)" +; #ENDIF +; #ENDIF +; #ELSE +; #DEFINE FDLBL "" +; #ENDIF +; +; +; #IF (IDEENABLE) +; #DEFINE IDELBL ", IDE" +; #ELSE +; #DEFINE IDELBL "" +; #ENDIF +; +; +; #IF (PPIDEENABLE) +; #DEFINE PPIDELBL ", PPIDE" +; #ELSE +; #DEFINE PPIDELBL "" +; #ENDIF +; +; #IF (SDENABLE) +; #DEFINE SDLBL ", SD CARD" +; #ELSE +; #DEFINE SDLBL "" +; #ENDIF +; +; +; #IF (PRPSDENABLE) +; #DEFINE PRPSDLBL ", PROPIO SD CARD" +; #ELSE +; #DEFINE PRPSDLBL "" +; #ENDIF +; +; +; ; .ECHO "Configuration: " +; ; .ECHO PLATFORM$NAME +; ; .ECHO DSKYLBL +; ; .ECHO VDULBL +; ; .ECHO DIOLBL +; ; .ECHO FDLBL +; ; .ECHO IDELBL +; ; .ECHO PPIDELBL +; ; .ECHO SDLBL +; ; .ECHO PRPSDLBL +; ; .ECHO "\n" +; ; +; +; eof - std.lib + +*/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CPMBIOS.H b/trunk/Apps/crossdev/CPMBIOS.H new file mode 100644 index 00000000..9b4764fe --- /dev/null +++ b/trunk/Apps/crossdev/CPMBIOS.H @@ -0,0 +1,104 @@ +/* cpmbios.h 6/ 4/2012 dwg - added bootlu */ +/* cpmbios.h 3/11/2012 dwg - added CURDRV */ + +/*************************/ +/* BIOS Memory Locations */ +/*************************/ + +#define CURDRV 0x00004 +#define BIOSAD 0x0e600 + +#define pBOOT 0x0E600 +#define pWBOOT 0x0E603 +#define pCONST 0x0E606 +#define pCONIN 0x0E609 +#define pCONOUT 0x0E60C +#define pLIST 0x0E60F +#define pPUNCH 0x0E612 +#define pREADER 0x0E615 +#define pHOME 0x0E618 +#define pSELDSK 0x0E61B +#define pSETTRK 0x0E61E +#define pSETSEC 0x0E621 +#define pSETDMA 0x0E624 +#define pREAD 0x0E627 +#define pWRITE 0x0E62A +#define pLISTST 0x0E62D +#define pSECTRN 0x0E630 +#define pBNKSEL 0x0E633 +#define pGETLU 0x0E636 +#define pSETLU 0x0E639 +#define pGETINFO 0x0E63C + +struct JMP { + unsigned char opcode; + unsigned int address; +}; + +struct BIOS { + struct JMP boot; + struct JMP wboot; + struct JMP const; + struct JMP conin; + struct JMP conout; + struct JMP list; + struct JMP punch; + struct JMP reader; + struct JMP home; + struct JMP seldsk; + struct JMP settrk; + struct JMP setsec; + struct JMP setdma; + struct JMP read; + struct JMP write; + struct JMP listst; + struct JMP sectrn; + struct JMP bnksel; + struct JMP getlu; + struct JMP setlu; + struct JMP getinfo; + struct JMP rsvd1; + struct JMP rsvd2; + struct JMP rsvd3; + struct JMP rsvd4; + +/* char diskboot; + char bootdrive; + int bootlu; */ + + char rmj; + char rmn; + char rup; + char rtp; +}; + + +struct DPH { + unsigned int xlt; + unsigned int rv1; + unsigned int rv2; + unsigned int rv3; + unsigned int dbf; + unsigned int dpb; + unsigned int csv; + unsigned int alv; + unsigned char sigl; + unsigned char sigu; + unsigned int current; + unsigned int number; +}; + +struct DPB { + unsigned int spt; + unsigned char bsh; + unsigned char blm; + unsigned char exm; + unsigned int dsm; + unsigned int drm; + unsigned char al0; + unsigned char al1; + unsigned int cks; + unsigned int off; +}; + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CPMNAME.C b/trunk/Apps/crossdev/CPMNAME.C new file mode 100644 index 00000000..72b9d023 --- /dev/null +++ b/trunk/Apps/crossdev/CPMNAME.C @@ -0,0 +1,86 @@ +/* cpmname.c 5/21/2012 dwg - */ + +#include "stdio.h" +#include "stdlib.h" +#include "portab.h" +#include "memory.h" +#include "globals.h" +#include "cpmbind.h" +#include "applvers.h" +#include "infolist.h" +#include "cnfgdata.h" +#include "syscfg.h" +#include "diagnose.h" +#include "std.h" + + + +extern cnamept1(); +extern cnamept2(); +extern cnamept3(); +extern cnamept4(); + +struct SYSCFG * syscfg; +int line; + +int main(argc,argv) + int argc; + char *argv[]; +{ + + + char *p; + char c; + int i; + + char * pC; + + line = 5; + + printf("CPMNAME.COM %d/%d/%d v%d.%d.%d.%d", + A_MONTH,A_DAY,A_YEAR,A_RMJ,A_RMN,A_RUP,A_RTP); + printf(" dwg - Display System Configuration"); + pager(); + pager(); + + ireghl = pGETINFO; + bioscall(); + pINFOLIST = ireghl; + + printf("pINFOLIST->banptr ==> "); + + dregde = pINFOLIST->banptr; + dregbc = 9; + bdoscall(); + pager(); + + syscfg = 0x8000; + + hregbc = 0xf000; + hregde = syscfg; + diagnose(); + + cnamept1(syscfg); + cnamept2(syscfg); + cnamept3(syscfg); + cnamept4(syscfg); + +} + +pager() +{ + line++; + printf("\n"); + if(24 == line) { + printf(" press any key to continue"); + dregbc = 1; + bdoscall(); + line = 1; + } +} + +/********************/ +/* eof - ccpmname.c */ +/********************/ + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CTERMCAP.C b/trunk/Apps/crossdev/CTERMCAP.C new file mode 100644 index 00000000..ca1ffaf6 --- /dev/null +++ b/trunk/Apps/crossdev/CTERMCAP.C @@ -0,0 +1,94 @@ +/* ctermcap.c 3/11/2012 dwg - terminal capbility file */ + +#include "stdio.h" +#include "stdlib.h" +#include "cpmbind.h" +#include "applvers.h" +#include "cnfgdata.h" +#include "syscfg.h" +#include "diagnose.h" + +int tt; + +crtinit() +{ + struct SYSCFG * pSYSCFG; + hregbc = 0x0f000; + hregde = 0x0C000; + diagnose(); + pSYSCFG = 0x0C000; + tt = pSYSCFG->cnfgdata.termtype; +} + +crtclr() +{ + int i; + + switch(tt) { + case TERM_TTY: + for(i=0;i<43;i++) { + printf("%c%c",CR,LF); + } + break; + case TERM_ANSI: + printf("%c[2J",ESC); + break; + case TERM_WYSE: + printf("%c+",ESC); + break; + case TERM_VT52: + printf("%cJ%cH",ESC,ESC); + break; + }; +} + +crtlc(line,col) +int line; +int col; +{ + int i; + + switch(tt) { + case TERM_TTY: + break; + case TERM_ANSI: + printf("%c[%d;%d%c",ESC,line,col,0x66); + break; + case TERM_WYSE: + printf("%c+",ESC); + break; + case TERM_VT52: + printf("%cY%c%c",ESC,' '+line,' '+col); + break; + }; +} + + + + +/* + +SINGLEQUOTE equ 0 +RIGHTQUOTE equ 0 +LEFTQUOTE equ 0 + +wy50row db ' !"#$%&' + db 39 + db '()*+,-./01234567' + +wy50col db ' !"#$%&' + db 39 + db '()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_' + db 96 + db 'abcdefghijklmno' + +templine db 0 +tempcol db 0 + +*/ + + +/********************/ +/* eof - ctermcap.c */ +/********************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/CTERMCAP.H b/trunk/Apps/crossdev/CTERMCAP.H new file mode 100644 index 00000000..8cb4ad4e --- /dev/null +++ b/trunk/Apps/crossdev/CTERMCAP.H @@ -0,0 +1,6 @@ +/* ctermcap.h 3/11/2012 dwg - declarations for termal capability */ + +extern crtinit(); +extern crtclr(); +extern crtlc(); + \ No newline at end of file diff --git a/trunk/Apps/crossdev/DIAGNOSE.ASM b/trunk/Apps/crossdev/DIAGNOSE.ASM new file mode 100644 index 00000000..c0e31d94 --- /dev/null +++ b/trunk/Apps/crossdev/DIAGNOSE.ASM @@ -0,0 +1,47 @@ +; diagnose.asm 5/23/2012 dwg - diagnose binding for Aztec C + + global hrega_,1 + global hregbc_,2 + global hregde_,2 + global hreghl_,2 + + public diagnose_ +diagnose_: + push psw + push b + push d + push h + + lhld hregbc_ + mov b,h + mov c,l + + lhld hregde_ + mov d,h + mov e,l + + lhld hreghl_ + + lda hrega_ + + db 0cfh ; rst 8 + + sta hrega_ + shld hreghl_ + + mov l,e + mov h,d + shld hregde_ + + mov l,c + mov h,b + shld hregbc_ + + pop h + pop d + pop b + pop psw + + RET + + END diff --git a/trunk/Apps/crossdev/DIAGNOSE.H b/trunk/Apps/crossdev/DIAGNOSE.H new file mode 100644 index 00000000..5e7be558 --- /dev/null +++ b/trunk/Apps/crossdev/DIAGNOSE.H @@ -0,0 +1,12 @@ +/* diagnose.h 5/23/2012 dwg - */ + + extern char hrega; + extern unsigned int hregbc; + extern unsigned int hregde; + extern unsigned int hreghl; + +extern diagnose(); + +/********************/ +/* eof - diagnose.h */ +/********************/ \ No newline at end of file diff --git a/trunk/Apps/crossdev/DPHDPB.H b/trunk/Apps/crossdev/DPHDPB.H new file mode 100644 index 00000000..188427a9 --- /dev/null +++ b/trunk/Apps/crossdev/DPHDPB.H @@ -0,0 +1,32 @@ +/* dphdpb.h 6/10/2012 dwg - CP/M Disk Parameters */ + +struct DPB { + unsigned int spt; + unsigned char bsh; + unsigned char blm; + unsigned char exm; + unsigned int dsm; + unsigned int drm; + unsigned char al0; + unsigned char al1; + unsigned int cks; + unsigned int off; +}; + +struct DPH { + unsigned int xlt; + unsigned int rv1; + unsigned int rv2; + unsigned int rv3; + unsigned int dbf; + struct DPB * dpb; + void * csv; + void * alv; + /* extension */ + char sigl; + char sigu; + int current; + int number; +}; + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/DPHMAP.H b/trunk/Apps/crossdev/DPHMAP.H new file mode 100644 index 00000000..89c9a90c --- /dev/null +++ b/trunk/Apps/crossdev/DPHMAP.H @@ -0,0 +1,19 @@ +/* dphmap.h 5/29/2012 dwg - declaration of DPH MAP structure */ + +struct DPHMAP { + struct DPH * drivea; + struct DPH * driveb; + struct DPH * drivec; + struct DPH * drived; + struct DPH * drivee; + struct DPH * drivef; + struct DPH * driveg; + struct DPH * driveh; +} * pDPHMAP; + +struct DPHMAP * pDPHVEC[MAXDRIVE]; + + +/******************/ +/* eof - dphmap.h */ +/******************/ \ No newline at end of file diff --git a/trunk/Apps/crossdev/GLOBALS.H b/trunk/Apps/crossdev/GLOBALS.H new file mode 100644 index 00000000..672b4a07 --- /dev/null +++ b/trunk/Apps/crossdev/GLOBALS.H @@ -0,0 +1,17 @@ +/****************************************************************/ +/* globals.h 3/11/2012 dwg - add BIOS_ADDR */ +/* globals.h 3/11/2012 dwg - declarations common to all modules */ +/****************************************************************/ + +#define CR 0x0d +#define LF 0x0a +#define ESC 27 + +#define BIOSAD 0x0e600 +#define INFLSTV 1 + +#define MAXDRIVE 8 + +/*******************/ +/* eof - globals.h */ +/*******************/ \ No newline at end of file diff --git a/trunk/Apps/crossdev/INFOLIST.H b/trunk/Apps/crossdev/INFOLIST.H new file mode 100644 index 00000000..38ccd4e3 --- /dev/null +++ b/trunk/Apps/crossdev/INFOLIST.H @@ -0,0 +1,16 @@ +/* infolist.h 6/7/2012 dwg - BIOS Information Structure version 2 */ + +struct INFOLIST { + int version; + void * banptr; + void * varloc; + void * tstloc; + void * dpbmap; + void * dphmap; + void * ciomap; +} * pINFOLIST; + +/********************/ +/* eof - infolist.h */ +/********************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/LABEL.C b/trunk/Apps/crossdev/LABEL.C new file mode 100644 index 00000000..dc7e3cb2 --- /dev/null +++ b/trunk/Apps/crossdev/LABEL.C @@ -0,0 +1,124 @@ +/* label.c 67/10/2012 dwg - */ + +#include "stdio.h" +#include "cpmbios.h" +#include "bioscall.h" +#include "cpmbdos.h" +#include "bdoscall.h" +#include "metadata.h" +#include "banner.h" + +struct FCB * pPRIFCB; +struct FCB * pSECFCB; +struct DPH * pDPH; +struct DPB * pDPB; + +testdrive(drive) + int drive; +{ + ireghl = pSELDSK; + iregbc = drive; + bioscall(); + pDPH = ireghl; + pDPB = pDPH->dpb; + if(0 == pDPB->off) { + printf("Sorry Drive %c: has no prefix area and cannot be labeled", + drive+'A'); + exit(1); + } + +} + +interactive(drive) + int drive; +{ + int i; + + struct { + char size; + char len; + char data[16]; + } rdcons; + + testdrive(drive); + ireghl = pGETLU; + iregbc = drive; + bioscall(); + if(1 == irega) { + printf("interactive(%d) says drive %c: can't have label",drive,drive); + printf("%c",7); + exit(1); + + } + rdsector(drive,0,11,&metadata,0); + printf("Old label = "); + for(i=0;i<16;i++) { + printf("%c",metadata.label[i]); + } + + printf("\nNew label = "); + rdcons.size=16; + rdcons.len =0; + dregbc = RDCONBUF; + dregde = &rdcons; + bdoscall(); + + if(0 < rdcons.len) { + memset(metadata.label,' ',16); + memcpy(metadata.label,rdcons.data,rdcons.len); + wrsector(drive,0,11,&metadata,0); + } + +} + +noninteractive(drive,label) + int drive; + char * label; +{ + int i; + + testdrive(drive); + + rdsector(drive,0,11,&metadata,0); + memset(metadata.label,' ',16); + for(i=0;idrive-1); + exit(0); + } + } + break; + default: + noninteractive(pPRIFCB->drive-1,0x85); + break; + } + exit(0); +} + \ No newline at end of file diff --git a/trunk/Apps/crossdev/MAKE.BAT b/trunk/Apps/crossdev/MAKE.BAT new file mode 100644 index 00000000..171311dc --- /dev/null +++ b/trunk/Apps/crossdev/MAKE.BAT @@ -0,0 +1,4 @@ +set tmppath=%path% +set path=\bin +bin\make %1 +set path=%tmppath% diff --git a/trunk/Apps/crossdev/MAKEFILE b/trunk/Apps/crossdev/MAKEFILE new file mode 100644 index 00000000..df23fc28 --- /dev/null +++ b/trunk/Apps/crossdev/MAKEFILE @@ -0,0 +1,119 @@ +# makefile 6/13/2012 dwg - build Apps using Aztec C Cross Compiler for Z80 + +MODE = debug +#MODE = release + +CC = bin\ccz -D$(MODE) +FLAGS = -o $@ +AS = bin\as80 +LN = bin\ln80 +LNFLAGS = -o $@ + +CHARS = $(MODE)\chars.o +CPMNAME = $(MODE)\cpmname.o $(MODE)\cnamept1.o $(MODE)\cnamept2.o $(MODE)\cnamept3.o $(MODE)\cnamept4.o +LABEL = $(MODE)\label.o +MAP = $(MODE)\map.o +META = $(MODE)\meta.o +SYSGEN = $(MODE)\sysgen.o +TESTER = $(MODE)\tester.o +VIEW = $(MODE)\view.o +GENOBJS = $(MODE)\asmiface.o $(MODE)\cbanner.o $(MODE)\bdoscall.o $(MODE)\bioscall.o $(MODE)\clogical.o $(MODE)\cmemory.o $(MODE)\diagnose.o $(MODE)\sectorio.o $(MODE)\ctermcap.o c.lib + +.c.o: + $(CC) $(FLAGS) $< + +.asm.o: + $(AS) $(FLAGS) $< + +all: $(MODE)\tester.com $(MODE)\cpmname.com $(MODE)\chars.com \ + $(MODE)\sysgen.com $(MODE)\label.com $(MODE)\map.com \ + $(MODE)\meta.com $(MODE)\view.com + +$(MODE)\chars.com: $(CHARS) $(GENOBJS) + $(LN) $(LNFLAGS) -F &&! +$(CHARS) $(GENOBJS) +! + +$(MODE)\cpmname.com: $(CPMNAME) $(GENOBJS) + $(LN) $(LNFLAGS) -F &&! +$(CPMNAME) $(GENOBJS) +! + +$(MODE)\sysgen.com: $(SYSGEN) $(GENOBJS) + $(LN) $(LNFLAGS) -F &&! +$(SYSGEN) $(GENOBJS) +! + +$(MODE)\label.com: $(LABEL) $(GENOBJS) + $(LN) $(LNFLAGS) -F &&! +$(LABEL) $(GENOBJS) +! + +$(MODE)\map.com: $(MAP) $(GENOBJS) + $(LN) $(LNFLAGS) -F &&! +$(MAP) $(GENOBJS) +! + +$(MODE)\meta.com: $(META) $(GENOBJS) + $(LN) $(LNFLAGS) -F &&! +$(META) $(GENOBJS) +! + +$(MODE)\tester.com: $(TESTER) $(GENOBJS) + $(LN) $(LNFLAGS) -F &&! +$(TESTER) $(GENOBJS) +! + +$(MODE)\view.com: $(VIEW) $(GENOBJS) + $(LN) $(LNFLAGS) -F &&! +$(VIEW) $(GENOBJS) +! + +$(MODE)\asmiface.o: asmiface.asm + +$(MODE)\cbanner.o: cbanner.c + +$(MODE)\chars.o: chars.c + +$(MODE)\clogical.o: clogical.c + +$(MODE)\cmemory.o: cmemory.c + +$(MODE)\cpmname.o: cpmname.c + +$(MODE)\cnamept1.o: cnamept1.c + +$(MODE)\cnamept2.o: cnamept2.c + +$(MODE)\cnamept3.o: cnamept3.c + +$(MODE)\cnamept4.o: cnamept4.c + +$(MODE)\ctermcap.o: ctermcap.c + +$(MODE)\bdoscall.o: bdoscall.asm + +$(MODE)\bioscall.o: bioscall.asm + +$(MODE)\diagnose.o: diagnose.asm + +$(MODE)\label.o: label.c + +$(MODE)\map.o: map.c + +$(MODE)\meta.o: meta.c + +$(MODE)\sectorio.o: sectorio.c + +$(MODE)\sysgen.o: sysgen.c + +$(MODE)\tester.o: tester.c + +$(MODE)\view.o: view.c + +clean: + if exist cpmname.com erase cpmname.com + if exist *.bak erase *.bak + if exist *.o erase *.o + if exist debug\*.* erase debug\*.* + if exist release\*.* erase release\*.* diff --git a/trunk/Apps/crossdev/MAP.C b/trunk/Apps/crossdev/MAP.C new file mode 100644 index 00000000..48dfb65b --- /dev/null +++ b/trunk/Apps/crossdev/MAP.C @@ -0,0 +1,322 @@ +/* map.c 6/7/2012 dwg - */ + +#include "portab.h" +#include "globals.h" +#include "stdio.h" +#include "stdlib.h" +#include "memory.h" + +#include "cpmbind.h" + +#include "infolist.h" +#include "dphdpb.h" +#include "dphmap.h" +#include "metadata.h" +#include "clogical.h" +#include "applvers.h" + +#define MAXDRIVE 8 + +/* Drive List Geometry */ +#define COL1 0 +#define COL2 (80/4) +#define COL3 (80/2) +#define COL4 (COL2+COL3) +#define LINE 3 + +/* Logical Unit List Geometry */ +#define LGUT 5 +#define COL1A 0 +#define COL2A (80/3) +#define COL3A (2*COL2A) + +/* Nomenclature Geometry */ +#define LINE2 8 + +/* Misc Info Geometry */ +#define CDLINE 6 + +/* BDOS Function number */ +#define RETCURR 25 + +/* function defined in bdoscall.asm */ +extern lurst(); + +struct BIOS * pBIOS; + +struct DPH * pDPH; + +int devunit; +int dev; +int unit; +int currlu; +int numlu; +int drivenum; +int drive; +int deflu; + +char szTemp[128]; + +int readsec(drive,track,sector,buffer) + int drive; + int track; + int sector; + unsigned int buffer; +{ + ireghl = pSELDSK; + iregbc = drive; + iregde = 0; + bioscall(); + + ireghl = pSETTRK; + iregbc = track; + bioscall(); + + ireghl = pSETSEC; + iregbc = sector; + bioscall(); + + ireghl = pSETDMA; + iregbc = buffer; + bioscall(); + + ireghl = pREAD; + bioscall(); + return irega; +} + + + + +int haslu(dr) + int dr; +{ + if(0 < lugnum(dr)) { + return TRUE; + } else { + return FALSE; + } +} + + + +void dispdph(l,c,drive,ptr) + int l; + int c; + char drive; + struct DPH *ptr; +{ + +/* + unsigned int xlt; + unsigned int rv1; + unsigned int rv2; + unsigned int rv3; + unsigned int dbf; + unsigned int dpb; + unsigned int csv; + unsigned int alv; + unsigned char sigl; + unsigned char sigu; + unsigned int current; + unsigned int number; +*/ + crtlc(l,c); + printf("%c: ",drive); + + devunit = lugdu(drive-'A'); + dev = devunit & 0xf0; + unit = devunit & 0x0f; + + currlu = lugcur(drive-'A'); + switch(dev) { + case DEV_MD: + if(0 == unit) printf("ROM"); + if(1 == unit) printf("RAM"); + break; + case DEV_FD: + printf("FD%d",unit); + break; + case DEV_IDE: + printf("IDE%d",unit); + break; + case DEV_ATAPI: + printf("ATAPI%d",unit); + break; + case DEV_PPIDE: + printf("PPIDE%d",unit); + break; + case DEV_SD: + printf("SD%d",unit); + break; + case DEV_PRPSD: + printf("PRPSD%d",unit); + break; + default: + printf("UNK"); + break; + }; + + if('L' == (unsigned char)ptr->sigl) { + if('U' == (unsigned char)ptr->sigu) { +/* printf("-LU%d",(int)ptr->current); */ + printf("-LU%d",currlu); + } + } + +/* printf("dpb=0x%04x, ",(unsigned int)ptr->dpb); + printf("sigl=0x%02x, ",(unsigned char)ptr->sigl); + printf("sigu=0x%02x, ",(unsigned char)ptr->sigu); + printf("curr=0x%04x, ",(unsigned int)ptr->current); + printf("numb=0x%04x", (unsigned int)ptr->number); +*/ + +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int mylu; + int drivenum; + int column; + int line; + char szDrive[32]; + char szLuNum[32]; + + if(argc == 3) { + + strcpy(szDrive,argv[1]); + strcpy(szLuNum,argv[2]); + + mylu = atoi(szLuNum); + + if(strlen(szDrive) == 2) { + if(':' == szDrive[1]) { + switch(szDrive[0]) { + case 'a': + case 'A': + luscur(0,mylu); + break; + case 'b': + case 'B': + luscur(1,mylu); + break; + case 'c': + case 'C': + luscur(2,mylu); + break; + case 'd': + case 'D': + luscur(3,mylu); + break; + case 'e': + case 'E': + luscur(4,mylu); + break; + case 'f': + case 'F': + luscur(5,mylu); + break; + case 'g': + case 'G': + luscur(6,mylu); + break; + case 'h': + case 'H': + luscur(7,mylu); + break; + default: + break; + } + + } + } + exit(1); + } + + + pBIOS = BIOSAD; + + crtinit(); + crtclr(); + crtlc(0,0); + + printf("MAP.COM %d/%d/%d v%d.%d.%d.%d", + A_MONTH,A_DAY,A_YEAR,A_RMJ,A_RMN,A_RUP,A_RTP); + printf(" dwg - System Storage Drives and Logical Units"); + + ireghl = pGETINFO; + bioscall(); + pINFOLIST = ireghl; + + crtlc(CDLINE,COL3A+LGUT); + printf("infolist.version %d\n",pINFOLIST->version); + + pDPHMAP = (struct DPHMAPA *)pINFOLIST->dphmap; + + dispdph(LINE, COL1+LGUT-1,'A',(struct DPH *)pDPHMAP->drivea); + dispdph(LINE+1,COL1+LGUT-1,'B',(struct DPH *)pDPHMAP->driveb); + dispdph(LINE, COL2+LGUT-1,'C',(struct DPH *)pDPHMAP->drivec); + dispdph(LINE+1,COL2+LGUT-1,'D',(struct DPH *)pDPHMAP->drived); + dispdph(LINE, COL3+LGUT-1,'E',(struct DPH *)pDPHMAP->drivee); + dispdph(LINE+1,COL3+LGUT-1,'F',(struct DPH *)pDPHMAP->drivef); + dispdph(LINE, COL4+LGUT-1,'G',(struct DPH *)pDPHMAP->driveg); + dispdph(LINE+1,COL4+LGUT-1,'H',(struct DPH *)pDPHMAP->driveh); + + dregbc = RETCURR; + bdoscall(); + drive = drega; + + crtlc(CDLINE,5); + printf("Current drive is %c:",'A'+drive); + + devunit = lugdu(drive); + dev = devunit & 0xf0; + unit = devunit & 0x0f; + currlu = lugcur(drive); + deflu = currlu; + numlu = lugnum(drive); + + crtlc(CDLINE,COL2A+LGUT); + printf("Number of LUs is %d\n",lugnum(drive)); + + if(0dphmap; + pDPH = pDPHVEC[drive] + pDPB = pDPH->dpb; + if(0 < pDPB->off) { + return TRUE; + } else { + return FALSE; + } + +} + +int getmeta(drive,buffer) + int drive; + struct METADATA * buffer; +{ + if(TRUE == hasmeta(drive)) { + rdsector(drive,track,sector,buffer,0); + return SUCCESS; + } else { + return FAILURE; + } +} + +int putmeta(drive,buffer) + int drive; + struct METADATA * buffer; +{ + if(TRUE == hasmeta(drive)) { + wrsector(drive,track,sector,buffer,0); + return SUCCESS; + } else { + return FAILURE; + } +} + +/********************/ +/* eof - metadata.c */ +/********************/ + + + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/METADATA.H b/trunk/Apps/crossdev/METADATA.H new file mode 100644 index 00000000..b9e31328 --- /dev/null +++ b/trunk/Apps/crossdev/METADATA.H @@ -0,0 +1,69 @@ +/* + * metadata.h 3/12/2012 dwg - + * + */ + + +extern initmeta(); +extern getmeta(); +extern putmeta(); + +#define METATRACK 0 +#define METASECT 11 + + +/* + * This structure is the same as the metadata sector + * in RomWBW storage drives. (track 0 sector 11) + * + */ + +struct MD_TAG { + char sig5a; + char siga5; + + char platform; + char device; + char formatter[8]; + char drive; + char lu; + + char filler[128-34-12]; + /* ... */ + char prot; + int updates; + char rmj; + char rmn; + char rup; + char rtp; + char label[16]; + char term; + unsigned int infoloc; + unsigned int cpmloc; + unsigned int datend; + unsigned int cpment; +}; + +struct METADATA { + unsigned int signature; + unsigned char platform; + unsigned char device; + unsigned char formatter[8]; + unsigned char drive; + unsigned int logunit; + unsigned char unused[0x51]; + unsigned char writeprot; + unsigned int update; + unsigned char rmj; + unsigned char rmn; + unsigned char rup; + unsigned char rtp; + unsigned char label[16]; + unsigned char term; + unsigned int infloc; + unsigned int cpmloc; + unsigned int cpmend; + unsigned int cpment; +} metadata; + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/PORTAB.H b/trunk/Apps/crossdev/PORTAB.H new file mode 100644 index 00000000..381d3b3e --- /dev/null +++ b/trunk/Apps/crossdev/PORTAB.H @@ -0,0 +1,11 @@ +/* portab.h */ + +#define TRUE 1 +#define FALSE 0 + +#define u8 unsigned char +#define u16 unsigned int + +#define U8 unsigned char +#define U16 unsigned int + \ No newline at end of file diff --git a/trunk/Apps/crossdev/SECTORIO.C b/trunk/Apps/crossdev/SECTORIO.C new file mode 100644 index 00000000..9784d3ba --- /dev/null +++ b/trunk/Apps/crossdev/SECTORIO.C @@ -0,0 +1,71 @@ +/*************************************************************/ +/* sectorio.c 6/6/2012 dwg - read and write physical sectors */ +/*************************************************************/ + +#include "cpmbios.h" +#include "bioscall.h" + +int rdsector(drive,track,sector,buffer,select) + int drive; + int track; + int sector; + unsigned int buffer; + int select; +{ + ireghl = pSELDSK; + iregbc = drive; + iregde = select; + bioscall(); + + ireghl = pSETTRK; + iregbc = track; + bioscall(); + + ireghl = pSETSEC; + iregbc = sector; + bioscall(); + + ireghl = pSETDMA; + iregbc = buffer; + bioscall(); + + ireghl = pREAD; + bioscall(); + return irega; +} + + +int wrsector(drive,track,sector,buffer,select) + int drive; + int track; + int sector; + unsigned int buffer; + int select; +{ + ireghl = pSELDSK; + iregbc = drive; + iregde = select; + bioscall(); + + ireghl = pSETTRK; + iregbc = track; + bioscall(); + + ireghl = pSETSEC; + iregbc = sector; + bioscall(); + + ireghl = pSETDMA; + iregbc = buffer; + bioscall(); + + ireghl = pWRITE; + bioscall(); + return irega; +} + + +/********************/ +/* eof - sectorio.c */ +/********************/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/SECTORIO.H b/trunk/Apps/crossdev/SECTORIO.H new file mode 100644 index 00000000..6f3e4c21 --- /dev/null +++ b/trunk/Apps/crossdev/SECTORIO.H @@ -0,0 +1,14 @@ +/*************************************************************/ +/* sectorio.h 6/6/2012 dwg - read and write physical sectors */ +/*************************************************************/ + +rdsector(); /* int rdsector(drive,track,sector,buffer); */ +wrsector(); /* int wrsector(drive,track,sector,buffer); */ + +/********************/ +/* eof - sectorio.h */ +/********************/ + + + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/STD.H b/trunk/Apps/crossdev/STD.H new file mode 100644 index 00000000..453a6260 --- /dev/null +++ b/trunk/Apps/crossdev/STD.H @@ -0,0 +1,524 @@ +/* std.h 6/1/2012 dwg - c version of std.asm */ + +#define TERM_TTY 0 +#define TERM_ANSI 1 +#define TERM_WYSE 2 +#define TERM_VT52 3 + +#define DEV_MD 0x00 +#define DEV_FD 0x10 +#define DEV_IDE 0x20 +#define DEV_ATAPI 0x30 +#define DEV_PPIDE 0x40 +#define DEV_SD 0x50 +#define DEV_PRPSD 0x60 +#define DEV_PPPSD 0x70 + +#define PLT_N8VEM 1 +#define PLT_ZETA 2 +#define PLT_N8 3 + +#define DPNONE 0 +#define DPDIO 1 +#define DPZETA 2 +#define DPDIDE 3 +#define DPN8 4 +#define DPDIO3 5 + +#define VPNONE 0 /* NO VDU */ +#define VPVDU 1 /* ORIGINAL ECB VDU (6545 CHIP) */ +#define VPVDUC 2 /* ECB VDU COLOR (PENDING HARDWARE DEVELOPMENT) */ +#define VPPROPIO 3 /* ECB PROPIO (NOT IMPLEMENTED) */ +#define VPN8 4 /* N8 ONBOARD VIDEO SUBSYSTEM (NOT IMPLEMENTED) */ + +#define CLRNEV 0 /* never clear ram disk */ +#define CLRAUTO 1 /* clear if invalid dir entries */ +#define CLRALLW 2 /* always clear ram disk */ + +#define FDM720 0 /* 3.5" FLOPPY, 720KB, 2 SIDES, 80 TRKS, 9 SECTORS */ +#define FDM144 1 /* 3.5" FLOPPY, 1.44MB, 2 SIDES, 80 TRKS, 18 SECTORS */ +#define FDM360 2 /* 5.25" FLOPPY, 360KB, 2 SIDES, 40 TRKS, 9 SECTORS */ +#define FDM120 3 /* 3.5" FLOPPY, 1.2MB, 2 SIDES, 80 TRKS, 15 SECTORS */ + +#define BTMENU 1 +#define BTAUTO 2 + +/* +; BT$MENU equ 1 ; WAIT FOR MENU SELECTION AT LOADER PROMPT +; BT$AUTO equ 2 ; AUTO SELECT BOOT$DEFAULT AFTER BOOT$TIMEOUT +*/ + +/* +; DIOPLT$NONE equ 0 ; NO DISK IO HARDWARE +; DIOPLT$DISKIO equ 1 ; N8VEM ECB DISK IO BOARD +; DIOPLT$ZETA equ 2 ; ZETA BUILT-IN DISK IO SECTION +; DIOPLT$DIDE equ 3 ; N8VEM ECB DUAL IDE W/ FLOPPY BOARD +; DIOPLT$N8 equ 4 ; N8 BUILT-IN DISK IO SECTION +; DIOPLT$DISKIO3 equ 5 ; N8VEM ECB DISK IO V3 BOARD + + + +; std.lib 2/21/2012 dwg - added TERM$VT52 + +; TRUE equ 1 +; FALSE equ 00 +; +; PRIMARY HARDWARE PLATFORMS +; PLT$N8VEM equ 1 ; N8VEM ECB Z80 SBC +; PLT$ZETA equ 2 ; ZETA Z80 SBC +; PLT$N8 equ 3 ; N8 (HOME COMPUTER) Z180 SBC +; +; BOOT STYLE +; BT$MENU equ 1 ; WAIT FOR MENU SELECTION AT LOADER PROMPT +; BT$AUTO equ 2 ; AUTO SELECT BOOT$DEFAULT AFTER BOOT$TIMEOUT +; +; VDU PLATFORM SELECTIONS +; +; +; VDUPLT$NONE equ 0 ; NO VDU +; VDUPLT$VDU equ 1 ; ORIGINAL ECB VDU (6545 CHIP) +; VDUPLT$VDUC equ 2 ; ECB VDU COLOR (PENDING HARDWARE DEVELOPMENT) +; VDUPLT$PROPIO equ 3 ; ECB PROPIO (NOT IMPLEMENTED) +; VDUPLT$N8 equ 4 ; N8 ONBOARD VIDEO SUBSYSTEM (NOT IMPLEMENTED) +; + +; RAM DISK INITIALIZATION OPTIONS +; CLR$NEVER equ 0 ; NEVER CLEAR RAM DISK +; CLR$AUTO equ 1 ; CLEAR RAM DISK IF INVALID DIR ENTRIES +; CLR$ALWAYS equ 2 ; ALWAYS CLEAR RAM DISK +; +; +; ; DISK MAP SELECTION OPTIONS +; +; DM$ROM equ 1 ; ROM DRIVE PRIORITY +; DM$RAM equ 2 ; RAM DRIVE PRIORITY +; DM$FD equ 3 ; FLOPPY DRIVE PRIORITY +; DM$IDE equ 4 ; IDE DRIVE PRIORITY +; DM$PPIDE equ 5 ; PPIDE DRIVE PRIORITY +; DM$SD equ 6 ; SD DRIVE PRIORITY +; DM$PRPSD equ 7 ; PROPIO SD DRIVE PRIORITY +; +; +; ; FLOPPY DISK MEDIA SELECTIONS (ID'S MUST BE INDEX OF ENTRY IN FCD$TBL) +; +; +; FDM720 equ 0 ; 3.5" FLOPPY, 720KB, 2 SIDES, 80 TRKS, 9 SECTORS +; FDM144 equ 1 ; 3.5" FLOPPY, 1.44MB, 2 SIDES, 80 TRKS, 18 SECTORS +; FDM360 equ 2 ; 5.25" FLOPPY, 360KB, 2 SIDES, 40 TRKS, 9 SECTORS +; FDM120 equ 3 ; 3.5" FLOPPY, 1.2MB, 2 SIDES, 80 TRKS, 15 SECTORS +; +; +; ; DISK PLATFORM SELECTIONS +; +; DIOPLT$NONE equ 0 ; NO DISK IO HARDWARE +; DIOPLT$DISKIO equ 1 ; N8VEM ECB DISK IO BOARD +; DIOPLT$ZETA equ 2 ; ZETA BUILT-IN DISK IO SECTION +; DIOPLT$DIDE equ 3 ; N8VEM ECB DUAL IDE W/ FLOPPY BOARD +; DIOPLT$N8 equ 4 ; N8 BUILT-IN DISK IO SECTION +; DIOPLT$DISKIO3 equ 5 ; N8VEM ECB DISK IO V3 BOARD +; +; CONSOLE DEVICE CHOICES FOR LDRCON AND DBGCON IN CONFIG SETTINGS +; +; CON$UART equ 1 +; CON$VDU equ 2 +; CON$PRP equ 3 +; +; CONSOLE TERMINAL TYPE CHOICES +; +TERM$TTY equ 0 +TERM$ANSI equ 1 +TERM$WYSE equ 2 +TERM$VT52 equ 3 +; +; +; ; SYSTEM GENERATION SETTINGS +; +; SYS$CPM equ 1 ; CPM (IMPLIES BDOS + CCP) +; SYS$ZSYS equ 2 ; ZSYSTEM OS (IMPLIES ZSDOS + ZCPR) +; +; DOS$BDOS equ 1 ; BDOS +; DOS$ZDDOS equ 2 ; ZDDOS VARIANT OF ZSDOS +; DOS$ZSDOS equ 3 ; ZSDOS +; +; CP$CCP equ 1 ; CCP COMMAND PROCESSOR +; CP$ZCPR equ 2 ; ZCPR COMMAND PROCESSOR +; +; CONFIGURE DOS (DOS) AND COMMAND PROCESSOR (CP) BASED ON SYSTEM SETTING (SYS) +; +; +; #IFNDEF BLD$SYS +; SYS equ SYS$CPM +; #ELSE +; SYS equ BLD$SYS +; #ENDIF +; +; #IF (SYS == SYS$CPM) +; DOS equ DOS$BDOS +; CP equ CP$CCP +; #DEFINE OSLBL "CP/M-80 2.2C" +; #ENDIF +; +; #IF (SYS == SYS$ZSYS) +; DOS equ DOS$ZSDOS +; CP equ CP$ZCPR +; #DEFINE OSLBL "ZSYSTEM (ZSDOS 1.2, ZCPR 1.0)" +; #ENDIF +; +; +; ; INCLUDE VERSION AND BUILD SETTINGS +; +; #INCLUDE "ver.inc" ; ADD BIOSVER +; +; +; #INCLUDE "build.inc" ; INCLUDE USER CONFIG, ADD VARIANT, TIMESTAMP, & ROMSIZE +; +; +; #IF (PLATFORM NE PLT$N8) +; +; +; ; N8VEM HARDWARE IO PORT ADDRESSES AND MEMORY LOCATIONS +; MPCL$RAM equ 78H ; BASE IO ADDRESS OF RAM MEMORY PAGER CONFIGURATION LATCH +; MPCL$ROM equ 7CH ; BASE IO ADDRESS OF ROM MEMORY PAGER CONFIGURATION LATCH +; +; +; ; HARDWARE INTERFACES +; +; PIO 82C55 I/O IS DECODED TO PORT 60-67 +; PIOA equ 60H ; PORT A +; PIOB equ 61H ; PORT B +; PIOC equ 62H ; PORT C +; PIOX equ 63H ; PIO CONTROL PORT +; +; 16C550 SERIAL LINE UART +; +; SIO$BASE equ 68H +; SIO$RBR equ SIO$BASE + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY) +; SIO$THR equ SIO$BASE + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY) +; SIO$IER equ SIO$BASE + 1 ; DLAB=0: INT ENABLE REG +; SIO$IIR equ SIO$BASE + 2 ; INT IDENT REGISTER (READ ONLY) +; SIO$FCR equ SIO$BASE + 2 ; FIFO CONTROL REG (WRITE ONLY) +; SIO$LCR equ SIO$BASE + 3 ; LINE CONTROL REG +; SIO$MCR equ SIO$BASE + 4 ; MODEM CONTROL REG +; SIO$LSR equ SIO$BASE + 5 ; LINE STATUS REG +; SIO$MSR equ SIO$BASE + 6 ; MODEM STATUS REG +; SIO$SCR equ SIO$BASE + 7 ; SCRATCH REGISTER +; SIO$DLL equ SIO$BASE + 0 ; DLAB=1: DIVISOR LATCH (LS) +; SIO$DLM equ SIO$BASE + 1 ; DLAB=1: DIVISOR LATCH (MS) +; #ENDIF ; (PLATFORM NE PLT$N8) +; +; +; #IF (PLATFORM NE PLT$N8) +; +; +; ; Z180 REGISTERS +; +; +; CPU$IOBASE equ 40H ; ONLY RELEVANT FOR Z180 +; CPU$CNTLA0 equ CPU$IOBASE+$00 ;ASCI0 control A +; CPU$CNTLA1 equ CPU$IOBASE+$01 ;ASCI1 control A +; CPU$CNTLB0 equ CPU$IOBASE+$02 ;ASCI0 control B +; CPU$CNTLB1 equ CPU$IOBASE+$03 ;ASCI1 control B +; CPU$STAT0 equ CPU$IOBASE+$04 ;ASCI0 status +; CPU$STAT1 equ CPU$IOBASE+$05 ;ASCI1 status +; CPU$TDR0 equ CPU$IOBASE+$06 ;ASCI0 transmit +; CPU$TDR1 equ CPU$IOBASE+$07 ;ASCI1 transmit +; CPU$RDR0 equ CPU$IOBASE+$08 ;ASCI0 receive +; CPU$RDR1 equ CPU$IOBASE+$09 ;ASCI1 receive +; CPU$CNTR equ CPU$IOBASE+$0A ;CSI/O control +; CPU$TRDR equ CPU$IOBASE+$0B ;CSI/O transmit/receive +; CPU$TMDR0L equ CPU$IOBASE+$0C ;Timer 0 data lo +; CPU$TMDR0H equ CPU$IOBASE+$0D ;Timer 0 data hi +; CPU$RLDR0L equ CPU$IOBASE+$0E ;Timer 0 reload lo +; CPU$RLDR0H equ CPU$IOBASE+$0F ;Timer 0 reload hi +; CPU$TCR equ CPU$IOBASE+$10 ;Timer control +; CPU$ASEXT0 equ CPU$IOBASE+$12 ;ASCI0 extension control (Z8S180) +; CPU$ASEXT1 equ CPU$IOBASE+$13 ;ASCI1 extension control (Z8S180) +; CPU$TMDR1L equ CPU$IOBASE+$14 ;Timer 1 data lo +; CPU$TMDR1H equ CPU$IOBASE+$15 ;Timer 1 data hi +; CPU$RLDR1L equ CPU$IOBASE+$16 ;Timer 1 reload lo +; CPU$RLDR1H equ CPU$IOBASE+$17 ;Timer 1 reload hi +; CPU$FRC equ CPU$IOBASE+$18 ;Free running counter +; CPU$ASTC0L equ CPU$IOBASE+$1A ;ASCI0 Time constant lo (Z8S180) +; CPU$ASTC0H equ CPU$IOBASE+$1B ;ASCI0 Time constant hi (Z8S180) +; CPU$ASTC1L equ CPU$IOBASE+$1C ;ASCI1 Time constant lo (Z8S180) +; CPU$ASTC1H equ CPU$IOBASE+$1D ;ASCI1 Time constant hi (Z8S180) +; CPU$CMR equ CPU$IOBASE+$1E ;Clock multiplier (latest Z8S180) +; CPU$CCR equ CPU$IOBASE+$1F ;CPU control (Z8S180) +; CPU$SAR0L equ CPU$IOBASE+$20 ;DMA0 source addr lo +; CPU$SAR0H equ CPU$IOBASE+$21 ;DMA0 source addr hi +; CPU$SAR0B equ CPU$IOBASE+$22 ;DMA0 source addr bank +; CPU$DAR0L equ CPU$IOBASE+$23 ;DMA0 dest addr lo +; CPU$DAR0H equ CPU$IOBASE+$24 ;DMA0 dest addr hi +; CPU$DAR0B equ CPU$IOBASE+$25 ;DMA0 dest addr bank +; CPU$BCR0L equ CPU$IOBASE+$26 ;DMA0 byte count lo +; CPU$BCR0H equ CPU$IOBASE+$27 ;DMA0 byte count hi +; CPU$MAR1L equ CPU$IOBASE+$28 ;DMA1 memory addr lo +; CPU$MAR1H equ CPU$IOBASE+$29 ;DMA1 memory addr hi +; CPU$MAR1B equ CPU$IOBASE+$2A ;DMA1 memory addr bank +; CPU$IAR1L equ CPU$IOBASE+$2B ;DMA1 I/O addr lo +; CPU$IAR1H equ CPU$IOBASE+$2C ;DMA1 I/O addr hi +; CPU$IAR1B equ CPU$IOBASE+$2D ;DMA1 I/O addr bank (Z8S180) +; CPU$BCR1L equ CPU$IOBASE+$2E ;DMA1 byte count lo +; CPU$BCR1H equ CPU$IOBASE+$2F ;DMA1 byte count hi +; CPU$DSTAT equ CPU$IOBASE+$30 ;DMA status +; CPU$DMODE equ CPU$IOBASE+$31 ;DMA mode +; CPU$DCNTL equ CPU$IOBASE+$32 ;DMA/WAIT control +; CPU$IL equ CPU$IOBASE+$33 ;Interrupt vector load +; CPU$ITC equ CPU$IOBASE+$34 ;INT/TRAP control +; CPU$RCR equ CPU$IOBASE+$36 ;Refresh control +; CPU$CBR equ CPU$IOBASE+$38 ;MMU common base register +; CPU$BBR equ CPU$IOBASE+$39 ;MMU bank base register +; CPU$CBAR equ CPU$IOBASE+$3A ;MMU common/bank area register +; CPU$OMCR equ CPU$IOBASE+$3E ;Operation mode control +; CPU$ICR equ $3F ;I/O control register (not relocated) +; +; N8 ONBOARD I/O REGISTERS +; N8$IOBASE equ $80 +; PIO equ N8$IOBASE+$00 +; PIOA equ PIO+$00 ; PORT A +; PIOB equ PIO+$01 ; PORT B +; PIOC equ PIO+$02 ; PORT C +; PIOX equ PIO+$03 ; PIO CONTROL PORT +; PIO2 equ N8$IOBASE+$04 +; PIO2A equ PIO2+$00 ; PORT A +; PIO2B equ PIO2+$01 ; PORT B +; PIO2C equ PIO2+$02 ; PORT C +; PIO2X equ PIO2+$03 ; PIO CONTROL PORT +; +; RTC equ N8$IOBASE+$08 ;RTC latch and buffer +; FDC equ N8$IOBASE+$0C ;Floppy disk controller +; UTIL equ N8$IOBASE+$10 ;Floppy disk utility +; ACR equ N8$IOBASE+$14 ;auxillary control register +; RMAP equ N8$IOBASE+$16 ;ROM page register +; VDP equ N8$IOBASE+$18 ;Video Display Processor (TMS9918A) +; PSG equ N8$IOBASE+$1C ;Programmable Sound Generator (AY-3-8910) +; +; DEFACR equ $1B +; +; #ENDIF +; +; +; ; CHARACTER DEVICE FUNCTIONS +; +; +; CF$INIT equ 0 +; CF$IN equ 1 +; CF$IST equ 2 +; CF$OUT equ 3 +; CF$OST equ 4 +; +; DISK OPERATIONS +; DOP$READ equ 0 ; READ OPERATION +; DOP$WRITE equ 1 ; WRITE OPERATION +; DOP$FORMAT equ 2 ; FORMAT OPERATION +; DOP$READID equ 3 ; READ ID OPERATION +; +; DISK DRIVER FUNCTIONS +; DF$READY equ 1 +; DF$SELECT equ 2 +; DF$READ equ 3 +; DF$WRITE equ 4 +; DF$FORMAT equ 5 +; +; DISK DEVICES (ONLY FIRST NIBBLE RELEVANT, SECOND NIBBLE MUST BE ZERO) +; DEV$MD equ 000H +; DEV$FD equ 010H +; DEV$IDE equ 020H +; DEV$ATAPI equ 030H +; DEV$PPIDE equ 040H +; DEV$SD equ 050H +; DEV$PRPSD equ 060H +; +; IMG$START equ 00000H ; IMMUTABLE: ROM IMAGE AREA START +; IMG$END equ 08000H ; IMMUTABLE: ROM IMAGE AREA END +; +; PG0$LOC equ 00000H ; IMMUTABLE +; PG0$SIZ equ 00100H ; IMMUTABLE +; PG0$END equ PG0$LOC + PG0$SIZ +; PG0$IMG equ IMG$START ; IMMUTABLE +; LDR$LOC equ PG0$END +; LDR$SIZ equ 02000H - PG0$SIZ ; CONFIGURABLE +; LDR$END equ LDR$LOC + LDR$SIZ +; LDR$IMG equ PG0$IMG + PG0$SIZ +; CPM$LOC equ 0D000H ; CONFIGURABLE: LOCATION OF CPM FOR RUNNING SYSTEM +; CPM$END equ 10000H ; IMMUTABLE: TOP OF MEMORY +; CPM$SIZ equ CPM$END - CPM$LOC ; SIZE OF CPM IMAGE (CCP + BDOS + CBIOS (INCLUDING DATA)) +; CPM$ENT equ CPM$LOC + 01600H ; IMMUTABLE: CPM ENTRY POINT +; CPM$IMG equ LDR$IMG + LDR$SIZ ; START OF CONCATENATED CPM IMAGE +; DAT$SIZ equ DATASIZE ; FROM CONFIG FILE +; DAT$END equ CPM$END +; DAT$LOC equ DAT$END - DAT$SIZ +; BIOS$LOC equ CPM$ENT +; BIOS$END equ DAT$LOC +; BIOS$SIZ equ DAT$LOC - CPM$ENT +; MON$IMG equ CPM$IMG + CPM$SIZ ; LOCATION OF MONITOR BINARY IMAGE IN ROM +; MON$LOC equ 08000H ; LOCATION OF MONITOR FOR RUNNING SYSTEM +; MON$SIZ equ 01000H ; SIZE OF MONITOR BINARY IMAGE +; MON$END equ MON$LOC + MON$SIZ +; MON$DSKY equ MON$LOC ; MONITOR ENTRY (DSKY) +; MON$UART equ MON$LOC + 3 ; MONITOR ENTRY (UART) +; ROMX$LOC equ MON$IMG + MON$SIZ ; LOCATION OF ROM EXTENSION CODE +; +; +; ROMX$SIZ equ 02000H ; FIXED +; ROMX$END equ ROMX$LOC + ROMX$SIZ +; +; +; VDU$LOC equ ROMX$LOC + 0 ; LOCATION OF ROM VDU DRIVER +; +; +; CBIOS$BOOT equ BIOS$LOC + 0 +; CBIOS$WBOOT equ BIOS$LOC + 3 +; CBIOS$CONST equ BIOS$LOC + 6 +; CBIOS$CONIN equ BIOS$LOC + 9 +; CBIOS$CONOUT equ BIOS$LOC + 12 +; CBIOS$LIST equ BIOS$LOC + 15 +; CBIOS$PUNCH equ BIOS$LOC + 18 +; CBIOS$READER equ BIOS$LOC + 21 +; CBIOS$HOME equ BIOS$LOC + 24 +; CBIOS$SELDSK equ BIOS$LOC + 27 +; CBIOS$SETTRK equ BIOS$LOC + 30 +; CBIOS$SETSEC equ BIOS$LOC + 33 +; CBIOS$SETDMA equ BIOS$LOC + 36 +; CBIOS$READ equ BIOS$LOC + 39 +; CBIOS$WRITE equ BIOS$LOC + 42 +; CBIOS$LISTST equ BIOS$LOC + 45 +; CBIOS$SECTRN equ BIOS$LOC + 48 +; +; MEMORY CONFIGURATION +; +; MSIZE equ 59 ; CP/M VERSION MEMORY SIZE IN KILOBYTES +; +; "BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS +; ; THAN 16K (REFERRED TO AS "B" THROUGHOUT THE TEXT) +; +; BIAS equ (MSIZE-20)*1024 +; CCP equ 3400H+BIAS ; BASE OF CCP +; BDOS equ CCP+806H ; BASE OF BDOS +; BIOS equ CCP+1600H ; BASE OF BIOS +; CCPSIZ equ 00800H +; +; #IF (PLATFORM == PLT$N8VEM) +; +; +; ; #DEFINE PLATFORM$NAME "N8VEM Z80 SBC" +; +; +; ; #ENDIF +; +; +; ; #IF (PLATFORM == PLT$ZETA) +; ; #DEFINE PLATFORM$NAME "ZETA Z80 SBC" +; ; #ENDIF +; +; +; ; #IF (PLATFORM == PLT$N8) +; ; #DEFINE PLATFORM$NAME "N8 Z180 SBC" +; ; #ENDIF +; +; #IF (DSKYENABLE) +; ; #DEFINE DSKYLBL ", DSKY" +; ; #ELSE +; ; #DEFINE DSKYLBL "" +; ; #ENDIF +; +; #IF (VDUENABLE) +; #DEFINE VDULBL ", VDU" +; #ELSE +; #DEFINE VDULBL "" +; #ENDIF +; +; #IF (DIOPLT NE DIOPLT$NONE) +; +; +; #IF (DIOPLT EQ DIOPLT$DISKIO) +; #DEFINE DIOLBL ", DISKIO" +; #ENDIF +; +; +; #IF (DIOPLT EQ DIOPLT$ZETA) +; #DEFINE DIOLBL "" +; #ENDIF +; +; +; #IF (DIOPLT EQ DIOPLT$DIDE) +; #DEFINE DIOLBL ", DUALIDE" +; #ENDIF +; +; +; #IF (DIOPLT EQ DIOPLT$N8) +; #DEFINE DIOLBL "" +; #ENDIF +; +; #IF (DIOPLT EQ DIOPLT$DISKIO3) +; #DEFINE DIOLBL ", DISKIO-V3" +; #ENDIF +; +; #ELSE +; #DEFINE DIOLBL "" +; #ENDIF +; +; +; ; #ENDIF +; +; +; #IF (FDENABLE) +; #IF (FDMAUTO) +; #DEFINE FDLBL ", FLOPPY (AUTOSIZE)" +; #ELSE +; #IF (FDMEDIA == FDM720) +; #DEFINE FDLBL ", FLOPPY (720KB)" +; #ENDIF +; #IF (FDMEDIA == FDM144) +; #DEFINE FDLBL ", FLOPPY (1.44MB)" +; #ENDIF +; #ENDIF +; #ELSE +; #DEFINE FDLBL "" +; #ENDIF +; +; +; #IF (IDEENABLE) +; #DEFINE IDELBL ", IDE" +; #ELSE +; #DEFINE IDELBL "" +; #ENDIF +; +; +; #IF (PPIDEENABLE) +; #DEFINE PPIDELBL ", PPIDE" +; #ELSE +; #DEFINE PPIDELBL "" +; #ENDIF +; +; #IF (SDENABLE) +; #DEFINE SDLBL ", SD CARD" +; #ELSE +; #DEFINE SDLBL "" +; #ENDIF +; +; +; #IF (PRPSDENABLE) +; #DEFINE PRPSDLBL ", PROPIO SD CARD" +; #ELSE +; #DEFINE PRPSDLBL "" +; #ENDIF +; +; +; ; .ECHO "Configuration: " +; ; .ECHO PLATFORM$NAME +; ; .ECHO DSKYLBL +; ; .ECHO VDULBL +; ; .ECHO DIOLBL +; ; .ECHO FDLBL +; ; .ECHO IDELBL +; ; .ECHO PPIDELBL +; ; .ECHO SDLBL +; ; .ECHO PRPSDLBL +; ; .ECHO "\n" +; ; +; +; eof - std.lib + +*/ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/STDIO.H b/trunk/Apps/crossdev/STDIO.H new file mode 100644 index 00000000..45335927 --- /dev/null +++ b/trunk/Apps/crossdev/STDIO.H @@ -0,0 +1,62 @@ +/* Copyright (C) 1982, 1984 by Manx Software Systems */ +#define fgetc getc +#define fputc putc +#define NULL 0 +#define EOF -1 + +#ifdef TINY +struct fcb { + char f_driv; + char f_name[8]; + char f_type[3]; + char f_ext; + char f_resv[2]; + char f_rc; + char f_sydx[16]; + char f_cr; + unsigned f_record; char f_overfl; +}; + +typedef struct { + char *_bp; + struct fcb _fcb; + char user; +} FILE; + +#else + +#define BUFSIZ 1024 +#define MAXSTREAM 11 + +#define _BUSY 0x01 +#define _ALLBUF 0x02 +#define _DIRTY 0x04 +#define _EOF 0x08 +#define _IOERR 0x10 + +typedef struct { + char *_bp; /* current position in buffer */ + char *_bend; /* last character in buffer + 1 */ + char *_buff; /* address of buffer */ + char _flags; /* open mode, etc. */ + char _unit; /* token returned by open */ + char _bytbuf; /* single byte buffer for unbuffer streams */ + int _buflen; /* length of buffer */ +} FILE; + +extern FILE Cbuffs[]; +FILE *fopen(); +long ftell(); + +#define stdin (&Cbuffs[0]) +#define stdout (&Cbuffs[1]) +#define stderr (&Cbuffs[2]) +#define getchar() agetc(stdin) +#define putchar(c) aputc(c, stdout) +#define feof(fp) (((fp)->_flags&_EOF)!=0) +#define ferror(fp) (((fp)->_flags&_IOERR)!=0) +#define clearerr(fp) ((fp)->_flags &= ~(_IOERR|_EOF)) +#define fileno(fp) ((fp)->_unit) +#define fflush(fp) flsh_(fp,-1) +#endif + \ No newline at end of file diff --git a/trunk/Apps/crossdev/STDLIB.H b/trunk/Apps/crossdev/STDLIB.H new file mode 100644 index 00000000..6b32b6b4 --- /dev/null +++ b/trunk/Apps/crossdev/STDLIB.H @@ -0,0 +1,13 @@ +/* + * stdlib.h 3/12/2012 dwg - POSIX-like standard library declarations + * + */ + +#define SUCCESS 0 +#define FAILURE 1 + +/* + * eof - stdlib.h + * + */ + \ No newline at end of file diff --git a/trunk/Apps/crossdev/SYSCFG.H b/trunk/Apps/crossdev/SYSCFG.H new file mode 100644 index 00000000..a4b1f978 --- /dev/null +++ b/trunk/Apps/crossdev/SYSCFG.H @@ -0,0 +1,22 @@ +/* syscfg.h 5/23/2012 dwg - declarations for the syscfg block */ + +struct JMP_TAG { + unsigned char opcode; + unsigned int address; +}; + + +struct SYSCFG { + struct JMP_TAG jmp; + void * cnfloc; + void * tstloc; + void * varloc; + /* cnfgdata starts here */ + struct CNFGDATA cnfgdata; + char filler[256-3-2-2-2-sizeof(struct CNFGDATA)]; +}; + + +/******************/ +/* eof - syscfg.h */ +/******************/ \ No newline at end of file diff --git a/trunk/Apps/crossdev/SYSGEN.C b/trunk/Apps/crossdev/SYSGEN.C new file mode 100644 index 00000000..de685095 --- /dev/null +++ b/trunk/Apps/crossdev/SYSGEN.C @@ -0,0 +1,229 @@ +/* sysgen.c 6/7/2012 dwg - 108 records 0,0 through 0,107 */ + +#include "std.h" +#include "stdio.h" +#include "globals.h" +#include "stdlib.h" +#include "memory.h" +#include "portab.h" +#include "cpm80.h" +#include "cpmappl.h" +#include "applvers.h" +#include "sectorio.h" +#include "infolist.h" + + +/* rdsector(drive,track,sector,buffer,select); */ + + +struct DPH * pDPH; +struct DPB * pDPB; + +unsigned char filespec[32]; + +unsigned char * pBUFFER; + +unsigned char szDrive[32]; + +char szTemp[128]; + +rdimage(filename,bufptr,bufsiz) + char * filename; + char * bufptr; + int bufsiz; +{ + int bytes; + FILE * fdsys; + +/* printf("rdimage called\n"); + printf(" filename is %s\n",filename); + printf(" bufptr is 0x%04x\n",bufptr); + printf(" bufsiz is 0x%04x\n",bufsiz); +*/ + + fdsys = fopen(filename,"r"); + if(NULL == fdsys) { + return 0; + } + bytes = fread(bufptr,1,bufsiz,fdsys); + fclose(fdsys); + return bytes; +} + + +strupr(ptr) + char * ptr; +{ + int i; + for(i=0;i= 'a' ) { + if( ptr[i] <= 'z') { + ptr[i] = ptr[i] & 0xdf; + } + } + } + +} + + +sysgen(drive,trk,sec,ptr,spt,cnt) + int drive; + int trk; + int sec; + char * ptr; + int spt; + int cnt; +{ + wrsector(drive,trk,sec,ptr,0); + while ( 0 < cnt ) { + + wrsector(drive,trk,sec,ptr,1); + + printf("drive=%c:, trk=%d, sec=%3d, ptr=0x0%4x ", + drive+'A', trk, sec, ptr); + printf("%c",0x0d); + ptr += 128; + sec++; + if(sec == spt) { + trk++; + sec = 0; + } + cnt--; + } + printf(" "); + printf("%c",0x0d); +} + + + + + +int main(argc,argv) + int argc; + char *argv[] ; +{ + int base; + int bytes; + int columns; + int spt; + int trk; + int sec; + int cnt; + int drive; + int dstdrive; + int off; + + char szParm[128]; + unsigned char * ptr; + unsigned char * p; + + + + crtinit(); + crtclr(); + crtlc(0,0); + + printf("SYSGEN.COM %d/%d/%d v%d.%d.%d.%d", + A_MONTH,A_DAY,A_YEAR,A_RMJ,A_RMN,A_RUP,A_RTP); + printf(" dwg - Write System Image to Storage Media\n"); + + /* scenarios: + + 1. "sysgen" + Copies ROM:cpm.sys to current drive + + 2. "sysgen filespec" + Copies filespec to current drive + + 3. "sysgen filespec x:" + Copies filespec to x: drive + + */ + + dregbc = RETCURRDISK; + bdoscall(); + dstdrive = drega; + + pBUFFER = 0x08000; + + if(1 == argc) { + /* copy ROM:cpm.sys to current drive */ + + for(drive=0;drive>8) ) { + break; + } + } + + sprintf(filespec,"%c:CPM.SYS",drive+'A'); + bytes = rdimage(filespec,pBUFFER,16383); + if(0 == bytes) { + sprintf(filespec,"%c:ZSYS.SYS",drive+'A'); + bytes = rdimage(filespec,pBUFFER,16383); + if(0 == bytes) { + printf("Sorry, could not read default system file"); + exit(1); + } + } + + } + + if(2 == argc) { + strcpy(filespec,argv[1]); + bytes = rdimage(filespec,pBUFFER,16383); + } + + if(3 == argc) { + strcpy(filespec,argv[1]); + strcpy(szDrive,argv[2]); + strupr(szDrive); + dstdrive = szDrive[0]-'A'; + bytes = rdimage(filespec,pBUFFER,16383); + } + + + ireghl = pSELDSK; + iregbc = dstdrive; + iregde = 0; + bioscall(); + pDPH = ireghl; + pDPB = pDPH->dpb; + spt = pDPB->spt; + off = pDPB->off; + + trk = 0; + sec = 0; + ptr = pBUFFER; + + cnt = bytes/128; + + if(0 == off) { + printf("Sorry, %c: Drive does not have reserved tracks\n", + dstdrive+'A'); + exit(1); + } + + printf("Preparing to transfer the CP/M system image to the "); + printf("%c: drive from %s\nfile which is %d",dstdrive+'A',filespec,bytes); + printf(" bytes long, OK? (Y/n): "); + printf("\n"); + + dregbc = 1; + bdoscall(); + if('Y' != drega) { + printf("Sysgen operation cancelled per your request.\n"); + exit(1); + } + + sysgen(dstdrive,trk,sec,pBUFFER,spt,cnt); + printf("%c: drive should be bootable now :-)",dstdrive+'A'); +} + +/*******************/ +/* eof - csysgen.c */ +/*******************/ + + \ No newline at end of file diff --git a/trunk/Apps/crossdev/TESTER.C b/trunk/Apps/crossdev/TESTER.C new file mode 100644 index 00000000..2b30401a --- /dev/null +++ b/trunk/Apps/crossdev/TESTER.C @@ -0,0 +1,13 @@ +#include "portab.h" +#include "globals.h" +#include "stdio.h" +#include "stdlib.h" + +main(argc,argv) + int argc; + char *argv[]; +{ + + + exit(SUCCESS); +} \ No newline at end of file diff --git a/trunk/Apps/crossdev/VIEW.C b/trunk/Apps/crossdev/VIEW.C new file mode 100644 index 00000000..037d4f60 --- /dev/null +++ b/trunk/Apps/crossdev/VIEW.C @@ -0,0 +1,315 @@ +/* view.c 6/7/2012 dwg - */ + +#include "std.h" +#include "stdio.h" +#include "stdlib.h" +#include "memory.h" +#include "portab.h" +#define MAXDRIVE 8 +#include "cpm80.h" +#include "cpmappl.h" +#include "applvers.h" + +#define DSM144 0x02C6 +#define DSM720 0x015E +#define DSM360 0x00AA +#define DSM120 0x024F +#define DSM111 0x0222 + +/* +#include "cpmbind.h" +#include "cbioshdr.h" +#include "std.h" +#include "infolist.h" +#include "dphdpb.h" +#include "dphmap.h" +#include "metadata.h" +#include "setlunum.h" +#include "applvers.h" +#include "cpmbdos.h" +#include "ctermcap.h" +#include "diagnose.h" +*/ + + + + +/* Drive List Geometry */ +#define COL1 0 +#define COL2 (80/4) +#define COL3 (80/2) +#define COL4 (COL2+COL3) +#define LINE 3 + +/* Logical Unit List Geometry */ +#define LGUT 5 +#define COL1A 0 +#define COL2A (80/3) +#define COL3A (2*COL2A) + +/* Nomenclature Geometry */ +#define LINE2 8 + + +/* BDOS Function number */ +#define RETCURR 25 + +/* +struct DPH * pDPH; +struct DPB * pDPB; +*/ + +/* int drive; */ + +dispdpb(line,column,pDPB) + int line; + int column; + struct DPB * pDPB; +{ + crtlc(line+0,column); + printf("[%04x] spt =%04x",&pDPB->spt,pDPB->spt); + crtlc(line+1,column); + printf("[%04x] bsh =%02x",&pDPB->bsh,pDPB->bsh); + crtlc(line+2,column); + printf("[%04x] blm =%02x",&pDPB->blm,pDPB->blm); + crtlc(line+3,column); + printf("[%04x] ex =%02x",&pDPB->exm,pDPB->exm); + crtlc(line+4,column); + printf("[%04x] dsm =%04x",&pDPB->dsm,pDPB->dsm); + crtlc(line+5,column); + printf("[%04x] drm =%04x",&pDPB->drm,pDPB->drm); + crtlc(line+6,column); + printf("[%04x] al0 =%02x",&pDPB->al0,pDPB->al0); + crtlc(line+7,column); + printf("[%04x] al1 =%02x",&pDPB->al1,pDPB->al1); + crtlc(line+8,column); + printf("[%04x] cks =%04x",&pDPB->cks,pDPB->cks); + crtlc(line+9,column); + printf("[%04x] off =%04x",&pDPB->off,pDPB->off); +} + +struct DPB * dispdph(drive,line,column) + int drive; + int line; + int column; +{ + + struct DPH * pDPH; + struct DPB * pDPB; + + unsigned char * p; + int devunit; + + ireghl = pSELDSK; + iregbc = drive; + iregde = 0; + bioscall(); + if(0 == ireghl) { + return NULL; + } + pDPH = ireghl; + pDPB = pDPH->dpb; + + p = ireghl - 1; + devunit = (unsigned char)*p; + + crtlc(line-1,column+1); printf("Drive %c: ",'A'+drive); + + switch(devunit) { + case DEV_MD+1: printf(" RAM"); break; + case DEV_MD+0: printf(" ROM"); break; + case DEV_FD+0: printf(" FD0"); break; + case DEV_FD+1: printf(" FD1"); break; + case DEV_IDE+0: printf(" IDE0"); break; + case DEV_IDE+1: printf(" IDE1"); break; + case DEV_ATAPI+0: printf("ATAPI0"); break; + case DEV_ATAPI+1: printf("ATAPI1"); break; + case DEV_PPIDE+0: printf("PPIDE0"); break; + case DEV_PPIDE+1: printf("PPIDE1"); break; + case DEV_SD+0: printf(" SD0"); break; + case DEV_SD+1: printf(" SD1"); break; + case DEV_PRPSD+0: printf("PRPSD0"); break; + case DEV_PRPSD+1: printf("PRPSD1"); break; + case DEV_PPPSD+0: printf("PPPSD0"); break; + case DEV_PPPSD+1: printf("PPPSD1"); break; + } + + + crtlc(line+0,column); printf("[%04x] xlt =%04x", + &pDPH->xlt,pDPH->xlt); + crtlc(line+1,column); printf("[%04x] rv1 =%04x", + &pDPH->rv1,pDPH->rv1); + crtlc(line+2,column); printf("[%04x] rv2 =%04x", + &pDPH->rv2,pDPH->rv2); + crtlc(line+3,column); printf("[%04x] rv3 =%04x", + &pDPH->rv3,pDPH->rv3); + crtlc(line+4,column); printf("[%04x] dbf =%04x", + &pDPH->dbf,pDPH->dbf); + crtlc(line+5,column); printf("[%04x] dpb =%04x", + &pDPH->dpb,pDPH->dpb); + crtlc(line+6,column); printf("[%04x] csv =%04x", + &pDPH->csv,pDPH->csv); + crtlc(line+7,column); printf("[%04x] alv =%04x", + &pDPH->alv,pDPH->alv); + if( ('L' == pDPH->sigl) && ('U' == pDPH->sigu) ) { + crtlc(line+8,column); + printf("[%04x] sigl=%02x",&pDPH->sigl,pDPH->sigl); + crtlc(line+9,column); + printf("[%04x] sigu=%02x",&pDPH->sigu,pDPH->sigu); + crtlc(line+10,column); + printf("[%04x] curr=%04x",&pDPH->current,pDPH->current); + crtlc(line+11,column); + printf("[%04x] numb=%04x",&pDPH->number,pDPH->number); + } + + if(DSM720 == pDPB->dsm) { + crtlc(line+9,column+1); printf("3-1/2"); + printf("%c 9 SPT",'"'); + crtlc(line+10,column+1); printf("720KB DSDD FMT"); + } + if(DSM144 == pDPB->dsm) { + crtlc(line+9,column+1); printf("3-1/2"); + printf("%c 18 SPT",'"'); + crtlc(line+10,column+1); printf("1.44MB DSHD FMT"); + } + if(DSM360 == pDPB->dsm) { + crtlc(line+9,column+1); printf("5-1/4"); + printf("%c 9 SPT",'"'); + crtlc(line+10,column+1); printf("360KB DSDD FMT"); + } + if(DSM120 == pDPB->dsm) { + crtlc(line+9,column+1); printf("5-1/4"); + printf("%c 15 SPT",'"'); + crtlc(line+10,column+1); printf("1.2MB DSHD FMT"); + } + if(DSM111 == pDPB->dsm) { + crtlc(line+9,column+1); printf(" 8"); + printf("%c 15 SPT",'"'); + crtlc(line+10,column+1); printf("1.11MB DSDD FMT"); + } + + dispdpb(line+13,column,pDPH->dpb); +} + + +int main(argc,argv) + int argc; + char *argv[] ; +{ + int base; + int columns; + char szParm[128]; + + dregbc = RETCURRDISK; + bdoscall(); + base = drega; + + switch(base) { + case 0: + columns = 4; + break; + case 1: + columns = 4; + break; + case 2: + columns = 4; + break; + case 3: + columns = 4; + break; + case 4: + columns = 4; + break; + case 5: + columns = 3; + break; + case 6: + columns = 2; + break; + case 7: + columns = 1; + break; + default: + columns = 0; + break; + } + + if(2 == argc) { + strcpy(szParm,argv[1]); + if(2 == strlen(szParm)) { + if(':' == szParm[1]) { + switch(szParm[0]) { + case 'A': + case 'a': + base = 0; + columns = 4; + break; + case 'B': + case 'b': + base = 1; + columns = 4; + break; + case 'C': + case 'c': + base = 2; + columns = 4; + break; + case 'D': + case 'd': + base = 3; + columns = 4; + break; + case 'E': + case 'e': + base = 4; + columns = 4; + break; + case 'F': + case 'f': + base = 5; + columns = 3; + break; + case 'G': + case 'g': + columns = 2; + base = 6; + break; + case 'H': + case 'h': + base = 7; + columns = 1; + break; + } + } + } + } + + crtinit(); + crtclr(); + crtlc(0,0); + + printf("VIEW.COM %d/%d/%d v%d.%d.%d.%d", + A_MONTH,A_DAY,A_YEAR,A_RMJ,A_RMN,A_RUP,A_RTP); + printf(" dwg - System Storage Drives and Logical Units"); + + if(0 < columns) { + dispdph(base+0,3,2+0); + } + if(1 < columns) { + dispdph(base+1,3,2+20); + } + if(2 < columns) { + dispdph(base+2,3,2+40); + } + if(3 < columns) { + dispdph(base+3,3,2+60); + } + + dregbc = 0; + bdoscall(); +} + +/*****************/ +/* eof - cview.c */ +/*****************/ + \ No newline at end of file diff --git a/trunk/Apps/doc/dwg-apps.man b/trunk/Apps/doc/dwg-apps.man new file mode 100644 index 00000000..0944e85b --- /dev/null +++ b/trunk/Apps/doc/dwg-apps.man @@ -0,0 +1,16 @@ +dwg-apps.man 7/22/2012 dwg - 2.0 Apps - Command syntax + +banker display version and specifics of bnk1, bnk0... +cpmname [-a] display values in syscfg and cnfgdata +setlabel edit drive label of current drive (interactive) +map displays current drives, mapping, and LU labels +map changes LU of specified drive to specified LU # +meta display and/or edit metadata of current drive +rem used in submit file to add remarks +sysgen writes default system onto current drive +sysgen writes specified file onto current drive +sysgen write specified file to specified drive +termtype display and or edit terminal type +view display tables of current and next 3 drives +view { A: | B: | C: | D: | E: | F: | G: | H: } dsply specified & nxt 3 drvs + \ No newline at end of file diff --git a/trunk/Build.cmd b/trunk/Build.cmd new file mode 100644 index 00000000..a4456616 --- /dev/null +++ b/trunk/Build.cmd @@ -0,0 +1,4 @@ +@echo off +pushd Source +PowerShell .\Build.ps1 %* +popd \ No newline at end of file diff --git a/trunk/Clean.cmd b/trunk/Clean.cmd new file mode 100644 index 00000000..09f058b6 --- /dev/null +++ b/trunk/Clean.cmd @@ -0,0 +1,5 @@ +@echo off +pushd Source +call Clean.cmd +popd +if exist Output\*.* del Output\*.* /Q \ No newline at end of file diff --git a/trunk/Doc/22Disk.txt b/trunk/Doc/22Disk.txt new file mode 100644 index 00000000..3769347b --- /dev/null +++ b/trunk/Doc/22Disk.txt @@ -0,0 +1,20 @@ +The following definitions have been contributed by Roger Hanscom +for use in 22Disk: + +BEGIN ZTA1 Zeta SBC 1440k format DSHD 3.5" +DENSITY MFM ,HIGH +CYLINDERS 80 SIDES 2 SECTORS 18,512 +SIDE1 0 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 +SIDE2 1 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 +ORDER SIDES +BSH 4 BLM 15 EXM 0 DSM 710 DRM 255 AL0 0F0H AL1 0 OFS 2 +END + +BEGIN ZTA2 Zeta SBC 720k format DSDD 3.5" +DENSITY MFM ,LOW +CYLINDERS 80 SIDES 2 SECTORS 9,512 +SIDE1 0 1,2,3,4,5,6,7,8,9 +SIDE2 1 1,2,3,4,5,6,7,8,9 +ORDER SIDES +BSH 4 BLM 15 EXM 0 DSM 350 DRM 127 AL0 0C0H AL1 0 OFS 4 +END \ No newline at end of file diff --git a/trunk/Doc/BankedBIOS.txt b/trunk/Doc/BankedBIOS.txt new file mode 100644 index 00000000..4f562c13 --- /dev/null +++ b/trunk/Doc/BankedBIOS.txt @@ -0,0 +1,146 @@ +ROM Page 0 +---------- + +Loc Org Size File Contents + +0000 0000 0100 pgzero Page Zero +0100 0100 0100 bootrom ROM Bootstrap +0200 0100 0200 syscfg System Configuration +0400 8400 0C00 loader Loader +1000 1000 3000 romfill Filler (for future use?) +4000 C000 1000 dbgmon Debug Monitor +5000 D000 0800 Command Processor (CCP, ZCPR, etc.) +5800 D800 0E00 Disk Operating System (BDOS, ZSDOS, etc.) +6600 E600 1900 cbios CP/M BIOS +7F00 FF00 0100 hbfill Filler for HBIOS Proxy (HiMem Stub) +---- +8000H = 32768 + + +ROM Page 1 +---------- + +Loc Org Size File Contents + +0000 0000 0100 pgzero Page Zero +0100 0100 0100 bootrom Reserved (unused, 'bootrom' used as filler) +0200 0200 0200 syscfg System Configuration +0400 0400 0C00 loader Reserved (unused, 'loader' used as filler) +1000 1000 7000 bnk1 Bank 1 BIOS Extension +---- +8000H = 32768 + + +COM File Image +-------------- + +Loc Org Size File Contents + +0100 0100 0100 bootapp Application Bootstrap +0200 0200 0200 syscfg System Configuration +0400 8400 0C00 loader Loader +1000 1000 7000 bnk1 Bank 1 BIOS Extension + +8000 C000 1000 dbgmon Debug Monitor +9000 D000 0800 Command Processor (CCP, ZCPR, etc.) +9800 D800 0E00 Disk Operating System (BDOS, ZSDOS, etc.) +A600 E600 1900 cbios CP/M BIOS +---- +BF00H - 0100H = BE00H = 48640 + + +RAM Page 0 +---------- + +Loc Org Size Contents + +0000 0000 0100 Page Zero +0100 0100 7F00 TPA +---- +8000H = 32768 + + +RAM Page 1 +---------- + +Loc Org Size Contents + +0000 0000 0100 Page Zero +0100 0100 0100 Reserved (unused) +0200 0200 0200 System Configuration (dynamic) +0400 0400 0C00 Command processor cache area +1000 1000 7000 Bank 1 BIOS Extension +---- +8000H = 32768 + + +RAM Page N +---------- + +Loc Org Size Contents + +8000 8000 TPA +C000 C000 1000 TPA/Debug Monitor +D000 D000 0800 Command Processor +D800 D800 0E00 Disk Operating System +E600 E600 1900 CP/M CBIOS +FF00 FF00 0100 HBIOS Proxy (HiMem Stub) +---- +10000H - 8000H = 8000H = 32768 + +General Startup Strategy +------------------------ + +A two phase boot strategy is employed. This is necessary +because at cold start, the CPU is executing code in lower +memory which is the same area that is bank switched. + +Phase 1 of booting copies phase 2 code to upper memory +and jumps to it to continue the boot process. + +Phase 2 of booting manages the setup of the RAM page +banks as needed. In the case of a hardware startup, +phase 2 just copies the code from ROM page 1 into RAM +page 1 and executes the loader. In the case of an +application startup (.com file used to load a new +copy of the system), phase 2 copies the first 32KB +of the application memory space into RAM page 1 +and executes the loader. + +See 'bootrom.asm' for the implementation of the ROM +(hardware) startup. See 'bootapp' for the implementation +of the application based startup. + +General Design Strategy +----------------------- + +The design goal is to locate as much of the hardware +dependent code as possible out of normal 64KB CP/M +address space and into a bank switched area of memory. +As calls are made to HBIOS, the lower 32KB of memory +is switched to 'bank 1' which contains all of the +driver code. The operating system is unaware this +has occurred. As control is returned to the Operating +System, the lower 32KB of memory is switched back to +normal 'bank 0'. + +HBIOS implements a small 'shim' (proxy) that lives in the +upper page (256 bytes) of RAM. This shim is responsible +for handling the HBIOS call invocations. It is the +target of 'RST 08' and will simply switch in RAM +bank 1 into lower RAM forward the call to the lower +memory, then switch lower memory back to RAM bank 0 +on return. + +In the case of CP/M and ZSDOS, CBIOS is built to +utilize HBIOS for most of the work. CBIOS contains +the required CP/M data structures such as DPH and DPB +and is responsible for translating and forwarding work +to HBIOS as needed. + +Notes +----- + +1. Size of ROM disk and RAM disk will necessarily be +decreased by 32KB each. User will need to make sure +that RAM disk is reformatted (CLRDIR). \ No newline at end of file diff --git a/trunk/Doc/Build.txt b/trunk/Doc/Build.txt new file mode 100644 index 00000000..c8ff39b8 --- /dev/null +++ b/trunk/Doc/Build.txt @@ -0,0 +1,331 @@ +Building a Custom ROM +--------------------- + +At present, the build environment assumes you are running +a current version of Microsoft Windows (either 32-bit or +64-bit). + +If you are using Linux, David Giles has contributed a Linux +makefile that should work for you. Please read the +LinuxBuild.txt file for more information. + +All required tools are included in the distribution. You +should not need anything other than what comes as part of +Windows or as part of the distribution. + +In summary, the process involves the 4 steps below: + + 1) Create/update configuration file + + 2) Update/Add/Delete any files you want incorporated in + the ROM Disk + + 3) Run the build script (or makefile if you prefer) and + confirm there are no errors. + + 4) Burn the resultant ROM image and try it. + +The process is really very simple. In fact, you can +essentially skip steps 1 & 2 if yoiu want to try simply +building one of the existing configurations. + +Each of the 4 steps above is described in more detail +below. + +1. Create/Update Configuration File +----------------------------------- + +The settings for a build are primarily controled by +a configuration file that is included in the build +process. In order to customize your settings, you +need to modify an existing configuration file or +create your own. + +If you look in the Source directory, you will see +a series of files named config_xxxxxx.asm. Each of +them corresponds to one of the standard configurations +listed in the ROMList.txt file. + +You have two choices. You can simply modify the existing +configuration file that is closest to your situation, or +you can copy it to a new config_xxxxx.asm file and modify +that. I recommend that you copy one to your own name so +that you will always have the unmodified standard configuration +files left in place. So, for example, you could just +copy config_zeta.asm to config_wayne.asm. You MUST +name your config file as congig_xxxxxx.asm. The xxxx's +can be whatever you want, but the rest must be exactly +as indicated. + +The config files are simply text files with various +settings. Open your target config file with your +favorite text editor and modify the settings as desired. + +Unfortunately, I have not yet documented each of the +settings in detail; that will be a separate document +provided in the future. However, there are comments +in the config file that will probably be sufficient +for the most part. + +2. Update/Add/Delete ROM Disk Files +----------------------------------- + +The files that are included on the ROM Disk of your +ROM are copied from a set of directories during the +build process. This allows you to have complete +flexibility over the files you want included in your +ROM. + +If you look at the RomDsk directory, you will see +a variety of subdirectories. These subdirectories +contain the files that will be included in the +ROM disk. The build process will determine +which subdirectories to include files from based +on the following rules: + +First, all files from either std_512 or std_1024 will +be incuded depending on on the size of the ROM you +are building. If you are building a 512KB ROM, then +all the files from std_512KB will be included. If you +are building a 1MB ROM, then all the files from std_1024KB +will be included. Essentialy, the files in std_1204KB are +a superset of the ones in std_512KB because there is more +space available for the ROM drive. + +Second, all files from the directory that corresponds to +your configuration file will be included. If you build +the "zeta" configuration, all files in cfg_zeta will +be added. Note that these files will be in addition +to the files from the std_XXXKB directory. + +If you created your own config file (like config_wayne.asm +described above), you MUST create a subdirectory within +the RomDsk directory and populate it with the files +you want added. Normally, you would include the +files from the original standard config. So, if +you created config_wayne.asm from config_zeta.asm, +then you would create a subdirectory in RomDsk called +cfg_wayne and copy all the files from cfg_zeta to +cfg_wayne. + +Finally, you will notice another subdirectory called +RomApps. This is directory is used to place a set of +RomWBW apps provided by Douglas Goodall. The driectory +will be populated automatically and the files will be +included automatically. + +3. Run the Build Process +------------------------ + +NOTE: The process described here is the more commonly +used build script. If you wish to use a makefile +instead, refer to the comments in the makefile in +the Source directory as an alternative to the +process described here. + +The build involves running a command at the command +prompt. From a Command Prompt window, you will need +to change to the high level directory for the build. +Normally, you would be changing to the RomWBW directory +unless you renamed it. + +To run the build and be prompted for required information, +just enter "Build". You will be prompted for the information +described below and the build should run. If an error is +encountered, the build should stop and display an error +in red text. + +If you immediately receive the error "the execution of +scripts is disabled on this system", then you will need to +change the PowerShell Execution-Polcy to "Unrestricted". +To do this, you need to right-click on FixPowerShell.cmd and +choose "Run as Administrator" to make the change. If is +critical that you right-click and use "Run as Administrator" +or the change will not work (you will get an error +indicating "Access to the registry denied" if you fail to +use "Run as Administrator". + +The build script will prompt you for the following information +which you will need to provide (don't worry, it is simple): + +Configuration: + +Respond with the name of the configuration you wish to build. +A list of all available configurations is displayed for your +convenience. For example, if you are buidling the provided +zeta configuration, just enter "zeta". If you have created a +custom configuration as described above, you would enter +"wayne". + +ROM Size [512|1024]: + +Respond with either "512" for a 512KB ROM build or "1024" for a +1MB ROM build. Only the two choices are possible at this time. +It is important that you choose a ROM size that is no larger than +the szie of the ROM you will ultimately be burning. This is +dependant on your hardware. + +CPU Type Z[80|180]: + +Respond with "80" if the ROM is for Z80 hardware such as the +N8VEM Z80 SBC or for Zeta. Respond with "180" if the ROM is +for Z180 based hardware such as the N8. + +System [CPM|ZSYS]: + +Respond with the type of system you wish to create. If you are +not sure which you want, you should enter "CPM". Refer to the +ReadMe.txt file for more informatino on the difference between +the two system types. + +At this point the build should run and you will see output related +to the assembler runs and somem utility invocations. Just review +the output for any obvioius errors. Normally, all errors will +cause the build to stop immediately and display an error message +in red. + +You will see from lines in the output indicating the amount of +space variouis components have taken. You should check these +to make sure you do not see any negative numbers which would +indicate that you have included too many features/drivers for +the available memory space. Here are examples of the lines +showing the space used: + + DATA space remaining: 39 bytes. + BOOT LOADER space remaining: 3503 bytes. + CBIOS space remaining: 161 bytes. + DBGMON space remaining: 860 bytes. + ROMX space remaining: 8191 bytes. + BOOT LOADER space remaining: 3503 bytes. + +4. Deploy the ROM +----------------- + +If you look in the Output directory. You should find the following files: + + .rom - binary ROM image to burn to EEPROM + .sys - system image that can be written to the start of a + disk to enable boot from disk functionality + .com - executable version of the system image that can be + copied via xmodem to a running system to test + the build. + +The actual ROM image is the file ending in .rom. It should be exactly +512KB or 1MB depending on the ROM size you chose. Simply burn the .rom +image to your ROM and install it in your hardware. + +Specifying Build Options on Command Line +---------------------------------------- + +If you don't want to be prompted for the options to the "Build" +command, you can specify the options right on the command line. + +For example: + + Build zeta 512 80 CPM + +In this case, you will not be prompted. This is useful if you +wish to automate your build process. + +Example Build Run +----------------- + +C:\Users\WWarthen\N8VEM\Build\RomWBW>build +Configurations available: + > n8 + > n8vem + > n8vem_dide + > n8vem_diskio + > n8vem_diskio3 + > n8vem_ppide + > n8vem_vdu + > n8vem_vdux + > simh + > zeta +Configuration: zeta +ROM Size [512|1024]: 512 +CPU Type Z[80|180]: 80 +System [CPM|ZSYS]: CPM + +Building zeta: 512KB ROM configuration zeta for Z80... + +tasm -t80 -b -g3 -fFF ccpb03.asm cp.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +tasm: pass 2 complete. +tasm: Number of errors = 0 +tasm -t80 -b -g3 -fFF bdosb01.asm dos.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +tasm: pass 2 complete. +tasm: Number of errors = 0 +tasm -t80 -b -g3 -fFF -dBLD_SYS=SYS_CPM data.asm data.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE +UTIL_DATA occupies 16 bytes. +FD_DATA occupies 427 bytes. +PPIDE_DATA occupies 584 bytes. +DATA space remaining: 23 bytes. +tasm: pass 2 complete. +tasm: Number of errors = 0 +tasm -t80 -b -g3 -fFF -dBLD_SYS=SYS_CPM cbios.asm cbios.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE +CNFGDATA occupies 69 bytes. +DSKMAP occupies 6 bytes. +UART occupies 77 bytes. +FD occupies 1991 bytes. +PPIDE occupies 832 bytes. +UTIL occupies 381 bytes. +CBIOS space remaining: 165 bytes. +tasm: pass 2 complete. +tasm: Number of errors = 0 +tasm -t80 -b -g3 -fFF dbgmon.asm dbgmon.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE +DBGMON space remaining: 831 bytes. +tasm: pass 2 complete. +tasm: Number of errors = 0 +tasm -t80 -b -g3 -fFF bloader.asm bloader.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE +BOOT LOADER space remaining: 3522 bytes. +tasm: pass 2 complete. +tasm: Number of errors = 0 +tasm -t80 -b -g3 -fFF romx.asm romx.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE +ROMX space remaining: 8191 bytes. +tasm: pass 2 complete. +tasm: Number of errors = 0 +tasm -t80 -b -g3 -fFF prefix.asm prefix.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE +tasm: pass 2 complete. +tasm: Number of errors = 0 +tasm -t80 -b -g3 -fFF loader.asm loader.bin +TASM Z80 Assembler. Version 3.2 September, 2001. + Copyright (C) 2001 Squak Valley Software +tasm: pass 1 complete. +Configuration: ZETA Z80 SBC, FLOPPY (AUTOSIZE), PPIDE +BOOT LOADER space remaining: 3522 bytes. +tasm: pass 2 complete. +tasm: Number of errors = 0 +Building zeta output files... +Building 512KB zeta ROM disk data file... + +C:\Users\WWarthen\N8VEM\Build\RomWBW> \ No newline at end of file diff --git a/trunk/Doc/ChangeLog.txt b/trunk/Doc/ChangeLog.txt new file mode 100644 index 00000000..bc38f0d1 --- /dev/null +++ b/trunk/Doc/ChangeLog.txt @@ -0,0 +1,251 @@ +Version 2.1.1 +------------- +- WBW: Corrected setup of Z180 wait states +- WBW: Added hd0-3 geometries to diskdefs file for cpmtools + +Version 2.1 +----------- +- WBW: Implemented write caching in (de)blocking algorithm +- WBW: Added Architecture documentation +- WBW: Config jumper controls default vs. alternate console for N8VEM/Zeta +- DGG: Added support for PPISD in SD Card driver +- WBW: Implemented screen saver in PropIO and ParPortProp (5 minute timeout) + +Version 2.0 +----------- +- WBW: Implemented Banked BIOS (drivers in separate bank) +- DGG: Updated in-site flash utility for greater chip compatibility +- WBW: Updated FDTST to latest version (improved support for 5.25" and 8" media) +- WBW: Added ParPortProp driver +- DWG: Entire new suite of Apps written in Aztec C +- DWG: BANKER.COM - displays bank identification and version information +- DWG: CPMNAME.COM - displays CBIOS header data and SYSCFG data, names and vaues +- DWG: CHARS.COM - displays ascii map as reference +- DWG: CLS.COM - clears screen +- DWG: LABEL.COM - displays and changes drive labels for drives with reserved tracks +- DWG: MAP.COM - like old map command, displays drives and logical unit labels and changes LU values +- DWG: META.COM - like old metaview command displays and edits drive metadata +- DWG: REM.COM - used in submit files +- DWG: SYSGEN.COM - replaces old writesys command, much nicer, more flexible +- DWG: TERMTYPE.COM - like old termtype, displays and changes terminal type +- DWG: VIEW.COM - displays drive DPH and DPB, with addresses, 4-up +- WBW: Updated FDTST to v3.0 (support for sector interleave in format) +- DGG: Support for CSIO based SD access for N8 +- DWG: Added DWG-APPS.MAN file to ROM describing command line syntax of new applications +- WBW: Prebuilt ROMs are now all 512KB -- works fine on a 1MB ROM +- WBW: Added driver for SIMH AltairZ80 hard disk (HDSK) +- WBW: Added support for SDHC/XC card to SD Card driver +- DWG: Extra Apps can be downloaded from Apps/apps-bins (limited to 100K in ROM) +- DWG: /XSource/Makefile is work in progress for Mac OS X build (experimental) +- WBW: Updated SIMH build for latest SIMH release v3.9 + +Version 1.5.2 +------------- +- DGG: Added in-situ flash programming application +- WBW: Added support for 8" floppy drives +- WBW: Upgraded FDTST.COM to version 2.7a on ROM disks +- DWG: Minor fixes to METAVIEW, and MAP +- DGG: Fixes for makefile.linux + +Version 1.5.1 +------------- +- WBW: Added ZSDOS clock drivers (see Support\Clock) +- WBW: Overhaul of ZSystem ROM Disk (see Doc\ZSystem.txt) +- WBW: Update PropIO ANSI emulation for compatiblity with ASSIGN +- DWG: Added version tags to all applications, and IDENT program to + check version of utilities. +- DWG: Added MULTIFMT program which prepares new media for use by + initializing the metadata and clearing the directory sectors of + all logical units on a specific drive (IDE,PPIDE,PRPSD,SD). +- DWG: Enhanced MAP program combines the functionality of DRIVES, + SLICES, and MAP. DRIVES and SLICES have been removed. +- DWG: ANALYSE and HELLO programs removed from ROM due space concerns +- DWG: Additional macro librarties added supporting program identification + (IDENTITY.LIB/ASM) and access to drive metadata (METADATA.LIB/ASM), + and realtime selection of logical units from within new application + programs (LOGICALS.LIB/ASM). +- DWG: Added TERM_VT52 for VDU compatbility, all apps now compliant +- DGG: Contributed Linux build (see Doc\BuildLinux.txt) + +Version 1.5 +----------- +- WBW: Upgraded XModem to version 12.5 +- WBW: Added support for PropIO (RomWBW specific firmware required on PropIO) +- WBW: Corrected RTC application for N8 (it now works) +- WBW: Included updated FDTST v2.6 w/ support for 5.25" floppy drives +- WBW: Added OS support for 5.25" drives +- DWG: New Apps ACCESS, ANALYSE, FINDFILE,HELLO,METAVIEW,NOACCESS,RTC2012 +- DWG: RMAC macro files re-written as hybrid libraries making executables smaller and faster +- DWG: Loader displays logical unit label with other stats +- DWG: CPMNAME enhanced to support new PROP I/O SD +- DWG: Much more inline doc in Apps source code +- DWG: Add ACCESS to verify file present in submit +- DWG: Add ANALYSE as sample program demonstrating macro usage +- DWG: Add FINDFILE to locate file(s) in any Logical Unit (slice) +- DWG: Add HELLO as clasic hello world sample +- DWG: Add METAVIEW to display and manage file system metadata +- DWG: Add NOACCESS to verify file not present in submit + +Version 1.4 +----------- +- DWG: Add various .SUB files used for application maintenance +- DWG: Enhanced utility building .SUB files to only contain libs utilitized +- DWG: Add BUILD.SUB to build all applications and DEVFILES.LBR +- DWG: Add/update RMAC macro libraries used in Apps - +- DWG: BIOSHDR, STDLIB, STRCPY, STRLEN, CPMBIOS, CPMBDOS, TERMINAL, HARDWARE, +- DWG: CPMAPPL, GLOBALS, ATOI, LUBIND, APPLVERS, MEMORY(memcpy,memset), PORTAB +- DWG: Add/Repair BIOS support for Boot Drive login during CP/M Coldstart +- DWG: All Apps utilities now licensed with GNU Public License v3 +- DWG: DRIVES utility now dispays labels for drives with reserved track(s) +- DWG: DEVFILES.LBR now include just .ASM, .LIB, and .SUB files +- DWG: Updated CPMNAME for latest config changes, added paging +- DWG: Add REM utility for use in SUBMIT files +- DWG: Add STOP utility to terminate execution of SUBMIT files +- DWG: Add PAUSE utility to pause the execution of SUBMIT files +- DWG: Add REQ1PARM utility to verify a parameter was specified +- DWG: Add HEADER utility to display addresses of BIOS header data items +- DWG: Add command line MAP utility "map A: 23" for use general use and in SUBMIT files +- DWG: Retired PPIDELUx utilities in favor of new MAP utility +- DWG: Add SLICES utility to display labels of all slices on current drive 3/line, formatted +- DWG: Add LABEL utility to insert label into drive/slice metadata +- DWG: Add 16 char label field to metadata +- DWG: ASSIGN utility displays and manipulates DPH/DPB & logical unit parameters +- DWG/WBW: Collaborated on design of Logical Unit DPH enhancemnt +- WBW: Proposed MAP utility functionality +- WBW: Implement slice selection API for DSK devices +- WBW: Record boot drive in config memory at load time +- WBW: Add DSKY_KBD flag to util.asm so that keyboard routines can be built only when needed to save space in CBIOS +- WBW: Support 16550 UART FIFO (selectively via config, enabled where available) +- WBW: Remove B: default from xmodem (default to current drive) +- WBW: Consolidate xmodem code variations using conditionals +- WBW: Add xmodem variation for N8 ASCI1 (N8 now has XM0 & XM1 instead of XM) +- WBW: Remove CCP extension that searches USER 0 area for executables +- WBW: Reset drives when exitting FDTST (media format may have changed) +- WBW: Switch from VDE to ZDE +- WBW: Added signature to system image prefix +- WBW: Modified SD card disk layout for consistency with other media (existing sd cards need reformatting!) +- WBW: Upgraded ZSDOS from v1.1 to v1.2 +- WBW: Modified build so that separate ('_z') config files are no longer needed + + +Version 1.3.3 +------------- + +- WBW: Changed startup banner for ZSystem builds +- WBW: Modified XM for ZSystem builds to default to current drive +- WBW: Included zsdos.lbr in Support directory + +Version 1.3.2 +------------- + +- WBW: ZSDOS/ZDDOS support added +- WBW: ZCPR support added + +Version 1.3.1 +------------- + +- WBW: Updated FDTST application to handle faster (20MHz) systems, slower is OK +- WBW: Small fix to SD card driver to handle card init failure in rare situations +- DWG: Updated WRITESYS to improve SELDSK BIOS call compatibility + +Version 1.3 +----------- + +- DWG: WRITEIMG renamed to WRITESYS, works on PPIDE, CPM.SYS added to ROM +- DWG: TERMTYPE gets and sets terminal type +- DWG: PPIDELUX programs will dynamically select storage "slice" on device +- DWG: DRIVES utility will show current drive mappings +- DWG: CPMNAME utility enhanced to include all new config settings +- DWG: DEVFILES Douglas Goodall's Development Environment added to Apps +- DWG: Configured Wordstar and front end utility added to Apps +- DWG: Added drive mapping display to loader +- DWG: Added "Logical Unit" support for PPIDE (allows full use of media) +- DWG: Designed Application Package format and Protocol +- WBW: Implemented IOBYTE and character device driver interface abstraction layer. +- WBW: Mapped VDU to CRT: device (N8VEM SBC w/ VDU hardware only) +- WBW: Implemented second UART for N8 as UC1: device +- WBW: Implemented SD driver (N8 only) +- WBW: Implemented hot swap for SD driver (N8 only) +- WBW: Added DSKY display for SD driver (N8 only) +- WBW: Corrected keymap in VDU driver (N8VEM SBC w/ VDU hardware only) +- WBW: Removed filler and allocated space to rom extension area +- WBW: Added new standard build configurations for N8 (fd, sd, ppide) +- WBW: Implement DBGCON selection (UART or VDU) +- WBW: Implement LDRCON selection (UART of VDU) +- WBW: Made ROM size selection part of build command +- WBW: Made processor selection (Z80 vs. Z180) part of build command + +Version 1.2 +----------- + +- DWG: Updated CPMNAME and WRITEIMG utilities +- WBW: Added N8 support (minimal, based on work by David Giles, but not as robust as N8RomDG). +- WBW: Added support for VDU board (code from Andrew Lynch, Dan Werner and James Moxham) +- WBW: Boot loader configurable for auto-selection w/ timeout (as requested by Bob Devries) + +Older Stuff +----------- + +This work is all derived from JC110508. Note that JC110508 included +the fix for DPB in CBIOS for large ROM drive. Specifically, EXM_5 +was changed from 1 -> 0 (as it should have been). + +1) Fixed the stack location in loader-b.asm. LOADER.COM was not working +for me without this change. + +2) Fixed the size of the ccp+bdos+cbios in bloader.asm and loader-b.asm. +It was too small before and would be a potential problem depending on +how many of the optional features were enabled. + +3) Fixed the "MON" command in cpm. It was jumping to an old/bad location. +I modified the way it works a bit to handle the situation where it can +become overlaid. There is now a routine in cbios.asm to reload it and +branch to the warm start location. The address of the cbios routine is +now saved in the cbios scratch area of zero page (40H) so that ccp does +not need to have a hard coded location in it. + +4) Corrected ROM memory layout a bit. Small ROM drive was starting at the +wrong location (4800H). It should have been 5000H. So, I gave the loader +2K more space. Required modifications to bloader and cbios. Renamed +'romdsk.dsk' to 'romdsk.dat' to help alert folks to the fact that this is +a different image and allows "clean" to remove anything with a suffix +of '.img'. + +5) Changed bloader to allow selection of DSKY or UART monitor using JP2. +A single ROM can now be dynamically configured to start via DSKY or UART. + +6) Fixed small ROM disk DPB in cbios. Changed DSM_6 from 31 -> 11. Based +on blocksize of 1024 and the fact that it is now a 12K area, 11 is the +correct value. Also fixed EXM_6 from 1 -> 0 (per DRI spec). + +7) Moved startup message from warm boot to cold boot. Also moved VDU init +to cold boot -- seems appropriate, but I have no way to test this yet... + +8) More DPB tweaks. I have reviewed the floppy and RAM/ROM DPB's. I have +not looked at ATAPI or IDE. May still be problems in those. + +9) Complete overhaul of build scripts. Reworked makefile to be compatible +with the make utility from gcc and created MakeRom.cmd to invoke the gcc +make utility. Created a PowerShell script as an alternative way to create +ROM (BuildRom.ps1) and created BuildRom.cmd to invoke it. Final ROM +image is now called rom.img -- made more sense to me, but I have no +compelling justification for changing that. BuildRom2.bat is still +there and I think it works. + +10) Played with the startup message in cbios a bit. Extracted the "build" +id and moved it to the top of the file. My intent is to make it easy to +update. Ultimately, I wold prefer that it be updated with the current +date of the build as part of the build scripts, but still debating how +best to accomplish that. + +11) Related to #10, I have extracted the 3rd party build tools into sibling +directories. So, for example, tasm is now found at tasm32. This makes it +very easy to update the 3rd party tools and to clearly differentiate the +3rd party tool files. All build script have been updated as needed. + +12) Removed ALL enable interrupt (EI) instructions in CBIOS. By leaving +interrupts disabled the BIOS will now start OK even if some vagrant +hardware is asserting an interrupt (DISKIO). Seems like this is better +anyway -- general idea is that we only enable interupts precisely +when desired for very specific controled purposes since there is no +concept of interrupt dispatching available. \ No newline at end of file diff --git a/trunk/Doc/DesignNotes-1.4.txt b/trunk/Doc/DesignNotes-1.4.txt new file mode 100644 index 00000000..155e511e --- /dev/null +++ b/trunk/Doc/DesignNotes-1.4.txt @@ -0,0 +1,16 @@ +Design Notes for 1.4 - + +12/25/2011 DWG - Logical Unit enhancement for block drivers + +The previous version implemented Logical Unit functionality +by poking an offset word into a private data structure in +PPIDE_DATA.ASM. + +In order to make the Logical Unit functionality more generic, +Wayne suggested adding the appropriate data items to the end +of the Disk Parameter Header data structure (because there is +one each for each drive). + +The added items consist of a Logical Unit enhancement signature +which is two bytes "LU", and several subsequent items including +a default slice number and status. diff --git a/trunk/Doc/FdTst.txt b/trunk/Doc/FdTst.txt new file mode 100644 index 00000000..fefec401 --- /dev/null +++ b/trunk/Doc/FdTst.txt @@ -0,0 +1,429 @@ +================================================================ +FDTST v3.1 for N8VEM DISKIO / DISKIO V3 / ZETA / DIDE / N8 +================================================================ + +Updated JuLY 1, 2012 +by Wayne Warthen (wwarthen@gmail.com) + +Application to test the hardware functionality of the Floppy Disk +Controller (FDC) on the ECB DISK I/O, DISK I/O V3, ZETA SBC, +Dual IDE w/ Floppy, or N8 board. + +The intent is to provide a testbed that allows direct testing +of all possible media types and modes of access. The application +supports read, write, and format by sector, track, and disk as +well as a random read/write test. + +The application supports access modes of polling, interrupt, +INT/WAIT, and DRQ/WAIT. At present, it supports 3.5" media at DD (720KB) and +HD (1.44MB) capacities. It also now supports 5.25" media (720KB and 1.2MB) +and 8" media (1.11MB) as well. Additonal media will be added when I have +time and access to required hardware. Not all modes are supported +on all platforms and some modes are experimental in all cases. + +In many ways this application is merely reinventing the wheel and +performs functionality similer to existing applications, but I have +not seen any other applications for DISK I/O that provide this range +of functionality. + +While the application is now almost entirely new code, I would like to +acknowledge that much was derived from the previous work of Andrew Lynch +and Dan Werner. I also want to credit Sergio Gimenez with testing the 5.25" +drive support and Jim Harre with testing the 8" drive support. Thanks! + +General Usage +------------- + +In general, usage is self explanatory. The main menu allows you to set +the unit, media, and mode to test. These settings MUST match your +situation. Read, write, format, and verify functions are provided. A sub-menu +will allow you to choose sector, track, disk, or random tests. + +The verify function requires a little explanation. It will take the contents +of the buffer, save it, and compare it to the selected sectors. So, you +must ensure that the sectors to be verified already have been written +with the same pattern as the buffer contains. I typically init the buffer +to a pattern, write the pattern to the entire disk, then verify the entire +disk. + +Another submenu is provided for FDC commands. This sub-menu allows you to +send low-level commands directly to FDC. You MUST know what you are doing +to use this sub-menu. For example, in order to read a sector using this +sub-menu, you will need to perform specify, seek, sense int, and read +commands specifying correct values (nothing is value checked in this menu). + +Required Hardware/BIOS +---------------------- + +Of course, the starting point is one of the support hardware platforms. +You need to start with either an N8VEM SBC, backplane, and ECB DISK I/O +card or a Zeta SBC. Additionally, a floppy drive connected via an +appropriate cable: + +DISKIO - no twist in cable, drive unit 0/1 must be selected by jumper on drive +ZETA - cable with twist, unit 0 after twist, unit 1 before twist +DIDE/N8 - cable with twist, unit 0 before twist, unit 1 after twist + + +It is preferable that the BIOS you use does not have DISK I/O support +enabled since the application assumes it has complete control of the +DISK I/O hardware. + +The DISK I/O should be jumpered as follows: + +J1: depends on use of interrupt modes (see interrupt modes below) +J2: pins 1-2, & 3-4 jumpered +J3: hardware dependent timing for DMA mode (see DMA modes below) +J4: pins 2-3 jumpered +J5: off +J6: pins 2-3 jumpered +J7: pins 2-3 jumpered +J8: off +J9: off +J10: off +J11: off +J12: off + +Note that J1 can be left on even when not using interrupt modes. As +long as the BIOS is OK with it, that is fine. Note also that J3 is +only relevant for DMA modes, but also can be left in place when +using other modes. + +The DISK I/O V3 should be jumpered at the default settings: + +JP2: 3-4 +JP3: 1-2 for int mode support, otherwise no jumper +JP4: 1-2, 3-4 +JP5: 1-2 +JP6: 1-2 +JP7: 1-2, 3-4 + +Zeta does not have any relevant jumper settings. + +DIDE should be jumpered as follows: + +K3 (DT/R or /RD): /RD +P5 (bd ID): 1-2, 3-4 (for $20-$3F port range) + +There are no specific N8 jumper settings, but the default +I/O range starting at $80 is assumed in the published code. + + +Modes of Operation +------------------ + +You can select the following test modes. Please refer to the chart +that follows to determine which modes should work with combinations +of Z80 CPU speed and media format. + +Polling: Traditional polled input/output. Works well and very reliable +including timeouts and good error recovery. Also, the slowest performance +which precludes it from being used with 1.44MB floppy on a 4MHz Z80. +This is definitely the mode you want to get working before any others. +It does not require J1 (interrupt enable) on DISK I/O and does not care about +the setting of J3. + +Interrupt: Input/output is interrupt driven. Works pretty well, but +is not able to recover from some errors. For example, if there is +no disk in the drive, this mode will just hang until a disk is inserted. +This mode REQUIRES that interrupts be enabled on the DISK I/O via +jumper at J1. On Zeta it requires the INT/NMI jumper be set for +INT. Mode not supported on DIDE or N8. Some BIOS variants will not +handle interrupts during boot. + +Fast Interrupt: As above, but sacrifices additional reliability for +faster operation. This mode will allow a 1.44MB floppy to work +with a 4MHz Z80 CPU. However, if any errors occur (even a transient +read error which is not unusual), this mode will hang. As above +you MUST have the appropriate jumpers for DISKIO and Zeta. DIDE +does not support this mode. + +INT/WAIT: Same as Fast Interrupt, but uses CPU wait instead of +actual interrupt. Subject to all the same issues as Fast +Interrupt, but does not need J1 shorted. J3 is irrelevant. +This mode is available on only on DISKIO (and not DISKIO V3). + +DRQ/WAIT: Uses pseudo DMA to handle input/output. Does not require that +interrupts (J1) be enabled on the DISK I/O. However, it is subject to +all of the same reliability issues as "Fast Interrupt". This +mode is known to not work on N8VEM DISKIO!!! It is included +for testing only. It is dependent on setting of J3. This +mode is NOT available on Zeta, DIDE, N8, or DISKIO V3. + +The chart below attempts to describe the combinations that +work for me. By far, the most reliable mode is Polling, +but it requires 8MHz CPU for HD disks. + +DRQ/WAIT --------------------------------+ +INT/WAIT -----------------------------+ | +Fast Interrupt --------------------+ | | +Interrupt ----------------------+ | | | +Polling ---------------------+ | | | | + | | | | | +CPU Speed --------------+ | | | | | + | | | | | | + | | | | | | + +3.5" DD (720K) ------ 4MHz Y Y Y Y X + 8MHz+ Y Y Y Y X + +3.5" HD (1.44M) ----- 4MHz N N Y Y X + 8MHz+ Y Y Y Y X + +5.25" DD (360K) ----- 4MHz Y Y Y Y X + 8MHz+ Y Y Y Y X + +5.25" HD (1.2M) ----- 4MHz N N Y Y X + 8MHz+ Y Y Y Y X + +8" DD (1.11M) ------- 4MHz N N Y Y X + 8MHz+ Y Y Y Y X + +Y = Yes, works +N = No, does not work +X = Experimental, probably won't work + +Tracing +------- + +Command/result activity to/from the FDC will be written out +if the trace setting is changed from '00' to '01' in setup. +Additionally, if a command failure is detected on any +command, that specific comand and results are written +regardless of the trace setting. + +The format of the line written is: +: --> [] + +For example, this is the output of a normal read operation: +READ: 46 01 00 00 01 02 09 1B FF --> 01 00 00 00 00 02 02 [OK] + +Please refer to the i8272 data sheet for information on the +command and result bytes. + +Note that the sense interrupt command can return a non-OK +result. This is completely normal in some cases. It is +necessary to "poll" the drive for seek status using +sense interrupt. If there is nothing to report, then +the result will be INVALID COMMAND. Additionally, +during a recalibrate operation, it may be necessary to +issue the command twice because the command will only step +the drive 77 times looking for track 0, but the head may be +up to 80 tracks away. In this case, the first recalibrate +fails, but the second should succeed. Here is what this +would look like if trace is turned on: + +RECALIBRATE: 07 01 --> [OK] +SENSE INTERRUPT: 08 --> 80 [INVALID COMMAND] + ... + ... + ... +SENSE INTERRUPT: 08 --> 80 [INVALID COMMAND] +SENSE INTERRUPT: 08 --> 71 00 [ABNORMAL TERMINATION] +RECALIBRATE: 07 01 --> [OK] +SENSE INTERRUPT: 08 --> 21 00 [OK] + +Another example is when the FDC has just been reset. In +this case, you will see up to 4 disk change errors. Again +these are not a real problem and to be expected. + +When tracing is turned off, the application tries to be +intelligent about error reporting. The specific errors +from sense interrupt documented above will be suppressed +because they are not a real problem. All other +errors will be displayed. + +Error Handling +-------------- + +There is no automated error retry logic. This is very +intentional since the point is to expose the controller +and drive activity. Any error detected will result in +a prompt to abort, retry, or continue. Note that some +number of errors is considered normal for this +technology. An occasional error would not necessarily +be considered a problem. + +CPU Speed +--------- + +I distribute the binary version of the application optimized for +20MHz CPUs. There is a configuration variable called CPUFREQ +at the top of the source file. Ideally, you should build +with that set appropriately. However, I have found that the +default build setting of 20MHz seems to work for 4-20MHz CPUs. + +Interleave +---------- + +The format command now allows the specification of a sector +interleave. It is almost always the case that the optimal +interleave will be 2 (meaning 2:1). + +360K Media +---------- + +The 360K media definition should work well for true 360K +drives. However, it will generally not work +with 1.2M drives. This is because these drives spin at 360RPM +instead of the 300RPM speed of true 360K drives. Additionally, +1.2M drives are 80 tracks and 360K drives are 40 tracks and, so +far, there is no mechanism in FDTST to "double step" as a way +to use 40 track media in 80 track drives. + +With this said, it is possible to configure some 1.2M 5.25" drives +to automatically spin down to 300RPM based on a density select +signal (DENSEL). This signal is asserted by FDTST for 360K +media, so IF you have configured your drive to react to this +signal correctly, you will be able to use the 360K media defintion. +Most 1.2M 5.25" drives are NOT configured this way by default. +TEAC drives are generally easy to modify and have been tested by +the author and do work in this manner. Note that this does not +address the issue of double stepping above; you will just be +using the first 40 of 80 tracks. + +Support +------- + +I am happy to answer questions as fast and well as I am able. +Best contact is wwarthen@gmail.com or post something on the +N8VEM Google Group https://groups.google.com/forum/#!forum/n8vem. + +Changes +------- + +WW 8/12/2011 + +Removed call to pulse TC in the FDC initialization +after determining that it periodically caused the FDC to write +bad sectors. I am mystified by this, but definitely found it +to be true. Will revisit at some point -- probably a timing +issue between puslsing TC and whatever happens next. + +Non-DMA mode was being set incorrectly for FAST-DMA mode. +It was set for non-DMA even though we were doing DMA. It is +interesting that it worked fine anyway. Fixed it anyway. + +DIO_SETMEDIA was not clearing DCD_DSKRDY as it should. Fixed. + +WW 8/26/2011: v1.1 + +Added support for Zeta. Note that INT/WAIT and DRQ/WAIT are +not available on Zeta. Note that Zeta provides the ability +to perform a reset of the FDC independent of a full CPU +reset. This is VERY useful and the FDC is reset anytime +a drive reset is required. + +Added INT/WAIT support. + +WW 8/28/2011: V1.2 + +All changes in this version are Zeta specific. Fixed FDC reset +logic and motor status display for Zeta (code from Sergey). + +Modified Zeta disk change display to include it in the +command output line. This makes more sense because a command +must be issued to select the desired drive first. You can +use the SENSE INT command id you want to check the disk +change value at any time. It will also be displayed with +any other command output display. + +WW 9/1/2011: V1.3 + +Added CPUFREQ configuration setting to tune +delays based on cpu speed. The build app +is set for 8MHz which also seems to work well +for 4MHz CPU's. Faster CPU speeds will +probably require tuning this setting. + +WW 9/5/2011: V1.4 + +Changed the polling execution routines to utilize CPUFREQ +variable to optimize timeout counter. Most importantly, +this should allow the use of faster CPUs (like 20MHz). + +WW 9/19/2011: V1.5 + +Zeta changes only. Added a call to FDC RESET after any +command failure. This solves an issue where the drive +remains selected if a command error occurs. Also +added FDC RESET to FDC CONTROL menu. + +WW 10/7/2011: V2.0 + +Added support for DIDE. Only supports polling IO and it +does not appear any other modes are possible given the +hardware constraints. + +WW 10/13/2011: V2.1 + +Modified to support N8. N8 is essentially identical to +Dual IDE. The only real change is the IO addresses. In +theory, I should be able to support true DMA on N8 and +will work on that. + +WW 10/20/2011: v2.2 + +I had some problems with the results being read were +sometimes missing a byte. Fixed this by taking a more +strict approach to watching the MSR for the exact +bits that are expected. + +WW 10/22/2011: V2.3 + +After spending a few days trying to track down an +intermittent data corruption issue with my Dual IDE +board, I added a verify function. This helped +me isolate the problem very nicely (turned out to +be interference from the bus monitor). + +WW 11/25/2011: V2.4 + +Preliminary support for DISKIO V3. Basically just +assumed that it operates just like the Zeta. Needs +to be verified with real hardware as soon as I can. + +WW 1/9/2012: V2.5 + +Modified program termination to use CP/M reset +call so that a warm start is done and all +drives are logged out. This is important +because media may have been formatted during +the program execution. + +WW 2/6/2012: v2.6 + +Added support for 5.25" drives as tested by +Sergio. + +WW 4/5/2012: v2.7 + +Added support for 8" drives as tested by +Jim Harre. + +WW 4/6/2012: v2.7a + +Fixed issue with media selection menu to remove +duplicate entries. + +WW 4/8/2012: v2.7b + +Corrected the handling of the density select +signal. + +WW 5/22/2012: v2.8 + +Added new media definitions (5.25", 320K) + +WW 6/1/2012: v2.9 + +Added interleave capability on format + +WW 6/5/2012: v3.0 + +Documentation cleanup + +WW 7/1/2012: v3.1 + +Modified head load time (HLT) for 8" media based on +YD-180 spec. Now set to 50ms. \ No newline at end of file diff --git a/trunk/Doc/HBIOS Functions.txt b/trunk/Doc/HBIOS Functions.txt new file mode 100644 index 00000000..7ae032c9 --- /dev/null +++ b/trunk/Doc/HBIOS Functions.txt @@ -0,0 +1,4 @@ +HBIOS FUNCTION CALLS +==================== + +HBIOS function calls are now documented in "RomWBW Architecture.pdf". Please refer to this document. \ No newline at end of file diff --git a/trunk/Doc/LinuxBuild.txt b/trunk/Doc/LinuxBuild.txt new file mode 100644 index 00000000..41424dfd --- /dev/null +++ b/trunk/Doc/LinuxBuild.txt @@ -0,0 +1,48 @@ +Assembling the RomWBW firmware under Linux. + +This method has been used under Ubuntu Linux and may have to be adapted for +other distributions. It is a bit more involved than the Windows procedure. + +What you need +You will need the TASM assembler, make, dos2unix and cpmtools. + +The TASM assembler is shareware and the Linux version is only available as +source code from the Author. I found one bug during compiling version 3.2 for +Ubuntu. In /src/tasm.c change the reference CLK_TIC to CLOCKS_PER_SEC. +After compiling install the tasm executable to /usr/local/bin and the table +files to /usr/local/lib. If you choose to place them somewhere else you will +have to edit the "makefile.linux" file to suit. + +The make, dos2unix and cpmtools packages are found in the Linux repository and +installed as for any other package. + +Before assembly +Some changes need to be made to cater for the differences between Linux and the +DOS/Windows environments. The examples below refer to the /RomWBW/current +directory, you'll have to allow for the stable or branches directories if used. +These are all done from a terminal. (: is end of the command prompt) + +1. Go to the RomWBW Source directory.e.g. +:cd /n8vem/RomWBW/current/Source + +2. I have included a new makefile called "makefile.linux" in the Source +directory. Rename this to just "makefile". Edit it to suit your targets and +if you have changed the default location for TASM. +:~/RomWBW/current/Source mv makefile.linux makefile + +3. The Linux version of TASM can't handle the CR-LF line endings. So from the +command prompt use dos2unix to convert all the source files. +:~/RomWBW/current/Source dos2unix -f *.asm *.inc *.z80 *.lib diskdefs + +4. You'll have to alter the disk definitions for the cpmtools package to cater +for the new roms. Easiest way is to copy the one given in the source over the +old. This must be done as superuser. +:~/RomWBW/current/Source sudo cp diskdefs /etc/cpmtools/diskdefs + +5. From now on it's the same as using the DOS/Windows instructions in Build.txt. +Make any last changes, go to the Source directory and make +:~/RomWBW/current/Source make clean ; make + +DGG + + diff --git a/trunk/Doc/MemoryLayout.txt b/trunk/Doc/MemoryLayout.txt new file mode 100644 index 00000000..ab3201fe --- /dev/null +++ b/trunk/Doc/MemoryLayout.txt @@ -0,0 +1,47 @@ +******************************************** +*** This file is deprecated as ov v2.X *** +*** Please see BankedBIOS.txt *** +******************************************** + + +7 6 5 4 3 2 1 0 ONLY APPLICABLE TO THE LOWER MEMORY PAGE 00000h-$7FFF +^ ^ ^ ^ ^ ^ ^ ^ +: : : : : : : +--> A15 RAM/ROM ADDRESS LINE DEFAULT IS 0 +: : : : : : +----> A16 RAM/ROM ADDRESS LINE DEFAULT IS 0 +: : : : : +------> A17 RAM/ROM ADDRESS LINE DEFAULT IS 0 +: : : : +--------> A18 RAM/ROM ADDRESS LINE DEFAULT IS 0 +: : : +-----------> A19 ROM ONLY ADDRESS LINE DEFAULT IS 0 +: : +-------------> +: +---------------> ++-----------------> ROM SELECT (0=ROM, 1=RAM) DEFAULT IS 0 + + + +RAM: + +ADDRESS COMPONENT SIZE PAGE COMMENTS +----------- --------- ----- ------ ---------------------------------------------- +00000-07FFF TPA 08000 0 Normally mapped to lower 32K of CPU address space + +08000-77FFF RAMDSK 70000 1-E 448KB RAM Disk + +78000-78FFF TPA/DBGMON 01000 F Pinned to upper 32K of CPU address space +79000-7CFFF TPA 04000 " +7D000-7D7FF TPA/CCP 00800 " +7D800-7E5FF BDOS 00E00 " +7E600-7FFFF CBIOS 01A00 " (includes DATA) + + +ROM: + +ADDRESS COMPONENT SIZE PAGE COMMENTS +----------- --------- ----- ------ ---------------------------------------------- +00000-000FF PAGE ZERO 00100 +00100-01FFF LOADER 01F00 0 +02000-027FF CCP 00800 +02800-035FF BDOS 00E00 +03600-04FFF CBIOS 01A00 includes DATA +05000-05FFF DBGMON 01000 +06000-07FFF ROM EXT 02000 vdu driver, etc. + +08000-FFFFF ROMDSK F8000 1-1E 960KB ROM Disk \ No newline at end of file diff --git a/trunk/Doc/RomWBW Architecture.pdf b/trunk/Doc/RomWBW Architecture.pdf new file mode 100644 index 00000000..dd162ec3 Binary files /dev/null and b/trunk/Doc/RomWBW Architecture.pdf differ diff --git a/trunk/Doc/SD-howto.txt b/trunk/Doc/SD-howto.txt new file mode 100644 index 00000000..7de38a57 --- /dev/null +++ b/trunk/Doc/SD-howto.txt @@ -0,0 +1,184 @@ +Using an SD card with the RomWBW firmware. + +This document describes using the SD-card interface for the Z80-SBC, Zeta and +N8 systems with the RomWBW firmware. +V2.0 supports the bit-bang method as well as CSIO port on the N8. It does not +support the original connection by Juha to the Z80-SBC MK-I. +V2.1 supports the Mini-PPISD board for the Z80-SBC and Zeta. + +All interfaces (except the PPISD) use the latch and input port used to +communicate with the DS1302 RTC chip. Each interface is slightly different and +will be discussed in turn. +The SD-card interface uses four signal lines. A chip select, data +out to the card, clock out to the card and a data in from the card. + +Zeta +The Zeta uses a 6-bit latch for the RTC so we will be doubling up on the RTC +data out and clock lines. The chip select uses a spare latch output and the +data in uses the 'config' header input. +First a modification to the Zeta board. The 'config' input has a 4k7 pull-up +resistor which must be removed or isolated (RTC_PLUP at pin 6 of RR1). To +isolate this resistor cut the pcb track on the underside of the PCB that goes +to pin 9 of U14 (the 74LS125). SD-cards work at 3.3v and a pull-up to 5v can +damage the card. The config header is left open. +Connections to the Zeta from the SD miniboard are: +Miniboard Zeta Use +1 +5v +2 GND +3 U14 pin 9 Data in to SBC from card +4 U11 pin 2 Data out from SBC to card +5 N/C alternative to pin 3 +6 N/C alternative to pin 4 +7 U11 pin 10 Clock out to card +8 U11 pin 7 Chip select to card +The jumpers on the SD miniboard are K1 1-2, K2 1-2. + +N8VEM Z80-SBC MK-II +This is the same as for the Zeta except using different pin numbers. +Miniboard MK II SBC Use +1 +5v +2 GND +3 U5 pin 9 Data in to SBC from card +4 U18 pin 15 Data out from SBC to card +5 N/C alternative to pin 3 +6 N/C alternative to pin 4 +7 U18 pin 12 Clock out to card +8 U18 pin 2 Chip select to card +The jumpers on the miniboard are K1 1-2, K2 1-2. +Resistor R11 must be removed. + +Testing the Zeta and Z80-SBC MK-II boards +With the miniboard connected to the Zeta BUT WITH NO SD-CARD INSTALLED do the +following. +1. Power up and check the voltages on all pins of the SD-card socket. None of +them should be over 3.3v. +2. From the monitor type +>I 70 and it should come back with something like 78 +Short out the config header to bring the data in line low, type >I 70 and it +should come back with 38 proving the data in line. +3. Test the outputs by turning them all on (except the DS1302 enable line) with +>O 70 CF +Now check all the voltages again. If they are 3.0 to 3.3v then go to the next +step. If two of them are closer to 2.0v then you are likely using a 74LS174 +instead of a 74HCT174 (or similar) for U11. To bring the outputs up enough +(3.0v) change the 2k7 resistors R4 and R8 to 560 ohms on the miniboard. +4. If you want to test the individual output lines then +>O 70 80 activates the data out line +>O 70 40 activates the clock line +>O 70 04 activates the chip select line +5. If all is ok then time to assemble new firmware. In your xxx_config.asm +file set SDENABLE to true and set the SDCAPACITY to the size of your card. +6. Power down, plug in the SD-card and power-up. There is no hot-swapping in +this interface. After that it should behave as the other drives. +Note that the SD-interface is SLOW and can take a few seconds to respond. + +N8 + Make sure you have cut the track to or removed 4k7 pullup resistor marked +PU4.7K-H that goes to the data out of the SD-card and pin 9 of U4 (the +74LS125). It has damaged the SD-card I was initially testing as they are not +designed for 5v on any pin. Before putting any SD-card into the connector, +check all voltages and make sure they are less than 3.6v, preferably about +3.3v. You can use the monitor's 'O 88 07' command to set all outputs on. + + The quick guide to modifying the SD-card interface to use the CSI/O +port on the N8-2511 board. + +It is assumed that you have got the standard SD-card interface running and +have a known working SD-card (though not necessary for either). + +1. Remove jumper JP-1 to disconnect SD-Data out from U4 (74LS125) + +2. Cut tracks/IC pins 18 and 19 of U11 (74LS574) to disconnect SD_CLK + and SD_DATA IN. + +3. If you are using U60 (MAX-232) for the secondary serial port RS-232 + interface, cut or bend pin 12 of U60 out of the socket. Cutting the + track between this pin and pin 56 of the cpu is not possible + with the chip sockets in place. + This will stop U60 from inhibiting the CSI/O receiver. If you are + using the RS-485 interface then you don't have to do this mod. + +4. Connect pin 55 of the CPU (TXS) to SD_DATA_IN. Easiest way is pin 3 of P49 + to R6. + +5. Connect pin 56 of the CPU (RXS) to SD_DATA_OUT. Easiest way is pin 4 of P49 + to pin 4 of RR3. + +6. Connect pin 57 of the CPU (CLK) to SD_CLK. Easist way is pin 2 of P49 to + R10. + +7. DO NOT INSTALL THE SD CARD YET. Power up the N8 and grab your voltmeter. +Looking at the SD card connector from the edge closest to the joystick headers +you should have the following voltages: +--9 3.3v not used, pulled high +-1 3.3v /CS +-2 0 or 3.3v data to card (TXS) +--3 0v GND +--4 3.3v Vcc +-5 3.3v CLK +-6 0v GND +-7 3.3v data from card (RXS) +-8 3.3v not used, pulled high + +If you have >3.5v on any pin, switch off and check your wiring. + +8. I had a fault in the PCB, there was a broken track around pin 5 of the + connector. A quick continuity check between the SD connector and the CPU + at this point may save headaches later. You should read 2k7 between pin + 55 of CPU and pin 2 of SD connector, 2k7 between pin 57 of CPU and pin 5 + of SD connector, and <10 ohms between pin 56 of CPU and pin 7 of + SD connector. + +9. Power up again and check each pin's operation. +RXS: From the monitor do the following + O 4A 06 ;sets up CNTR with slowest clock speed + O 4A 26 ;receive a byte + I 4B ;read byte + the result should be $FF due to the pullup resistor in RR3. + Now clip a jumper wire from any 0v point to RXS and do the last two + commands again. The result should be $00. + +CLK: Use a logic probe or oscilloscope connected to the SD_CLK pin. + CLK is normally high and will pulse low when used. Use the + O 4A 26 to receive a byte and watch your probe/scope. + +TXS: TXS will stay at the same level as the last bit sent. If it is hi use + O 4B 00 ;send lo byte + O 4A 46 ;enable transmit + or if it is lo use + O 4B FF ;send hi byte + O 4a 46 ;enable transmit + +If everything has gone as detailed above then you should be ready to try the +firmware. + +N8 Firmware +There are two extra configurations for the CSIO port in the config_n8.asm file. +SDCSIO should be set to TRUE if you are using the CSIO port. The CSIO +transfers data LSB first, the SD card uses MSB first. Each data byte has to be +mirrored (i.e. swap bits around). There are two methods used. The rotate and +shift is slow but uses very little code. The lookup table is much faster but +uses an extra 256 bytes of code space. + +Mini-PPISD board +The PPISD is an updated version of the bit-bang design. It uses the PPI port +found on the N8VEM range and can be used with the 6x0x mezzanine board. It has +full 5v to 3.3v level translation, can use power from the PPI connector or an +external supply and has a choice chip select inputs so two boards can be used +on the one computer. An extra header is given for daisy chaining a DSKY board +or another PPISD board. +There are only a few points to watch out for. It cannot be used with a PPIDE +or a ParPortProp board as they double up on several pins. The chip select line +is active LOW - opposite to the Juha board. +If the PPI is being used for other purposes (such as the DSKY) then the only +programming requirements are that PPI outputs PC4 and PC5 must be kept high. +There are two jumpers. K1 selects the power source. Jumper 1-2 for an +external supply (Z80-SBC MK-I or 6x0x system), or jumper 2-3 to be powered +from the PPI connector (Z80-SBC MK-II, Zeta, N8 or SBC-188). +K2 selects which card-select line to be used. 1-2 uses PC4 and is the default +for the RomWBW firmware. Jumper 2-3 to use PC5. +There is a page on the N8VEM Wiki with the latest details. + +DGG + + diff --git a/trunk/Doc/Source/RomWBW Architecture.docx b/trunk/Doc/Source/RomWBW Architecture.docx new file mode 100644 index 00000000..ee0779b3 Binary files /dev/null and b/trunk/Doc/Source/RomWBW Architecture.docx differ diff --git a/trunk/Doc/Source/RomWBW Architecture.vsd b/trunk/Doc/Source/RomWBW Architecture.vsd new file mode 100644 index 00000000..76b85fa7 Binary files /dev/null and b/trunk/Doc/Source/RomWBW Architecture.vsd differ diff --git a/trunk/Doc/Z180 Clocking.txt b/trunk/Doc/Z180 Clocking.txt new file mode 100644 index 00000000..3f60b889 --- /dev/null +++ b/trunk/Doc/Z180 Clocking.txt @@ -0,0 +1,19 @@ +The table below can be used to determine the correct value for CLKDIV AND CNTLB +in an Z180 (N8) configuration file. OSC Freq referes to the hardware clock +oscillator frequency you are using. You can then choose a CLKDIV value which +will result in the CPU speed (frequency) shown below the oscillator frequency. + +Using your oscillator frequency (OSC) and chosen value for CLKDIV, you can +use the appropriate column to derive values to use for CNTLB for different +baud rates. + + ----- CLKDIV = 0 ----- ----- CLKDIV = 1 ----- +OSC Freq (MHz) 6.144 12.288 18.432 6.144 12.288 18.432 +CPU Freq (MHz) 3.072 6.144 9.216 6.144 12.288 18.432 + +1200 baud 04H 05H 24H 05H 06H 25H +2400 baud 03H 04H 23H 04H 05H 24H +4800 baud 02H 03H 22H 03H 04H 23H +9600 baud 01H 02H 21H 02H 03H 22H +19200 baud 00H 01H 20H 01H 02H 21H +38400 baud --- 00H --- 00H 01H 20H \ No newline at end of file diff --git a/trunk/Doc/ZSystem.txt b/trunk/Doc/ZSystem.txt new file mode 100644 index 00000000..ff807ebf --- /dev/null +++ b/trunk/Doc/ZSystem.txt @@ -0,0 +1,47 @@ +This file is a log of the work done to adapt the ZSDOS distribution to the N8VEM platforms under RomWBW. I strongly recommend reviewing the zsdos.pdf file in the Doc directory. + +The starting point was the general public release of ZSDOS that is generally available. The first line of the README file is "ZSDOS-GP. General Public Release of the ZSDOS 1.x Operating System." + +The actual ZSDOS source code was minimally modified to achieve TASM assembler compatibility. In order to minimize the number of changes to the source, I created a "wrapper" that defines a bunch of helper macros to improve compatibility. The wrapper uses a #INCLUDE to imbed the actual ZSDOS source. + +ZSDOS is really two things. ZSDOS and ZDDOS. It is the same source file, an equate determines which variation you want to build. The wrapper mentioned above can be changed to pick either one. Basically, ZSDOS has more features. ZDDOS has less features, but inlcudes date stamping code. Refer to the zsdos.pdf file for more information. I have chosen to use ZSDOS to pick up the maximum number of features. DateStamping is still available, it just uses memory outside of the OS. + +The source also allows you to compile the OS code as either v1.1 or v1.2 via an equate. This can be controled by the wrapper just like the choice of ZSDOS/ZDDOS. Version 1.2 has only a couple of small changes versus v1.1 (apparently a minor bug fix). However, there are warnings in the source that compiling the DOS as v1.2 will make it incompatible with existing overlays and applications. I encountered this myself with the date stamping code -- won't work with v1.2 because it does a version check. For now, I have chosen to use v1.1 to maximize compatibility (seems to be what everyone is doing). Ultimately, I may go back and try to rebuild everything in the distribution to bring it all up to v1.2. That is for the future though. + +As I worked through the files in the distribution, it became clear that there were problems with the distribution. For example, the .CFG files for some apps (like FILEDATE) are not acceptable to ZCNFG. Additionally, the STAMPS.DAT file contains code that simply does not work. In all of these cases, I found updated or fixed versions of the files. However, the point is that I concluded I would need to go through the distribution file-by-file and validate everything, replacing anything that was not working as needed. See the notes below for what I did. + +Beyond the construction and integration of the actual DOS itself, the majority of the work has been to update the distribution files as needed to get them all functional. Then, as appropriate, I have added application files to the ROM Disk for the ZSystem builds. + +The remainder of this document details the changes I made as I went along. In all cases, my goal was to keep the result as close to the original distribution as possible. I started by copying all of the files from the distribution (contained in zsdos2.zip) into Support\ZSDOS. From there I tested, modified, updated, and customized as documented below. Finally, I cherry picked files that made sense to include on the ZSystem ROM disks. + +1. CLOCKS.DAT has been updated to include the N8VEM clock drivers, N8VEMCLK AND N8CLK. I have also added the SIMHCLOK clock driver. + +2. STAMPS.DAT has been replaced with an updated version. The update was called STAMPS11.DAT and was found on the Walnut Creek CP/M CDROM. The original version has a bug that prevents RSX (resident system extension) mode to fail to load properly. + +3. The original LDTIMD and LDTIMP were built against ZSDOS 1.0 and refused to load under ZSDOS 1.1. Used SETUPZST to recreate LDTIMD and LDTIMP for compatibility with ZSDOS 1.1. They were built exactly the same as previously: Relative Clock driver and RSX mode loading. + +4. Updated FILEDATE.COM and FILEDATE.CFG from original v1.7 to v2.1. The FILEDATE.CFG originally supplied was invalid. + +5. Updated COPY.CFG. The original one was invalid and appeared to be for a much oder version of COPY. + +6. Updated FILEATTR to v1.6A. Original FILEATTR.CFG was invalid. FILEATTR.CFG replaced with FA16.CFG. Added associated files FA16.DOC, FA16A.FOR, FA16CFG.TXT. + + +Usage Notes +----------- + +1. ZSDOS has a concept of fast relog of drives. This means that after a warm start, it avoids the overhead of relogging all the disk drives. There are times when this causes issues. After using tools like CLRDIR or MAP, you may need to run "RELOG" to get the drive properly recognized by ZSDOS. + +2. ZSVSTAMP expects to be running under the ZCPR 3.X command processor. By default, RomWBW uses ZCPR 1.0 (intentionally, to reduce space usage) and ZSVSTAMP will just abort in this case. It will work fine if you implement NZCOM. ZSVSTAMP is included solely to facilitate usage if/when you install NZCOM. + +3. FILEDATE only works with DateStamper style date stamping. If you run it on a drive that is not initialized for DateStamper, it will complain "FILEDATE, !!!TIME&.DAT missing". This is normal and just means that you have not initialized that drive for DateStamper (using PUTDS). + +4. ZXD will handle either DateStamper or P2DOS type date stamping. However, it MUST be configured appropriately. As distributed, it will look for P2DOS date stamps. Use ZCNFG to reconfigure it for P2DOS if that is what you are using. + +4. Many of the tools can be configured (using either ZCNFG or DSCONFIG). The configuration process modifies the actual application file itself. This will fail if you try to modify one that is on the ROM disk because it will not be able to update the image. + +5. DATSWEEP can be configured using DSCONFIG. However, DSCONFIG itself needs to be configured first for proper terminal emulation by using SETTERM. So, run SETTERM on DSCONFIG before using DSCONFIG to configure DATSWEEP! + +6. After using PUTDS to initialize a directory for ZDS date stamping, I am finding that it is necessary to run RELOG before the stamping routines will actually start working. + +7. Generic CP/M PIP and ZSDOS path searching do not mix well if you use PIP to copy to or from a directory in the ZSDOS search path. Best to use COPY from the ZSDOS distribution. \ No newline at end of file diff --git a/trunk/Doc/cpm22-m.pdf b/trunk/Doc/cpm22-m.pdf new file mode 100644 index 00000000..d030d4ac Binary files /dev/null and b/trunk/Doc/cpm22-m.pdf differ diff --git a/trunk/Doc/flash.man b/trunk/Doc/flash.man new file mode 100644 index 00000000..3b6a35df --- /dev/null +++ b/trunk/Doc/flash.man @@ -0,0 +1,42 @@ +NAME + flash - in-situ 29F040 flash ROM programmer for N8VEM, Zeta and N8 + computers. + +SYNOPSIS + flashz + flashn8 + +DESCRIPTION + The flashz and flashn8 erase and program the FLASH ROM chip from an + image file. flashz is used for the N8VEM Z80-SBC and Zeta computers. + flashn8 is used with the N8 home computer. Both function the same + except in the way memory is addressed. + + flash expects a 512k file in the same directory containing the image + that will be programmed into the ROM. This file must have the + unimaginative filename of ROM.IMG. The whole process of erasing and + programming the ROM takes less than a minute for an 8MHz Zeta - far + less than the time taken to upload your new image. + + This program is only suitable for 512k FLASH ROMs. Older chips + use 14-bit addresses of 5555h and 2AAAh for their command sequences, + newer chips use x555h and x2AAh. This program uses the older addresses + as the newer chips are backward compatible. Versions of this program + earlier than v0.6 were for newer chips only. + + Assemble with TASM using the commands + tasm -t80 -g3 flashz.asm flashz.com + tasm -t80 -g3 flashn8.asm flashn8.com + +JUMPERS + The following jumpers must be in place on the boards to allow the + 29F040 to be programmed. + For the N8VEM Z8-SBC MK-II: K1 1-2, K6 2-3, K8 2-3 + For the N8: K3 1-2, K4 2-3, K5 2-3 + For the Zeta, no jumpers need (or can) be set. + +AUTHOR + Written by David Giles so he doesn't have to open the box his Zeta + lives in so often. Reports to N8VEM group or vk5dg@internode.on.net + + diff --git a/trunk/Doc/zcpr.doc b/trunk/Doc/zcpr.doc new file mode 100644 index 00000000..940508d3 --- /dev/null +++ b/trunk/Doc/zcpr.doc @@ -0,0 +1,1387 @@ + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + + + Documentation on ZCPR - A Z80 Replacement for the CP/M CCP + + + + + ZCPR is a Group Project By the CCP-GROUP: + RLC - Richard Conn FJW - Frank Wancho + KBP - Keith Peterson RGF - Ron Fowler + + + ZCPR Documentation By RLC + + + + + + + + Table of Contents + ----- -- -------- + + Introduction 2 + + Part A: Installation Instructions 4 + ZCPR Integration Example 5 + Setting the ZCPR Inline Options 8 + REL, BASE, CPRLOC, RAS, SUBA, CLEVEL3 8 + Customization Symbols 8 + NLINES, WIDE, PGDFLT 8 + PGDFLG, MAXUSR, SYSFLG, SOFLG, SUPRES, + DEFUSR, SPRMPT, CPRMPT, NUMBASE, 9 + SECTFLG, FENCE 10 + Patching SUBMIT.COM 10 + + Part B: Usage Instructions and Explanation of + Commands 11 + The ZCPR Command Hierarchy Search 11 + The ZCPR-Resident Commands 14 + DIR, ERA 14 + LIST, TYPE, SAVE 15 + REN, USER, DFU 16 + JUMP, GO, GET 17 + ZCPR Error Messages 18 + + Part C: ZCPR Command Levels and How to Use Them 19 + + + + + + + + + Page 1 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + Documentation on ZCPR - A Z80 Replacement for the CP/M CCP + + + + + ZCPR is a replacement for the CP/M Console Command Processor + (CCP) which is designed to run as part of CP/M on Z80-based + microcomputers. In most cases it is upward-compatible with the + original CP/M Version 2.2 CCP. + + ZCPR, however, provides many extensions to the CP/M CCP. + Included in these extensions are the following features: + + . The TYPE function can be made to page or not page its + output at the user's discretion + + . A LIST function is available which sends its output + to the CP/M LST: Device and does NOT page + + . The DIR command has been extended to allow the dis- + play of the system files or all files + + . The ERA command now prints out the names of the files + it is erasing + + . The current user number may be included as part of + the command prompt; if the user is under a number other than 0, + the prompt is of the form 'du>' (like 'A2>' or 'B10>'), and, if + the user is under 0, the prompt may be 'd>' or 'd0>' as per his + choice + + . The SUBMIT facility has been changed in two basic + ways: + - the prompt changes to 'du$' or 'd$' when the + SUBMIT command is printed + - the $$$.SUB is executed from drive A: (note that + the original SUBMIT problem now exists, but the new SUB.COM + facility corrects it); the CCP-GROUP definition of an Indirect + Command File now applies, and this definition is that any + sequence of commands which may be issued from the console is also + a valid sequence of commands for execution from an Indirect + Command File; hence, the sequence: + + DIR + B: + DIR + A: + + may be issued from either the console or an Indirect Command + File, and the results of the execution of this sequence are the + same. Basically, this says that Indirect Command Files are + upward-compatible to the console input (but not necessarily that + the contents of an Indirect Command File may be issued at the + console without modification). + + + Page 2 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + . A command-search hierarchy is now implemented which + is executed roughly as follows: + - the user's command is checked against the CPR- + resident commands and executed immediately if a match is found + - failing that, the current user number on the + current disk is scanned for the COM file; the COM file is loaded + and executed if found + - failing that, a default user number (initially 0 + but can be reset with the DFU CPR-resident command) on the cur- + rent disk is scanned for the COM file; the COM file is loaded and + executed if found + - finally, failing that, the default user number + on disk A: is scanned for the COM file; the COM file is loaded + and executed if found or an error message (COMMAND?, when COMMAND + was the user's command name) is printed + + . The numeric argument for the SAVE command can be + specified in hexadecimal so that the user may employ the values + presented by tools such as DDT exactly as they are given + + . A GET command which loads a file at a specified + memory address and a JUMP command which "calls" the subroutine at + a specified memory address have been added; a GO command which + "calls" the subroutine at 100H (subset of the JUMP capability) + has also been added + + + This document provides the user of ZCPR with the following + information: + + Part A: Installation Instructions + Part B: Usage Instructions and Explanation of Commands + Part C: ZCPR Command Levels and How to Use Them + + + + + + + + + + + + + + + + + + + + + + + + Page 3 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + Part A + Installation Instructions + + In order to install ZCPR on a target microcomputer (must be + currently running CP/M 2.2), the user must know two basic things: + + 1) Where his CCP is currently running in memory + 2) Where his CCP is located in the SYSGEN image, or, + for systems which don't support SYSGEN (such as P&T CP/M 2.2 for + the TRS-80 Model II), where his CCP is located on disk and how to + place the new ZCPR on top of it + + The first question is answered relatively easily. A pro- + gram, known as either BDOSLOC or BDLOC (for BDOS Locator), is + provided with ZCPR. You should assemble this program for your + particular computer (change the base ORG if you are running non- + ORG-0 CP/M) and execute it. Upon execution, it will provide you + with the base address of (1) the BDOS and (2) the CCP for your + particular system. BDOSLOC has worked correctly for all systems + tested so far, but there is always a chance that it may NOT work + for some non-tested system. For the time being, assume that it + works correctly and record the starting base page address of your + CCP. + + The second question is not answered nearly so easily. If + you have the ability to SYSGEN your system, it is much easier + (commonly) than if you do not. You must, after assembling the + ZCPR properly, integrate it into the sysgen (or disk) image of + CP/M. This can be done by obtaining a SYSGEN image of your + system, scanning it via a debugger such as DDT to find the offset + for the CCP, reading the new CPR in on top of the old one, and + finally running SYSGEN again to place the resultant system on + disk. If you DO NOT have SYSGEN capability, a Disk Utility + program is required to locate the CCP on disk and then write the + new ZCPR on top of the old one. The net result of this + integration is the placement of the new ZCPR onto disk in the + proper place so that it will be loaded with the rest of CP/M on + cold boot and executed properly. + To find the original CCP, you typically have to locate it by + its appearance. It is probably stored contiguously on disk, so, + once it is found, a sequential overwrite is all that is required. + Probability is extremely high that it is stored contiguously in + the SYSGEN image. The CCP starts with two (2) and ONLY TWO jump + instructions followed by a buffer area (possibly containing an + initial command and/or the Digital Research copyright notice). + The Digital Research manuals show the CCP to reside at address + 980H in the SYSGEN image, but this may vary with system. To + find this image, use DDT or some other such debugger, load the + SYSGEN image you can get via SYSGEN, and examine memory starting + at around 900H for the two (and ONLY two) jumps described above. + If you find an area with more than two jumps (a group of them), + you are probably looking at the BIOS and should go lower for the + CCP. The CCP will probably start on an even page or half-page + address (like 900H, 980H, 1100H, etc). + + + Page 4 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + Now that the location of the CCP has been found, record this + address for later. You are now ready for the integration of ZCPR + into your system. To do this, perform the following steps using + the information of the page address of the CCP (obtained from + BDOSLOC and called CPRLOC within ZCPR) and the SYSGEN image + address of the CCP (called IMAGE for reference in this document). + + 1. Edit ZCPR and set the CPRLOC equate to the value + obtained from above. Also set any flags and values as you desire + (see the section on ZCPR Customization below). When satisfied, + end the edit session. + + 2. Assemble ZCPR with MAC (or equivalent). This + assembler is required because of the MACROs used. Only the + resultant HEX file is required. + + 3. Assuming that you can use SYSGEN, obtain a SYSGEN + image of your current CP/M system and save it on disk. + + 4. Load the SYSGEN image into memory with DDT (or + equivalent). Once loaded, verify that the original CCP is at the + IMAGE address found above and compute the integration offset + using the DDT H command: + H, + The second number displayed gives you the OFFSET value required + for step 5. + + 5. Integrate ZCPR into your SYSGEN image via DDT's I + and ROFFSET commands. Use IZCPR.HEX (or the name of your version + of ZCPR) to load the FCB and ROFFSET (where OFFSET was computed + in step 4) to load the ZCPR.HEX file into memory at the proper + location. Check to see that ZCPR is indeed properly loaded by + examining the SYSGEN IMAGE area. + + 6. Place the new system on disk by running SYSGEN and + NOT loading the system from disk (use the memory image). + + For further clarification of the above process, the + following is a sample terminal session which outlines the steps + taken. + + ZCPR Integration Example + + + B>; Sample terminal session for integrating ZCPR + B>sysgen + SYSGEN VER 2.2 + SOURCE DRIVE NAME (OR RETURN TO SKIP)b + SOURCE ON B, THEN TYPE RETURN <-- I hit the RETURN key here + FUNCTION COMPLETE / + DESTINATION DRIVE NAME (OR RETURN TO REBOOT) <-- and here + B>save 44 cpm56.com <-- We now have a SYSGEN image of CP/M + to work with + + + + Page 5 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + B>xdir + XDIR Version 2.6 User Number: 0, Double Density + File Attributes: Non-System + + Filename.Typ Size K Filename.Typ Size K Filename.Typ Size K + -------- --- ------ -------- --- ------ -------- --- ------ + !TEXTWRK.-12 0 CPR .DOC 8 EE687 .TXT 4 + CPR .AQM 34 TFS .HLP 6 EE687PRE.TXT 4 + CPR .ASM 50 CONTENTS.T01 6 SW1 .TXT 10 + CPR .BAK 4 CONTENTS.T02 4 SW2 .TXT 2 + CPM56 .COM 12 CONTENTS.T03 4 + B: 30 Entries & 22 Files -- 338K Bytes Remaining + File Data: 14 Files -- 154K Bytes Displayed + B>bdosloc <-- Now to locate the CCP's address + The Base Page Address of this system's BDOS is C5 + The Base Page Address of this system's CCP is BD <-- This is it + B>ddt cpm56.com <-- Now to find the CCP in the SYSGEN image + DDT VERS 2.0 + NEXT PC + 2D00 0100 + -d900,90f <-- Start looking around here + 0900 31 80 E7 3E 06 3C 3C FE 1B CA 00 C2 DA 11 E7 D6 1..>.<<......... + -da00,a0f + 0A00 31 00 01 01 01 0C C5 CD 0F E4 21 00 BE 11 00 04 1.........!..... + -db00,b0f + 0B00 31 00 01 01 01 11 C5 CD 0F E4 21 00 C0 11 00 02 1.........!..... + -db80,b8f + 0B80 31 00 01 01 09 01 CD A8 00 21 00 D2 11 00 C2 0E 1........!...... + -- Detail Left Out -- + -d1100 <-- I found it at 1100H; note the 2 JMP's + 1100 C3 FF BD C3 FB BD 50 10 20 20 20 20 20 20 20 20 ......P. + 1110 20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 ........ + 1120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + -- Detail Left Out -- + -^C <-- Return to CP/M; I know that CPRLOC will be + BD00H and the IMAGE offset is 1100H + + B>ed cpr.asm {edit ZCPR here and place CPRLOC=BD00H}# + -- Detail Left Out -- + + B>mac cpr $pz sz <-- Now to assemble the CPR + CP/M MACRO ASSEM 2.0 + C4F0 <-- Note that CPR MUST end before BDOS + begins! + 014H USE FACTOR + END OF ASSEMBLY + + + + + + + + + + + + Page 6 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + B>ddt cpm56.com <-- Now to integrate! + DDT VERS 2.0 + NEXT PC + 2D00 0100 + -h1100,bd00 <-- Compute offset for new CPR + CE00 5400 <-- Offset is 5400H + -icpr.hex <-- Init FCB + -r5400 <-- Read in new CPR with offset + NEXT PC + 2D00 0000 + -^C <-- Done! + B>sysgen <-- Now to SYSGEN onto disk + SYSGEN VER 2.2 + SOURCE DRIVE NAME (OR RETURN TO SKIP) <-- Use memory image + DESTINATION DRIVE NAME (OR RETURN TO REBOOT)b <-- onto B: + DESTINATION ON B, THEN TYPE RETURN + FUNCTION COMPLETE + DESTINATION DRIVE NAME (OR RETURN TO REBOOT) <-- Done for now + + B> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page 7 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + Setting the ZCPR Inline Options + + The following are the four basic options available to the + user under ZCPR for customization of his package. + + Option Name Function + + REL Configures CPRLOC (CPRLOC equ 0) for integration + via MOVCPM rather than the DDT/SYSGEN technique + outlined above; set to TRUE for MOVCPM integra- + tion or FALSE for DDT/SYSGEN integration + + BASE Base address of your CP/M system; standard CP/M + has a base of 0, but some CP/M systems (such as + for the TRS-80 Model I and Heath/Zenith H89/Z89) + start physical RAM memory at a higher address; + equate BASE to the starting RAM memory address of + your system + + CPRLOC This is the starting address of ZCPR; set the + second CPRLOC equate to the address you obtain + from BDOSLOC + + RAS This is an equate which masks out selected ZCPR + command functions for security purposes on + Remote Access Systems such as Bulletin Boards; + the masked out functions currently include + SAVE, ERA, REN, JUMP, GO, and GET; set RAS to TRUE + to mask these out or FALSE to leave them in + + SUBA This is an equate which determines the drive + onto which ZCPR will look for an executing + Indirect Command File. If the basic philosophy + of the Indirect Command File described above is + to be maintained, this symbol should be set to + TRUE (look on drive A: for the $$$.SUB file); if + not, this symbol should be set to FALSE (look on + the default drive from the $$$.SUB file). To + review, the basic philosophy of the Indirect + Command File is that any sequence of commands + which may be issued from the console (within + reason, which means NOT to erase a $$$.SUB file) + may also be issued from within an Indirect + Command File, and the resultant execution should + be identical (same functions performed). + + CLEVEL3 This equate enables or disables extended Command + Level 3 Processing. If set to TRUE, extended + Command Level 3 Processing is enabled and the user + command line is automatically capitalized, the + terminating zero is placed at the end of the + buffer, and the internal CIBPTR is set correctly + (see later for more information). + + + + Page 8 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + Customization Symbols + + The following symbols are provided for further customization + of ZCPR to a user's particular tastes and hardware facilities. + + Option Name Function + + NLINES Number of lines on the user's CRT for paging + + WIDE This equate is used to select a narrow or wide + display under the DIR command; if WIDE is equated + to TRUE, each file name is separated by two + spaces, a FENCE, and two more spaces; if WIDE is + equated to FALSE, each file name is separated by + one space, a FENCE, and one more space + + PGDFLT This is the Paging Default flag for the TYPE + command; if PGDFLT is set to TRUE, the TYPE + command will page its output by default and + the P option on the TYPE command (see below) + will prohibit paging; if PGDFLT is set to FALSE, + the TYPE command will NOT page its output by + default and the P option will enable paging + + PGDFLG This sets the option character in the command + line for the TYPE command (the 'P' mentioned + above); if the user wishes to change this option + character, he need only change this equate + + MAXUSR This is the largest user number recognized by + the USER command; if the user wishes to protect + the higher user areas, he may set this symbol + to the highest area normally accessable; 15 is + the largest permitted value for MAXUSR + + SYSFLG This is the option character for the DIR command + line which is used to specify that DIR search + All Files (both $SYS and $DIR) for its display; + the distributed default for this is 'A' + + SOFLG This is the option character for the DIR command + line which is used to specify that DIR search + ONLY the $SYS files for its display; the distri- + buted default for this is 'S' + + SUPRES Set SUPRES to TRUE to suppress printing the user + number when the user is under User Number 0 or + set SUPRES to FALSE to ALWAYS display the User + Number with the CPR prompt; with SUPRES set to + TRUE, a user on B: in user 0 sees 'B>' as the + prompt, but with SUPRES set to FALSE, a user on + B: in user 0 sees 'B0>' as the prompt + + + + Page 9 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + DEFUSR This is the CPR-default user number which is + searched in the command hierarchy for the COM + files (distributed as 0); the DFU changes this + temporarily until a Warm Boot or Cold Boot is + done, at which time the search reverts to this + value + + SPRMPT This is the CPR prompt character which indicates + that a SUBMIT file is in execution; by default + it is set to '$', so prompts like 'A$' appear + during SUBMIT file execution + + CPRMPT This is the CPR prompt character which indicates + that the CPR is awaiting a user console command; + by default it is set to '>', so prompts like + 'A>' appear during user input to the CPR + + NUMBASE This is the escape character used by those + commands which require a DECIMAL number as + an argument; placing this character after + the number argument switches the base to + HEXADECIMAL; for example, 'SAVE 15 MYFILE' can be + expressed as 'SAVE FH MYFILE' if NUMBASE is + set to 'H' (the default) + + SECTFLG This character constant is the suffix option for + the SAVE command which specifies that sectors, + as opposed to pages, are to be saved; the default + value is 'S' + + FENCE This is the character printed to separate entries + in a directory listing; it's default value is '|' + + + Patching SUBMIT.COM + + SUBMIT.COM may be patched to run with ZCPR by the following + procedure (this is recommended if the user does not have + SUB.COM). This patch simply makes it always place the $$$.SUB + file on Drive A:. Illustrative terminal session follows: + + A>ddt b:submit.com + DDT VERS 2.0 + NEXT PC + 0600 0100 + -s5bb <-- Patch is at 5BB Hex + 05BB 00 1 <-- Change 0 (default drive) to 1 (drive A:) + 05BC 24 . <-- That's it! + -d5b0 5cf <-- See change + 05B0 00 00 00 00 00 00 30 30 31 20 24 01 24 24 24 20 ......001 $.$$$ + 05C0 20 20 20 20 53 55 42 00 00 00 1A 1A 1A 1A 1A 1A SUB......... + -^C <-- Done + A>save 5 newsubmt.com <-- Save new SUBMIT.COM file + + + + Page 10 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + Part B + Usage Instructions and Explanation of Commands + + + The following instructions are written with the assumption + that the reader is quite familiar with how to use CP/M 2.2 and + its CCP. ZCPR is written as a logical extension of the CP/M 2.2 + CCP philosophy and should be addressed as such. + + + + The ZCPR Command Hierarchy Search + + The first, and most basic thing, to learn about ZCPR is the + order in which is searches for a COM file for execution or a file + specified by the GET command. Under the CP/M 2.2 CCP, if the + specified COM file command was not found on the current drive in + the current user area, the CCP aborted with an error message. + ZCPR, however, continues searching from this point a maximum of + two more levels. This command hierarchy search was outlined + above and is described here in further detail. + + 1. If the command is of the form 'COMMAND' and NOT + 'd:COMMAND', the CPR-resident command list is searched for a + match. If the match is found, the CPR-resident command is + immediately processed. If the match is not found or the command + is of the form 'd:COMMAND', the next step is taken. Note that + the 'd:COMMAND' form is good for executing a command COM file + which has the same name as a CPR-resident command (such as SAVE + or DIR). + + 2. If the command is of the form 'd:COMMAND', disk + drive 'd:' is temporarily logged in for the purpose of the + command search. Otherwise, the currently logged-in drive is + used. + + 3. Now the file named COMMAND.COM is searched for. If + found, it is loaded into memory starting at 100H and executed. + If not, proceed to step 4. + + 4. Now that the first search for COMMAND.COM has + failed, the CPR checks to see if the user is under the current + Default User Number. The Default User Number may be that set by + the DEFUSR equate in the CPR or that set by the user via the DFU + command. DEFUSR is in effect if DFU has not been issued since + the last Warm or Cold Boot, and DFU is in effect if it was issued + since the last Warm or Cold Boot. If the user is NOT under the + current Default User Number, ZCPR temporarily logs him into it + and searches the directory. If COMMAND.COM is found, it is + loaded as described above and executed. If not, ZCPR proceeds to + the next step. + + + + + + Page 11 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + 5. The user is now in the Default User Number, and at + this point, ZCPR checks to see if the user is on disk drive A:. + If not, it temporarily logs into A: and searches the default user + number of A: for COMMAND.COM. If found, it is loaded as + described above and executed. If not, ZCPR prints the command + name as an error message and returns to command input mode, + aborting the SUBMIT file if COMMAND came from it. + + In all cases of the search above, if COMMAND.COM is found, + after it is loaded into memory, ZCPR resets the user to his + original disk drive and user number. Hence, the files referenced + by the user by default are obtained from this environment. + + To illustrate this command hierarchy search, consider the + following examples: + + Example 1: DEFUSR equ 0 {default user number is 0} + + B10> <-- User is on Drive B:, User Number 10 + B10>ASM TEST.BBZ <-- User wishes to assemble TEST.ASM in + Drive B:, User 10 + <-- At this point, ZCPR looks on B:/10 for ASM.COM, fails, + looks on B:/0, fails, and finally looks on A:/0; it + finds ASM.COM here and goes back to B:/10 for the file + + + Example 2: DEFUSR equ 0 and DFU issued + + B10> <-- User is on Drive B:, User Number 10 + B10>DFU 5 <-- User Selects User 5 as default + B10>ASM TEST.BBZ <-- As above + <-- At this point, ZCPR looks on B:/10 for ASM.COM, fails, + look on B:/5, fails, and finally looks on A:/5; it + fails here also and prints ASM? as an error message + + Example 3: DEFUSR equ 0 + + B> <-- User is on Drive B:, User Number 0 + B>ASM TEST.BBZ <-- As above + <-- At this point, ZCPR looks on B:/0 for ASM.COM, fails, + looks on A:/0, fails, and prints error message + + Example 4: DEFUSR equ 0 + + A10> <-- User is on Drive A:, User Number 10 + A10>ASM TEST.AAZ <-- As above, but file on A: + <-- At this point, ZCPR looks on A:/10 for ASM.COM, fails, + looks on A:/0, fails, and prints error message + + + + + + + + + Page 12 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + Another Example: + + For example, if the user is logged into Drive B: in + User Area 10, the Default User Number is 0, and the following COM + files are present as indicated -- + + WM.COM on Drive A: in User 0 + MBASIC.COM on Drive A: in User 0 and on + Drive B: in User 0 + TEST.COM on Drive B: in User 10 and Drive B: + in User 0 + + then the following happens when the following commands are + issued from the console (or Indirect Command File): + + B10>WM TEST2.TXT + \ \ \__ File to be edited + \ \__ Invoke the WM.COM file (Word Master editor) + \__ User is on Drive B: in User Area 10 + + Results: + ZCPR searches B: User 10, B: User 0, and A: User 0 for + WM.COM; it finds WM.COM in A: User 0, loads it, logs the user + back into B: User 10, and executes it. + + B10>MBASIC + \ \__ Invoke the MBASIC.COM file (MBASIC Interpreter) + \__ User is on Drive B: in User Area 10 + + Results: + ZCPR searches B: User 10 and B: User 0 for MBASIC.COM; + it finds MBASIC.COM in B: User 0, so it doesn't bother to look on + A: User 0. MBASIC.COM is then loaded and executed as described + in the previous example. + + B10>TEST + \ \__ Invoke the TEST.COM file (TEST program) + \__ User is on Drive B: in User Area 10 + + Results: + ZCPR searches B: User 10 for TEST.COM; it finds + TEST.COM in B: User 0, so it doesn't bother to look further (if + it had, it would have found TEST.COM in B: User 0). TEST.COM is + then loaded and executed as described above. + + B10>TEST2 + \ \__ Invoke the TEST2.COM file (TEST2 program) + \__ User is on Drive B: in User Area 10 + + Results: + ZCPR searches B: User 10, B: User 0, and A: User 0 for + TEST2.COM; it doesn't find it, so it issues the error message + 'TEST2?', which says it couldn't find TEST2.COM. + + + + Page 13 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + + The ZCPR-Resident Commands + + The following pages describe the ZCPR-Resident Commands. + These are commands located within ZCPR itself which are executed + from within ZCPR. The phrases and refer to ambiguous + file name and unambigous file name as per the CP/M convention. + + Command: DIR + Function: To Display a listing of the names of the files on disk + Forms: + DIR <-- Displays $DIR files + DIR S <-- Displays $SYS files + DIR A <-- Displays both $DIR and $SYS files + Customization Variables: + WIDE SYSFLG SOFLG FENCE + Examples: + DIR *.ASM <-- All $DIR .ASM files + DIR *.COM S <-- All $SYS .COM files + DIR *.COM A <-- All .COM files + Notes: + If a file is scanned for and no such name exists on disk, + the 'No Files' message will appear. However, if a file is + scanned for and the name exists as a $SYS file and $DIR files are + being scanned for, no file name is displayed but the 'No Files' + message does NOT appear. For example, if TEST.COM is a $SYS file + and 'DIR TEST.COM' is issued, no message appears. If 'DIR + TEXT.COM' is issued and TEXT.COM does not exist on disk, the 'No + Files' message is displayed. + + + Command: ERA + Function: To Erase the specified $R/W files from disk + Forms: + ERA <-- Erase both $DIR and $SYS files + Customization Variables: + WIDE FENCE + Examples: + ERA *.ASM <-- Erase all .ASM files + ERA *.* <-- Erase all files + Notes: + If a $R/O file is encountered, a BDOS error message will be + displayed and the procedure is stopped. The user is unsure at + this time as to which files have been erased and which have not + and should check. Sorry for this problem! The ERASE command (to + be given to SIG/M by RLC in the near future) is a solution to + this problem. + + + + + + + + + Page 14 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + Command: LIST + Function: To Print the specified file on the CP/M LST: device + Forms: + LIST <-- Print the file (no paging) + Customization Variables: + -None- + Examples: + LIST TEST.TXT <-- Print TEST.TXT on LST: + Notes: + If the file has a $SYS attribute, it will be found as well + as those with $DIR attributes. + + + Command: TYPE + Function: To Print the specified file on the CP/M CON: device + Forms: + TYPE <-- Print the file with the paging deflt + TYPE P <-- Print the file with the paging deflt + negated + Customization Variables: + NLINES PGDFLT PGDFLG + Examples: + TYPE TEST.TXT + TYPE TEST.TXT P + Notes: + When the display pauses during paging, type any char to + continue or ^C to abort. ^S also works. + + + Command: SAVE + Function: To Copy the TPA starting at 100H to disk + Forms: + SAVE <-- in DEC + SAVE H <-- in HEX + SAVE S <-- Number of sectors + SAVE H S <-- Number of sectors + Customization Variables: + NUMBASE RAS + Examples: + SAVE 15 MYFILE.TXT <-- 15 pages saved + SAVE FH MYFILE.TXT <-- 15 pages saved + SAVE 10H MYFILE.TXT S <-- 16 sectors (8 pages) saved + Notes: + If the file name to be saved already exists, then SAVE will + exit with the message 'Delete File?'; if the user REALLY wants to + save under this name, he may then type Y or y and the current + file will be deleted and then recreated containing the specified + part of the TPA. + + + + + + + + Page 15 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + + Command: REN + Function: To Change the name of a disk file + Forms: + REN = + Customization Variables: + RAS + Examples: + REN NEWFILE.TXT=OLDFILE.TXT + Notes: + If already exists, the message 'Delete File?' will + be printed and the user may respond with Y or y to delete the + current and then rename to . + + Command: USER + Function: To Change the current user number + Forms: + USER <-- in DEC + USER H <-- in HEX + Customization Variables: + -None- + Examples: + USER 15 USER FH USER 0 + USER <-- Same as USER 0 + Notes: + -None- + + + Command: DFU + Function: To Temporarily Change the default user number for the + command hierarchy search + Forms: + DFU <-- in DEC + DFU H <-- in HEX + Customization Variables: + -None- + Examples: + DFU 15 DFU FH DFU 0 + DFU <-- Same as DFU 0 + Notes: + See above for explanation. + + + + + + + + + + + + + + + Page 16 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + + Command: JUMP + Function: To "call" the subroutine at the specified page address + Forms: + JUMP
<--
in HEX + Customization Variables: + NUMBASE RAS + Examples: + JUMP E000 or JUMP E000H <-- Jump to E000H + JUMP <-- Jump to 000H + JUMP 0 <-- Jump to 000H + Notes: + JUMP performs a subroutine "call", so the called routine may + return to the ZCPR by either a RET or a Warm Boot. + + + Command: GO + Function: To "call" the subroutine starting at 100H + Forms: + GO <-- Execute reentrant at 100H + Customization Variables: + RAS + Examples: + GO *.ASM <-- Assuming XDIR is loaded, + gives directory of *.ASM + Notes: + This command is identical in function to JUMP 100H; JUMP, + however, leaves the address as the first entry in CP/M BASE + 80H + (the input line buffer), while GO has no such address. + + + Command: GET + Function: To load a file from disk into memory starting at the + specified page + Forms: + GET
<--
in HEX + Customization Variables: + NUMBASE RAS + Examples: + GET 8000 TEST.80 <-- Load TEST.80 starting at 8000H + GET 100 TEST.80 or GET 100H TEST.80 <-- Load TEST.80 + starting at 100H + GET 0 TEST.80 <-- Load TEST.80 starting at 000H + Notes: + GET searches for the specified file according to the same + command hierarchy search employed by the ZCPR command scanner. + Hence, if the user is on B:/10 and the file is on A:/0 with the + current default user number at 0, GET will search from B:/10 to + B:/0 to A:/0 in looking for the file. + + + + + + + Page 17 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + ZCPR Error Messages + + The following are the error messages issued by ZCPR and + their meanings. + + Message Meaning + + ? Printed after a command or an argument means that such + was invalid + + No File From DIR, this means that DIR did not locate any files + Also from ERA with the same meaning + + All? Issued in response ERA *.*, asks the user is he really + wants to erase all the files. Unlike under the + original CP/M 2.2 CCP, single character input is + required (Y or y for yes and anything else for no) + with NO to end the line + + Full From SAVE, means that there is not enough space on + disk + From GET or command load by CPR, means that there + is not enough space in memory + + Delete File? + From REN or SAVE, means that the file specified already + exists on disk and the user may type Y or y to delete + it and proceed with the REN or SAVE function + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page 18 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + Part C + ZCPR Command Levels and How to Use Them + + + ZCPR Version 1.0 and beyond supports three distinct command + levels in its implementation. Each level constitutes a different + way to issue a command for ZCPR to process. + + Command Levels 1 and 2 are common to all implementations of + CP/M and CP/ZM from CP/M Version 1.4. Command Level 1 is that + command level in which the command is issued by the user from his + console terminal. The prompt 'd>' or 'du>' appears on the + terminal, and the user is allowed to enter the command with + editing from the terminal. Command Level 2 is that command level + in which the command is entered from an executing $$$.SUB file. + + In both cases, the command is stored in the internal ZCPR + buffer called CIBUFF (Command Input BUFFer). Under both Command + Levels 1 and 2, the command is placed into this buffer, the + characters of the command line are capitalized, a character count + which indicates the number of characters in the command line is + stored in CBUFF (the byte before CIBUFF), an ending binary 0 is + placed after the last character in the command line, and the + internal pointer CIBPTR (Command Input Buffer PoinTeR) is set to + point to CIBUFF (the first character of the command line). + + Command Level 3 is an extended concept to Command Levels 1 + and 2 which is specifically supported by ZCPR Version 1.0 and + beyond. This command level allows a transient program to place a + command line into CIBUFF and the character count into CBUFF and + have this command line executed by ZCPR. Once control is trans- + ferred to ZCPR to execute the command line, the transient program + which placed the command line loses control and the command is + executed exactly as though it had been typed by the user at his + console terminal. + + In order for a transient program to utilize the Command + Level 3 facility, this program MUST do the following: + + 1. Locate the ZCPR. Since the ZCPR is ALWAYS 2K bytes + in size and located directly under the BDOS, the transient can + locate the ZCPR by examining the BDOS entry page address at + location 7 and subtracting 8 from this number (8 pages = 2K + bytes). The resulting number is the base page address of ZCPR. + + 2. Store the command line in CIBUFF and the character + count in CBUFF. Knowing the base page address of ZCPR, the + following information is useful in doing this: + + + + + + + + Page 19 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + ORG CPRLOC ;Base Address of ZCPR + JMP CPR ;Enter ZCPR and Execute Default Cmd + JMP CPR1 ;Enter ZCPR and Don't Execute + MBUFF: DB BUFLEN ;Size of CIBUFF in bytes + CBUFF: DS 1 ;Number of Bytes in Command Line + CIBUFF: DS BUFLEN ;Buffer for Command Line + DS 1 ;Buffer for Ending 0 (set by ZCPR) + CIBPTR: DS 2 ;Address of CIBUFF (set by ZCPR) + + + 3. Obtain the User/Disk Flag. Location 4 contains + this number, but the user may select a flag of his choice. This + flag is one byte long, and the high-order nybble (4 bits) + contains the user number and the low-order nybble contains the + disk number to process the command from. The User/Disk Flag is + to be passed to ZCPR in the C Register. + + 4. When ready, transfer control to ZCPR to process the + command by JMPing to the base address of ZCPR. The first JMP in + the JMP Table given above is at this address. At this time, ZCPR + will log in the user and disk in the User/Disk Flag and process + the Command Level 3 Command Line. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Page 20 + + + + + + ZCPR - A Z80 Replacement for the CP/M CCP + + + + + The following is a sample program which illustrates the + steps outlined above: + + ; + ; Demonstration of Command Level 3 Facility by RLC + ; + udflag equ 4 ;Address of User/Disk Flag + bdos equ 5 ;Address of BDOS Entry Point + + org 100h + + lxi d,prmpt ;Print User Prompt + mvi c,9 ;PRINT function + call bdos + + lhld bdos+1 ;Get address of BDOS + mov a,h ;High-Order Address in A + sui 8 ;A=High-Order Address of CPR + mov h,a ;HL=Address of CPR + mvi l,0 + shld cpr ;Save address in buffer + + lxi d,6 ;Point to command line buffer + dad d ;HL points to command line buffer + xchg ;DE points to command line buffer + mvi c,10 ;READLN into this buffer + call bdos + + lhld cpr ;Get Address of CPR + lda udflag ;Get User/Disk Flag + mov c,a ; ... in C + pchl ;Run Command Line + + cpr: ds 2 ;CPR Address buffer + prmpt: db 'User Command? $' + + + + + + + Enjoy using ZCPR! + -- RLC + + + + + + + + + + + + + Page 21 + + + + + + \ No newline at end of file diff --git a/trunk/Doc/zsdos.pdf b/trunk/Doc/zsdos.pdf new file mode 100644 index 00000000..f78a2775 --- /dev/null +++ b/trunk/Doc/zsdos.pdf @@ -0,0 +1,13114 @@ +%PDF-1.4 +%ÔĊĜ +5 0 obj +<< /S /GoTo /D (section.1) >> +endobj +8 0 obj +(1 Introduction) +endobj +9 0 obj +<< /S /GoTo /D (subsection.1.1) >> +endobj +12 0 obj +(1.1 About This Manual) +endobj +13 0 obj +<< /S /GoTo /D (subsection.1.2) >> +endobj +16 0 obj +(1.2 What is ZSDOS?) +endobj +17 0 obj +<< /S /GoTo /D (subsection.1.3) >> +endobj +20 0 obj +(1.3 The History of ZSDOS) +endobj +21 0 obj +<< /S /GoTo /D (subsection.1.4) >> +endobj +24 0 obj +(1.4 Differences Between ZSDOS and ZDDOS) +endobj +25 0 obj +<< /S /GoTo /D (subsection.1.5) >> +endobj +28 0 obj +(1.5 Differences Between CP/M 2.2, ZRDOS and ZSDOS) +endobj +29 0 obj +<< /S /GoTo /D (subsection.1.6) >> +endobj +32 0 obj +(1.6 Program Summaries and Usage) +endobj +33 0 obj +<< /S /GoTo /D (subsubsection.1.6.1) >> +endobj +36 0 obj +(1.6.1 Program Summary Conventions) +endobj +37 0 obj +<< /S /GoTo /D (subsubsection.1.6.2) >> +endobj +40 0 obj +(1.6.2 Built-in Help) +endobj +41 0 obj +<< /S /GoTo /D (subsubsection.1.6.3) >> +endobj +44 0 obj +(1.6.3 Command Line Options) +endobj +45 0 obj +<< /S /GoTo /D (section.2) >> +endobj +48 0 obj +(2 Features) +endobj +49 0 obj +<< /S /GoTo /D (subsection.2.1) >> +endobj +52 0 obj +(2.1 Automatic Disk Relog) +endobj +53 0 obj +<< /S /GoTo /D (subsection.2.2) >> +endobj +56 0 obj +(2.2 Improved Error Handling) +endobj +57 0 obj +<< /S /GoTo /D (subsection.2.3) >> +endobj +60 0 obj +(2.3 Archive Attribute Support) +endobj +61 0 obj +<< /S /GoTo /D (subsection.2.4) >> +endobj +64 0 obj +(2.4 Larger File and Disk Sizes) +endobj +65 0 obj +<< /S /GoTo /D (subsection.2.5) >> +endobj +68 0 obj +(2.5 Fast Fixed Disk Relog) +endobj +69 0 obj +<< /S /GoTo /D (subsection.2.6) >> +endobj +72 0 obj +(2.6 Backgrounder II Support) +endobj +73 0 obj +<< /S /GoTo /D (subsection.2.7) >> +endobj +76 0 obj +(2.7 Wheel Protection) +endobj +77 0 obj +<< /S /GoTo /D (subsection.2.8) >> +endobj +80 0 obj +(2.8 File Access Modes) +endobj +81 0 obj +<< /S /GoTo /D (subsubsection.2.8.1) >> +endobj +84 0 obj +(2.8.1 Normal Access) +endobj +85 0 obj +<< /S /GoTo /D (subsubsection.2.8.2) >> +endobj +88 0 obj +(2.8.2 Path Access \(ZSDOS only\)) +endobj +89 0 obj +<< /S /GoTo /D (paragraph.2.8.2.1) >> +endobj +92 0 obj +(2.8.2.1 Path Directory Access \(ZSDOS only\)) +endobj +93 0 obj +<< /S /GoTo /D (paragraph.2.8.2.2) >> +endobj +96 0 obj +(2.8.2.2 Path File Access \(ZSDOS only\)) +endobj +97 0 obj +<< /S /GoTo /D (subsubsection.2.8.3) >> +endobj +100 0 obj +(2.8.3 Public Access) +endobj +101 0 obj +<< /S /GoTo /D (subsubsection.2.8.4) >> +endobj +104 0 obj +(2.8.4 Combined Access \(ZSDOS only\)) +endobj +105 0 obj +<< /S /GoTo /D (subsection.2.9) >> +endobj +108 0 obj +(2.9 Enhanced Write Protection) +endobj +109 0 obj +<< /S /GoTo /D (subsection.2.10) >> +endobj +112 0 obj +(2.10 \040Re-entrancy Potential) +endobj +113 0 obj +<< /S /GoTo /D (subsection.2.11) >> +endobj +116 0 obj +(2.11 FCB User Number Support) +endobj +117 0 obj +<< /S /GoTo /D (subsection.2.12) >> +endobj +120 0 obj +(2.12 File Datestamping Support) +endobj +121 0 obj +<< /S /GoTo /D (subsection.2.13) >> +endobj +124 0 obj +(2.13 Run-time Configuration) +endobj +125 0 obj +<< /S /GoTo /D (subsection.2.14) >> +endobj +128 0 obj +(2.14 Other Significant Enhancements) +endobj +129 0 obj +<< /S /GoTo /D (section.3) >> +endobj +132 0 obj +(3 Installing ZSDOS) +endobj +133 0 obj +<< /S /GoTo /D (subsection.3.1) >> +endobj +136 0 obj +(3.1 Installing the Operating System) +endobj +137 0 obj +<< /S /GoTo /D (subsubsection.3.1.1) >> +endobj +140 0 obj +(3.1.1 Installing ZSDOS with INSTALOS) +endobj +141 0 obj +<< /S /GoTo /D (paragraph.3.1.1.1) >> +endobj +144 0 obj +(3.1.1.1 Using INSTALOS) +endobj +145 0 obj +<< /S /GoTo /D (paragraph.3.1.1.2) >> +endobj +148 0 obj +(3.1.1.2 Creating a Boot Disk) +endobj +149 0 obj +<< /S /GoTo /D (paragraph.3.1.1.3) >> +endobj +152 0 obj +(3.1.1.3 INSTALOS Error Messages) +endobj +153 0 obj +<< /S /GoTo /D (subsubsection.3.1.2) >> +endobj +156 0 obj +(3.1.2 Installing ZSDOS with NZCOM) +endobj +157 0 obj +<< /S /GoTo /D (subsubsection.3.1.3) >> +endobj +160 0 obj +(3.1.3 Installing ZSDOS with JetLDR) +endobj +161 0 obj +<< /S /GoTo /D (subsubsection.3.1.4) >> +endobj +164 0 obj +(3.1.4 Installing with XBIOS) +endobj +165 0 obj +<< /S /GoTo /D (subsection.3.2) >> +endobj +168 0 obj +(3.2 Clock and File Stamp Installation) +endobj +169 0 obj +<< /S /GoTo /D (subsubsection.3.2.1) >> +endobj +172 0 obj +(3.2.1 Selecting a Clock Driver) +endobj +173 0 obj +<< /S /GoTo /D (subsubsection.3.2.2) >> +endobj +176 0 obj +(3.2.2 Installing Clock and/or Stamp Method) +endobj +177 0 obj +<< /S /GoTo /D (subsubsection.3.2.3) >> +endobj +180 0 obj +(3.2.3 The LDTIM Program) +endobj +181 0 obj +<< /S /GoTo /D (subsubsection.3.2.4) >> +endobj +184 0 obj +(3.2.4 Preparing Disks for DateStamper \(PUTDS\)) +endobj +185 0 obj +<< /S /GoTo /D (paragraph.3.2.4.1) >> +endobj +188 0 obj +(3.2.4.1 PUTDS Interactive Mode) +endobj +189 0 obj +<< /S /GoTo /D (paragraph.3.2.4.2) >> +endobj +192 0 obj +(3.2.4.2 PUTDS Expert Mode) +endobj +193 0 obj +<< /S /GoTo /D (subsubsection.3.2.5) >> +endobj +196 0 obj +(3.2.5 Preparing Disks for P2DOS Stamps \(INITDIR\)) +endobj +197 0 obj +<< /S /GoTo /D (paragraph.3.2.5.1) >> +endobj +200 0 obj +(3.2.5.1 INITDIR Interactive Mode) +endobj +201 0 obj +<< /S /GoTo /D (paragraph.3.2.5.2) >> +endobj +204 0 obj +(3.2.5.2 INITDIR Expert Mode) +endobj +205 0 obj +<< /S /GoTo /D (paragraph.3.2.5.3) >> +endobj +208 0 obj +(3.2.5.3 INITDIR Error Messages) +endobj +209 0 obj +<< /S /GoTo /D (subsection.3.3) >> +endobj +212 0 obj +(3.3 Installing BackGrounder II for ZSDOS) +endobj +213 0 obj +<< /S /GoTo /D (subsubsection.3.3.1) >> +endobj +216 0 obj +(3.3.1 BackGrounder Installation using MLOAD.COM) +endobj +217 0 obj +<< /S /GoTo /D (subsubsection.3.3.2) >> +endobj +220 0 obj +(3.3.2 Installation using DDT.COM) +endobj +221 0 obj +<< /S /GoTo /D (subsection.3.4) >> +endobj +224 0 obj +(3.4 Advanced Installation Techniques) +endobj +225 0 obj +<< /S /GoTo /D (subsubsection.3.4.1) >> +endobj +228 0 obj +(3.4.1 Replacing CCP and BIOS with INSTALOS) +endobj +229 0 obj +<< /S /GoTo /D (paragraph.3.4.1.1) >> +endobj +232 0 obj +(3.4.1.1 Replacing the CCP) +endobj +233 0 obj +<< /S /GoTo /D (paragraph.3.4.1.2) >> +endobj +236 0 obj +(3.4.1.2 Replacing the BIOS) +endobj +237 0 obj +<< /S /GoTo /D (subsubsection.3.4.2) >> +endobj +240 0 obj +(3.4.2 User-Developed Clock Drivers) +endobj +241 0 obj +<< /S /GoTo /D (subsubsection.3.4.3) >> +endobj +244 0 obj +(3.4.3 Customizing Stamp Installation with SETUPZST) +endobj +245 0 obj +<< /S /GoTo /D (paragraph.3.4.3.1) >> +endobj +248 0 obj +(3.4.3.1 The Different Stamp Modules) +endobj +249 0 obj +<< /S /GoTo /D (paragraph.3.4.3.2) >> +endobj +252 0 obj +(3.4.3.2 Installing a Stamp Module in High Memory) +endobj +253 0 obj +<< /S /GoTo /D (paragraph.3.4.3.3) >> +endobj +256 0 obj +(3.4.3.3 Installing Stamp Module in NZCOM User Space) +endobj +257 0 obj +<< /S /GoTo /D (paragraph.3.4.3.4) >> +endobj +260 0 obj +(3.4.3.4 Changing an existing LDTIM.COM program) +endobj +261 0 obj +<< /S /GoTo /D (subsubsection.3.4.4) >> +endobj +264 0 obj +(3.4.4 Tips on Using ZSCONFIG with Clocks/Stamps) +endobj +265 0 obj +<< /S /GoTo /D (paragraph.3.4.4.1) >> +endobj +268 0 obj +(3.4.4.1 Patching in an Existing Clock) +endobj +269 0 obj +<< /S /GoTo /D (paragraph.3.4.4.2) >> +endobj +272 0 obj +(3.4.4.2 Speed Tip) +endobj +273 0 obj +<< /S /GoTo /D (section.4) >> +endobj +276 0 obj +(4 ZSDOS Utilities) +endobj +277 0 obj +<< /S /GoTo /D (subsection.4.1) >> +endobj +280 0 obj +(4.1 COPY -- Copy Files) +endobj +281 0 obj +<< /S /GoTo /D (subsubsection.4.1.1) >> +endobj +284 0 obj +(4.1.1 Using COPY) +endobj +285 0 obj +<< /S /GoTo /D (subsubsection.4.1.2) >> +endobj +288 0 obj +(4.1.2 COPY Options) +endobj +289 0 obj +<< /S /GoTo /D (paragraph.4.1.2.1) >> +endobj +292 0 obj +(4.1.2.1 Archive Option) +endobj +293 0 obj +<< /S /GoTo /D (paragraph.4.1.2.2) >> +endobj +296 0 obj +(4.1.2.2 File Existence Option) +endobj +297 0 obj +<< /S /GoTo /D (paragraph.4.1.2.3) >> +endobj +300 0 obj +(4.1.2.3 Inspect Files Option) +endobj +301 0 obj +<< /S /GoTo /D (paragraph.4.1.2.4) >> +endobj +304 0 obj +(4.1.2.4 Multiple Copy Option) +endobj +305 0 obj +<< /S /GoTo /D (paragraph.4.1.2.5) >> +endobj +308 0 obj +(4.1.2.5 No Replacement Option) +endobj +309 0 obj +<< /S /GoTo /D (paragraph.4.1.2.6) >> +endobj +312 0 obj +(4.1.2.6 Quiet Option) +endobj +313 0 obj +<< /S /GoTo /D (paragraph.4.1.2.7) >> +endobj +316 0 obj +(4.1.2.7 System Files Option) +endobj +317 0 obj +<< /S /GoTo /D (paragraph.4.1.2.8) >> +endobj +320 0 obj +(4.1.2.8 Verify Option) +endobj +321 0 obj +<< /S /GoTo /D (paragraph.4.1.2.9) >> +endobj +324 0 obj +(4.1.2.9 Archive if Only if File Exists Option) +endobj +325 0 obj +<< /S /GoTo /D (subsection.4.2) >> +endobj +328 0 obj +(4.2 DATSWEEP -- Directory Tool) +endobj +329 0 obj +<< /S /GoTo /D (subsubsection.4.2.1) >> +endobj +332 0 obj +(4.2.1 Overview) +endobj +333 0 obj +<< /S /GoTo /D (paragraph.4.2.1.1) >> +endobj +336 0 obj +(4.2.1.1 The Six Windows) +endobj +337 0 obj +<< /S /GoTo /D (paragraph.4.2.1.2) >> +endobj +340 0 obj +(4.2.1.2 Logging In and Selecting Filesets) +endobj +341 0 obj +<< /S /GoTo /D (paragraph.4.2.1.3) >> +endobj +344 0 obj +(4.2.1.3 Filespecs and Datespecs) +endobj +345 0 obj +<< /S /GoTo /D (paragraph.4.2.1.4) >> +endobj +348 0 obj +(4.2.1.4 Flags \(attributes\)) +endobj +349 0 obj +<< /S /GoTo /D (subsubsection.4.2.2) >> +endobj +352 0 obj +(4.2.2 Using DATSWEEP) +endobj +353 0 obj +<< /S /GoTo /D (paragraph.4.2.2.1) >> +endobj +356 0 obj +(4.2.2.1 Tagging Examples) +endobj +357 0 obj +<< /S /GoTo /D (subsubsection.4.2.3) >> +endobj +360 0 obj +(4.2.3 DATSWEEP Command Summary) +endobj +361 0 obj +<< /S /GoTo /D (paragraph.4.2.3.1) >> +endobj +364 0 obj +(4.2.3.1 File Operation Commands) +endobj +365 0 obj +<< /S /GoTo /D (paragraph.4.2.3.2) >> +endobj +368 0 obj +(4.2.3.2 Tagging Commands) +endobj +369 0 obj +<< /S /GoTo /D (paragraph.4.2.3.3) >> +endobj +372 0 obj +(4.2.3.3 Miscellaneous Commands) +endobj +373 0 obj +<< /S /GoTo /D (paragraph.4.2.3.4) >> +endobj +376 0 obj +(4.2.3.4 Viewing a File) +endobj +377 0 obj +<< /S /GoTo /D (paragraph.4.2.3.5) >> +endobj +380 0 obj +(4.2.3.5 Viewing Squeezed Files) +endobj +381 0 obj +<< /S /GoTo /D (subsubsection.4.2.4) >> +endobj +384 0 obj +(4.2.4 Command Line Options) +endobj +385 0 obj +<< /S /GoTo /D (paragraph.4.2.4.1) >> +endobj +388 0 obj +(4.2.4.1 Special Characters) +endobj +389 0 obj +<< /S /GoTo /D (paragraph.4.2.4.2) >> +endobj +392 0 obj +(4.2.4.2 OSPrompt Level) +endobj +393 0 obj +<< /S /GoTo /D (paragraph.4.2.4.3) >> +endobj +396 0 obj +(4.2.4.3 SUBMIT or ZEX Scripts) +endobj +397 0 obj +<< /S /GoTo /D (paragraph.4.2.4.4) >> +endobj +400 0 obj +(4.2.4.4 Passing Parameters) +endobj +401 0 obj +<< /S /GoTo /D (paragraph.4.2.4.5) >> +endobj +404 0 obj +(4.2.4.5 The \137C Switch) +endobj +405 0 obj +<< /S /GoTo /D (paragraph.4.2.4.6) >> +endobj +408 0 obj +(4.2.4.6 Limitations of the Command Line Option) +endobj +409 0 obj +<< /S /GoTo /D (subsubsection.4.2.5) >> +endobj +412 0 obj +(4.2.5 Installation and Configuration) +endobj +413 0 obj +<< /S /GoTo /D (paragraph.4.2.5.1) >> +endobj +416 0 obj +(4.2.5.1 Installation) +endobj +417 0 obj +<< /S /GoTo /D (paragraph.4.2.5.2) >> +endobj +420 0 obj +(4.2.5.2 Configuration) +endobj +421 0 obj +<< /S /GoTo /D (subsubsection.4.2.6) >> +endobj +424 0 obj +(4.2.6 Technical Information) +endobj +425 0 obj +<< /S /GoTo /D (paragraph.4.2.6.1) >> +endobj +428 0 obj +(4.2.6.1 Filesizes and Disk Space) +endobj +429 0 obj +<< /S /GoTo /D (paragraph.4.2.6.2) >> +endobj +432 0 obj +(4.2.6.2 Error Procedures) +endobj +433 0 obj +<< /S /GoTo /D (paragraph.4.2.6.3) >> +endobj +436 0 obj +(4.2.6.3 Very Large Directories) +endobj +437 0 obj +<< /S /GoTo /D (subsection.4.3) >> +endobj +440 0 obj +(4.3 FILEATTR -- Set or Display Attributes) +endobj +441 0 obj +<< /S /GoTo /D (subsubsection.4.3.1) >> +endobj +444 0 obj +(4.3.1 Using FILEATTR) +endobj +445 0 obj +<< /S /GoTo /D (paragraph.4.3.1.1) >> +endobj +448 0 obj +(4.3.1.1 FILEATTR Display Commands) +endobj +449 0 obj +<< /S /GoTo /D (paragraph.4.3.1.2) >> +endobj +452 0 obj +(4.3.1.2 FILEATTR Set Commands) +endobj +453 0 obj +<< /S /GoTo /D (paragraph.4.3.1.3) >> +endobj +456 0 obj +(4.3.1.3 FILEATTR Options) +endobj +457 0 obj +<< /S /GoTo /D (paragraph.4.3.1.4) >> +endobj +460 0 obj +(4.3.1.4 FILEATTR Output) +endobj +461 0 obj +<< /S /GoTo /D (subsubsection.4.3.2) >> +endobj +464 0 obj +(4.3.2 FILEATTR Error Messages) +endobj +465 0 obj +<< /S /GoTo /D (subsection.4.4) >> +endobj +468 0 obj +(4.4 FILEDATE -- Display File Dates) +endobj +469 0 obj +<< /S /GoTo /D (subsubsection.4.4.1) >> +endobj +472 0 obj +(4.4.1 FILEDATE Syntax) +endobj +473 0 obj +<< /S /GoTo /D (paragraph.4.4.1.1) >> +endobj +476 0 obj +(4.4.1.1 FILEDATE Syntax Summary) +endobj +477 0 obj +<< /S /GoTo /D (paragraph.4.4.1.2) >> +endobj +480 0 obj +(4.4.1.2 The File Specification Field) +endobj +481 0 obj +<< /S /GoTo /D (paragraph.4.4.1.3) >> +endobj +484 0 obj +(4.4.1.3 The Option Field) +endobj +485 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.3.1) >> +endobj +488 0 obj +(4.4.1.3.1 Sorting by Date) +endobj +489 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.3.2) >> +endobj +492 0 obj +(4.4.1.3.2 Using Access and Create Stamps) +endobj +493 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.3.3) >> +endobj +496 0 obj +(4.4.1.3.3 Displaying All Stamps) +endobj +497 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.3.4) >> +endobj +500 0 obj +(4.4.1.3.4 No Pause) +endobj +501 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.3.5) >> +endobj +504 0 obj +(4.4.1.3.5 Showing System Files) +endobj +505 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.3.6) >> +endobj +508 0 obj +(4.4.1.3.6 Showing All User Areas) +endobj +509 0 obj +<< /S /GoTo /D (paragraph.4.4.1.4) >> +endobj +512 0 obj +(4.4.1.4 The Date Specification Field) +endobj +513 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.4.1) >> +endobj +516 0 obj +(4.4.1.4.1 Date Signifiers) +endobj +517 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.4.2) >> +endobj +520 0 obj +(4.4.1.4.2 Dates) +endobj +521 0 obj +<< /S /GoTo /D (subparagraph.4.4.1.4.3) >> +endobj +524 0 obj +(4.4.1.4.3 Date Specifications) +endobj +525 0 obj +<< /S /GoTo /D (paragraph.4.4.1.5) >> +endobj +528 0 obj +(4.4.1.5 The Complete FILEDATE Syntax) +endobj +529 0 obj +<< /S /GoTo /D (subsubsection.4.4.2) >> +endobj +532 0 obj +(4.4.2 FILEDATE Output) +endobj +533 0 obj +<< /S /GoTo /D (paragraph.4.4.2.1) >> +endobj +536 0 obj +(4.4.2.1 Default Display) +endobj +537 0 obj +<< /S /GoTo /D (paragraph.4.4.2.2) >> +endobj +540 0 obj +(4.4.2.2 Display Sorted by Access Date) +endobj +541 0 obj +<< /S /GoTo /D (paragraph.4.4.2.3) >> +endobj +544 0 obj +(4.4.2.3 Display Selected by Modify Date) +endobj +545 0 obj +<< /S /GoTo /D (paragraph.4.4.2.4) >> +endobj +548 0 obj +(4.4.2.4 Note on Relative Times) +endobj +549 0 obj +<< /S /GoTo /D (paragraph.4.4.2.5) >> +endobj +552 0 obj +(4.4.2.5 Notes on Missing Stamps) +endobj +553 0 obj +<< /S /GoTo /D (subsubsection.4.4.3) >> +endobj +556 0 obj +(4.4.3 FILEDATE Error Messages) +endobj +557 0 obj +<< /S /GoTo /D (subsection.4.5) >> +endobj +560 0 obj +(4.5 RELOG -- Reset Disk System) +endobj +561 0 obj +<< /S /GoTo /D (subsection.4.6) >> +endobj +564 0 obj +(4.6 TD -- Read and Set Clock) +endobj +565 0 obj +<< /S /GoTo /D (subsubsection.4.6.1) >> +endobj +568 0 obj +(4.6.1 Using TD) +endobj +569 0 obj +<< /S /GoTo /D (subsubsection.4.6.2) >> +endobj +572 0 obj +(4.6.2 TD Error Messages) +endobj +573 0 obj +<< /S /GoTo /D (subsection.4.7) >> +endobj +576 0 obj +(4.7 ZCAL -- Display Month) +endobj +577 0 obj +<< /S /GoTo /D (subsubsection.4.7.1) >> +endobj +580 0 obj +(4.7.1 Using ZCAL) +endobj +581 0 obj +<< /S /GoTo /D (paragraph.4.7.1.1) >> +endobj +584 0 obj +(4.7.1.1 ZCAL System Requirements) +endobj +585 0 obj +<< /S /GoTo /D (paragraph.4.7.1.2) >> +endobj +588 0 obj +(4.7.1.2 ZCAL Syntax) +endobj +589 0 obj +<< /S /GoTo /D (subsubsection.4.7.2) >> +endobj +592 0 obj +(4.7.2 ZCAL Error Messages) +endobj +593 0 obj +<< /S /GoTo /D (subsection.4.8) >> +endobj +596 0 obj +(4.8 ZCNFG - Configuration Utility) +endobj +597 0 obj +<< /S /GoTo /D (subsubsection.4.8.1) >> +endobj +600 0 obj +(4.8.1 Using ZCNFG) +endobj +601 0 obj +<< /S /GoTo /D (paragraph.4.8.1.1) >> +endobj +604 0 obj +(4.8.1.1 ZCNFG Toggle Displays) +endobj +605 0 obj +<< /S /GoTo /D (paragraph.4.8.1.2) >> +endobj +608 0 obj +(4.8.1.2 ZCNFG Value Displays) +endobj +609 0 obj +<< /S /GoTo /D (paragraph.4.8.1.3) >> +endobj +612 0 obj +(4.8.1.3 Note on COPY) +endobj +613 0 obj +<< /S /GoTo /D (subsection.4.9) >> +endobj +616 0 obj +(4.9 ZPATH - Set ZSDOS Path) +endobj +617 0 obj +<< /S /GoTo /D (subsubsection.4.9.1) >> +endobj +620 0 obj +(4.9.1 Using ZPAT) +endobj +621 0 obj +<< /S /GoTo /D (paragraph.4.9.1.1) >> +endobj +624 0 obj +(4.9.1.1 ZPATH Option Characters) +endobj +625 0 obj +<< /S /GoTo /D (paragraph.4.9.1.2) >> +endobj +628 0 obj +(4.9.1.2 ZPATH Examples) +endobj +629 0 obj +<< /S /GoTo /D (subsubsection.4.9.2) >> +endobj +632 0 obj +(4.9.2 ZPATH Error and Warning Messages) +endobj +633 0 obj +<< /S /GoTo /D (subsection.4.10) >> +endobj +636 0 obj +(4.10 ZSCONFIG -- Configure a Running ZSDOS System) +endobj +637 0 obj +<< /S /GoTo /D (subsubsection.4.10.1) >> +endobj +640 0 obj +(4.10.1 ZSCONFIG Interactive Mode) +endobj +641 0 obj +<< /S /GoTo /D (subsubsection.4.10.2) >> +endobj +644 0 obj +(4.10.2 ZSCONFIG Expert Mode) +endobj +645 0 obj +<< /S /GoTo /D (subsubsection.4.10.3) >> +endobj +648 0 obj +(4.10.3 ZSCONFIG Options) +endobj +649 0 obj +<< /S /GoTo /D (paragraph.4.10.3.1) >> +endobj +652 0 obj +(4.10.3.1 Public Files \(ZSDOS and ZDDOS\)) +endobj +653 0 obj +<< /S /GoTo /D (paragraph.4.10.3.2) >> +endobj +656 0 obj +(4.10.3.2 Public/Path Write Enable \(ZSDOS and ZDDOS\)) +endobj +657 0 obj +<< /S /GoTo /D (paragraph.4.10.3.3) >> +endobj +660 0 obj +(4.10.3.3 Read-Only Vector Sustain \(ZSDOS and ZDDOS\)) +endobj +661 0 obj +<< /S /GoTo /D (paragraph.4.10.3.4) >> +endobj +664 0 obj +(4.10.3.4 Fast Fixed Disk Relog \(ZSDOS and ZDDOS\)) +endobj +665 0 obj +<< /S /GoTo /D (paragraph.4.10.3.5) >> +endobj +668 0 obj +(4.10.3.5 Disk Change Warning \(ZSDOS and ZDDOS\)) +endobj +669 0 obj +<< /S /GoTo /D (paragraph.4.10.3.6) >> +endobj +672 0 obj +(4.10.3.6 Path Without System Attribute \(ZSDOS only\)) +endobj +673 0 obj +<< /S /GoTo /D (paragraph.4.10.3.7) >> +endobj +676 0 obj +(4.10.3.7 DOS Search Path \(ZSDOS only\)) +endobj +677 0 obj +<< /S /GoTo /D (paragraph.4.10.3.8) >> +endobj +680 0 obj +(4.10.3.8 Wheel Byte Write Protect \(ZSDOS and ZDDOS\)) +endobj +681 0 obj +<< /S /GoTo /D (paragraph.4.10.3.9) >> +endobj +684 0 obj +(4.10.3.9 Time Routine \(Clock Driver\) \(ZSDOS and ZDDOS\)) +endobj +685 0 obj +<< /S /GoTo /D (paragraph.4.10.3.10) >> +endobj +688 0 obj +(4.10.3.10 Stamp Last Accessed Time \(ZSDOS and ZDDOS\)) +endobj +689 0 obj +<< /S /GoTo /D (paragraph.4.10.3.11) >> +endobj +692 0 obj +(4.10.3.11 Stamp Create Time \(ZSDOS only\)) +endobj +693 0 obj +<< /S /GoTo /D (paragraph.4.10.3.12) >> +endobj +696 0 obj +(4.10.3.12 Stamp Modify Time \(ZSDOS and ZDDOS\)) +endobj +697 0 obj +<< /S /GoTo /D (paragraph.4.10.3.13) >> +endobj +700 0 obj +(4.10.3.13 Get Date/Time Stamp \(ZSDOS only\)) +endobj +701 0 obj +<< /S /GoTo /D (paragraph.4.10.3.14) >> +endobj +704 0 obj +(4.10.3.14 Set Date/Time Stamp \(ZSDOS only\)) +endobj +705 0 obj +<< /S /GoTo /D (subsubsection.4.10.4) >> +endobj +708 0 obj +(4.10.4 ZSCONFIG Error Messages) +endobj +709 0 obj +<< /S /GoTo /D (subsection.4.11) >> +endobj +712 0 obj +(4.11 ZXD - Extended Directory Utility) +endobj +713 0 obj +<< /S /GoTo /D (subsubsection.4.11.1) >> +endobj +716 0 obj +(4.11.1 Using ZXD) +endobj +717 0 obj +<< /S /GoTo /D (subsubsection.4.11.2) >> +endobj +720 0 obj +(4.11.2 ZXD Options) +endobj +721 0 obj +<< /S /GoTo /D (paragraph.4.11.2.1) >> +endobj +724 0 obj +(4.11.2.1 Select Files by Attribute) +endobj +725 0 obj +<< /S /GoTo /D (paragraph.4.11.2.2) >> +endobj +728 0 obj +(4.11.2.2 Date Display Format) +endobj +729 0 obj +<< /S /GoTo /D (paragraph.4.11.2.3) >> +endobj +732 0 obj +(4.11.2.3 Disable Date \(NoDate\) Display) +endobj +733 0 obj +<< /S /GoTo /D (paragraph.4.11.2.4) >> +endobj +736 0 obj +(4.11.2.4 Output Control Option) +endobj +737 0 obj +<< /S /GoTo /D (paragraph.4.11.2.5) >> +endobj +740 0 obj +(4.11.2.5 Output to Printer) +endobj +741 0 obj +<< /S /GoTo /D (paragraph.4.11.2.6) >> +endobj +744 0 obj +(4.11.2.6 Sort by Name or Type) +endobj +745 0 obj +<< /S /GoTo /D (paragraph.4.11.2.7) >> +endobj +748 0 obj +(4.11.2.7 Primary DateStamp) +endobj +749 0 obj +<< /S /GoTo /D (paragraph.4.11.2.8) >> +endobj +752 0 obj +(4.11.2.8 All User Areas) +endobj +753 0 obj +<< /S /GoTo /D (paragraph.4.11.2.9) >> +endobj +756 0 obj +(4.11.2.9 Wide Display) +endobj +757 0 obj +<< /S /GoTo /D (appendix.A) >> +endobj +760 0 obj +(A ZSDOS Functions Quick Reference) +endobj +761 0 obj +<< /S /GoTo /D (subsection.A.1) >> +endobj +764 0 obj +(A.1 Summary of BDOS Return Codes) +endobj +765 0 obj +<< /S /GoTo /D (appendix.B) >> +endobj +768 0 obj +(B BIOS Functions Quick Reference) +endobj +769 0 obj +<< /S /GoTo /D (appendix.C) >> +endobj +772 0 obj +(C Datespec and File Stamp Formats) +endobj +773 0 obj +<< /S /GoTo /D (appendix.D) >> +endobj +776 0 obj +(D ZSDOS Memory Allocation \046 Usage) +endobj +777 0 obj +<< /S /GoTo /D (appendix.E) >> +endobj +780 0 obj +(E File Attributes) +endobj +781 0 obj +<< /S /GoTo /D (subsection.E.1) >> +endobj +784 0 obj +(E.1 What are file attributes?) +endobj +785 0 obj +<< /S /GoTo /D (subsection.E.2) >> +endobj +788 0 obj +(E.2 File Attribute Meanings) +endobj +789 0 obj +<< /S /GoTo /D (subsubsection.E.2.1) >> +endobj +792 0 obj +(E.2.1 Public file attribute \(f2\)) +endobj +793 0 obj +<< /S /GoTo /D (subsubsection.E.2.2) >> +endobj +796 0 obj +(E.2.2 No access stamp attribute \(f3\)) +endobj +797 0 obj +<< /S /GoTo /D (subsubsection.E.2.3) >> +endobj +800 0 obj +(E.2.3 Wheel protect attribute \(f8\)) +endobj +801 0 obj +<< /S /GoTo /D (subsubsection.E.2.4) >> +endobj +804 0 obj +(E.2.4 Read-only attribute \(t1\)) +endobj +805 0 obj +<< /S /GoTo /D (subsubsection.E.2.5) >> +endobj +808 0 obj +(E.2.5 System attribute \(t2\)) +endobj +809 0 obj +<< /S /GoTo /D (subsubsection.E.2.6) >> +endobj +812 0 obj +(E.2.6 Archive attribute \(t3\)) +endobj +813 0 obj +<< /S /GoTo /D (appendix.F) >> +endobj +816 0 obj +(F Clock Driver Descriptions) +endobj +817 0 obj +<< /S /GoTo /D [818 0 R /FitH ] >> +endobj +820 0 obj << +/Length 1124 +/Filter /FlateDecode +>> +stream +xڍVKsâ8ó+tUAħ$ż´{"$$L%„§f³3s0 ‚ĞŒÍÊ&İüûmİĊ+ĊVÍIÒ§ŻßŬ–òFrß ŝg½É:×Cž0Á£d+""Ċ“8NW-ÉúÏìöyÖíÉ$˘œŬ_Ù7ÒS!KDDz‚3ĊSäġ‘3˜\?áN0››ƒ‚İŜ–ùBotĠ•œĥVĝz˘HX¸ŒX$8éɐħ÷aŜ ŭDÛ2f!Û\2&x˙›ş\‚ Ó!³kBoêH釕ÔESsċ%½×ƒ|£M]Ħèw/:¨[S”]NK'üH‰ŻrĤ9ˆŬ;‰ˆcÈLÂR!wr;DâX ŝ}jн‚ÓDÀ !gĥns'UĝïMñ3àqğĈ£…n˙ ˘Àèw„%œ8ŞŒY …daè=Ô[gÒok›%W LJ0#kġò´>=ÉdêŽ4p&şXIğĦ׋Ğ4B×`›\ĦË’ĴÒÓÌ.Ï#ÇÄüá›N{ÂLüná”WžsĦÜħ/·Ğuç.ëüÛáàt@8I #ÉĴ‹MçÇŻ€,˙fS¤RòáXĈ)Ĵ%™uŝÂĦJ‰b*†9‚$XúNĝNÍÖEVƒ˜nMŭfò öàÊhğĤ^µ>Ž”ĉF˙ 0ĦKàXÈ+ܽ,bk½xÑâ +‘_×÷›ş }I—Ċêóœ´Ğ–ÚsÚµWj³ñNĠĞ/w÷żÑ•69NIp^™Én^  İ„> ]5VXA, ÛŬÜNXÑX­œ.‘:·ñ}"í8ìĤ’bfà4s™I™9áÔIŜÂ\AĥBĦ¨.@‡Amï–~˜: +şèN­yoĦCCR—<…•·HġE0gqûi¨·Öž” +°H†´Ì[çà'ž”)ĦÎ…Ÿ6 + +șǏ%_úğ +WŒ„Gt cŜ³fö¸ €ûÂáĥ½Cĉ§Ä]£WğҎ(W ú}”=<żd(Ùżz´Ë9§ŭé´?Î^}“~@Úë]{İ-4Ĉm=„÷4â´ĜlËÂĊ7şı1˜şvŸ?¸qµı§ğİE`ÔÖ½3zeŻžd4eğÙ ÁĦċ?OñĤĜĉNğiH³ÑàċħïŻ'/ÓÉóìŽ!k}w!t +‰ĊŬƒCíûcûËö|1ҋ?Žwc0–ŭ›fċböĤ6ž·ÔmïÌĊ^yĊŜbÒRï>‰°_çŝ½ÁÒbôBĝyNn—ŜĤí>ÑşDŠQ€QrŒC”pqŒÒ*-ëê qÛ ĥĜÒ°ó-mÛ% +háUuk{.„Ñ6E{9ë5fg?´cúOœf_>šH>˙4\!8Şì +â$Bì)oÜġ÷9Ôóáċ°ÜË7íħ§>*—Êc/³>ğĝ’HxÒ(ùŬ—äì7íôE‘üŽÊŞÄ‡ĠYÛÓÁꁲzó +endstream +endobj +818 0 obj << +/Type /Page +/Contents 820 0 R +/Resources 819 0 R +/MediaBox [0 0 612 792] +/Parent 827 0 R +>> endobj +821 0 obj << +/D [818 0 R /XYZ 72 720 null] +>> endobj +822 0 obj << +/D [818 0 R /XYZ 72 720 null] +>> endobj +819 0 obj << +/Font << /F16 823 0 R /F17 824 0 R /F23 825 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +831 0 obj << +/Length 2040 +/Filter /FlateDecode +>> +stream +xÚµ]sÛ6ì=żÂoSvħ*ê’ÖŬn޽ÄéĠİ/r×ğt{P$ĈÖ"K>Jn–?€;f·§½X$€ĝho°xƒë3ż—˳wWÉ uӑ?,ħ?ˆ…çzAœc™ĤµI³¨FœC$%T‰ï +ZÔfíÛ4‰˜Ŝ7XÏÜħûÁ$˘Ú­VœVCúŒëšÎîLŬïL&vRQ ”ÖB{s{³œŜÜı“Os(Zz?öA5Ċ…İ$À£×i”œ[ÌŬ…h…u…D@ĦN+ >DŽ$œç5I`Ĥsşômûҕ Á‡í+l"¤Û÷.XÏĈèxyEY6´acYâLçG™û;;Ŝ³émşa(bgğVaŻf$­3|÷ñ@Û·s³­ċkÁ#\BkĤ šŒ4]ŸoĥZlE.ıñÈ/pÌ~£)‚Ǩŭò7wœÍmݝCšì+Ŝ‡Ú{Ûá†lg ›ûÉíŜvMĝ)…=vZôa|4‚ ĝ0Ì|˜Á^Ĥә]ϵ|Aytó/Z6Bè×yóD4ëjC°ÇV$ŻkÊÜŞYÑюeCżhY›˘Ŝ•’€¤Kì\ÓĥjÌÖ°9¨~ΌŞ*WĉâyĠ“odmWSÇßN=hyZ(˙&¸J*> endobj +828 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [434.072 323.542 453.776 334.944] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.10) >> +>> endobj +832 0 obj << +/D [830 0 R /XYZ 72 720 null] +>> endobj +829 0 obj << +/Font << /F8 826 0 R /F11 833 0 R /F23 825 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +836 0 obj << +/Length 491 +/Filter /FlateDecode +>> +stream +xÚmSQo›0~ÏŻÛŒT`H`{jÒYĞŞÓ@ÚÔi¸`ĊÁ‘mċßÏĝLÖV}Áçğï>ßwwĨC1ş]Äŝ\׋Û•QıL—¨~FĞ­’8ŠÉ +Ġ-ú…ż>VWAHÁT4ò0Ùg‡çàw}giÂ$‰Ê<‡„§êĉ’tóÒ+;ޤhÁğà\Ë ]áS˜)p…€ŜSrßßH£¸o€J_p\X;šë#qTÔwŬLì9'ÁÚîÀ‚0Át7úÓ{švŒ*3ĊϖŒħéé°×Ŝ–p~ç@ ·MOĠÀ´UœĊ ûë¤AÖÊ÷‘mPĴ,›ħe|l%NŞÚ˙İÚ0>x̵˙Žz9ç‰í³ƒq]‘ŭĠ{*½‚Ŝ?–á;ÚÈ?ĥŽÄkĊÛÎM§´ğÀM3Ĵìú'Ĵ!.ÈħaÀñ UÇf†:(2lgdóÎ@ó Ôí'SVĜw_ *Ú1ŸN‡ı0ÛóıvĜ‡ĵëŬñ,}”·|èÀ9êW²— ûÄM[czĈ,ôL¨![8”g·Ŭê~Ĵàfz%Çγñ9óHĤpT\úġv{cOĊ£šı]½ü–(%I”Ç% +óĵŒIĦTò +ô^üËëĝĜ +endstream +endobj +835 0 obj << +/Type /Page +/Contents 836 0 R +/Resources 834 0 R +/MediaBox [0 0 612 792] +/Parent 827 0 R +>> endobj +837 0 obj << +/D [835 0 R /XYZ 72 720 null] +>> endobj +834 0 obj << +/Font << /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +840 0 obj << +/Length 128 +/Filter /FlateDecode +>> +stream +xÚ3PHW0Ppç2€ÒN!\ún +–z–fFf +!i +ĉF +ĉ†zĈĉ +!) +Ñ!™ĊšşĈĈĈ‰éİ –‰L$3OÓÈB£$Beĉç%ĉäTB”ä¤Ĥ•@%ċ$ĉekĈ†xÁíT026Ô35°T53ĥ@Ĝd‚˘È5„ ˎ) +endstream +endobj +839 0 obj << +/Type /Page +/Contents 840 0 R +/Resources 838 0 R +/MediaBox [0 0 612 792] +/Parent 827 0 R +>> endobj +841 0 obj << +/D [839 0 R /XYZ 72 720 null] +>> endobj +838 0 obj << +/Font << /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +876 0 obj << +/Length 1260 +/Filter /FlateDecode +>> +stream +xÚíš[sÚ8†ïó+|iÏÔ%˲uµ“„¤ÉNÓ0NgÚì…*h +6#ËğÛŭġ+Yì $mìÀĝ÷ùô~;tFNèĵ; +Íö¤ôö`  B:ŭŻN„A%Nè|qO‹Ü‹€+¨Ŝ”Ŝ_ŭ?€<:tĝÈÑ;7ïäi`ꐀ`ˆĠYBLJi O<ŸÀĜ½”ç€à…çËí°&ÏNhoÈA1bÉ?ôÁëŬżœbB¤ÄÈë‚B÷ĝΓ÷•WŽ"·?fÚCîU–{ò—*›,ßǟ➇ánnŭ+bb Ë~Ŭ„ĤÂb4€>3ƒĈ‚ùÜë\÷ŝX½NŒÉo+Ùkoĥ„(2ˆúcŞÉ\°RüğĈU|ĠÛ×ê%‘\Y;%év"§L´6dÀtĜm"Êi> fñœPĦ\íġAs/V”Ĥ•ċCƒ­Ó‚ÀdGtoU­­tĵĤÒ§Ŭ·WZ_À7Fé£>’ê{ÀŜ‡²êréŻíV[’YğĵñlŞuêUÓiĈ™ĠwİËlDBĊñŜċèVñ§Ä‡0 5Ô@è>d‡W  îżë—ğ‰ĞŞĥ²qáOuö̈́nFy]ä(O*6>3&qA'³Ġk$Ŝóܸ6ĵÈ9-Ĥ2âÁ’!żg9Ġ=k t È.öÏW>yBù•–’ SÓBMêĈÜ#Ĝ™¨8-ïÓèá˘ĴD1ÍhĉV~ÓÌoè¤5V<âXàùPi6Y‚µš{8, gâë/™ù¨ĞrO&ĈĤ ·pn8œOé‘[ä“ïò+XEşŬñu³™îÒ´ˆ_/ˆ%şż8,g)*Ñ´‰&ŻId{Á[‡oS?›6–ŽüœqCT›éé?•vÙ­î&vĠnÎÏè×ö8ĥb„9ZL†•Kßħܢ>ê–Eégî=ıó´cGñ˜ó“‚ûíE +1ĠäY>Îòü“ê¤9³SĤ.—=@kŭŸ†xϗF+ ´vĝƒóÓğ7Ô§ġ3?Á%“kÛ/„}Ĝ|_*Žö} ŝ˘ldù×ó%‰áôDÛÍǒšÙĝ‡jŞ~ŻıÙ1†²ĤGf³8Ċ‡ùVĜ@fŜ w2AK‘MgêqĊê\RÍë¤É"^ŸE¤YÜTı/ĜÔ8-òÛ Q%µçY[Ipr°­À4Žk1ĥVĠc£\½G…™Î%ĉAŸNŝS“y0‘ĠÀ~é–ßt˜˙ b×MF"­ü2ݳŝÑ˙ à D +endstream +endobj +875 0 obj << +/Type /Page +/Contents 876 0 R +/Resources 874 0 R +/MediaBox [0 0 612 792] +/Parent 827 0 R +/Annots [ 842 0 R 843 0 R 844 0 R 845 0 R 846 0 R 847 0 R 848 0 R 849 0 R 850 0 R 851 0 R 852 0 R 853 0 R 854 0 R 855 0 R 856 0 R 857 0 R 858 0 R 859 0 R 860 0 R 861 0 R 862 0 R 863 0 R 864 0 R 865 0 R 866 0 R 867 0 R 868 0 R 869 0 R 870 0 R 871 0 R 872 0 R ] +>> endobj +842 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 680.149 151.106 689.06] +/Subtype /Link +/A << /S /GoTo /D (section.1) >> +>> endobj +843 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 661.22 197.253 670.131] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.1) >> +>> endobj +844 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 642.291 186.045 651.202] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.2) >> +>> endobj +845 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 621.425 210.702 632.273] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.3) >> +>> endobj +846 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 604.433 290.957 613.344] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.4) >> +>> endobj +847 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 583.014 340.909 594.969] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.5) >> +>> endobj +848 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 564.638 248.173 575.486] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +849 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 545.709 282.212 556.447] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.1.6.1) >> +>> endobj +850 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 526.78 199.882 537.628] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.1.6.2) >> +>> endobj +851 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 507.851 247.537 518.699] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.1.6.3) >> +>> endobj +852 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 480.897 130.324 489.725] +/Subtype /Link +/A << /S /GoTo /D (section.2) >> +>> endobj +853 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 460.03 207.769 470.879] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.1) >> +>> endobj +854 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 441.101 221.523 451.95] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.2) >> +>> endobj +855 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 422.172 226.892 433.021] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.3) >> +>> endobj +856 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 403.243 225.729 414.092] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.4) >> +>> endobj +857 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 384.314 207.824 395.163] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.5) >> +>> endobj +858 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 365.385 220.388 376.234] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.6) >> +>> endobj +859 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 348.393 187.124 357.305] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.7) >> +>> endobj +860 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 329.464 190.86 338.376] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.8) >> +>> endobj +861 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 310.535 207.077 319.446] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.1) >> +>> endobj +862 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 289.116 261.014 301.071] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.2) >> +>> endobj +863 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 270.187 346.333 282.142] +/Subtype /Link +/A << /S /GoTo /D (paragraph.2.8.2.1) >> +>> endobj +864 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 251.258 321.648 263.213] +/Subtype /Link +/A << /S /GoTo /D (paragraph.2.8.2.2) >> +>> endobj +865 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 234.819 202.483 243.73] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.3) >> +>> endobj +866 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 213.4 284.122 225.355] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.4) >> +>> endobj +867 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 196.961 230.185 205.872] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.9) >> +>> endobj +868 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 176.095 209.678 186.943] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.10) >> +>> endobj +869 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 157.166 231.375 168.014] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.11) >> +>> endobj +870 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 138.237 229.936 149.085] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.12) >> +>> endobj +871 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 119.308 215.075 130.156] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.13) >> +>> endobj +872 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 100.379 251.66 111.227] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.14) >> +>> endobj +877 0 obj << +/D [875 0 R /XYZ 72 720 null] +>> endobj +878 0 obj << +/D [875 0 R /XYZ 72 700.172 null] +>> endobj +874 0 obj << +/Font << /F16 823 0 R /F28 879 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +915 0 obj << +/Length 1249 +/Filter /FlateDecode +>> +stream +xÚíšIs›HÇïŝáĤ7–£-l)ËR\5ċd”Ô‘¨hÀžd>ŭ44 !’;N"ĦıˆFBŭŜëżMe˘˜ÊŬ…Y{5•d˘ÁŬĊuxqy Ċ5\ ZJĝYħĦbÓ0‘­„cċ£Š4Ŭ…DġiÍfñb˘éÈÁê³ÔÀÓt ò‘öWĝĦ‚‰eŒĜIñ)>ï~yğygc`×Utà.tËû€ŬĊ„pûR³)ÍXĴ4:*M˘,^°§™·ƒoiFçÛOöQ‡­šNLóGĜußáW~Ġa€TFiw BX°Fa€ñŽ=˜KŜ àĤù'ÎĤ|ä?Ħĉ ġê~ì>vñÏúßżĜ>r€04.CËVŸÒÚÛżÒĥÜn9ìáŬ}Í&°äÛKh%∗…œ,3~êĊé¸Î1‚RˆQ‰˜û-ĉ~[èÄ “è$Y&üĴOÓ4šT✺8ÈÑÔÛdEwž{ƒŝî¸uK  c Eoaûf÷Ŝ£à°ŽyêÓ˙pĈD‚1naĵûçµ/.nÄt~ǟ?†ù ‡^oÜ`F÷f|}iìċ 7A´s ÜĈ3ÊGAÍWeèÁ ĈVÊċBx&à˙-ñĤÖt@gt”ĠĦŒ?Dħ $‰_5h³G~zt >ùž5Ĵ7Kl]Rı ìÜve6G.y²19òĝ%›ò‹Ç s£+kŞ-·ZS*Oż÷BżÏ“ċ$‰ĉb\m˜Œ›ĜĞev˜U”Ô.§1)‡˙ırc/ÊhéÊEŭ„żûÉ$ĉ)ô6B”cáSMÈ1KÈÒ:!/¸TĞbÏM"&áŻù¸tó~)TLiPGYo“³ÖİĝÙ›Ż•C–)xŸ/ˆ"Q‚OqIÛo:9z›˙’%a넧P†”_šk‚˙à‡ž˙Ĝ¤ +Èljµ$”ĠRë@Éâ%hò[ []ŒÁ0”RKÀÔEÀĈ¸[aÂ;˘EhĞêj­YÈíH &“­,†í’]¤¨uñLá.Y,ĈU ċëï(,/) Ċ#r6'ŒäòfTçÍ-¸7ËĊ;/ëöI˙~ċÊ3šê˘èĜDŽ›)"ÛÉpk8xŽç…MXĴóĞ"ìgÜR]2\_5BÔh1˘6·,úx´(ïLñß/˘ü"lìú>vÀrkx¤ĞY4ZWtzşŒSjĥ_5¤ëV[È9îr4›#^ĵъŜâYo@Ĝ]9ívq^ްÙîÛÔħ˜ÊtXéÉÔ×ëßSJóÍJ‰T=x”'j³e™fŒ÷ßóTDj Ï(I$\½Ş÷^Òl9˙ÍM3[TòÜÖmÚêĵ²Ën§ásÀ +˘¸G-ÁDV‚Q-Áa% ^üɈ&”J6Œ +£˜“]mgÌ/ì“YáŝİHÍ9=Ŭx?Ż\—Ş„n½}0ú 5ÏŞG—ĦôñdZċÓóeòMĜsHàqNeK +j‡ĥŸVµ5¸œİrĠQ[E#ħĵ ÉoDm)D¸Ú`6“-Ż*!ŻqşŜyVtĈŒËŞı;Fxdŝ³½ĊħŝXÀ°mĥ(C™%—mWğ /ŝtDö +endstream +endobj +914 0 obj << +/Type /Page +/Contents 915 0 R +/Resources 913 0 R +/MediaBox [0 0 612 792] +/Parent 827 0 R +/Annots [ 873 0 R 880 0 R 881 0 R 882 0 R 883 0 R 884 0 R 885 0 R 886 0 R 887 0 R 888 0 R 889 0 R 890 0 R 891 0 R 892 0 R 893 0 R 894 0 R 895 0 R 896 0 R 897 0 R 898 0 R 899 0 R 900 0 R 901 0 R 902 0 R 903 0 R 904 0 R 905 0 R 906 0 R 907 0 R 908 0 R 909 0 R 910 0 R 911 0 R ] +>> endobj +873 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 707.104 175.778 717.952] +/Subtype /Link +/A << /S /GoTo /D (section.3) >> +>> endobj +880 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 688.175 250.747 699.023] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.1) >> +>> endobj +881 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 669.246 295.274 680.094] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.1) >> +>> endobj +882 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 650.317 261.54 661.054] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.1.1.1) >> +>> endobj +883 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 631.388 276.926 642.236] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.1.1.2) >> +>> endobj +884 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 612.459 303.383 623.196] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.1.1.3) >> +>> endobj +885 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 593.53 282.959 604.378] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.2) >> +>> endobj +886 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 574.601 279.915 585.449] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.3) >> +>> endobj +887 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 555.672 240.895 566.52] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.4) >> +>> endobj +888 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 536.743 259.104 547.591] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.2) >> +>> endobj +889 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 517.814 248.643 528.662] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.1) >> +>> endobj +890 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 498.331 313.29 510.286] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +891 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 479.956 238.127 490.804] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.3) >> +>> endobj +892 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 460.473 334.322 472.428] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.4) >> +>> endobj +893 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 444.035 295.689 452.946] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.2.4.1) >> +>> endobj +894 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 423.169 279.223 434.017] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.2.4.2) >> +>> endobj +895 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 403.686 350.539 415.641] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.5) >> +>> endobj +896 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 387.248 301.501 396.159] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.2.5.1) >> +>> endobj +897 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 366.382 285.035 377.23] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.2.5.2) >> +>> endobj +898 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 347.453 293.835 358.19] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.2.5.3) >> +>> endobj +899 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 328.524 279.874 339.372] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.3) >> +>> endobj +900 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 309.595 352.878 320.443] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.3.1) >> +>> endobj +901 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 290.666 270.976 301.514] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.3.2) >> +>> endobj +902 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 271.737 257.638 282.585] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.4) >> +>> endobj +903 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 252.808 332.579 263.656] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.4.1) >> +>> endobj +904 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 233.879 267.988 244.727] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.1.1) >> +>> endobj +905 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 214.949 270.755 225.798] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.1.2) >> +>> endobj +906 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 196.02 273.55 206.869] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.4.2) >> +>> endobj +907 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 177.091 360.087 187.94] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.4.3) >> +>> endobj +908 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 158.162 313.594 169.011] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.3.1) >> +>> endobj +909 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 139.233 375.169 150.082] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.3.2) >> +>> endobj +910 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 120.304 395.703 131.153] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.3.3) >> +>> endobj +911 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 101.375 379.625 112.224] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.3.4) >> +>> endobj +916 0 obj << +/D [914 0 R /XYZ 72 720 null] +>> endobj +913 0 obj << +/Font << /F28 879 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +951 0 obj << +/Length 1164 +/Filter /FlateDecode +>> +stream +xÚíšMw›F†÷ŝ,ÑB˜ùféX–{’ȍhrÒ´ *ċ9E ŠĉÏw†a¤ArB£VŜ!,£óÜ;ï}ï\kfıÖġ™Ğ@ĵşV6³Ô›w×gŻÂ³óa`Q‡z³Â; ¸Ô H`ùÀu\ä[áÔúd#;¸×c;ä‹ĵ×GÛi"Èŝ%çÉL½ŭu|9z;ĵıVÀ‹{ġùeœöú0°'=ñòg~>.˘ıĝ7ż‡?UżÍúÔG˜ĜNŻO\÷Àż@lĴ}l˘µp‚X}8ÒI–óí[‰#*J*÷Dž(|‘ĉ{ġ…çEuuċĉO (>4„˜Ò½àu›ÈBMvĵ|›ħİb)²Ö¸ ÜL·>„uÁè{ÔñµDN:*B,($B£ħ@ D˘à1/DtlÎ6>&žC0'êğ´ĵÜtµûb Béz¨µċBh_Žn?ŞĜĠ ']È%ó¨Î†î@gßH;hòH§ü@şÁ IĵnÑ/%èt>ވKq"Ĵúĉ욂™˜´ğ•n•ÌO=âHÁ,*ûC½£\26}9M‰ZBT™6CĥáóT<Ġ-ĈF´´ڕ…{ó ‹(aé2ߝ›ĝÚ7ǕW{/şêŞŻˆjc"C8až÷x·Zá&M¸Ç-û›Mw<žïaŒtp­ħ[ğ‚Ġ#šríK %Âuéà^ódmÛT]@ğ³§òŻĝoĊ_نĠӇĊşÖŬGY4)Xf +2ĈÉ}éê2€ûVúDñ]oL³ŭcÏa +endstream +endobj +950 0 obj << +/Type /Page +/Contents 951 0 R +/Resources 949 0 R +/MediaBox [0 0 612 792] +/Parent 953 0 R +/Annots [ 912 0 R 917 0 R 918 0 R 919 0 R 920 0 R 921 0 R 922 0 R 923 0 R 924 0 R 925 0 R 926 0 R 927 0 R 928 0 R 929 0 R 930 0 R 931 0 R 932 0 R 933 0 R 934 0 R 935 0 R 936 0 R 937 0 R 938 0 R 939 0 R 940 0 R 941 0 R 942 0 R 943 0 R 944 0 R 945 0 R 946 0 R 947 0 R ] +>> endobj +912 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 706.55 350.996 718.506] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.4.4) >> +>> endobj +917 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 688.175 314.535 699.023] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.4.1) >> +>> endobj +918 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 669.246 228.137 680.094] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.4.2) >> +>> endobj +919 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 642.291 169.109 651.202] +/Subtype /Link +/A << /S /GoTo /D (section.4) >> +>> endobj +920 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 621.425 198.083 632.273] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.1) >> +>> endobj +921 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 602.496 199.937 613.234] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.1.1) >> +>> endobj +922 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 583.567 209.623 594.305] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.1.2) >> +>> endobj +923 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 564.638 250.581 575.486] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.1) >> +>> endobj +924 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 545.709 278.559 556.557] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.2) >> +>> endobj +925 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 526.78 272.665 537.628] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.3) >> +>> endobj +926 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 507.851 280.164 518.699] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.4) >> +>> endobj +927 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 488.922 288.882 499.77] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.5) >> +>> endobj +928 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 469.993 241.697 480.731] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.6) >> +>> endobj +929 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 451.064 272.388 461.912] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.7) >> +>> endobj +930 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 432.135 243.385 442.983] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.8) >> +>> endobj +931 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 413.206 343.123 424.054] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.1.2.9) >> +>> endobj +932 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 394.277 243.607 405.125] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.2) >> +>> endobj +933 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 377.285 183.443 386.085] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.2.1) >> +>> endobj +934 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 358.356 260.848 367.267] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.1.1) >> +>> endobj +935 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 337.49 327.874 348.338] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.1.2) >> +>> endobj +936 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 318.561 288.688 329.409] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.1.3) >> +>> endobj +937 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 299.078 260.516 311.034] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.1.4) >> +>> endobj +938 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 280.703 228.026 291.44] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.2.2) >> +>> endobj +939 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 261.774 263.477 272.622] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.2.1) >> +>> endobj +940 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 242.845 293.309 253.693] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.2.3) >> +>> endobj +941 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 223.916 299.481 234.764] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.3.1) >> +>> endobj +942 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 204.987 270.257 215.835] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.3.2) >> +>> endobj +943 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 187.995 295.274 196.906] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.3.3) >> +>> endobj +944 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 167.129 246.817 177.977] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.3.4) >> +>> endobj +945 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 148.2 285.339 159.048] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.3.5) >> +>> endobj +946 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 129.271 247.537 140.119] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.2.4) >> +>> endobj +947 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 110.342 264.777 121.19] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.4.1) >> +>> endobj +952 0 obj << +/D [950 0 R /XYZ 72 720 null] +>> endobj +949 0 obj << +/Font << /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +989 0 obj << +/Length 1216 +/Filter /FlateDecode +>> +stream +xÚíšMw›F†÷ú³D Ñùb`–Ž-ç8ÇiÜçäÔ͂ ħÌİ* :n˙|g`„%fT7Tv%܅FÂXϽĵ÷½w€` x;€z‹ä+ù Ô;ßŜ„ƒÎÀ]Î0á-@ı>áÀG…ÄáÜ8ÔĊüŽfóar5DNžòwg)wËáˆê\Šß‡8pÄ|ĝ%|×\܌<8îPnàżĦœ?ïZß!ä9 o6 _G(p9ĉ›À‰>ı~óŝ"T‰“ċġöçñçšú$΃eY´/í{`°˙;úVĤ¤SŞ™^İTŠ"YÌj ġĴídBэ,´A]ĞÉ8ώԍuòl8’I‹éJŞë4ü9ĉĴ×I½•Û{dn1? êˆüAwòQ>ëLÎE\fy"Lĉ>>Ú.}˙)=ò¨ësŻ YVwûùĊċĝDIv~ĴÉŝİB”۝½ÔŽċIÜîè†w;Sކ>ŜòoFùR=Ħ~+²ĝ5_ĠLžĴá@ŬĵmĵœŽ‡ïÔ*3ÖµaQċè›QŸÏ8ĵ†pĜċˆĥLŬúħ¤^˜YI"[̐—v˙û—y醽 ïÄĥ‚HdËjö!âDÍWfí@}F̧F˘û¸K½ı’6Wmòvó½ÒñÑӈ1—*X9W:@îL²ĵlÔżnÔDU ÍvÎïñÀÈ'ŬrĥRĊòúñф“8–Ĥ½f˜ µ–‰2J—fïÇfÈl%D;"š†ózD5×ë ĠnDÍ#J&ÂúÑĴuĈH5Ĉ³Í`V…q£zŒ‚)Ĝ^ÙzkAĵËĠû&?'E)R=‡T‹GFGüì%è…ò;³cğĜ5÷öu!ôĴüDŠ ÓE½ÏğÑîrLÛĥçìħN|Ÿô÷òĴÄ1aŭލÉÙÀ™ÌI˃ŒÒ~ XĴ@½N÷8mLŽuB¨˙gnÒmŜFUCŽÁˆ`—@Mv{d;¤ Ĝ +endstream +endobj +988 0 obj << +/Type /Page +/Contents 989 0 R +/Resources 987 0 R +/MediaBox [0 0 612 792] +/Parent 953 0 R +/Annots [ 948 0 R 954 0 R 955 0 R 956 0 R 957 0 R 958 0 R 959 0 R 960 0 R 961 0 R 962 0 R 963 0 R 964 0 R 965 0 R 966 0 R 967 0 R 968 0 R 969 0 R 970 0 R 971 0 R 972 0 R 973 0 R 974 0 R 975 0 R 976 0 R 977 0 R 978 0 R 979 0 R 980 0 R 981 0 R 982 0 R 983 0 R 984 0 R 985 0 R ] +>> endobj +948 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 707.104 256.392 717.952] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.4.2) >> +>> endobj +954 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 688.175 292.728 698.912] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.4.3) >> +>> endobj +955 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 669.246 268.762 679.983] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.4.4) >> +>> endobj +956 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 652.254 247.221 661.165] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.4.5) >> +>> endobj +957 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 631.388 366.286 642.236] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.4.6) >> +>> endobj +958 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 612.459 274.823 623.307] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.2.5) >> +>> endobj +959 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 595.467 233.174 604.378] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.5.1) >> +>> endobj +960 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 574.601 243.385 585.449] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.5.2) >> +>> endobj +961 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 557.609 238.515 566.52] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.2.6) >> +>> endobj +962 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 536.743 290.016 547.591] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.6.1) >> +>> endobj +963 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 519.751 258.495 528.662] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.6.2) >> +>> endobj +964 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 498.885 281.991 509.622] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.2.6.3) >> +>> endobj +965 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 479.956 284.122 490.804] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.3) >> +>> endobj +966 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 461.027 222.215 471.764] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.3.1) >> +>> endobj +967 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 442.098 323.031 452.946] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.3.1.1) >> +>> endobj +968 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 425.106 304.296 434.017] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.3.1.2) >> +>> endobj +969 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 404.24 272.748 414.977] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.3.1.3) >> +>> endobj +970 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 385.311 270.478 396.048] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.3.1.4) >> +>> endobj +971 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 366.382 264.058 377.119] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.3.2) >> +>> endobj +972 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 347.453 254.04 358.301] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.4) >> +>> endobj +973 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 328.524 227.279 339.261] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.4.1) >> +>> endobj +974 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 309.595 313.262 320.332] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.1.1) >> +>> endobj +975 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 290.666 304.241 301.514] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.1.2) >> +>> endobj +976 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 271.737 259.824 282.585] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.1.3) >> +>> endobj +977 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 252.808 292.064 263.656] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.3.1) >> +>> endobj +978 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 233.879 366.037 244.727] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.3.2) >> +>> endobj +979 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 214.949 320.098 225.798] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.3.3) >> +>> endobj +980 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 197.958 263.587 206.758] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.3.4) >> +>> endobj +981 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 177.091 317.054 187.94] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.3.5) >> +>> endobj +982 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 158.162 326.103 169.011] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.3.6) >> +>> endobj +983 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 139.233 308.668 150.082] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.1.4) >> +>> endobj +984 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 120.304 286.031 131.153] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.4.1) >> +>> endobj +985 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 103.313 247.26 112.113] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.4.2) >> +>> endobj +990 0 obj << +/D [988 0 R /XYZ 72 720 null] +>> endobj +987 0 obj << +/Font << /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1026 0 obj << +/Length 1210 +/Filter /FlateDecode +>> +stream +xÚíš[sâ6Çßó)ühpu³%=Ĥ\Òt’ÀowöÒ/8ijĈP0dúċ+!°%âv1y&f†Ëïŭ˙ç Xc XW ğBñĴùĜROîŻ.~ġ/~é2‹;ÜCžċ?XBÇCÔ˘8SËY_lâŠ?ÜhB̸ŬÒ°ÑÄۃY£‰˜£Ż’aFÓdÑĝÓ˙}ŭ™Ö—&€ÙN£ép¸ áüàïiş” „M½ÂmĞĠDÜaŒYMÈŽĝ6FW@Dµŭnjak:™ĊaN´{}Ói7µ/ŒĜ~GŜ%ö íçDŜNƒ§òwr]t˙}E’ +’P'‰GHÈ`½e:̖iùc9À?5”Ñô8ì ƒ³„n‡Á2NU·£Ċ,BžµPús‚y‹ĝë°½=`g”sŜBĞDx:O‘zŝM„ìŝċp.Y<¤d—uƒş?œÏ‘²×ïĈáˆôvşòğQôĵ›+ĉäԁ²J@IônšğÙ4Q×û0µÁߒq¨ڏ&ĦV)¸„ÖK‡×Ŭ‚ğ(Ò½‹(gBLfYQӝŜZ? ҝeŝÏ2˘3Ÿ‹*b:W˙Ŭ +9 Ĉ†´uÙİS­ +žż\ #‡CR/³ dßwnzWŠî?ıT,ÂMñ=KêçEN´¤^-‹†ŠÁ`àĠÂâeaÛ™ùÉhӁé†v›VĴĴp(5ŭğBNĉ‘ÍËq2ŻoUjKħú°‘{ı2{ÈÏú[‡G_Fën4_HÂ8”kàĞ4&°˘ħLÑ>·.o +šĤUù·S5Py,ĉsµ•ŭƒŞi5iĜ*Vċ)Á‘‡Z5X2¨Ú G„d=ÉW Î+ĴĝkÍI¨ŒĤd”’“ K5’À &Rp 3[îñ³Ka#j\ħs£kËŬ(ŭĤëT“ÒċXĝÍ:ÎÖ6{ו)žġpÍ|K#‘ûAċ|µ#¤n~H£8J#a÷ÒsŻp숆ÙU󔵇xġBy˜Tݳ:ħ‚§n-lû †íéx‡Z]jĜ9E°&ŭš‘.yµÏ²‚ÏÀŝ!ÁñržW3Ħ9 ]ĵsˆßêġ?éM,³HïÛ}ÑH]Q´p·ŒœçFڗé{)üßïf•f‚>h÷ê^_ĉu ·@~>]£cöUnôĠÜ!P‘*bŜû´ím"d6Zm´[É–Poĥİ?[Á<ĤĞ!ĥÜĠÑ]ÁZú€ûjàÛ.ĞSí<òȒ>8‹´72zމoÚXŬĥúÙġ>ÌG`ždr¤:]™ÒĤn—s^ŻrœVlW!o+]vêŬuŻ‹;Ž›n5+x‚lìµL’êoÌ×ĵ‰?YñeĠìݽrŻŻÈġZM½B)·…CĞ3ÔiGfġε|ŭ1Á™xwžf+á<ŬâÌìÑjÏV;ġEÎûĴ#UÀcxU^èçAy/Â5îV+ñ$|İ3T#ŭċ7‘Óq4TüğQœŸ…ú +\°ÑkżüÜ÷ċP+ĠıwŞz]"ı~zĦT”Èn¤ĝ“½_ü HBf +endstream +endobj +1025 0 obj << +/Type /Page +/Contents 1026 0 R +/Resources 1024 0 R +/MediaBox [0 0 612 792] +/Parent 953 0 R +/Annots [ 986 0 R 991 0 R 992 0 R 993 0 R 994 0 R 995 0 R 996 0 R 997 0 R 998 0 R 999 0 R 1000 0 R 1001 0 R 1002 0 R 1003 0 R 1004 0 R 1005 0 R 1006 0 R 1007 0 R 1008 0 R 1009 0 R 1010 0 R 1011 0 R 1012 0 R 1013 0 R 1014 0 R 1015 0 R 1016 0 R 1017 0 R 1018 0 R 1019 0 R 1020 0 R 1021 0 R 1022 0 R ] +>> endobj +986 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [170.63 707.104 305.652 717.952] +/Subtype /Link +/A << /S /GoTo /D (subparagraph.4.4.1.4.3) >> +>> endobj +991 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 688.175 333.437 699.023] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.1.5) >> +>> endobj +992 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 669.246 229.216 679.983] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.4.2) >> +>> endobj +993 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 650.317 251.715 661.165] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.2.1) >> +>> endobj +994 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 631.388 317.718 642.236] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.2.2) >> +>> endobj +995 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 612.459 327.265 623.307] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.2.3) >> +>> endobj +996 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 595.467 287 604.378] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.2.4) >> +>> endobj +997 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 574.601 293.946 585.338] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.4.2.5) >> +>> endobj +998 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 555.672 263.643 566.409] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.4.3) >> +>> endobj +999 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 536.743 239.912 547.591] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.5) >> +>> endobj +1000 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 519.751 224.041 528.662] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.6) >> +>> endobj +1001 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 498.885 185.547 509.622] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.6.1) >> +>> endobj +1002 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 479.956 227.39 490.693] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.6.2) >> +>> endobj +1003 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 461.027 214.134 471.875] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.7) >> +>> endobj +1004 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 442.098 197.723 452.835] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.7.1) >> +>> endobj +1005 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 423.169 307.977 433.906] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.7.1.1) >> +>> endobj +1006 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 404.24 244.05 414.977] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.7.1.2) >> +>> endobj +1007 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 385.311 239.566 396.048] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.7.2) >> +>> endobj +1008 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 366.382 247.246 377.23] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.8) >> +>> endobj +1009 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 347.453 205.541 358.19] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.8.1) >> +>> endobj +1010 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 328.524 290.03 339.372] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.8.1.1) >> +>> endobj +1011 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 309.595 285.879 320.443] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.8.1.2) >> +>> endobj +1012 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 292.603 250.691 301.403] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.8.1.3) >> +>> endobj +1013 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 273.674 228.054 282.585] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.9) >> +>> endobj +1014 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 252.808 196.616 263.545] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.9.1) >> +>> endobj +1015 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 233.879 301.169 244.727] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.9.1.1) >> +>> endobj +1016 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 214.949 262.231 225.798] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.9.1.2) >> +>> endobj +1017 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 196.02 305.735 206.869] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.9.2) >> +>> endobj +1018 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 177.091 335.858 187.94] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.10) >> +>> endobj +1019 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 160.1 272.208 169.011] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.10.1) >> +>> endobj +1020 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 139.233 255.742 150.082] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.10.2) >> +>> endobj +1021 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 120.304 232.385 131.042] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.10.3) >> +>> endobj +1022 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 100.822 335.983 112.777] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.1) >> +>> endobj +1027 0 obj << +/D [1025 0 R /XYZ 72 720 null] +>> endobj +1024 0 obj << +/Font << /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1061 0 obj << +/Length 1271 +/Filter /FlateDecode +>> +stream +xÚċš]SĞ8Çïŭ\íÀE‘$ĵ$—µµÎÙYn[×Ïîĥħ2Rp =süö›„µÊ íêMKJg~ù?ŻÁ1f†cœ9úÉOÇÈf\ ώNĈGÇj0›ùĜ7Ĉwr‘fÈħİñtm9"6ĥ:˜—‹[ ™q49´p`†âŜêBÌk‹3‹‡áiŜĈúúÇsnFŭ‹ dŞ.\óĤ/“7‘ġïĝ÷ċ2ĉaÓĥ:ž´ċ2ĥíŜ³iBžÉ6WS…&?;ˆÚ ³ < y8í\$ñ<ë_Š +Ÿˆ4ƒñh‘‹0JrÁÄċ%<¸ ,êša.àAÑ/>…‡ïGù\ yœÎà~= ²ë´è­_mâò׊Jï>Lf|ÍÔÂ,‰’YC!y­pÚ­ wçäk§daşĉŠ"qŸ.„ĥ¸§\9èŞż ‘E· Qï›RiıµÂBìPEš‘ +´˘Ê'ñ0›(ÚĤ7%¨C: œp^ßs£“'ÁkCáe– +ş4ĉ“ŭiÍm‡œq4׆ңdÍäzqju¤ĝ +>š~ŭTCžšy6—Ħ=x/Ż'äHÔH„óGxÂ?tp$fw2áy.™!SkdĊóí?ŜK>[ƒ*tzK³*i¸ŻuVÄó>ԇ·)0ż!B\Ax†7îž^T•LÓKKï%{óÙaúġ !1Äθ6ÜñŠÑ’äĞeçÑà$4ڛЅÖ6Šü}¤ò Ğ˘Ĝ:ٔ˘x’œïJ ġ.¤Ó,+KĈsÂÏĞ–GSWïoÛl'mŒm†Ü +mQTÊzów0wt³â—àÉtUŠfEĊŭ•ˆâH¨ìĝİÚ§  oŸ[°mlzżÊuùêÛñl’À£ŸYĠûܧfO°öA]\<Š(M*.Çû Zäp“³7l‡/w9ÎíĜäž(K Š˜ëò‘˜ƒ(–‘ ¸ĵ—µÂFcı—"䓊f„k_ĥ³ûËz˘ċq¨@j¨UĈ§Ù<Ot?ìÛäK–ÌĠAÀ +ĥJż§j\ÖúîĈâîcÑàĠ£0ïSfmòÖ-İaİìıj$†eQ£_úĥôâÈɲÇ8äb‘é—.zş˙]m¨a~ +ĥV&ŝ%RîÉşDN¤D(6OmUˆĞ‚w+$@D)$Ĝ˘ċ)ŠıÌŬ“sKIİà–Ğn36ùf„2 +4\É§Ì˘hK—Ë,޽Ş0|/ċ2èeh}ı D×­äœÏĦŸ(—"EZĴmÉzñ‡ßàŜ•êôVu‰•Óovv6­cf;HZ+ql‚|XÚ,ŬNÇG˙V,ĵż +endstream +endobj +1060 0 obj << +/Type /Page +/Contents 1061 0 R +/Resources 1059 0 R +/MediaBox [0 0 612 792] +/Parent 953 0 R +/Annots [ 1023 0 R 1028 0 R 1029 0 R 1030 0 R 1031 0 R 1032 0 R 1033 0 R 1034 0 R 1035 0 R 1036 0 R 1037 0 R 1038 0 R 1039 0 R 1040 0 R 1041 0 R 1042 0 R 1043 0 R 1044 0 R 1045 0 R 1046 0 R 1047 0 R 1048 0 R 1049 0 R 1050 0 R 1051 0 R 1052 0 R 1053 0 R 1054 0 R 1055 0 R 1056 0 R 1057 0 R ] +>> endobj +1023 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 706.55 399.19 718.506] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.2) >> +>> endobj +1028 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 687.621 398.415 699.577] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.3) >> +>> endobj +1029 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 668.692 381.424 680.648] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.4) >> +>> endobj +1030 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 649.763 380.427 661.719] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.5) >> +>> endobj +1031 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 630.834 389.006 642.79] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.6) >> +>> endobj +1032 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 611.905 325.992 623.861] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.7) >> +>> endobj +1033 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 592.976 399.08 604.932] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.8) >> +>> endobj +1034 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 574.047 411.533 586.002] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.9) >> +>> endobj +1035 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 555.118 402.926 567.073] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.10) >> +>> endobj +1036 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 536.189 335.402 548.144] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.11) >> +>> endobj +1037 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 517.26 373.011 529.215] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.12) >> +>> endobj +1038 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 498.331 348.588 510.286] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.13) >> +>> endobj +1039 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 479.402 346.305 491.357] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.10.3.14) >> +>> endobj +1040 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 461.027 264.542 471.764] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.10.4) >> +>> endobj +1041 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 442.098 259.658 452.946] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.11) >> +>> endobj +1042 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 423.169 191.912 433.906] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.11.1) >> +>> endobj +1043 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 404.24 201.598 414.977] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.11.2) >> +>> endobj +1044 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 385.311 290.902 396.159] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.1) >> +>> endobj +1045 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 366.382 275.404 377.23] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.2) >> +>> endobj +1046 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 346.899 320.126 358.854] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.3) >> +>> endobj +1047 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 328.524 285.727 339.372] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.4) >> +>> endobj +1048 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 309.595 262.093 320.332] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.5) >> +>> endobj +1049 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 290.666 282.157 301.514] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.6) >> +>> endobj +1050 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 271.737 271.917 282.474] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.7) >> +>> endobj +1051 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 254.745 247.675 263.656] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.8) >> +>> endobj +1052 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [140.742 233.879 242.445 244.727] +/Subtype /Link +/A << /S /GoTo /D (paragraph.4.11.2.9) >> +>> endobj +1053 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 204.987 263.096 215.835] +/Subtype /Link +/A << /S /GoTo /D (appendix.A) >> +>> endobj +1054 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 186.058 258.883 196.906] +/Subtype /Link +/A << /S /GoTo /D (subsection.A.1) >> +>> endobj +1055 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 157.166 253.438 168.014] +/Subtype /Link +/A << /S /GoTo /D (appendix.B) >> +>> endobj +1056 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 128.274 259.043 139.123] +/Subtype /Link +/A << /S /GoTo /D (appendix.C) >> +>> endobj +1057 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 99.383 272.768 110.231] +/Subtype /Link +/A << /S /GoTo /D (appendix.D) >> +>> endobj +1062 0 obj << +/D [1060 0 R /XYZ 72 720 null] +>> endobj +1059 0 obj << +/Font << /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1074 0 obj << +/Length 522 +/Filter /FlateDecode +>> +stream +xÚíWÉnÛ0½û+x¤d¸Šäİp( Häö +Œ-Tħ ‰)ż):F´E{¨'Ž(‚šÑ{³°\NÈVRżP/@|¸œœf““ÓÀ`“²d÷@1 (Á„+Ŭ[x‘ %œ••M×NΠsu9tĥI~dŸwßBĴİô›ö.Ĵ=ê=™½Ö‰—X+ +ĠĜ0³ĠŒi‚´`f™;Ż›s˜×6>|'T´qó`LBakϧA·­É8A’ĦĈì=;"ÑùÍ<)•;šöğ‰_{Ô°HÍÖ-<#ӄé[ÄW_l*W‹f Sŝ§ĜHŒRÂG cĜP1à%Iüú8ŻÊ˘-> endobj +1058 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 709.041 162.696 717.952] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1063 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 690.112 218.894 699.023] +/Subtype /Link +/A << /S /GoTo /D (subsection.E.1) >> +>> endobj +1064 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [85.948 669.246 216.237 680.094] +/Subtype /Link +/A << /S /GoTo /D (subsection.E.2) >> +>> endobj +1065 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 649.763 247.786 661.719] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.E.2.1) >> +>> endobj +1066 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 630.834 275.764 642.79] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.E.2.2) >> +>> endobj +1067 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 611.905 265.663 623.861] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.E.2.3) >> +>> endobj +1068 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 592.976 248.893 604.932] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.E.2.4) >> +>> endobj +1069 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 574.047 236.079 586.002] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.E.2.5) >> +>> endobj +1070 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [108.862 555.118 237.989 567.073] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.E.2.6) >> +>> endobj +1071 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [71.004 526.78 218.453 537.628] +/Subtype /Link +/A << /S /GoTo /D (appendix.F) >> +>> endobj +1075 0 obj << +/D [1073 0 R /XYZ 72 720 null] +>> endobj +1072 0 obj << +/Font << /F28 879 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1078 0 obj << +/Length 2608 +/Filter /FlateDecode +>> +stream +xÚµÉrÛÈġîŻàmÀ*Ĉ2—”ċ­”ÇS–ĤRċL- Iv 8Ŭ€dċëóĥ@Šöd>áġëííK#ZìÑâ‹HW·/^½‹Eœ…iV$‹Ûí˘Le…QZ.nëĊżƒxıŠ$Ûe½í–+ĝÖCĠ›]ŝçöŻŜŻ›pS$nĞd–›ŒwYŬ<ı^–Ğ,ÛoğgèÓq ëmUoÚxċK”렳ͣàËÍ2Ŝ~şyÉCx­jùĞÛ½j+]óÈêc£*}íïıġGġ{8J3|œİŝ„(à ىp“̎g&-ÀéŬt"ş-ßüúê#BQ„‰LYŝ~ù Ĵ0‡_y‘{ž@²úàÂċ*ϋàZü=гŜ1lZŝö{Í@ğÄcŞáaĉ÷B×÷hTMÓ“•êAjssfħGŝ"˜äBNCZÇ áşıègŸ~kvĤ'aY;Úl…KöÈ.|?{ƒÌ´ĵ.Ÿ^É×9ĈÔx|W­’2BI÷5OtCïL­G/1J Ĥİg0ÍÎÄSd;8S‘ĜÊ/ƒ{žTmÍêİÑĵ°7}6]ƒ¨ċü^Ždïˆw‘ ³}Ȟ„H$&âKi–_z_|}GNL˘VóàvoCıé˘ĵèšy˜⚲ ñò +sÚŝ$èKÀŞkq¤XD*l?žÖ ré-Ş‘XòñfÍ ;G™o;4DXĝâĝÒ:Ĉ¤Wï“tF5„ĤM–QTI7 “/ÏöÌE(<­ŭ { 1E`0é•Ӈx’GQ gŜ"X PÓjĈ£3 rŻ›#cžèn`ôŽÌıçñ†K€şœŒôÖZĈvrAӚŜ€G>-×iΰβ9ıEp´ò ë  4CöŞ€ĉzTĈݰ'ûLƒVx]|~÷úíÇwaòÏ·<ċĠ%,Šċ× wkî†I5ÌïhlĊò_Ċ›°Lòżħ[O÷{”‹Vŭ`µĜ[^ĈB|ɸǽáp"ÔiEsnoµ +Rm5$ ™“ĜÑ£ċ>âZ·gŝ0:q­~0Ŭ tpŒuá˙-†âŻ‹áş…pÑ4’ó‘g„ÑlÁXŞîpltOVHy3ö9!ĉ0r•5GÖ"È +áğgçY9|Á–Tv o>Ÿ¸Ç´Ìas+ÔrTg%1ŒRûĦB#ÛI’'ÁßzӀ£i"Jr¨]¸ €ä²ı3˜HAÄIħıà–`%4;Mğ˘ ›]+Hn¨×wó_Ċ˘FŠ%ıĝöç4¢hJ SöC…t£)2+ ·:ÂÍÂ_[›ÑEfÁe–µáò,<,Ħp|7†zÍ^ٚŠŻÁÀ´ĊŠEôCù{Í×íšÎ9eŸ˜žyyÂA+äì<Ż='} óہôĜÁ=ı¨C9hĝ#CċëÖ__믧LܓŠŸ$FbëlíÎJ“Ŝ*çUyÎÍ<Á@äM8‚„ ‰9*%1§£ä1nÌ"ÄŻĥÛYu8pY“9V`‰â£Î‰‘áŒ[$p, )|ıyüʂçÁ( ĥC[M‘T×ȍÔÂĞבìwjd¸öı´ĠîµË.jd¨ż*²ôšFÏìÁKK5Ïâ:}4êÎW‰RWĤÈÉŭN +OU×yñşġ1K·Rô=öT)ŝkݤFô" ìïßE“>6a™âĝë³ H Ĉıïĥd–£ÒZ!È­Bçŭâ°Œ€lĝÈħĉ(ŠċĜ–żœEp 5U4eù+M‚ÔT!0Oçşċú"ڜĦŒÒ_§V˘8"HlĝmĞf¨ÉAhÄßJ99ë‰p…ĜŸMSS^E4Šñqßñ ÚïÍg/:01½è€Zèmdïí;Ž$vBb¸r#Ä:ġ{Ğġ%Í %N˜I4ž½ ĦŭëàSë×NúÓ³W˜&şb_BR‚œ²pև]_ĝyÑÂÔÍ$ZNCˆĵ’–™Û É&J² ÷mcÈ£é麉ƒ³[ĉÏâ,P23îĈGšÁ~%ÍsîÒ _[ġ“)ĥòüYXb$ 9…ît+ ì@& J|“‹)â{*wÌxğÓm×_bùġ (TĉàVó^*/‘é¸Öû!ĥüD$!Këg?H&ÈÔÁ@ġ’_>EE:wÑFۗü +;…`t_á/ëxcĞĞŝœ>y)MÇd^Šh>8f @È5T‘sLÌÖ³G ŒX>˜ŜµçéÑ4èMônñÄ ‰eÜÉ˝JkF&…éû-YCâoY^àµdU|‡4÷ùĦ7ŭ :ġ5íĠġ§›od+ˆk*Ú6,^ü>ZÓ÷ĝ“lĤ…Sƒ3éĥŞÂ—!+ğEBşÂ—žĴ˘g5ZOµ6FIx£ƒ2*47s%BL‰=ÍqĊ+|ĴĊ¨xџ9ˆĈŻhRéêŒ@LĉÉ{Njı'})d (œ4öÇàÖfĝĉ“& İÎb +qÛ(ɓs; +xé™ÓÄü6ßIÔ¸°RíO=OÜÍWS§xɨˆ=AóäGA‚EQšä )TFDüì× Ĝk9¨%Ü.Á.áĤ'N͜âŭ-Ï>P–GÔ/°ŝݍĜ#´ç°‡€—^Oŝ™FÀ-* ĤœhÏY/ÙêGĵ<8—Ĝ^0™nthÜY×+ş`d–žäOĦŽĉ2Ÿġ•ä˽*o¨X¤Ĥ5ÇÓï­ÔQŬɓĜ¸­=yrX$É&Œâ ô„›p½^K[™œ,zwûâó½s& +endstream +endobj +1077 0 obj << +/Type /Page +/Contents 1078 0 R +/Resources 1076 0 R +/MediaBox [0 0 612 792] +/Parent 953 0 R +>> endobj +1079 0 obj << +/D [1077 0 R /XYZ 72 720 null] +>> endobj +6 0 obj << +/D [1077 0 R /XYZ 72 720 null] +>> endobj +10 0 obj << +/D [1077 0 R /XYZ 72 629.585 null] +>> endobj +14 0 obj << +/D [1077 0 R /XYZ 72 358.44 null] +>> endobj +1076 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F23 825 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1082 0 obj << +/Length 3307 +/Filter /FlateDecode +>> +stream +xÚ}Z[wÛ6~ïŻ[èmĴˆ¤(Qħ“´ÉÖ­í=ٓí> dqC,HĈqŭÎ73 )—é“€\À\jyöpĥ<ûé‡ŝ^Ŝ˙ê]~ĥ]l×Éúì~ĥIÎ6ñrħL7g÷ğ³˙DŬÁµöü"Ŭä‘óçqT>”µİŞ'!µ}ÓTŬĦ·‰Ëî ôî`…T¸cÓwÖ/Î/2êŭfŽMe[aşŭ0şĠñe]TŭN7ü÷ċûßÍıĦ+çÑuYxw]Öç - ĵğË8_<˙ïŭ:ÛE/ĥY&§xôe×ÙúübE£?Ÿ'›èIÚ×Ĥ"ŭO{l^R3K#SÓQw oeG_ïb3Z†ĉwBğ?ÏÓ¨÷ŸÏ/ˆĉnÁùíZX"µx<şÈġ&Ĥ‹tŭƒ.­fÍÍA,§³ìQ Iċ2Ewrµú÷`E“Ò8Ħžü’E•Âo@ƒ5“&k”÷\nDn\}ĵĈÈ'!“ŠJƒ4¨ĥ³:B‡èÖû0Ŭ*Ĉ,PÚ-Ĝú*ÒéҍovV—r³ímS‘òí0uM +ı³*=µD;á}Ác{γ¨rl³e͏ù˘ +œ¨4HmGÇ!£Ô|f4ödÇnÔ ŬB<ÑŭĦԑ']6••qz]éê|³sG ŻžËĞZ†ÜÏ˘OwlJhâ­ñĞ÷!ÁÀp^‚‘ô.‡‰şż´i]zĜUˆ§ŞuuVĜAŒÔV·)k•‡´iĉLÁĵ^´b¤awXnëö£ĉÓ-Ïúgö=Ğġ–]’g³ ĉ¸ŜŽÇ!êä…‰‡£ ‹\ışulŻXďĴ¸àÜxq+…m[çI­³¸CžvuƒHĥžˆ„ˆ<îCż·GÄğşeß0s+Ż·[Ö ´Ż!#ށÍ/á|äŜĥìk k+œÇ;Y˘óĊidÀNEɘŽ:Aì–ÈŻkÚŝh•êI–z+gÂ&bÓ2§;Ċ¸E’mèìô–Ŝ–™­ĥĈĈ Ÿ—o£;+pÁI™×•UÙİwa<2Öĝ}™-Û>8PŒnüĉŭ­4``T„ô͸ħĈ3áŠ@4òƒ`HĞÇşŞ·áċKĦÚĊ °ŒRE_0ċêĉVHdRUĥú|6Bôƒ˘}ĞÀ†^zîpäk<MŸ¸Ì£ŠVòÒ웚ÑÀ7µ?˜0PçÎŭi‚VK²EşN5½•7ĉÉC˘•^hL"@‡“‡Càp6''‡›Àş_‡×Ïġ2 .!Zġ3ù&¨KNûVÖ´V{-Áa+#ŜcêêAżÌÇxͳĉ´ÛğF}=WB,I~Ċ‰lċš ÔK4­*2$ +%j¤›8'}luÔéħ0~r, Ĝ{k‡@ÈĜ“žòg9&o] IŒÎ—o…!˘ú–´ż¤œ9ïM"ŝ'KGϚ­˘Ÿ_"—QXB˘^úŝ: : ×C„_9Ĵ›èìù’µŒÓÌ wçK‘ħ+żĈPV¤*Íj" Á [§2|,+jżœ³`šûc’Ñ;OĤ£}µ¸\HëNƒÂRÍ^=Í ö!U~6ùÒÖ˙3GF[¸§ÓĝŜ~ü럍wĠNwÓ]/'™[ĜVԖ˜úh&‹8žŻ ŒžĉJÁšgoF„ e¸Î—ß)4ħı'݆(nQt1\=HRAĝÖ%á43ZScf}ÇpğÄ8gĦİFO4>ŬK€™œ–Î/+ğ…‚”²Ûß]Ê*‰ŜXÊ,ZiÄ9üC4ıì—è–>÷â=VÉÉ*ŻĞ†l”›wR:‘Εó +ş|ˆ&D…sÖ²ê*4¨ażĥGħK R.PïRB¨SñĜĈĵAbĥF*p›ŜXoN?^l4hôÔJ•×pħïiRim Ġ`=€Ïw!tÊĊŽˆ&ϵHĦJšÇš6·ÒÑĞŻ+Ħ>FŠ“ĉK²üĥ” ́S†ä„zÁh´ĴĊûÈçĤê˙q#>mo‹NˆúL/da·ŝċ'ïúš!¨eİâÔ³Ĝó é]gŽÁ  N€(”uÉ.×'…\ĦéWÊG݈8*uZxLIMSNGMZVĤïÎëp9 ?âfa•É×Gż(FÏC˜;MïÈŬ‡˜¤ÓÂX˘PŒ R¤—vÂhĵŭŠÂ ‹GÑÒĴI,Ÿ!=6ħf¤)ùŠkPçƒîKZÙWŒ,u7½€$Ôi`ĤĴ2ĴŜr„AIé´6ۚ½UlŞÈŽMĈ…„$Ġ; ß^ ı…ë+µ‡gèÌn`Ĥ.w•cñíġwӔ2‡á¨¤ĵ²Ğd.0'áĞ tĉ^̞ĉ4‡²r­kÁTĠÀ$¨ Ò3'ëħ΅öXÍÂhıÔ᪠ù*yـˆáC\Ÿô­Š4[àŜ÷uPv:u ¸tS=ŭ)˜,<„˘Eó•hû&‹ê)ı ·‡Ĥ9Ĝcù§Üe jœĴäâXžoèí8&ǘÍ0Fi:ĝžħ4÷ıJEB\öĊݵݍ5°–‘ßvÈìˆĞîN²ʤDĈüĦµ”úŝ×;Ž Ż‘Fd~ġÛŻïŜ˙ôòfÑŬÛûŬ|˘ás"ĜQ>mÈSVnDı3Jǧä‘Ĵò·ĤÓï8Bcgsy**ûw$YĊVšä&˘…a(Ŝ%2 â÷ú͊ˆ{o&Ö$_ŒÒ4€CÙżĵz× ,.WYĤÑ­Áêĝȵ^âş8ÉbaÊİ MßĈ=çjν÷mĤĞHS9Ê4ż•ŞYĥ:wÙj€@h“bj6°“éd”8 İ)ÜEıÓéÇ1%£ñdžT²Ġ FݜWQ—işĦ)ĵb…™h#OӄöTÂèüĠRÀŽŜŜÚJZ!GûY.D‰Ŭ‡R]NİOĈWscr†:Ç[$Úbƒi2cÀ2AL6MĤ&K=ÍÖÒx4Ĉ9ì.ŬvÇÓ}U„•‹RÓÏ(ñùx{Câ3­^Ê\C¸‘Ağ²@9ŭ Éı£Î o&Ċd]…Y@:@g!–˙ğœF´ä|.N§ÊÔ +EëL(aPÂÁváȊ˜ôˆ)ZœNï–zµĞ/§,Ħ„@é+ä+³¸Lá†+T+E”V:%Ùk]L1¸Erí1 j)‘Rĝ˜ +²Fd’èoŭĞÓŻD­‚c›ùîÌnmĝ‹ĈY’lËx{Fñc‘§Z‰Ó“Aoïĝ?TX˘ +endstream +endobj +1081 0 obj << +/Type /Page +/Contents 1082 0 R +/Resources 1080 0 R +/MediaBox [0 0 612 792] +/Parent 1084 0 R +>> endobj +1083 0 obj << +/D [1081 0 R /XYZ 72 720 null] +>> endobj +18 0 obj << +/D [1081 0 R /XYZ 72 433.581 null] +>> endobj +1080 0 obj << +/Font << /F8 826 0 R /F16 823 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1087 0 obj << +/Length 2397 +/Filter /FlateDecode +>> +stream +xÚ­YYsÜĈ~çŻ@ċEX a08“'KSqE1MҕD–S.†ğˆ°ÀxĊüúô5X€\YĊÄ/ÜAOÏÑ=_Ÿ ½z> ċ÷ÍŬÙë+•zJE’DŜŬƒ—E^Ĥ ԙwWy?ù*ˆWJE‰Y •6½i×Ĉ.t–ĝo̰ÒÊ?àcZ&~¸½üŝ–‡eğR~%äK$˙|÷ŬëĞÜ+‚"RĠMǨè€ ĜÉ£e>=#rqÍ%àu@°âčÁ°ĤìYyçĝ +,Ğbfۍ›­;¨>]×ĤÑ鴒N‘{`_oJ+7r1@$&H:&úh³[h"eM,qÇ!AĞ ĤτÚü òë*IA5£ oŜÔëzpŠQˆ#‘²ç}™[$ñ„\•ñŞLT…‡péŭàN`KÈ}ò k\ŬŒèŒp[ŝœÌ0Ħè +h…ÖŝĴjû‡-ì\ğ/XÏĊÍ-Ѝ˜™›Ÿ:‚½‡X‘C€öÌ#„èìĜ°Và‹Ħ|Ü.í„ŝ+Kè‹ü•CÛrç~¸¸eTpŸó¨ëy=ı8Ħ zS‡6à‚QJİÓ +N¸,s;”;öûÂp:OÉy!Ǜ@VJH‚aSöÓ<2Ooŝ O`yFî˘&ż3œùÌÎܑğÚÑ|=äùI|ÔŭeĴÉá—ù<€£!{‡0ê|ÏĜĵbœ_%żèWI@…0—EµÀ;“Ġi‰ĥÄS Mm·nÇ +ƒáӅÌ|T|j0ù“1Œ½j\ ~>-ùĠ8gO‹D‚8@°ĈNeg/‰?ÌÜ0"?Yŝ´ { +Ĝq>wŬq1áb&rܑ yçÔ½7ÎÔ²ŠŭÈ^ƒû}dĵ²a&VşD+8%-j>À6@Y` ]‘×êì5á‹7E† F@…×òèĊӕrˆFÒí?íÁÈ&}!‡sqàŜ!u“×2‹Ë™ +T’ÀğŜ”dRÄ|<ŝĦë×ĉ”~$Ï1rF/;ŠÎ‰÷âTŽ1Ìe~p cZz#̚BùP³,”@ĤàŬÚ=ú^Œq@Cx\&“dĜ.‘<çñA‚Ž·ċ<ĉ8Úìäë£Ò1ífÛ  W 1B*$*ƒlfùwÜójÒ6|ŸObeÖ5…$ĥġ2áÓ: {È£X9Žġ`ğžvĈT§ÊßWıö%,{l!|Lħ0™RÉŜˆ;ì—<–2ꃘxb,[÷aêžYÀƒPş—VâÔÉÌĠ—’ÏsN뜣²{=\ÉÑ~VoržħÄTà8’\)Jvé‡êq5ÄkË; nmġ¤\‚ı{[”œ0r ŭÚá +—/ìf(ìҝ½ğ;ûċL8Ħ§°N‹sDEä­wg?ŭzAĜ@ıw eyk6ŜíÙO–§E tŝ[ËCİ e9•‹Ñĵz˲ Èr/΢ ‹DżWĞ"ġÙcƒ‘è߇-IE—oċ]–òè$ěüROd ëâVI’YżT%§4’²LħF$k˙šŠ°PE\(˙oĝȅ*ü’ıÙ/ĞċĊ[ÊÇAż‡\qÄJbĈ‘¨ÊvÁ2ŝµnË$ü× üUtäiôġċiö5}è4È;ÏÒSŒ×ÜíÈĵXÓ°*ÉÀNrOİÓáŬûç=DŜĊŒíJŠí˨àÛq/ôPd]ag* Ê"íż£ü/Ġ8ĵË7_Ví‹u³TmE˜ŭP‹â .¤/tMFt5ĠQ·Ĝ.(]'ˆ”³¸ĝˆİw³<;ŝ-ĵX‚BpA‰úƒb/VQhÚfݐ@Ŭ;$`zÎÂp÷ŠóÀnğÛ´8†+v<ÂÓh0Ûß=?ìwÀŭ¨• ĞYÜşŽ0€àÄvÖ^¤‘K·éÁx@bşˆµ³§;dċܤÂ÷jĤÙ(Hw÷[³’zĊ8˜ş> endobj +1088 0 obj << +/D [1086 0 R /XYZ 72 720 null] +>> endobj +22 0 obj << +/D [1086 0 R /XYZ 72 720 null] +>> endobj +26 0 obj << +/D [1086 0 R /XYZ 72 346.349 null] +>> endobj +1085 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F28 879 0 R /F7 1089 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1092 0 obj << +/Length 2329 +/Filter /FlateDecode +>> +stream +xÚ­Z[sÛ6~÷ŻL–nW0î ú–ÄN§i’µíl²y %Ĝĉ,%ş$UÇŭġ{.´hˊéòE"A<ßwîéìjFg?ĝ˙ǃ:c3g†Y’S6[Ĵ|³%Œ˙:£DĜ|vëïZ̈́V„[ÇĠììà_ž§†hİ÷=w2b•Šż9?8zÇó™%Vs=;żœCĴÉAF¸³óċìKöîäġĦĠÙù§Ó“9cR³ìíÇ£ßç"—'9ÙçÓg8(2FL<ÁŻçżœœoI+…ñ8Ĉ‹üħ”ĉĊŒi‹ĊXĈvĤmNrcaÇeP!DvċüÌÖî[ZÔëĥ\<9ä&ğ.šbÑıĉpΕáÙûúphQ"ûÏ!PíÚ§‰dHD.ˆf +"rM,—ˆ“Ĥİ›ùe"Ĝr}Èó €V@ÜâiĵV_ž–‡,CŝÀ€2 Lr-!&‘ħŸÑˆ†„FDÎ˙!\H3˜IÂP´Œb½ h/6˙L¸Ĉ-êM”ë›M²•˘ŞöĦ-ĉ²DòIÔĦ,ŞŭmôÜÔĠü4àhQPíÍ yžĠM‡ş×ċ\ĉ‚=Rñ{ˆ^Bô0| +ôŠŞ˘Ž_oş:€^–í˙‚zWĠW@ċÉĞѽƒW#3^Ikžáç£eBŠ(6‰Â…%ŒĈ ñ;ŞŞhÖàß,ğ +Wm‹ĞäÜë0X<âFôÜpİöQsĉ*ŞĊ8ÉÓ쌆7d‡ ˘ô$Á a2ùÓ³ÓFż—ßÜò É9c›…Ñ0†,À%Mġ,0E˜6rêşM³~ÄA ĝ‰ Œh­•B€H>ò?Àż²–€COŸ +¨˘òÇĝ{ŭÁ/×F½_ŭߍ…bÏĦ³Sè^aúË{ŬÏ]L Ċzq‡U¤áâ!2ÈÑRAEŒœBÁÊX"xT™‹ŝ&ÔÁ ^‡ġO\Ġ>ï-AFHö’’fĵÜCĜ˘M>‰nµ!fĵŻñ"Ĉòјİŭmînş*9AĦĜ{żYıĈŸ ޳“ġUUĥ×{ŽwˆR2”S UŠHH*!–—•[+×‡ï›Ş@r6Eġ2şyŻŝ­lèğ˘ĝñ é€t5Rİ£òYlrÊĞâÂÓıÔûôŜ–ÁX„|û96?Zî!lÈvŠ„#ŠF#<Ùğ‡mìĜRSĈ_|ĴäCܐy­žDŬÌ˘ş?n.ŞàÁhûĜäÖM‰ŝnEΞÊ×÷%˞R~ĵÀCĵT:‰³SC”5áÍbhœïòàçTf£Ċ€”–C—1…RUDC& (Ñq‹î:àĵlêUpaŸĊ˜ŻÚ‹vRÇ <ěS2…NĦ­$2I,EŠ?ĴĞğ€41p”Ġv›6JĊc…"Ö9´ r +̆#ĜӘ›JÏ?}Ú +×ŝí½]ÀÈċÙ³X dȃ҄ċv +”%ĈDŬ˙~í\ÀŜ4u(RÒ{·É™|q]:^ì!j)Ħ]˜DûÒè$·ÚÏÍzѕuĴK„Ùêĵۘ°Ŭeë3U\,/=kç–ÈuŬ­A 9œp3‰%Er-áSëbÍşF@à+<¸€"Ŭ„–ĞÖrï0Fĵ}ƒ"ìîî;DŒF2$‚½|à‚ĜhħSÙ/ÇAí—HĊ½­Hżny…qQŞŒAġ£„™Ìa„RŽO-÷6͉“è?Ŝċq˙ìş‡›ÌÚXŬ`Ê3ùž5ĝö`-ìа)v#$zÒ]8!·³á/èg.‰Tù8Ež*ê´+ħ?c‚qö´£îƒ7Z!<ĦU˜BÂhBíM&tBѧñ>t£Ċ˘Ó”(9‰ò´$LDċ›ô[+R‰`–ŝT+q÷n ),³Ïëç û²MÛWŒ5ö ÀŭÎç_…{Ŝ×ħrL›ĵ½(íĉ~×/v™ OwíZ—JPw´˙L—êÍU„ĥ›§E‹”l ï‡WUi1.AĜzS{×vnĠz0GÁQ{€M`ĝ+׌h̔lêĞĤÀŜĜ¨ìl³ZaéOĥ.|ò‹|~ÚÁg0+WPÜÏJÎ 1ü~^àĉEÜwa·R…Àó‡ž˘Š]o[;r—Ë<Û´ŝÀf­ ŭ^ƒŠÁ+Ċ>lŻ‘,ÇŬ +•w´ċ{a^„ Ŭ`A½^ ++düïË8²*ü=›ôÜóñkM&wéĦ(ä-J—Rŭ•hŽxí&Pt˙`_Ċ˘ëÍqĞĥ .ŠÀòJïĦĠá÷ LİrhhTf×qaܰ䧞ÔD6`¸q7 ĜR£2Ž ĝ0ùç=ßÂùez?~>óĝ‹MYuó2ÎqüËi8XÔ`aëċO>ÔÑŸ ½ôî5Q,67~&ûeùÓ×/ĊċúënsÙzä<ù£A|CY{Ó{•’ô@v̇ġ"Ĥ]żŠ_oÂIċŠ´_—6­Ħ2Á-ûˆ²êŸËs2E%¸îRëTÄĤşˆËċUÑżòşĈwŜßmkğuÉùÒĞBŬö_I—‹˘ğ˙¤Ä[Pğ3f¸ìÒ\áoË$sëÒ+Ê~ğ:Ċñ€ûÏYŞ'ı Ñ%ç6BD‡,עlq%ه…t$20÷ç–PfÁV-Éó¸ÏĈÔà&(ŝÊQÎ +endstream +endobj +1091 0 obj << +/Type /Page +/Contents 1092 0 R +/Resources 1090 0 R +/MediaBox [0 0 612 792] +/Parent 1084 0 R +>> endobj +1093 0 obj << +/D [1091 0 R /XYZ 72 720 null] +>> endobj +30 0 obj << +/D [1091 0 R /XYZ 72 267.47 null] +>> endobj +34 0 obj << +/D [1091 0 R /XYZ 72 239.727 null] +>> endobj +1090 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F16 823 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1097 0 obj << +/Length 2674 +/Filter /FlateDecode +>> +stream +xÚ­ZYsœH~ׯèËÒV‰˘ŠË/òµ£‰ÏHŽĜġñ€ÔM mËú÷›Y™EC µğ_Ԑuù‘•LJÜĊzá.ŝ}ĉòï˛³‹·Ñ"qà‹›ğEè-Bé +W…‹›tñÑyù°<מtVUıô"ç+ŝÉÌe›WċsԞ“ßѤĵÍĥ ]&ğŬòÜ ,İyĴÄ_×)Ş%ˆïÍ>5‰VI“™”ó€òŞ#ùvyĦäMwÛ´yÛµ?¤ VĴDB·uRyšùşô')şĴĦ)wëÖn’–Dh>U,?ßü +K)bß',È<âĦyyı&Z¨Täĵ÷îÍ_$zuyŭ†„eUo“˘x ğ-b5-ŬŬÂV€Ŭ ¸ĦÓfu–²à[²ji!<·!a³İô{|Jğ`AĠ­74§Û-³£=kU5-+h>!c‚?eì}^8C9iµG#ħӄ댜ĦN`žp‘íĥ·úNr{[g_ó¤Ħá¤ÎhĴk4Ñ ‘u5Ŭ +·Ŭ˘†&¤yó7IÒ:§ç6`ş/óɕşÈh°Lĥ½Üî&-š§ˆċyJçşÚNš} 8ÚŠżÀİgonΜIXá.$”@‡Â Ġbµ=ûĝÙ]¤ ‡ŭ„Š£Ċ½™µ]¨.)×g,WZÄ2>ĥf’n´ÜœVot\C‡l ß È„Ë à˞ë:żeI‰~úÈ +8½¨ß|UY??Šƒç ?çâ0ƒé{ĝXèù‘s³1'K;ŻŜ]üĈmĵÉ\Yo˘)EÖÂÉ÷~I?íĤĥgK;Ĥà0lSĈHHƒÒ €ZȘCxGvP N‡ÑĠ˘'²ĤI& v[üËQ‰Žû ċ(yŠıĥŒHŝI|Âġ„§­Oä`gàGħ}ı^½ûËúD­ÚŞ~ s1’<§‘ğşÚ2„%ûI[‘ Ë +̅$ĤȕÔ°{/˘Ĵ ÀµÊuğyŻù‹ž.?v…q$éî@ù@ĊĦsÉVĵ\0{Üĉë²LĠħwĵ͋ŒfüžP`6rĤ–cCˆ2ú§|Bħ.XFB)IV~r}·äúI* ™/]%u:ġNŸÑ´}’Â)I³_üŻgXÈ@,Ó½ŸÏúLÂ+ ·zûJ(%ŽĤùĤ‘ <Ĉ§Ž *dïHŒwh_ġŜqI|ƒCġŽĦÉ1|kë:ƒ1—mb‹}Íw`™k×ߑҧ€Ċ×êH‚ċŒ +Âaâ)Şô zrù5. ù:o*,S—)…ĦÄm$ßè>͚UïLĞ mıVĦĦ›pŬ!ŬĞrĴ˜ ß!§ùÒñó=çj3œ÷·™Ü²zXd|dĦ›hġ?cq6ĊÔMó•á 2*Ħġ^ìZTs8Tä%O²d‚Vžó?ì +‘µÂĴlBŒUfĞz/ŒHè;eĠÚNJ.nH—†ŬÒ°¤[öğ}ñevĘL§mé—É´zÊxĥ +i7ċ¤Ó!&}"ó¤Pqp“V4Ş›%ÚنĈğĤ#v oF4,Jxì.銖n.}ı8x0ÏŞĝıÖħKKĉ¸ċúĠ+ž`É"ù™ 3´–Cℋxš=ĜSÖo=îÖ<:ü³GIyİڍ¸k^Àœ \N*cF(Sá”I=Ìé"6MÇiżá^GÖ£+‹Ĵiú­›l¨Ê§Ugĥy‡YñĠ(ÇanĴĈÁ6K' ż÷ Q5È\ԙıÔO0Ä šœíbqöÍ@ —ŬnÀQÂ=uLpqHR‚ˆbċĈc‚ÎÊìÒġgf–<ü0~ñŞ{Kü˜”4÷3­Ùސ,ŠEimuŸPÊ4'vÏ%İat×-ÈğüƒÑ}Ċô{Ú4Ѩ"Âŝq˘1p… § 6*Ä'!üzñŞÚîġ)—Û~—nTj9_ĦGöèˏÂHĦô)¸%@ġ§˜[2ŻÒ‡‚żœ_/yxUï ħ^ŸDĞd—· y'xIĠDέ“Á04`C§Í|2xòÙF1Ó1ÌŭİNGGPŞ…ò=À.°'Ş˙ĥħ/Jûo˜]µv.! >ïK~Ëú VrIz[pìğ|OO˘4×Ì1H*MO‚’†:Ñ2 +}büQ޳/]^s¨ž6fĥ:ck<_èlŽ­?ħj •½StGJ†BÚöúcúâ3œÔ@KKÑ@°~A´]Ó&}opgî +ŞU¤³NЉŻŠż°ßŬUEŸÈà³ç–jċħŞŠŞ<ògƒ0Ĉ•ÂNsr]_H[Q½ÜŸĥ+ËlMG.iG}ĉ^efY S?ŠkûNżñuġÙVŽ@ò˘z&ŭ3ŝ3[ à¨ÁIš^/’³MïÇäül>‡ŽIÚïĝÄÜ Y.K•ĥ“-ûÜ<Üm7™ħçáİ·8„1†/BWŸÂĠ½ ĥìíÇä·Böû1u;hÈDƒžbè1]ó‚#`yñ/?(š&Š@ĜFÒ9H"˘ô]çe—íı)f ŝ%+vhÉ^¨§!#¨@ñ‡jÓOIî $¨Aáúġ×$ÛĠèĤkŒğx•l‰Ò5ÓĈß `òm‡,聓’ċTÇ,šÚ²†Ä÷›ĵ˙ŽcšĜì@„{nlÈëċA݃Ïġ;’ı iŝoa‡yr8†Ê@›1Ġ§†$b†ÄĊ†€Ì_ç >Á +#>•.ŝ; y”9İ,Ë÷ÊUŸSZtkϳ Î#wuÖl7psŸbÇG_/P½"i6? —‹ ú`c”½hċQ˜ĠŜvW@#‡.îü'ÒĊ[ċ¸J$˘˜sö‡˙†0½ïĊĊ´[á\.Ä›Ĉġ‚X²Jpû>§A2Eì{ ˵Y™ô``ĝ…n™ArBōƒPî˙p;^1òáĜO‰ĦqA¸3‘Ĥ^ŭ~>Ġ^ß,#ˆà˙1;ˆ" ŸĥUŬ7˘ -l `xϚ&Y[€Î)2îS&iÑ÷M1 iÔFŒŜíÂóbˆ§ñâ܇RTr@•ÁhÄş˙VÒ'á +endstream +endobj +1096 0 obj << +/Type /Page +/Contents 1097 0 R +/Resources 1095 0 R +/MediaBox [0 0 612 792] +/Parent 1084 0 R +>> endobj +1098 0 obj << +/D [1096 0 R /XYZ 72 720 null] +>> endobj +38 0 obj << +/D [1096 0 R /XYZ 72 251.364 null] +>> endobj +1095 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1102 0 obj << +/Length 741 +/Filter /FlateDecode +>> +stream +xÚ­UMoÛ0 ½çWĝ(‹#Yvb_ğ.† -ÖŠĥ;hĥ sĴ@VÚċߏċ$‚v‰(Šä£C£MD£û çíj2[ĤET&ċ<GĞu´H££ ċ‹hUGŻ„%ó„ÇSĈrJ>ëíVtu<ċ'ßT'”‘‡UşëŸĞݳċy,MÓ<ásŽĦ‹.N rˆ§iY’—§ğ‡'wFoŒĜöxۊ8] VżàX—ˆR˘ĵ˙ğûÑżŬŻĴÑjmô%ÛH*À +° äd¤F˙VıKöĦlƒĤ:à÷—FU.ts +K?†’]•Œ%ežc•VC|Vx䀰GÌ„?ûVmWŞm¨İĠe\éë´¨üp²rè]AI<ÍxInƒOOMq~Šù);Uĉ,… 6j°FŭÚJƒ˘† +Íw˜5\vŞ•VşüZxd´ıÖ +ùGlw­t`8Çîqž‘Gĵ#8”Uwa3¤‡¨G²çlÉéˊ¤(SLúò|Oó4'7É +×™yĉS‰}/{äĊqÈ>ÓÔÊÈÊj(ı·ŞUöŒ£~âž^½Eh[TÁ<³Vj½Ñœ(8‰ċû)‡›²ŠŜÛŬŜŽ“œqׇçsċôÑO`ŒÓDɂħ\™óù‚ôŞÛ´2È­èq3€ f•Ë: %9 ÑĦ UA ›€ht’ +ÏğVTrp³•˘î2żF>>/°!ì{§@żéÔú€ŝĥvBh#{;NâžtàD|àc‹9OȇùöğëKgĉôn;²ŒĴ`ĦäZ\‚l 8˙ŸŭƒĜ mUÀĞêáۍŞüwħoŜVŠ[îÖP_ Ŭùô>D {6޽ vO°(!*`hd6 +?î'ÑĞ÷ÈĈFu{='kOV‡E›|ĝ>@ÍÈì‘[š– ee.“´ŝħ#Ğ/ĞÉ_³ôÊu +endstream +endobj +1101 0 obj << +/Type /Page +/Contents 1102 0 R +/Resources 1100 0 R +/MediaBox [0 0 612 792] +/Parent 1084 0 R +/Annots [ 1099 0 R ] +>> endobj +1099 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [335.485 517.8 355.189 529.755] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.11) >> +>> endobj +1103 0 obj << +/D [1101 0 R /XYZ 72 720 null] +>> endobj +42 0 obj << +/D [1101 0 R /XYZ 72 720 null] +>> endobj +1100 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1106 0 obj << +/Length 2708 +/Filter /FlateDecode +>> +stream +xڕYŬoÛÈÏ_!ôtÓüĤxb'ĝKŒÄÀiú°WŠH*ŠÑ3ó›(‡)z/âììììì|ï*XlÁâׁ~Ż^\Ŭ†Ù"Lü8ɢĊz‘G‹< ü Îċâ_^tq†QêŬ^‰gÍpèlñï‡ßn—‹Â/²(UÁâ2Zúy‘`Ñ珯ßĵ¸LÂÀĞz| >Ğv·Żí`1êì6+ğ³ÍE´ô ×màúĤÁ÷ĉŝêw@‘ĝĵ ^ŜÛ×YŽ£ÏŽàEħ÷ñf€MoK>Ÿ$ ŭ"Íp’ŝİìŽÏžÑuÍ£ċˆŭüòúß1§Ëŭ‹Ëċ2ĠB[·Ş·ß„[gj {TMİ&8ìl×t‘mĥĤYÙ„kgP·ÙARdßµÌĉ[Uò²¨ÈEİüm‡­íBQ‘Y&÷>AGî²ĵ%ï'6­ŞÇÚb|Ĵ†í9ÛÜ#‚‹ħµ=Y#ïñ0œ‹³k{ǐŒÒ$çµ>4ĞĦj˘Š“gÌŬóț=1œ1ŜÜ_„žH’³$ 5ugMİ´ö{ĊR0žċb”Ŭî•â RĜŻ6Ìî âLq_ŝv‚µ] Ġ͍lŝġW²iSÚN·Şĉù%Hƒĥ‚Ŝˆ0Nĵ’äoI3ÄĥfT,cK C +ŞšU} ċĝ>Kżˆ +ìó°2ÒvoEĞl*Pç 2ïħĞì§„œÎĝ­"É,ÇÛt­ħ8ı.ÖŽœ<˜ÀNàŝ|İúœlŜ”˜(úT ­ì·éu£STÈÊ/AÓħĉü(šlÙ[($òèÀŝ%*8Ħ½˜‰ ,Òp²ˆ$#ñKÀ³ß×ĠÊ8% yèĤ3ğcuìŞĦj6Ài"eĦçcĝħŬ)Ż [Ûrc§ÂD?‹dÌ8#3íá0Ñ ׳şŸ.B”İ€? ŻtOݧb §Œ²ġ֑İğ´i’{wk`U 6lYĈšµÙUue:Œ‘$˜¤Ç)YÒµÛAĞ– RC’<öȄ%’ċM£ü5;òo¸<ÏádŸ/aœ”š¨Wï˙jÛñêVysïÏ#.I¸GᲙç.µngM£ I:8ȊżèèšVżŒz/­3(*ƒ(^hX9Ê@‹ ƒÏM‹&Ğkë˝9í€Jĝ9–”Ğvûa.ŝCi1&fóu,4\!Ŝ ßLÇlAd94\%Bï֔eĊلój–ş„İkE+ô­[rˆœICœJŬG)(Lí)…@x„]·NĵĠ|M‡İ¸ÊŒAÇeàeċ0İ­´E”|X‚-™Dš˘llz,šĤ^9YDÍ QRqh!™+ +”µ CŽ I/ ™qG·ħè ’dKÛŭ^Óc49‚¨q³3GŸDßKM-´WÓ¨Ù%ҊË?ÎCŸ4ıT’iÂà£ĥÄ,kÍK £Ñ—Ċü_­ %Dqö0a)y‘TŬƒ\­x–fu*c´§]*ân…6DR)ğ†”}Zèn/nܛµe˙Îĝ­ĥ!Ĵ—K¨Z8*ŒDċO’'³É; R%#:1C]ÖxY +\aèÜêÌá,U‚HYÏò*ÍP‡Yëœ&µî,·¸ u„lÀŠƒmT–ö%ÂĦ4ƒ=W6Lş²6WżF“I8%jî(Çü½“A}Ĵu3üJ˘\–VcƒZi(Gb,ƒ9yUÓâ;´ĴÉĥ 1›Ğğ wßMŒéô.‚éWîq Œ‡‹e"Eé‰IÑrî£4K2‘+†ÌKҏ³“Íx‹KçœWÍ4[M4?ô¸„\oIĴ5İj2ä›ʑ4K†ƒƒWÚ…“N&Š#?Ï2’Gäĝû½NîçIáĉùö…dv%Ÿ†éyN;yA4wör W%ĞSÔ]Èc÷ÈM½Èht^0öŒĵ€Z[6Óĉ žf?ó]Wp‰kGìÚĠè44ş7up‚*ŝöîoŜ½úŭ˙Ï{·ÏÜ˙£:H·wÉOû11Ï€ÙèÒVúBHn·Ż5Ëq!ÒÇA½ú™{u<Ċ£‡Êˆo€ô•51vމä +!ĉ·§gĴE.ŸµŸÎáĵŭ'ÏıŞ+nš~‚fݽ•éôéÖ5HëgïÇqt::ğĥŬÙk G4r³—­V.vy†ç°<÷ŝàĈNËgžÄ=Hĝ4× Ï] ȈôD4‡<›ó? Ğɳı\’ĝ5ٖċxıS0!N×FÂö‡½öŬ;†CWI~Kó“2röħ-ħàt4˙·Ş"§˜héŜZ}ÎĴъ-ız +FÎˀ;/îëâG™" z0|êz–ÏğĈH׳Ô÷ÏglÜĠ•aşœô=^&xiï÷JdŸĉE~T´#? ôU.\ž½yxñ_Vİo +endstream +endobj +1105 0 obj << +/Type /Page +/Contents 1106 0 R +/Resources 1104 0 R +/MediaBox [0 0 612 792] +/Parent 1084 0 R +>> endobj +1107 0 obj << +/D [1105 0 R /XYZ 72 720 null] +>> endobj +46 0 obj << +/D [1105 0 R /XYZ 72 720 null] +>> endobj +50 0 obj << +/D [1105 0 R /XYZ 72 550.794 null] +>> endobj +54 0 obj << +/D [1105 0 R /XYZ 72 333.159 null] +>> endobj +1104 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F11 833 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1113 0 obj << +/Length 2979 +/Filter /FlateDecode +>> +stream +xڍËrÛ8òžŻPċŞÖVħȣÄYïĉá²=5µ™ì! eŠTä8Î×ożR1“ÍEl4€F£Ño-gğÙröŝĊR—÷/^_ċ³bQdQ6ğßÎVÑl.Ëx5ğ/gŞŞĉçqM7ƒ½žŸ‡ELhkÛòĴbÔ<ÊeŒ\ÏÏaĜÀï +·3Âm6=ï ³ċ‰/wo?ß JˆšZĈ J½U}ĠŽgüİ–z1?O’ep|âě½Şwş|A·­ÚiĈÔ|š˙÷ŝ_ “ó0\iÊ·çàş8t­ÖƒQŠ“ 4íĞ:ùÖ(ˆ'^ҙƒPx4ŬžĦŽ8„É/wo>şş~Ïè3•éxo ÏS(˘‚yr‚J@܆^ UµƒŞ <ʰ–ïñX™êL#ˆNÖwêa.w„mŭ›–1Nj‚0ËÊÔ;mms`hÄÑÚŬà °2ĴîëÍpx’âKe+x)xì Á—AĞIbı%ùpf1pX Šp4úVX(D•Ŭ!h@ĞëMĠ—~ٟ(yk:Í +šŽÓ ŬO Oµ†…Ex|÷’ÙğÄċJwzÓ‡×ôœÄ9?|­îz[3ĵiH‘:ÛTE>'°5zQÀ!Ĉ6;Ğ-J7-‚‹áÑċÊ HĦĴXÉÁxĜ–MµŜ ½Ĝ§SFVóċkÜßMŬŻTb͚ĥTç+7_’Żà‡#°ğĴ€l7éoĤíèİpt”ë‚ôÓ() N&)ŒEcĠÊ÷pĴôA³ŒÑ†İdRù3Žì„Çĥ_ƒ>2ÜlOnŭ¨ĵI”0%>˘4xsóú?àVá*¸îd•ïÏjlÇ.Dĉğ½êx·xR0ôÉrPêÁ[Dñy·£?ĊY +Ǣš6މ'ġ&ï + eÈs1L@ >:'ŭ-S?˜şmĴĉžĝœ Žlı +.xjA;YRêvcÍQԒ….G!;òòşr8‰P™šü3 Œ,An'îĉœ +èë ó íĞ–=ġG~‘^UgâäÙWĤ(Ĥ ÀèV•U~îÂ9>eEP7ö *†ËF.'ï–Çâv³Á˘C¤ĴdÍà À”yĠ²UY9ö8HëtŬŠcèZí ĤĠ|ɜvĥC—xĝ„ ­>Vj­ +%„Ž1Iĉ0ħĊoW0‰Ç!Žl…Q$tÖ<Äş“ƒîĵĠU{şŜıĠ£ŭ5£Ç2=ajgœG#<¨ËÄ Áвƒn/BX²œÙŬŒÛ÷/f‘.\,BZàÒ-ĜM +ñú*ÌfL3ÂĴ Nˆ“EžĊ|B´ˆáŭB0Í ğ™Çy/ĝàcĴ9£ ëĴY÷ îzd +à9ĝ€qRä£t;òĴ~ )mšÓ9pŭ  0½6_—é²Ġnéo^–[D‹ìGħÉî)ÀÀ:q ‘ż%Шžxò™“Ĉ%dÈİĜÀ‚q÷쐞cÜ!jGqRaAí¤WI°îAHÁ³ Ż+S#£."”†—"ĞĥÌL\ EĴ€z.V@ÍpıOĜÂ1m§:ĦóÈ1zLúë2LqşàœG68İKF +)֝g ŝeâÖC°ˆóH ĉ…=X·%Àó;’_—5ĵÏĊP|[žùĈÉZÑŜ‡ŝĝ’—ùXë“X r°BwÌv(éÒ"ħLf’tµ(GGz4¨>QÎ) ⸅e°œsá-/Ú62ĠŞ­’rP•¨XnÒê²ŻKUo`2 0ñŠ—`Ž,^20d)C´/.KħŽ5`W2 b´žxĦğ*/ĤwAô^^n ĝ“7aéîıRÈpQĠ<ä²+)³ekŸË<ĵM Ž÷Â9O íĠP=HŝMGı èCR²Ñ~*Eb•@Y…‹Ä-ïb]§żÓğ†’SÀJĉġTZöċêúğ[ Ŝ—œqXżııÁ—“Ħ›•R¸í%¤ò‚q…F‹Ŝ|ùÏâÍç<-Ǘnä‰ráà(¤Äa'' X/`6ó‹ÉÛó‚žġ—á%rá%‘òAÙz+ïµVĴxËiĈóÍ뗁Ċ;Ĉ˘ù‘3H-£*wÀ¤LlmˆpĤœE#‡Úòô°ċĦËL˘àË­’äŽÖ4B˜jäjĜ–³BXÒ`ùœ§` r3d”ÎÀG}¨ú‘ħ1÷ ŞIGž-“ü,]eĝˆp/.…É—ÇÌfÈàÎ씛–’$qòĉH.( ïR*·pܓîâs7BĊÑÙ*ËÊL1|7­g'náE(ÓD’ +rüÀË/Ü­°ŸĥN”ègs@EYt&‰ĞwPŻV<°zÓĜR–![éz×í/‰JEËŻĉ6%¤çßô3ŭĠpô˙Ġï‹áúL’zdD:êljÒΆ’Áô¸‡:ldÏCñ7Kx“Ò(˙ìŻ:×.³Ç'ħú0êĠ—ŽÑ‡âCQ†”> Üì•}Ĉ0÷°–ÁíĊÇaJž˙r2WòŭĉŠdŻistħ*YĤDëKĴx¨ı)Uó%ó˜ 7A‡)ÇKž‘]ÂnŽ ƒ¤Ê J‡-9ôı‘Ò-6p½ dz珴Ċb4]q7™/Z­Jâ,vû‘*˘Jcİßc´ĴĦb…ŭ'^!7ƒıZĉxĜ>µ>dAÍp† ¨e,ï’4—ĴvéŜ“0FMÇiWä£`šÁӛĥí9• ³QbÍ_–Í+ıçË-TBP­˜Rç¤HF5ĜĴvŠşmC´_ı@Ĝ ‚œöĤİ(xwËĝQéıd“P9ĠF¤!:÷ĝ§4FQNSÏ˞M% +’[dè4$Ŭtœksœĝb qW˜ÓŬPıŬü§ŠÓX-÷…y—häה•ÒAĉzƒQ—_B VžœëšİWÉ'NtĤ‘ŝ˘ĈıŽ˜[ófµsħĝş81Êr;wÇħ÷L g +ˆ÷­cDk\UiêdäëFŞşQ|^ŽSÌ3‹|â‚&lÑġ^y&$-wÛ 0%{ށ™íİ.§\‚X;ÑéY0ĵ$QÊW.QÊċ=<ŭ+ä/¤ğJˆËk2D€¤È]9gCǸċr<²˜‘ò–żC:ˆe4§rۘĠêĊn:8=ToÙâš[܇UZ„˙Î_Q²’P˙ĉG:Òż=ŒRhpRâĝâm ı2Ż·üġüâ`”ġQjA$I{wf ÈzċhüÇb‘´GúwıoZ¤(½˘È“€T>Ç­µŭ‘ûxÈіżž”óŜ¤!Ôgxpê%|(ŝ qU{èŜL§3ÒçÚt½Ä·œ˙´ÎÈ`ı‡“żšyH½˜sħ!ĊI]0GÚ{~$\ı¤P2ω‹ĉÚ_4=_"ò~<—gĊ=XPے{+Âġ–÷’,OZQT,–aġ”6‘˜KXœ,zw˙âUïib +endstream +endobj +1112 0 obj << +/Type /Page +/Contents 1113 0 R +/Resources 1111 0 R +/MediaBox [0 0 612 792] +/Parent 1115 0 R +/Annots [ 1108 0 R 1109 0 R 1110 0 R ] +>> endobj +1108 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [116.666 542.72 133.879 553.569] +/Subtype /Link +/A << /S /GoTo /D (subsection.A.1) >> +>> endobj +1109 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [230.473 481.941 254.744 493.897] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.E.2.6) >> +>> endobj +1110 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [487.886 422.166 502.608 434.121] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.1) >> +>> endobj +1114 0 obj << +/D [1112 0 R /XYZ 72 720 null] +>> endobj +58 0 obj << +/D [1112 0 R /XYZ 72 529.776 null] +>> endobj +62 0 obj << +/D [1112 0 R /XYZ 72 409.221 null] +>> endobj +66 0 obj << +/D [1112 0 R /XYZ 72 325.639 null] +>> endobj +1111 0 obj << +/Font << /F8 826 0 R /F16 823 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1119 0 obj << +/Length 2525 +/Filter /FlateDecode +>> +stream +xڕÛrÛĥòŬ_ĦĉĊTĈVDPĵ¨ou{Ò6‰Çv§3iÎ,AĈĦC‚qü÷go )›ÍäèAÄ.€ĊŜwùd;™ONĉò½¸;ysYL–³eĤ²ÉŬf’ĞIÏgó$ŸÜ­'˙D_nß}ž'ވüεÓ8ÚîĤ*<âòèÇşa@óşŻóxñŬĴXÛĉg›v½6UùÄĝûé9ü›•Û›ğSw8Laĝ4-’è Ñ˞tpG-tÍŜħSü}i(?SÀÒM[­P5 %ù‘ş3–O53Eµ\ ¨DԑMÄhü$, ‡‘oœÈL(İ]SvİŜó bÏǽìùˆ$ϟqê{ úîööœ#œÓ—Ó’Œè“żp#\aöÇSžXMċà@şmHV‹îpè+5:Ĥʏ,L†Dĝ!UMm+’PĥR˜ppTĞT‘Jħq$ÌwvĤÓ*t4bo%j&ÀÚFo€ÛAeĊS:eŽ(U›,stêBœz9,‚Ktur=BKĴ/ħâ¸FlÌ#q²ìjŒ ŽpT†&ï†Ż^­LÓ’ƒ¤4Áè›Ġ<£Żótîı6şlŝĊŝÛښ+²^°"ÜpüZÊZ#Ù0ñ,ċY——’#œƒ9²y…ƒȷωŒĜh[6ĵ— Öò 5dı™‘ÛŽ›÷~â!gPĉzDş½î²r10fÒÏû‘$(ĉЂuŒÜƒHè$’“œbƒÊƒšw1(“CSÙÉĦ’C‚˘aÑğ·ÜÜŜ1~(! "ü[Gĉċ£ÏĠ”Òß\Ĉل×)ìyaW²˜YÂğÔ,ĥc•FP% ÷ğސA+ Q‚CÚJĥqv…ÑuÙfßß@ş:­Ó\`zĠcZË_ŒĈ‹+kğȈ#eQs#î@ġĜÔ&䋀ë|Ĉĉğ7UÓE@>˘2ìx16îV ó9 Ĉ–^>Jĝĵùí#/áR1"êg1Ċƒ^Âqß‹Ü QÀÁĈa+…Eˆ¸`/ LĞz +ġ–i@qÁш¸Bíğs FbĉÏÒeôN{-+´ïb Ĵ06ñBçŸñz€Ş i`DègœÌı*Ô3FU“‰7Tx`Ú|×ûC‰M¤ZR'„+ŠxÁ"5ƒÍĦ6zŬì UW@ ¸ “•;XވĠSĊ5bˆHjCĦÇ ‡ZĥáÒµŝúħ6HNφ§ƒ +M„r99“3ŞÖ"1ı2Â븖v!KħżĤr½”kJĝTD9µPïúwp›êÔËÂZ´ÁéHH#Wh_Œ)%15dC_ÓŬp‹|Ċ(PíJŽgëä/ÒÌlÌKîP†ú‰Ż•Füœ{kı0†&χ8kŭ/|żş5rġğ5]orAóI½àĉêdòmKf -„N˘ _(FàŞnĥj|è)înKŬĈĊXö‡UD…*’Kùĵ¸äjq];ßKôZvİëmĜE0%HĝR‚Tsp¸rI—™˜ë2L½~ó‘1è‘u#ӎn{Ü⨸oq`L•÷,! Ȏ@;›K+sîa­I*ñŸħ,îÂAZŠŽ¸·2 tR`ôÊ}}_Ĥ1ÚxlċÎ ùÙ³ëŝpÄôi8ïàU[ï<x'$ ú@o$€“ mĦ#`YWȀ´‡Èĵoŭ³ĞlŸT*çƒŝ¤[,£˘ĥ*ıĠE›îdEçJ,çM°q:o(x`êŞtM£ë'ÑÚÀs\Eħ´[CŠä yO1lİ\½—ŜNĊüX§ ĝÓFlŝöú&}F˘ŠMmÜġù%+?~Z;ĥˆ” rşžbÍŸzĈWÜ‗g¤Û4íŜĵ ÎŻxĜµr£³wwƒúëŭƒ[ûÍb~ߎ‰Ŭ ùŸoÚRŜÈ ü|³Ùbëû3餐triɃ!›ünA0ŝè¨ ]³Ğŭ0³5¤ÏžÓBâCÊ é†@ɏ#PêÉACŠ—½ÁR|ù•Óe4ŽN™ˆÙ!ÀŜ ƒÏ>Q—ÔàËÜàÑÏ"pa,é 6 ¨?Pĝvŭ–w$ğ[dĤöŒgÒğF’ĊÜC´WıxCžŸa>Q&a:âÂGАep^•Ï#BÍïÂĝfTÓɓ<ÂÔëqâá'ˆKÀŭ_ttÛ{è’Zòt”È[GÛ=ż$ħħRÏXKÌTĵ86Èk^‰Ê +Ô?Ù_ŬRğ^ìżĵ“ĝé9QÀĉÂòdħÓühÍûğ“˙*ĜÇ +endstream +endobj +1118 0 obj << +/Type /Page +/Contents 1119 0 R +/Resources 1117 0 R +/MediaBox [0 0 612 792] +/Parent 1115 0 R +/Annots [ 1116 0 R ] +>> endobj +1116 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [218.257 429.693 232.98 440.541] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.3) >> +>> endobj +1120 0 obj << +/D [1118 0 R /XYZ 72 720 null] +>> endobj +70 0 obj << +/D [1118 0 R /XYZ 72 538.687 null] +>> endobj +74 0 obj << +/D [1118 0 R /XYZ 72 416.748 null] +>> endobj +78 0 obj << +/D [1118 0 R /XYZ 72 308.702 null] +>> endobj +1121 0 obj << +/D [1118 0 R /XYZ 72 225.556 null] +>> endobj +1122 0 obj << +/D [1118 0 R /XYZ 72 207.568 null] +>> endobj +1123 0 obj << +/D [1118 0 R /XYZ 72 185.705 null] +>> endobj +1124 0 obj << +/D [1118 0 R /XYZ 72 167.717 null] +>> endobj +1125 0 obj << +/D [1118 0 R /XYZ 72 147.792 null] +>> endobj +1117 0 obj << +/Font << /F8 826 0 R /F16 823 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1134 0 obj << +/Length 2834 +/Filter /FlateDecode +>> +stream +xÚYKsܸëW0§UYÁ7ZÛrœJlEšÔVÙÙEBTĝ˜%9–ġïÓ/˜­ŬM.C ğ4€~| ĵG/>œòŭy{vy{…_¤aêmĵ,ô2ĝA”yÛÚûşÙîô¨Ï/â$ߔUÇÛĊĤ*÷ċ½iÌıÚLF ħ6˙T¤ú–[Ó·sô2WÓpc?èoĤ?ŒÜûùŬç;n zߔ•nuw ÀW›7ÀʋéŞĉP›î‘%żÜ ŸÛ×f§7çżn˙ğğPÊ/’„÷ñċŽĤŽ +µ%Fc;œ÷„íĥĞYèŝü:"5ê‰İSτ[]ÖLùÜ5ÏLëĤ ïò—ó<Ú fÒL3,‡Ûĥ:|;_Vh{ZŻÖ#ì$UĊĉNW}WŽƒÔÑR9’<2™xuÛeGz›„?Î w…Ŭ#om™úşÉ=>‹.+œkÇ=>TÔE%¸ÍyOtIȞvúhN€id"ZÍ]Ž“–é—=rì #ZAßjwIy2`e‡ií ô÷=-ڏĴNÈ=Àİ-s@‡n ıÜ­Í Ğİž™JJYŸtWëš{Ĵ&š_”€ùutjp÷p‘²fÔO;žĉpߘJFÒĠ Şd‘ÊAËâƒ.§yMávŭ–Íږ—Iâ`ó´Ó·žqŝÀžM˙ĝHSCÛ°ğġÜ[ƒĈğÁ°µ^ŝk¤ Ú¨4’…Ìl<ú™[ƒMĈĊàL2ı{ĵ¨N'*Ìî íĥìÌŝ”“éğ£}ĤĵÏ1ˆPE›‡CW‘(ġè˜˘ĜÙ5ŸÎ :MÍ]k ‰?/ûEX7.GRFÁqOҚvċěÁûÍä~1ß/´eCĦ{żHd`óĜñÁ+ˆƒĤ-C.K oŜ^•véyÖĤ/ehıߢlœĉꇲ—+&·c&ƒ`әŭ ĥèxsEĉ0év?‰óâjs ƒ ŽĤ‹ĵ¤y@†“WóHĵâ5wër*yĴcü +\š½TáÁ ˙a!tuĤ pÑċ dôŭz0€K~šÚY ·§ÜpG›kt^R8ĴFf|hĤí8KX)͜ñ.dĊÄ: ġÌĈĈp3n8>FÒ2‡ëif­V4‘#JŬĝÚĝJè‚Ql@ÀËYżuà'Ê5ÊD-w–‹ ŭ˘Îa Ġ ×sKÄıÈZĉ8‚Äşt˘f[9pŬ[+2Hy˘ä>ëg +vx£ÇÛgŜW +ŭ܏IÄbb’ ̔ƒĥŠŻŸ…Éé/ŻCX³ ÂuäSâ€{ċàœŸhĝÉè0ñ£4âávHì€ l âwNì´şì,ŝv„ó`‰Ú%LA–èŝÙ:4=! q ? 礅sl6$"œ‹1@!ġ^€ĥçˆ3îYÇA)°AI’€dpágHù­ävx úÀ:L6âêÓì 8À}:ĈĞ?t5Z8Àvg„=#&ÉV!#ħ#‚šd,‰şoo.˙Á”EÓ0*ÈHêa!bÖúĦ„(!)Ȃh·^h[µÈ²İ˘mbݘeZ,vŠ]ŜœGĦ8ób™Ĉù’ÀB_ làÁ@RżkĥWä‚Í—·7·ÑÁ‰îŸŒ£.‡ +MlÇŭ=­â!sJɎžœ2Myo:ùʑaC R§)L3İĥö‹ŠÙġì`ĴI^Ħd†%Â`ì#ËP™²rħ˜Èq}Ñ úÜfğ–-w¤+ġŠİŭ$ÔŞo[V :rjĵ{èİ!dĴÄAìänp˜qİPĦ¸ˆÁ5êğݘ"Ç­Ž÷@!Rh#rĴ˘ĠˆÌœ²éİÈR6tMŒ i6…ü*–Ü…9(ç\!Ä5d0?"k.'5è=è˘0CL 3ÀÓßËJĈteĞ}^ç=ÜŻħ!XGÙħEZÙµd[=täċŭl!ÈF‹-iÉıŻż›QôÈ X`âTRĦ[!.Şmfĥ äĈI™K—’ÏIÉ wċTĤ•ĠëhÇĤż§rce×µÑçpÂfòíĴΘ '*ÓhQ }ı{ûùÓġÇ>w·Ô á¨=3şyà6ЍE5¤’‘—×4ö 2GƒÉ.ùċ‘Ĝŝl˙Ê$Fû<ÁŞ}'ÁH)`ŽZ`,ŻB ħ_œ œKĦÇħÀ’(ŝ°Ö} I°.™|]œƒL‘’ĊÑQ„­[ĉTb7ìĴ)[ĈÇKs‰Ó’Âqĉ,ú:Ëĉ AÌıQ`Ìy +8Œ)‘xÁ"gYñ`žh€VLÏ.bŽ'Î7ïP S²Q“daÓ=gŸÈĜBĜi„ш:qQżî¤Öê—ĠTÌŞ9P ĜB…Š›°“ÀC÷#ĉu[NÓ` š ÄǍAâçJž€Rġl†^ĉ™ÏÚ¤?M L€ÒZ4@úân¨=ŝ°PżGƒY}Üq ËxsmĊÎ)ÇX´üv0 áĜâ¨Ĝ}! ˜‚w +ƒ¸`oŭÜ!ûy)ĈIN$GâŬŒäNf_üuÛËawµùŝŠ+èû[W û8ŝşŸŻŬnBöë?‚ùġ/è*Ğu,:,‚9L#Ë[Ĝŭ1Ĝ +£ÌϲV=ıÇ0 H–<€ĴvÜĊ”ŠBUÓCH~frĠpßòĉĠĠT£ş“5K ĴB 9qóc*ÓlˆdÇħ5#j0Ü1ÍÌ]ì +<~ûĜˆsßpĝ€4:ò0Î$[U34§Ê)‰–zĝz(G¨Ié1XŜs4KíÌn=‚ö€tWÛKùèômˆŸ@×ïċ\Ázñ á³ï…ĵ;?ş@όÀO…€EòyH˜9ÛjÂ9`×ì÷ŭöì7ñċİ$ñ"ôÀ|•†^Ġž}ŭ5j`Â9ĝQ‘{O$ÚzQ üXnĵğ³žL˘§ÒÀ/ŠäµI/GKÎeŽ`í•x*óC•Ädîiâ牳O&Ĉ/ç +àîĠí§Ÿ>ĵô D4ĉ"„kT9ùˆy,Yò4éÄàËw—Èğ +ĉ7hî>ácĵÈÖÌèd?‰œ$#gÖnfාŒŠñ#ñ{s|ßĉ­cÛȳEĤNÇ\ûb=œ€DŠïϽHb³äë<à=ñżħó”ĵ˘àĦ³¸Xjà[ŜûùߊüċĞ/>Ësċ„l)œçŭÜÁ))”ÏR„ƒL)Ûĵħ˘ĜIĝ ² wÊ(¨Ġs$,Ñ%w Ü}¨NŬw?ML'ÀTÎo$@9BĴ(MǝË_=+Xƒ\ä%ŝà3:Ÿox–ëÏĝw{kóÈħëÇIê'Añ?xíˁsdEúgÂızxòïĦŠ8yì&ÒµgŠâùóƒExü`–CUèG‘²9T,- +ž{ ëTéĊİJG†Àì£÷yp+0gŬNgŽM8³Š&'a‡x +2ħJÜż°S|½âĉR0coY™aÖép<ı…™/ ‡ğ ¨ITa ĉ˜¤L³dÄ9˜âŸƒD›ċgĊ+ĝ€ÈÄKîşè3$àßÛIÂtàZ2µĊĦ˜hmÉĊÇċâ:aXĝ*Ë%~H˘ Ġ‘8ŸA +endstream +endobj +1133 0 obj << +/Type /Page +/Contents 1134 0 R +/Resources 1132 0 R +/MediaBox [0 0 612 792] +/Parent 1115 0 R +/Annots [ 1126 0 R 1127 0 R 1128 0 R 1129 0 R 1130 0 R ] +>> endobj +1126 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [463.985 591.98 486.456 603.935] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.4) >> +>> endobj +1127 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [125.854 379.873 140.576 391.828] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.9) >> +>> endobj +1128 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [202.234 379.873 209.208 391.828] +/Subtype /Link +/A << /S /GoTo /D (section.4) >> +>> endobj +1129 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [477.893 337.033 486.665 348.989] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1130 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [243.528 162.988 258.25 174.943] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.3) >> +>> endobj +1135 0 obj << +/D [1133 0 R /XYZ 72 720 null] +>> endobj +82 0 obj << +/D [1133 0 R /XYZ 72 569.571 null] +>> endobj +86 0 obj << +/D [1133 0 R /XYZ 72 487.428 null] +>> endobj +90 0 obj << +/D [1133 0 R /XYZ 72 312.134 null] +>> endobj +94 0 obj << +/D [1133 0 R /XYZ 72 146.656 null] +>> endobj +1132 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F15 1136 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1141 0 obj << +/Length 3216 +/Filter /FlateDecode +>> +stream +xڝZYsܸ~ׯ˜·pRĞ1 ‚×£ĵĥ'YÛħ”rĠ:û@ 1#”yhyXÒżO_ 1#ĈIöi€F£qu}pÂÍqnŜ]„òûúöâĠu)vEŞÒÍía“İM…ğ0Î6·ĠĉkċŜÖf{İ“4ïíÀ­ĤÜŞ$âL‚Jvq³7Mg ?)N¸˙HOOÁm[Âóà³-{ŬÛêˆï‡żĜ‘ßÏÔ5—­Ìyczóiżì˙6['Œà{ ùS=ŭùßñ.‰7`uÏhpkÍOœDÑ"tQ}yèğc_6pU„ĝÚ¤³ĜFWEúrĜĊÇJmäġwheÏĜ™<2‘{Sr ›£Êaƒî³l¤W‚]é8 n Ĥhv]“n=J6›MùN)ËFÓÎğ¨¸ċôpĠl’ìŽ;4(Ĉ‡ÍPŻ£ĤĈa×2²`ÏÇHçüDçëg="ƒŞ<èj×÷†²dÂfĈŭ•.J +²éqÂȘ…$‡)ïğáT"Óù1hs0ħg~ +Oħzĝ2 ġİz$ÉĞ$`W<†û„ÑVS-`fBOĝ-_=Z‚IhŬّ‡Š ĝBŒƒŒƒfíĵÚŒ#ڊïŽökd:Á5Îo £pFĤ^=°[0meŸ~;ÀúörÜm|[F½œ—YşÀî>Çħ·wÓh†Ŭ|çùPKıħ-j”ġ‚3a²8:hïɝ†(Ñ[¸7 ÏOĥebe ïûĊ7 г +°ƒ¸‹ NŜ–„ /@ê£Ä@ô\3 ÈŜoGÚßQ0ĥżP5QÌ4UȨfċ:kQĉ(µm,+’Ñœî˖;žNS¤ññuü…Áƒ\¨˜Ş[p6”s_,˘Ĵo“DÀl,Fèg(ŝҙ(KVÑvê%,P#.µŠ bè‡ñ'D—\ŜXöığP ĜN°mċ·ä­à.m]’1™ÚŠ`šżyóñFĝeı,r< 5~½ĈÓÀ'wm%XA•˜ĵ…eüMħX ż(҉üpĤĤ·šsŒĜ.ùg6$‰É`… ~Y#ħĠ—˘AY¨EB|•Ì…d!Y7ĤÁÜ?>’ÈmĴy¸ŝ·Eó1ü ûûĤlĊ`öÊÑKôĈ{ËÁ††bLpNY0CŽ;óYE‹k/0( @È3¨ÔĜEìäìÒPVÄĦ}9QEEŻB6_$FÖĵ#çŜskLt„íÁ”½ Ü÷nÇTĴÖ³ûN#QYí“ —Ê{a°%M€­ŽÌ +o:.<ŝ%§§QâŝŒħĜM9Ë Ù`¸p½˜|k#GËTñtuîöùü˘-äC2È  &Îí^ öĤaä1˙~°oÊç‹ĉÁÚ4ĤW” 0ÛrĜ­1V˜u{ħ;R| ^d LĦÌ^%ÎI‚óĜêE)1CçEñ)0Ï)ò‚ùEĴ"÷q"JV‰9ÜoӘ +m˘–k]9ï-^2À¨Ħ ĥXVÎ=,ŝ²KÀ§ ĝn^š+lyŝ*wÉË §û’NŽ‹§pœâ6ĦċÜ&4Émĉîêóù:Ħ5_"¨Mq)†+ŭ™Ä‹è#–èCSvżŠWC†ë™1ОĴÎŝxÇû(œ +“˜ş~2¤ŠBÒҌPşd†ÀÖv"ì'-ŠëÂ7"'O&ıɂ(Nĉ”ü3; ™żNyì öñƒHD^$…‡ž‰İDžXwo•°šS(ôôsSŠÈÜažëR‚[şŝÑ2„‹ó%Żìö.;qšÊİ×/mFU’‹İ÷d‡ĠÁ™ĤçĴéħB\(Áħâ­ŞÏRÖ hgèejIìa)VċX2îryÇ Ĥ&RT`)m +U(µ($?Š·ĦLÖJE$^ż˙û[Xŝ +ĊŜŜ~f"xĥڎ. P˜+v°ğ!Xë9ĜÁ6 +½Â‚K +ë°a˜Ĉĉjzp1*†İsJ̊AôGy÷(À{‚Ht Î8˘şCí…ËĜ!SÓÚÓ\IÔá›jÉIĦ[քT\%N;Vžó` +F8Ÿ°Ĝ£Ÿë4³S]j6ëH"'F‚–&–,ĥĉFzóûd{sbÏ&xeLĵ 6ôTœLώÜ3í;Jµı F@ĝΧn^>ËàxëdX³üĊ‘Mz- ĊËÜ$hì§~ÉŻâ,òcM1D˜˙lkëÊÈßSĥx7”Gva f´œbpż“…Écc>J6 f Îdħ³×SĊÏ +L72cŸŽW7K”²rÜĉi” –´tċm_âk°ÈIV=YòdĦĜ‰w.8ÄÎħîî–*" ÂWċRe· ĵ-U&mcÎ#hİVbÖòóÇ×ïßqχ^Ì~Óŭ½½ĝ]üm´‰’d§ +µ‰£tWDéfß\|ŭ-ÜT0²‹‹|óHĴÍ&£–pSon.ŝq&DÑF%ÑNEêGBÂMšì’P‹Œp­†%›(A‰ĈZ$àù.O"ZHÉl#H³Ż>x˙áŬËòċeĈ4çRÁœ(ç9ïœ08ËÌ$“Ìv›Ĝ ÛÊ|_Ĉ9ÖşžXĉ,"KȤ~3 ŞŭE9 ÌĠvĤ°á ²4òÓSú$Á­ÈS?ŸĴĈFp˘ô:IA‹? Ż/ e„Qü˙)ı:ûR@Uu-5{-5ûŸğfCtn[z‰œŞPˆ„ >aÎ_DŻ‘³z* +ŝ·Ê›£#QùŒ*ÌĜ_>hùú£ħ–Ñ n† ^ü +lâĤ½b‚ö>+]˘H>Ê'Ë)cx­Ä<Ù;?–Ñ‘“¨‡ò*I7|´. !$N‹àµÌšèË̊Şr$›ë ı{ˆ(NiXTħ]aüOµE*…ÌŝĈúċ#öK7i^×K ŝ§Ġ“Éıĥ‰żòQà| ›˜Q0SeżÛj*ëµpÙ!&¸‰÷ÌKû”3b@ċŞŻ0xŝµÇıÀNœÎŜħ%öĜ‘Â3úı/ûÊñQ’ì ÊOINr*“1,SIŜm³Ş,BœœċĵP"NJ‹ħQ[J(áL%~†=~0ïK³ò‡hB7ĠXYPRTßC9P-Ûs‘(ñ$A›8'ŠI(ÙùÊúşËì½p([‘šGÙRÍͽjîÔöBsq‹?D%Λ Ÿ7 WÉ@k]Äŝ}Nä +=W,ħM67_Ş@˙‰!N÷ t” 9$àÏĠÌ2òŻìÜá“û41ÈÎé™ +ÔjŒÓ·ÙÁC áâ½^NıĤ •Içîğ?´P+N–Ή—ÖlğFC…šH˙ >­µTûž¤ò×[Óîp ş`mU–,ÇÑ4"fQJ7iİĜj—ñ™5q­ÊJúµšžÜRQ†êx²gî Ààïŝôíä‰”|v#²Ğ=AûÊ;œJìMcĜ3ÈmÈ0ߚš‹èç2—Jn‹Ñ'_’ì¸ê™‹“RRxßbÑïN‡è)uÂ˙ß:Úß +endstream +endobj +1140 0 obj << +/Type /Page +/Contents 1141 0 R +/Resources 1139 0 R +/MediaBox [0 0 612 792] +/Parent 1115 0 R +/Annots [ 1131 0 R 1137 0 R 1138 0 R ] +>> endobj +1131 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [463.339 682.64 485.81 694.595] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.4) >> +>> endobj +1137 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [532.224 588.542 540.996 600.497] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1138 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.873 445.578 128.344 454.489] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.4) >> +>> endobj +1142 0 obj << +/D [1140 0 R /XYZ 72 720 null] +>> endobj +98 0 obj << +/D [1140 0 R /XYZ 72 669.696 null] +>> endobj +102 0 obj << +/D [1140 0 R /XYZ 72 236.873 null] +>> endobj +1139 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F15 1136 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1145 0 obj << +/Length 2788 +/Filter /FlateDecode +>> +stream +xڝَ¸ñ}ÂÉËŞnnY '³½é`73Ĝ609Ĝm#KŽŽuz~ĞXĊCġ,’'‘ĊbħXwQáê¸ +W?ĵ ùûn÷ĉífUË<ÎWğވWE¤XíŞĠ?ÑÜěàċĉ.MË`ìeG#ÑIA£ĥoé& +äÍ](tĴ:Ğ_nâ"·*6ÁG¤'[ïŜ‹†˙ +£´İhüq|ĠŜÁkÙÓäµg>u8VĤLġW­:>á˘n›#  .ÀÍúĉßğż€Dî˘h]fŬŭáf“-Oà*òżâ|İñI–ŭxıÜÜÁMÚ^"$ál¤ÉgœHy™,1ĦODµzDGë-˙˘·tµòîiE%‚’ÜÓÔ +'Ş!ş•êä~hğo£û5ÜŻ,‚ŬIġ„"êZŸuíxÚ%Œú~›ÙN=ĥBÚH6‘6’'>€…š`­‰MÀäĥ·ô}ZżždC Ç€ëöHP ˜$ޤGUŒ$ËÄß[ğÂħ6Q1Ĝû85,\|߂ş…jPT Äá¤7–›@ ÑĤ‹ƒĤ4-ÍÀìħ0VCOKzċ‰Ġb3ò³6/ı¤²îË`ëŝé…w:rrĞ~”%›úeéê’âìŝËú¸Ŭŭ™Ìêíû?lß4ĴëIùĦ¤—²'Š­ a^c£$JÒmx˙{ è\Ÿ†N@@†ğAÚäPôp£ú½Ÿĉjš|B&Î\bĊe86dŠI1+(üA·TÈÈN Ĉ äJĴ_vĉ}ž9Ġ4ùOèqĦv<žv§s§ŞĝèĤhpl§>]Ħ ;ĞU8YšïÇÙ2LÀCdVĥ|ëëI‹ĉh—Yx d§ßÒȑ‚|wĈÉ`ċŞ£Y'çĊ–żš³p%EzıS‡.XüÏh +ċ~P:ĥòA;Ğ;·ëe} |Nƒ€ÁÙˆ{;Ì{‹é÷‰GĦ9;šħQ:ŻDC.ÇÑFPSŭƒWêTXё"šÖ 0%żObmYEX:ĞĵIxVg2á^G#ÜÓ2ÉP“LĤġÑRè$ÂÙĞ\gĥ`@§€D蔌 Œ• ¸²jöÒÂAyTûÀÔA˜°ìRAİÎġ2lš*œP˙‚ÔTižúÂ%/ÚjM+Ż4÷K92}ğá:MŒW +8šè•.N´•}Â*ÇñÔ뀨Ĝ\5&{KBú{ûE#ŭ@Â'|AÑ.““pjCHNĜC6emšñġ܏ÏCÍ:Y ôİŝ¤.a] kÑ5Ž@fë ċĞ75ùPœ„²ŽfĜŒŒƒĥ“<›•7çĥ˜Ĥmrc›ğ]à&ËŭuÌHÛÌÂs˙r>›Ò…í4G;UĤ2šFpş@FĴ+Ê$P)à*£MôLÓÂĥnÑ1M*Zs/TNá÷ıSĠQÒĜôŝ…éŭuSl2,pzi—hÀYñ…fÜ ŒƒġaĴiÉ×0Al _12vfa1Á\:›Xm€nAaâSv…‰lN‚PĴ`ÁĤâĥ;#ĈšpÇ +LRŽb€z_DW9GŽ òŸĥ&ùV·&aĝ]tF÷â<ıd³Zßħg÷~:ä2CA3i°qŞ|'ž ˆLx!ÑÚ˘HŸĜŭğ˜,û.ä Dî‰÷ŭ(ggïÑâ£àÌé˙, ?=QġĝÓßü~½ûÛî7KHĠôC7îêvÂeW,ÎtÙrµ‹œÔ(3œËJıîÔġŒÓÁn_èâ†SCÓ ~'ƒ‘„q +²CŽ7żš77ßġÀŒ„½qsIòkLé=²”ĉµĠjĦäjP݀ˣ$xdÈ@ypĝ‚ô”àħ8ŜCOi˘Ğ–(ÎuîŞte 7ċsŜr1HŬo0áĥ­ŞŠĦÔ èä£ÙÛĜœ¸<•µqâDċ:·Ró‚ħ'}”6}í˙Q°=P6àİŒĤ}AˆËĊw˜Ğ:7oğ'ïöÌyÚ]3ßPöż˜ä>oX´›˘ âŻö˘öĞ örq–|òD· _üġú#ĵ˙ŬRĜú¤cPĴË~—•Ĵ°¸t* Eäó;Oŭ³q^İŠZY8 ÷<4 †˜yc£VMtN‚Şà(<Ó +ךà8´gĦ%´Ü{f$âf^šDú¸==À+…œï@k[bKj2: 0@˙mÈ'Î'b4‡ FrmĴĈäġZ B3Gi|á’ŭg9é?˧Ù9Wŭàòìİ™ßëÁäYhI}Ö "ĜxaRĜ¸r—JwôùÖJvhí9?ĵ´‚j‚]O43%|–›d—ċΞ3S'ƒÖò=Û5÷yĥ÷ÂR£ĈšŠ‰ıuâ—Ĝ“ Ù{u1§?û,Klş˘ċY3>X΢·úpÒÍĝAĠ ·Ï´í˙Ä@';h²3ô^yâ7Ó¤ +c„7³YlqàÉԓ06”¨ÒÏ8ö?“·Ċfy\†N=/ah™àβ˘ĵòC+ĉŸUñÔżcû³Ş¤'ŜMN 5’z!§NQ…öéIż2âì Ü çbêjÒh‹RŝS”NhǢ<ÔqwljÒçÂ~z(âEħt)Иxç z‹1WĝġS ?:ÁÊÛIcAKĵÒ|„àßÀ\V$ı•}T˘U,°bœ*1îQ/Ĉı™§D‰İtµ§DÌvCş˜a›{ë?AA`ĝ™&ĥD~Ĥ§t@û€Mc­#‡Jì0žß.zJJ&{żĉtɂ˘x.úÈŝĝ„>ÜżVG·KŽë’ĥĤñŜĈ06– #gLX%Ñǚ ŜëIݳŠrF%4*ċz³Ùcq2Aú~÷ĉW3+a +endstream +endobj +1144 0 obj << +/Type /Page +/Contents 1145 0 R +/Resources 1143 0 R +/MediaBox [0 0 612 792] +/Parent 1115 0 R +>> endobj +1146 0 obj << +/D [1144 0 R /XYZ 72 720 null] +>> endobj +1143 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1150 0 obj << +/Length 2613 +/Filter /FlateDecode +>> +stream +xڝÙr6ò}Bğ/ĦŞ,™—Hqßf&qjĥ2c—íÄU“ìLBkx¨r<ŜŻßÀCĉlRyènô-ġ´òW?żñċûîŝÍċĠ~•m³$LV÷‡UÒÀßúQşş/Vż{o‹şì:]T/ë}ä]Ĵ7qyŬħ´ëM”žŝĤêSyâ€ĥ­ġóQu<ËכÀk›u¸÷:S~ĊŻ.Ñc/›J÷­ŞŜvFuÚáÒpî1Şb€é+·Öµü=´UĠ"Ŝgž?uƒ£½—·5ÂËĤlžÖ˙ı˙70½ ‚mĥÛ1{7¸Ĵş#l"O5bïĤĴÊü_xbĠ*·Aš6a²M“˜ÏÛùžß7;ß÷>Ş/Ä&#³½YnÒħ\à2ƒÇĝAÌlÁUµ@,Áğ£–Í(„‘N#à“i;óô`€_Âñ¸Ŝ CDâaٛgƒ/ڜQŽ‚Éĥ~*‚ ûµ*-£¤'ƒĞJ™7:‡5e^„ô–—ñ6=3#ĵ_ĴÒ +Wżòs‚şœ?Ġ[RĞ| Ĉên~ï­V"•놕÷; ËKF‹ ?€*i‘›ˆœ$ÛZ[>VúB^x¸Ü½×Ŭ‹í´ĵ…ê@ïAÓeİ= Rĝ‰§0èaäġVÔfÎüUY üm>ŠÀ‰Q9E‚jb ˜ŞŻĵòʅĴ7öjÍ6Zĥ éSĥsʚĊ€F‹R¸“W‰%XœP PĉÁNÓikÇĈıóŒĥ}ĠY†—‚êɀÀËvl2gÎb×ĉšZ5ıvd)A–+A šżdì*GúŽvÚx@aúŜs‰DhdghŠzğŜ¤~ìŭĜk$g\$™i:ƒ?/‚DĈ1š}ÑO’ŒÁqħŒ2˘éƒ²c›ï@^Ĉ.GV+#|-ğ¸˘…ˆ´‘ç)%>* +v—Ħ/Q–‡ôŒ‰0†ĞjÍ Âyn^ĝßùVËÚx T4Ÿn÷WĉiĊƒ[2$<n÷ÛèÌ 8Í.Œĵû#P+<”‡5J ä8×Ĥ‹bâ@ÄOċ‘ˆ<&Ĵ¤ħ ·ÏP{R^"ħjú|âV´ß‰]Ĥ3ğ„Y |Ÿt7ì„(œ]Î&’Ĉ£‰L°ÔíÌâöÜ´dí0! T„÷Òĝğ÷€—T¤=ueM=ݘš.Èq\^Ɋ7‡˜ ÀÑ(ŜĈYââDê„;ï§ĉˆ†Y0%k°Eqŭ0½á@%j2O9c¸ÛFI$=hĝÊHħqO‚š +I’íáR/‡9â¤*k +VˆÁùK“œá;ş^ÜÛÒıê܏&ôفç^ +ħ5²gÑ&ˆ%ÁˆCPìĦ²G÷ùîÇë;^g´‹OÒ äℍ€œ“ƒçԆó"ĵ Ŝ1Ĉò4Ğí‹çä^ ‹ĉÌ4s—µXóùd+˜ƒ(6àÈ8 ˆWŝ§Ür`ärK2ğ…½¤ÇïÀÔ'Ŝ×Rñ`0§%‰ şÇÎı‚$$ö>ĤÀiŽ@—zÀÈûÎÀ)Á´(­‚8^ȁÒŭ|÷ŝúÓĠ‡Ÿyĉŝéî#ĉÛ_àùXñ +²×ġİ“ XN³ËhÙĝ µ%o’…³ĝò­ÂçTW³H(/pü ½ ´1­ħ Ĥ‚ÙT† +Ë'UQĴ1ĝ€mq^‚ğD[:¸°ûÔHŠS~:£Aâú9ıĝ¤xò´(ÊÀ5mSÁäeÉ ÷’Dâİo{;M9sum·Ñŭ6 3>::š8ÎżH$ï|˘<”§à`ÛʨiAI O*I*ž˘Ċ!ĞóPş¸+ùá+ö‹CK‰žĊ{0O9 Jâ +[?ŽÈúiôċ[y·Ĵ w†=dÊA”Âk4NAÓAAÌŞ³*„Ô%U÷‚Á(Ë+…Î+/ˆw8Ӈ0‡‘É%Áx¸g¨Ñ#T.pXsÌÂh :HÎ"ijŻŬċ‘ç$*ĜŬġĤ‘£İKöò¤ +.ê€IͅÒêŞeÎŽóĥŻkĴdıċ xA*/ˆ<ìhDŽ–a5ÀOšáB +€™½ĵ Ï)L&Ñ4c‰]áÎ ¤xpĥ×H:‹GCìHĤ$ÀûĤr™jĜ\–"êaVµĈ“FÊ8€Ü  8açŬËĞ0šäpAĵÍâx^\Eéٙiڇ£à´÷j°!4÷.Ì%VQéÙ!Œ~üJçÇR_ÌMU4K½ğŭ l˜œYKàï1pÔZŒ÷fŜžAÖ{ÇÚ¤Ŭ4ävhĥîx$•˜_§ŝoˆŜ^p–ġĠĵO”Kĉ•Nğ3-Ÿwfàı.Ż+‹MJä§çġEàƒ›^Ì­Ŝ@Úésg ŝżHa€{ +$Ŝ%d3V_0ÊwM¸ʝâ[žS”²‡Í+@l·=Uğ==ˆĵĤ47]nùéDVDèQ`ŒĦte¸l““m°Ş(J}YïߓŒ]ËĞrüM’óäw,;~0Óñ!ZâĜċ<0YÁ™ô?|çÉq4ÁA‘O~ı”ó,­óK öóípìĤêR—ËQ ",·q‚!ˆGFŸ*• 9Ô.ş-îgàòËħbÒѐ–˙ĵj­ËC&?xƒxvĤÔÜ$ñŜğÂq+Èóĥ>İ|,Ğ1 ôƒAZd+mGχA +ž]ßü`İɽ—Ĵg!ĥŭIş‰Ĥ;·^X2gúŠÀA*—}NÒgo!/ô‘Z+,0‡ĞXLˆˆ:j’#û‘Ç_ĵâ•-ıÊä׌ÌĠmê³\M ‘Ùı?—M½ËħÊYkóƒàú¨H ġsŝœ ˙Ôğ%V˜;'sRĝ݁+³˙J"¤sq…>äŭ;v(żJ_eç}êkt*HDĦç€wôfèsL÷§ĉAšŭ”żżıċ• +Âż:iAr%9é À°(ġžù˜ŝ>°˙À:"RĜÂ÷§ġö +ı ÜÍJ|Xzw^âGXcœä„Ñ—äÔ§¨*ÛòìKT5> endobj +1147 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [292.573 579.007 315.044 590.962] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.3) >> +>> endobj +1151 0 obj << +/D [1149 0 R /XYZ 72 720 null] +>> endobj +1152 0 obj << +/D [1149 0 R /XYZ 72 686.832 null] +>> endobj +1153 0 obj << +/D [1149 0 R /XYZ 72 665.821 null] +>> endobj +1154 0 obj << +/D [1149 0 R /XYZ 72 646.193 null] +>> endobj +106 0 obj << +/D [1149 0 R /XYZ 72 543.072 null] +>> endobj +110 0 obj << +/D [1149 0 R /XYZ 72 265.317 null] +>> endobj +114 0 obj << +/D [1149 0 R /XYZ 72 158.191 null] +>> endobj +1148 0 obj << +/Font << /F8 826 0 R /F16 823 0 R /F23 825 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1159 0 obj << +/Length 3225 +/Filter /FlateDecode +>> +stream +xڍÛrÛşñ=_ĦÉK¨ÖRxżô-ĥOÒÓišLìLgzÒZ„$LxQA2ŽûġŬ@JĤ3}‘‹ĊXìŝê°òW^ùò}˙êíû|Ul‹4LW÷ûU²ÀßúQĥşŻVxQ­7Q\xwŝçŜ:̽§A°CÇĜ~½ ``ŬŞŻ½2Œj×aĉ ~Xoà×N<UËÄ%#ùA\ËzŬ3;ñšVUÛġ&.|ïn|èĠFE|‡uàĠOë<ò€>‰<…g*+€záßV <=(áÌ7€›í^óŭweğŝ÷ŭß@V› ĜIÂR‘M˜zMY”yz8vÀè]Y׺=̝=LŠ\úĉ'ŝ~lwƒîZĤBÀv6ˆM?à{·xY6 D·ÀZv)§EµBI„ö)Ârö€€Ġr =ôŒxÓ7׌}ÔuÍhĵqĉɢ^ KR!QF‘lĊr7=£ċÎ-ëL|úòĤbEÉPî˙uëvË·EXn˙şğŭtrñá‘O§ZïJaϘĤÄ-žx0”ß×ü\ħ‚FüX')(â†ò èn/Ĥµê‘)Òİ|Ië$6cŬñżŞu£ÛrfM×<ñA ·G6FNŒŞˆÀŬ³ùÁ˘*ġ izïJQٗúsñXDV„ò…yA"ϟ‹hEä³ġ$ò+Çİežq"xDî;sħ£3€IGAi ½ ?òîráŠ5_+é!˙ìz0n•ŠÉú`Pu-A°] .€Y´;™=Mw͙aN£wċĜ ħ½Ĝ´9DŠx+E·ÜôZ|˜&^]Ô0M—iPHpóùíGĈœ› bQlÔÈŞĝšq"Š7=/w>çx‡^ŸI84 $ÜĠŞ”­I;‡>ˆvFġ'D¸ì^ÙEĦlƒ€\ä­>èĦĴñEġÀ{‡TGĈTşjß ĞĤçĜœÑ˘ğĦ˘àk÷Pî%ż?"£ÒTĵb×5'É[zŽ–Žhħbİzá~2ŬÁ”M*$^ß52ÁŞ´p5ëêñjpÑY€ŒêĊ\v6NXÉá4żÎ\óÌäO"zôIäÔaôˆ3GrÚ VVÍTĈ0l:zËJˆŽœPôœÜ Áġƒ(FżïĝÌ <ê‚(Ú/ œ€' +0ŽÜÑİ-¤’ƒ™9ŒÍ)Â%]ïy£>› ?Ùh)ì4{8ö>şĜ€tn"kËĉ9ú7Sö—ĜĜğ9–íaÑŻ½#óŒ~AŸ³q5ÊĜ â#í‘ürĝ‰ŭHÁ   +ŬŻ8Ñ·ïƒtĊç 1·…ÓFñ6O#>m¸ B}&ô”°>Kĵ[°ŭP6'ÖÀ܍§5¸ıÎóeà&ÛÈòĵîK„ynß&Ì1ïÔ­ àŞŠçĝ䈲‘ħ˜ÏêC =9L޳ó!mOç” ²şcZôô[FŬSVƒHŝ‡ÌÛöM}Tġ Î"4‹I/ŠɄà£LI>ĝ;)pż#_01ߚĠħä€Öx~cÄìĠ ŭ=£AŬ:T˙GÚ·™/8Iĥ9]£˙Éêq!f„É<#\¸=…O| ŝ›Ŝ͐éhiܑ7Ñá•<à,d„…èvW•<&Ĵ„Àµƒ:J^e4V6zŠ*,Y„ŜMâ;Òe’Ħ˘Ö”ĠtÇ´ê’—ÛUÔ)³J·”sb4bŠp>ÄŜQğè‹Ó½$üîâb°ĥ"@íbŠÎÊV˙WY›n$=\H{Ĥp ›5ċOŬˆBŸ¨Ÿ6RcNΉQ“Ù²/tö‡`k#%Œi1ıώe÷Ċ§5…yNސBİY­¤sE•‚mv +äcşÍR*ĝCWÈ7D÷óénSи—ŞĊoOÚuá´9ĠŞq™#˘ħ +‰ĝi¨¨Áəżĵì TRxÊZ–Z˙KàĈÈ}v2J˙qêÌÇòÇö)wS?wê4xWsjàà*£9)|‡éG4d6x„á„[†ĥµvV c:ŭ•À"wdÎûÙó´ĵĞdY& Ħ™ğÑĈžb9ĦĥAá{µÚ ‘r”œVːσ˙™„p¤$Atkʝf‹¤Âò½kİ|ŻQ y +Ŝä`5 ­ öÉämySĝ—ŽÔÄzÓĊۑ @'r~LŒ êç L zá +’böĤHS>ÔƒÓRÈr…Äıú\– ˘ïQ6=çé6xN4ż°É…û9­èCIlEJt„ŻşâĵïÜ6x!eñÉÒ a†=hn¸âŸ>³ŝïÁù3òò’h²˙(4Ëú¨ÀyÙz•4ŝé‘ıGÇe<¸Uv‹H$ÁP*YˆĈ9ŭ’šûĵZ¸!î"ëvDÒİĠ„èĈ5z4xnS>˘mÂÀwŠ{+kĵĤµƒ`û‚àS@iak*ZÁHµÄTXç…%™Q&™+°şSœ´ÂQ^pe+|xµúƒD[*h]UÒ'Ì-R€Hي)Ó)že:·‰–bó3'ı’k¤lj!–Rnf"k~³rùšHÖ((ô™gÏxúŠĦ)Œqµĝ,²ħ'š"I$Eğ’OÄßSò SG]UX›!ĵ7]w `êSĴmÎ>ÂP$ħşâŜSŻÎ}K”A¨žÈÏ,™çlrĈÓRòçUP' óg•Ïë4œ·ĠO‰š€ˆ”:ˆÙĥá˘Hò}/mSĜDŽw u|ëĴüفxHqç CW N†àû³†˜ï2Èv%éŬÄZŽϏÀ£éˆóú_ïżxu×.Ž3˜GċĜƒÂžá‰óĥb –m+6ƒsUJˆ]G!µí˙lĉó3ëëeğž)YÀJÈíĝĠ`àB:ı8•†‚‹:köÒ#Ls.uÓÂĥNrT+)öp„]¸ħµ9Q_ÖŻ™ïÂÑ6J˘ĠfF†7× NmÖYŭıMs› ³ı&Î4RäInʟ²\ +ÜÌÖ˲’7şÛX)mÂR€\V¨µ¤eÔ÷üİ’9öŝ‰Mñ´jwŬhè›Tdm²’Ké³ÖE´Ôş 4›ŭ˜…ĴàĦۊşŒ#,?LÙî‚ËÂQ{ċZ #·c‘Ù8U˙0Ù/‡c°aóC,=rĠUìÍċÎt½À–Ĉ/!ŬÉv"og@ÏYeŞù‡E;?¨Zro Ġĥ’zFÇ€Z?˜Ò<Í·äĝ˙ìFÒ5ü2ĥ.ĵħOxÓµÈê0—˘ü²U8Ż_CÈ/!ñĴ)qÇ'·uŞË{ş‹ï*\¤˜+4ŽŸ¨“1ò€J.äŜJ† (MsÂ6ĴDO<ÚĞrà!Ċˆ„ÚÚO}`ûċé5dòKŸ„ÙĞ˘#ıùô÷żà‘äYh vI@ğĉÓĝĠ€éK $ˆčÄSZ +´ˆçÚ9j·™Ò™<ħ/û£4SŽéŽSJYJ„şiJŝf"†’NŬ‰ĊĴsŝƒ˘‡Àèĵ c°û ™…Ċxֈı_×Hg›Òa6 8›Ġà~gôiè_nšıç£ŝœäChKR›™Nzè6.ψ²öżœ‡Ì0,ĥ~P€1DÛĜĊ’3˘ßî_ŭpĠG +endstream +endobj +1158 0 obj << +/Type /Page +/Contents 1159 0 R +/Resources 1157 0 R +/MediaBox [0 0 612 792] +/Parent 1161 0 R +/Annots [ 1155 0 R 1156 0 R ] +>> endobj +1155 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [351.55 350.988 366.272 361.836] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.2) >> +>> endobj +1156 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [372.374 260.328 381.562 271.176] +/Subtype /Link +/A << /S /GoTo /D (appendix.C) >> +>> endobj +1160 0 obj << +/D [1158 0 R /XYZ 72 720 null] +>> endobj +118 0 obj << +/D [1158 0 R /XYZ 72 536.75 null] +>> endobj +122 0 obj << +/D [1158 0 R /XYZ 72 192.589 null] +>> endobj +1157 0 obj << +/Font << /F8 826 0 R /F16 823 0 R /F7 1089 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1166 0 obj << +/Length 2790 +/Filter /FlateDecode +>> +stream +xÚµZKsÛ8ûWèŞ*˘ ı·Ĝ޳ÙZO²ĥ3ÙJv4 É,S¤’qòï§_(YòĴĤœşÑ_£ğрäMoòîÄÛùžŬžœ^úÁ$s³Ĝ'·óIğYNċı^LnËÉWçžJĤÜŝkÍvz™ŽX°ĉ~îêŞ˜Î‚ @°ÖĜe;ù‰SjwGÒÖê3–5S |£W˙Ôi^şó²y}ŭ£×ĤÉkî­òŝŝ˙×#ŝV˜úİ‹ryQŽî:î“-R°…5S䕕ÑEߚŸ˘aġق0AŭRuotÏëŽġE‹`kOß…àeÚµÎËÓÏÓ4pLĠë1CèyɽMŭsš†Î/u‚KÔ$ïúŝ²~YuĴğÑuğXTÍâ—-3BN+˙Ž Íĉ~7t}^5żTËŞ–})ó^z˕…>™ùĦ›y |7Ëfĝrsñáĵ4Jœĵî_£ÔİàlEzƒƒFw+rĉĥ);žĠ·¨³0ùr‹Y~ò0oċ5ä<ğ††Ì¸Çs †4déT9-ï6´=Ò­K@sèÀ{¸É›‰ Í×Tß+ŻÔ]aŞ;Z²8ÚÍ1HîG†ĥÔĉ•H¸Z›52ú}Eìt~WïEĠéU4&›€“ÍéŠ'<Çǎ t=•1‡ïŞ,İüÈùšĦْÈıİM… ¤5™ÉopÏB/5}§ïXŝ8ĝ@şıAĜ4Q†bçÂL•S}G‡B7˜ŝ)e M!ğ Ô ÁĴÏí˘5p:àF÷ÀÜħ ²ŽŜ !-'dòT$O…Ħó§WLÉúr vwyĝŞt ÔĠz :™ßu’’xıÏÔ¨}Ġ°†ĴÒ藓HİĤ$ƒÑŞZ5V5·wÍ€xú#k‡Z˜({óˆĜ2›žçC-kJ˘r5gJ5ċŭ³ÂòŽ;x h۽𤨝$˘64Hmn–UÙĵêBšÂn“¤ìÖŻx†:‡°j)Cçlß +ĜÙRëáÈ0GybR˜1ÚߎG;ŭ}Ê[3Ħ@DzÉ sÓ.Ÿ{àú>xAYâ\ä›ĥž½ċAJMmZŝÖ-ˆ6Üä~ÓëRdÜŜ[–•Ħ“óBTüı˘rPÏZSAA³§M€9óvŞYğ;[yÙĦFJ M£ħÉİlŠ)·ŒĦÊAÙ†]ù×iM-@ ç×èv·ŻÖ•K,<š|Ċ­" +›Hİ-+}b–JbE|1vş|İmĝHޏŝëòĜ­^˘Y„áROîÜç"Yr¨–pŜ50ù~Ï ŒJ°áŽŒŬBȋV]=˙pï,§ŝ­òBHxä‹óJQĝŽf/ƒÍiéÀ1†ž‚E8ä,7°˘6hżĜ·£AĥYŻÉËä"Ùä hd4pÖež€›œ%7´J.³) Û´B7úÛPaɀ¸ +°’Œ(„G6ç,ôşA@S/êgŒ×֔7}Žâ ĥgX·ĞMÑ.—t”5xšËêT?{7&„…<ç‹0@aĤ÷tZÖ°›MÚX‚ò^‰ aVµTË<§‹—Ót³„öì­u@C¨Ô:_Ïéj(ĵoBŬp’QxR@öÔÜŜM’a \ŽàÂÌ1\…E׏râ@ƒ÷žZxĈŜ7ĞAê µ§ò܃LqÌù™Tî™=ˆħĠP†Íví„C Šï|[ÈĜ)“Ĥ˜I‘‚éżTpÎ$zQÈ͒{gü€Ôö#…„×ŜZşG×  ŬɕÛä +.·?5›3Ö` Mš½­OCŻk:lŻ£UĊ£˜€ähê|Ëëšc³ŝ²úAfA–9ìÉhrBıĉÀ$ÓİÄ".ŠĦ + t#€Żœd‘ˆ/xĝDĈŬíaLŜŸ èrĊowtĵR b—7ċá gĤ*ı,âU%'Şċımyê€Zğë9 +ŸK|ŸÛ\ݰܛoÑ°Š 5ú‘+GžoñáÀ½\yŻqpÙĠZL^RrÇ&‚ÁŻġä  + ‰xÎĵ#a§Ğ~pnd¸‚ SYñ“ċҋÁJ5{M­á£3ĜĊfûR&hpj°d5CŻ!²I°ú?èaáííÉ7yP“ÄŸĝQäŞ(˓Żx“谂déä‘f-'~şA”@ğžÜœüg‡? \Ï ž÷ä.-ìôŽ<'‰›%)HŠŬ(=Ëmî6 È`+87)9ZŸ—ŞËJžíBˆ5~ĥ œ·‹J&ŝNî@ïhOŒ(àdہr½0} CĦÑ!K„‘Xbŭ+fÀç)ˆpñ„’œħ/Ğ›WäÖÊ\/{?}7N:B˜<çtÄcËILż¸z#Ïù| ­ì!üŒAŽF´m/qU"ŝ +%~x ésħÍú1ÙtÂ:ż tːú9SeË*ƒ“ú/` +•nô ċy` ߖ [ĝéu?ÊŬa˜Çëı 3 \ßO^fğİ +TóĉoÁN›ïĵì;R‚ôV ò9§£Ë?ŸäğEÍ5.•ÓÛY~°?àĜŠieI}[[Wgş“ƒƒMâ˲B0öçÏùĉ]àÙ:B…‘ĝÑs^Ħ²UI´żŽPAƒê%‚'ˆŬ$JOfÓċ:Eœ×l7°AĜ9q#żÊ]àKÌè°kêxŭ·áûÊġUôŭM=˙ ül·zĜż?ŝÑúo÷2Pĵzċği˜Μŝî!ñ´ùĠó"·żKs^8ŒùX· gŝĵÙpÏsÓÌ? 9ÈüĞ;>“÷zë:÷{ĝWĜÖ~ğòâcrĊ֟PĈF> endobj +1162 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [264.13 563.362 283.834 574.21] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.10) >> +>> endobj +1163 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [473.63 163.9 488.353 175.855] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.2) >> +>> endobj +1167 0 obj << +/D [1165 0 R /XYZ 72 720 null] +>> endobj +126 0 obj << +/D [1165 0 R /XYZ 72 527.351 null] +>> endobj +1164 0 obj << +/Font << /F23 825 0 R /F8 826 0 R /F16 823 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1170 0 obj << +/Length 668 +/Filter /FlateDecode +>> +stream +xڕTMoÜ ½çWĝ,u]üµ6×U›J½TJ,UJÓñ²k$\À‰òï;0x?޽ôäÌ<ŜÌL“cB“ow4~wŬŬç‡6aÛÛ¤;$M‘49ÍhÙ$Ŭ>ùEÒĥ$‹êÔÊĤ›²¤$§…9áj §%ŭBóR\ÌF Ÿ&aì˘ĥ½é&'*-Zâ||½CVa…y“êˆkÈĴFĜÉI\ ĦdÏ]ܲŽO³ÍÒMUU¤€%ŭŬ}‡š7yžħşĈê•1Â-F!^R'˙,—Àç–ÖëtŞ÷"Ú X ;ċyldx—n@ƒêrŻ÷•x„ײÂÓ˘!ož7ż Bı%é}3ıÈÖ€e?n şċQ‰²’8íżÈ×òÒW8ÍÜÉWluıj¤Ŭ€ŝVd÷ċÇÓ½ĊíZÓ÷ò‚Fm˘cy~„°Èİ‘°× +zUËŜY FZh_g'ÉmĈ +†’ŸŸ¤#–ykra‹#‚ġ.€yÖxPû^B/B{|K[<è!Í[P³Ĉ[`Ĝ(ŝ!\ÂŒ‹ĈµĞë×·˘AĈFï Çë¸áN,cçĥ£g(öù ŒV#Z,GCĵ†Óß:) +–Ñœ%–•eWÍUÔ×îî/Ħ§‹‘ +endstream +endobj +1169 0 obj << +/Type /Page +/Contents 1170 0 R +/Resources 1168 0 R +/MediaBox [0 0 612 792] +/Parent 1161 0 R +>> endobj +1171 0 obj << +/D [1169 0 R /XYZ 72 720 null] +>> endobj +1168 0 obj << +/Font << /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1187 0 obj << +/Length 2103 +/Filter /FlateDecode +>> +stream +xÚÙrÛ6=_Ħ·R3Í[Rßb§ö¤SǙȽœô! cŠT ²ûġŬ )3WûB.‹Ċîbħ‚ÉvL_òż¸{q~f“0ñ$‹&w›É<šÌÀâùä.Ÿĵ÷âé, £Ô{]ÚF…)·ÓYP Š—˜(’Ä!Ä!ۍĊ“Ĥ”x +ŬhžÓgâè°SV&?ÏQ Ó· ms¨ĊÚZĤ‘AfYÄ$s Ñ9BdY°>qVDa&½ŝ·%e‹´;q°ShFŽrŒQüôT?°ĊÓ.°#h%„I²tÈrO,Ÿ„ dhìŽĦF0˜ÁÀKJzIiXŒ>-Mĵ{eħRQó™I˘%duösôbâs°<ŬzDëdùÍÂ+5FDU ! ük½UF–´+­ :‚ÎÏxiU›­á ‰QÓ)†oĝßs§ˆ‹ħ1ĠT£|îi°)˘™Hşš8ñY/swEĴ=˜¤1OtIpÇ$ŭĵgJŭ8“žéNJ‹Ĝ•@z½Ä ‘ŞàYċËۏxùb}2 ü4M$9†šßV˘t1_Ŝ½~³şCO|ùçáo* +Âϗ(_%À›ûÙċíÍ×n·Ž˙÷Ö?êĉ§WïŝƒÖÉ˙Ŝú·‹×R÷ôOVĝ†škì!j­rêÂj¨˘,÷Öı›Ŭ¸ž†o0"ñb"ĉ‹)‰ŸûM̅ DöħJé8PO€¸˜i]Ŭ=,¨+íâs÷;÷MúMžÖv8ÉI *ĜgCO‚vtUÈ_Ìûħ DMOîÏâXš-:ĥÀ“\ĜÙħ ÙXEQ÷4 ǽ˜FrTÛTPŠ™5uċ„ŞŽµx](òNË3Çž(Šğê;™íwŬĞ­È–‡IŠŻ-RÔÒĉ–9ŬÜ"òü\½ñ%Lžž)÷\=żá÷ž8]›Ù²ŝ~ġûŠÓ$’Ócš£_:Í]àĠ ïċG[m£yä´ ’ċuáXòKÎ!{ío}b– ÜY‚›w£C{İPŜĤ…{BµWá²ë½òK_Ä(ŝ•ú‘' 2XW\ğC‰bžm™„ĥ:ïqG§‡Pˋ¨I —½ce™\ƒ#y§CŜéF +é“W;¸![ŻÄƒZŸ¸aGŬ BR2Xû84BduĴԈàX6 +;cq%y|IkSµ2ÑŬk|§ŻDmíĴE[ç‘óĥÎ +†­3bşX‘œl÷šÑÁ‹Uï :öè%aGQrKĤ“Ç"ĜĜ=_ÓjWoŬŻ.oß\½îCGô‡a4Š–~.'P’û‰(-4?ܽĝ^˘+˘ +endstream +endobj +1186 0 obj << +/Type /Page +/Contents 1187 0 R +/Resources 1185 0 R +/MediaBox [0 0 612 792] +/Parent 1161 0 R +/Annots [ 1172 0 R 1173 0 R 1174 0 R 1175 0 R 1176 0 R 1177 0 R 1178 0 R 1179 0 R 1180 0 R 1181 0 R 1182 0 R 1183 0 R ] +>> endobj +1172 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [78.199 584.605 92.922 593.018] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.1) >> +>> endobj +1173 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [78.199 564.68 92.922 573.093] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.2) >> +>> endobj +1174 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [78.199 544.754 92.922 553.167] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.3) >> +>> endobj +1175 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [424.077 501.97 438.799 512.819] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.4) >> +>> endobj +1176 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [70.45 336.086 92.922 344.498] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.1) >> +>> endobj +1177 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [70.45 316.16 92.922 324.573] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.2) >> +>> endobj +1178 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [70.45 296.235 92.922 304.648] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.3) >> +>> endobj +1179 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [70.45 276.31 92.922 284.723] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.4) >> +>> endobj +1180 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [243.277 245.481 265.749 256.329] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.1) >> +>> endobj +1181 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [389.724 233.526 412.196 244.374] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.2) >> +>> endobj +1182 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [416.104 233.526 438.575 244.374] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.3) >> +>> endobj +1183 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [461.621 233.526 484.092 244.374] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.4) >> +>> endobj +1188 0 obj << +/D [1186 0 R /XYZ 72 720 null] +>> endobj +130 0 obj << +/D [1186 0 R /XYZ 72 720 null] +>> endobj +134 0 obj << +/D [1186 0 R /XYZ 72 412.258 null] +>> endobj +138 0 obj << +/D [1186 0 R /XYZ 72 208.626 null] +>> endobj +1185 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1191 0 obj << +/Length 1648 +/Filter /FlateDecode +>> +stream +xÚµXŬoÛ6Ï_áíIlEߖ3ìĦ‰ÓCĥÛĦÙö@ÛT,T=}Ĵġż;ŜQ–\om˘ñHŜÇïŽG;ƒ§3xuċ÷v}uŭ2LíiäEƒu2˜xƒ‰ëĜŽ?Ĵwƒß­×Ğġ0ö­oĞáĜw]+­ëY;YO…Ü·VÄÍĊÇĦ[’Fġž‰´¨j‘e˘NUA %ĴÉ­ĴxCQьĠħËñĴHN,…‚pŝfèZ™DÒŽbŭ–Ö{ZúĥÇ!lh i)ħŝıŝü0v]{†dñŽdOv|+)UŽT`öÄڕéßÚDĊŽˆĤ’%˖Rœm:97¨CĈ[ß½ÑÖ}YŞ’·—µÜ˘qì*`ĵ—ü\ˢâÓGh…s:}%·zXtċ‚MΠ|ħ|u5ĝ] ùĥ 2à)•>ġŽğà–\xn#2ŠIÒd‡I~>d"ÌAËX‚‚´ÁA6qaO²Òˆ­—i!p?׆EŬÀy:pħĊÇU"‘ĉhħ!h”u÷LżsĤà™Bв]*^0ñ İRmhĉĝµ1'C˜%hO4s§H°TÙĝÎn7Œíİ7 oe˘JIҍYô3"ĵ1’ġ^ëĴ)IӉ]KĦO>µ +œê·@á#jš’ĝĞ™v³´ŞËtÓ0²@8iN˜ÓÑFI†ŬôprŭÒó;… ìi Àcv<ġÚԙœ­éÖ¤|àkY­—ŭ¸|cl  êq6[€µíl` IÉÛè8ÉŬN4LÔrU‹œ(y›”=ƒ…Ş”;8Áŭ/ƒĈ¤ŜĜ…Ż>ß .ôìğĊ\b쁛œIßMë=ûjb +3<.†Ġ7 Áa½{{='ŞġÚ² ôêXĠ2oƒŝ‘´ïšŠħ%²JŸRˆ‘&ĥXÓM&ż=úîó5_ 2ïñßŬÛıv×ĜB 4 ƒ5"ŠNĴ÷Ğ+Q_ôq‰•rüĊ޳D!·$şġŻs(9f5:™èDħle+4[f‹à1€Ûş~ñU$“ŻCN(:o´"4-ÒunıÉ.„˜†{a]Ħô‰Äwi}n*Ŝĥĉ*¨ĝĤ-ÁÀو˘ Fܓ˘†òŻFVu§tÒ)"ż^•ô׍°¨nžZ.&eÂ6e4™¤SèJüD½Ŭ‰×ÊL&˘ÉêŸç‹÷œ"şyó7_OÊĠq)3~âˆZlŒ%m¸óS˙3§¸˘J]3çJgÈı%'Ì“%nߒŒ°Pşa@]èy?è‹s$M@JaiŒ£NŞh> tažPŒ´€{9×/ĈŸ ùş™OİYÁ’™•´½XŽÄÌSÓşÇdşĉġúñ|Âìj³~_&@ û˜ ÔèÒċ7Ŭˆž˘XJx½vèkÑ4ġ3 g ĠO˜ğ0pĦx51—÷ëwˇ ú&ë5ŽÙâ&{lqÖ§ĥMY²{‰ħƒw[Ğ’HŒvíŠÁR2ĥ×Mµ}SÈ·°:£žpŻP‡Ñ)a5BrŽŬšnéúŬˆšÍûhµ‰ù‹,yşPUİÜPüg‹ +> endobj +1184 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [480.602 695.149 510.822 705.997] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.1.1.3) >> +>> endobj +1192 0 obj << +/D [1190 0 R /XYZ 72 720 null] +>> endobj +142 0 obj << +/D [1190 0 R /XYZ 72 502.821 null] +>> endobj +1189 0 obj << +/Font << /F8 826 0 R /F23 825 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1196 0 obj << +/Length 1875 +/Filter /FlateDecode +>> +stream +xÚĠXYoÛF~÷ŻúDûP ĥ'nm+„qÒkjeáĦTl˙ûÎìÌR¤B'F€>TÚŬÙkŽoŽ5şY£×'ÖíÙêäĊıkb3œ`´ÚŒBgږiıáhµ}4–u#óñÔw|"w’ş›4^SRğM²î'Ë·ĉr#öYóëĠâŭìí•9[\ĠĤù—ÔĜÖK˜½Y~XŽ˙Zŭŝâ<ê°aĤNdFħÍ\ÈL&M=žşk\-ĈNh¨x.˂Úf+İ“Œ§ĥħÛFUÉ74D_Wé×ħrB}-+ìyÀ‰Œ|£¤# i֜˙\A3ԏı¸œ?­çiŭ¨=Ŭ´˘“ĵŸlכŭÂjHö¤§ˆôäµzq QIĦ4ƒ·Ú‘;1Ŭş(<*´‹ëċjıĈéċbI”O–íò‹uMc² t*ùe/AeëşLÙ"²´!â×ħ"Kע‘ĵ˙Y+÷ÊŬxŠ‚T˘I‹;˘Ġlì§h´è‡ĈĊĉˆƒÙì-ò:ĦÑÙ\³\V­ĥû> yvĦĉƒÀ ;ËŞIËı +B£Ü $2ÔşŠH§·u™í›o‡Ĉ(ĞTĴeF$R m1U6j¤„ġÌV´²aNEAtYUrĉ²żŽoê5uìS<ÁñC4DjĥiM=V_êöìXµÓı@ú# Hĥ$A â8Ŭ蛨=hïҚÁV#vïñ@ÁüdXƒÒ$ú9s{ğgI냷†¸u@r­R”ċ3.“ê¸À¸O›mIG²‰ħóâ”Úz +”Ĝ‘BRoI'͖†ı„#ÈĴ5QJ^˜ˆ,SĜĊAß~Hو4:ì"UÍlÈ˘ŜWR³$˜zĊjĠ’ÓXyäK'p;Y(WÂ@]UŜU"§2'´Ç>Ç 55{D…£6›´ó¨ÎrO…a찁Ğ% •Qğr+Z‹BG(ĞÏ-ë"=ŝAôˆ˜ &=ħƒƒĜu½Ñ‹+ĥ“ĈTF‹Z/„>ħ‹‹ûCJ"Š˘lh]7~Ħ‡úùpŝ>Í2ÚUèÛT<Ä+Jj“’’–HĝÌN„}È%ÜS\ +È/yê~[vnÄ{Ú¤˘á< p<ƒ ŻnÇlPB6H8c²9€Éo3™&2ğ˘gÔEàh/k§µĵBLR +ğÈ +ÚhŽĞµ °ŸCĊÍ[Z&xŻJ÷*ĞàŞĝÊFVµòĦ˜òò\T4(™[ZÒql¸ż5Ñ×i½Ë8œ!(×ĉbUĤq;¨ÇAÍ’¤(†2³ĞŒM›@÷:]ıĊœêû–4ïÌ ­ê^— “^ñġĝ%. e|7…(^Y§yš ĥmSü‰ +èt½ y Î°jAc[w +£ôPĦ<‚—ÖRòâ}ħĈrğóùŞ[ ĦžÀ´}§ŻlÌâŬbɊ#ë FË2ψżQ6ÌáIžmFŜÑIXè’ÔŝÎ!Ħ>d BûÏż³?šÓŝ~%7 B3޽JW[Jâ [‚Ѩ÷ğ:ǑHy¸Í9: Ö\ÉaS•ıŽ_²ÖIċJœĈLŒ“Ìâ„Ĉĵ¨ÍzˆĴP!‹b]ë⸐U.™Q ~o&ƒ>ÓŻ\„,Ô! +)İŞċ!)Tp{‡šŸk9ŒRZ‹à͑¤DOě%Èǧx”(`ŝf¤'#Ŝs]žéd¸âÜ6Élrô˜Ñŝj>(İÍnכ½˙µ7ŸÍĴçyì̳~è•sÇzĥçò#J°;0ĉÂö½Ĝڤ뚠íƒE:¨L×ú"ŒĜhUÖAbZAS>ˆ|—éï·İNy8IO}$QLŻ+& ,Fd_€‚à+0:@Ş$ñq‚Ä’JQôÄT!_‰¤Tü„aÛĈ9>5ô>%mL‹Ġ£^nè4HCÏo01Ó‡ú€ŜĞÒÌqÄâGĞò\ˆú3Ġ¸4d~}ŽN@) ´|MnzáhžÂAа8ŝZÓĞ|ğċ. ŝ™¤u,)ĵ"ÚùŽ>ÄużşnŜ]smùŽ›– Ĥ1]‹żMşVoÇĞĠÉż4t™ +endstream +endobj +1195 0 obj << +/Type /Page +/Contents 1196 0 R +/Resources 1194 0 R +/MediaBox [0 0 612 792] +/Parent 1161 0 R +/Annots [ 1193 0 R ] +>> endobj +1193 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [514.331 156.17 529.054 167.018] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.4) >> +>> endobj +1197 0 obj << +/D [1195 0 R /XYZ 72 720 null] +>> endobj +1194 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1201 0 obj << +/Length 1854 +/Filter /FlateDecode +>> +stream +xÚ­koÛFì{~…‘O2`+zX~7/dKì"öÚ&m1œ³-DÒ:9iöëG)[ò”´ öĊâ‘<òÈ#y¤ÖŞċ´.ŝŸ\ [#{Ô÷ú­ù²5Z×ħšG­/Ö|-Û]ÏY‘\ŠmRàbh}uÜ^„˘í ­ç ,†–$²(˜´Ž5AHX*ΐ™İ%íŝöşCû[&)—‹ĥ¸ÖŠúY2ċm@0›nâ0W3µä­·çׄ_Ş<-˘·!*^ÓJhâˆb]ä1(UÖŝ6˙<Òu]{dûcۜAvĝŽgİ%~]8òÙtF(‘K‰˜\Kñ* ċĤ‘Ŭîöüž5fbAŽh‰ï ˆ µ%TŸ’¤\jò†Ê""?ĊĊšµbıMB¨œ0‘ħ`dy[H`Y2Œ +c;Éñ N¸šÌĉíĦoŻĊê6€Œ`÷Ĵ)#Pdċñ'µŽ³3Ñġ‘c@†Rw!†X¸œ‡[-óħûJÍ2İ´w‡Ú#oD‡žfĦ<~ò5­׊p3YUÙ|`>íRm÷Ğ—*IZú´³ÉUşaĆġˆ\żCî’üž\ĝN%ġÀoh;Al¸ŸAŒÙínàÖ,ŝG4ŭÓĥmġ(óD<͈|ÌvÓžiœÉ“ÓµÈV,ÂÈ&"ĵX@˜ÓúĞ8_îLp'Ü;úüâëċâàÌcNoX&ż?Zœüp“=Çç¸ê•qDéNMë}J 4E²BÌĥ×tÀ  ù톰Zb*… ÊË3ÉKzˆ‹½`hL ÙÚwëjyhB\?SŜäè8‹9çF.,à@IRĉ×È!ġ@1Z;?µİh"œËPİ4aìĊ‹ö~€Ċʁ&pBŸÉ ĜñĠġ{uLX/ĝ.¨:‹r›ìs}LX׊ˆA?ě’U6™ÙöCĞ\l֍ÉhĵéUKœ7²$ƒÌ‰ĥ/@£Z 2]ÁaÇdMˆ]1!ëšBûzâÑ ƒ•ĉ6Uµg'r$“E¸Á9Ĥ£Àf-ıIgxßëà$ó0ÂMánĵġ*+fQ,`ĵ*ÙŒ½Qĉ‘Ĵ^ò-SĊD”‰X&’ŒÉä£*ï ĉÖ5RżŬL?ÒTr:½yCZİüWì˙ŸÍîföÍÙġN;^‰˜ZJŻs@×éŽÌt>09 ‹ƒéÜsÊÁ A,<‚I§2ïÒÉLœ°|a@÷ŒNFgR‘f`·ìqjsíTĉqX<ŜÔlÔ g~›l9Ŭt È> V§ónàx4€ QŞASY9} ç‘b]âŠe@šĠ4ÓÎßĜ⛠€LS è}6>·ó K4nBÊ÷ûŸô°ĊÉyĜ÷aLÑ i>ŝİœÄÑ^Š™`N(šF€wq`ċÌ]*×ğż#•ż#ú`94n†ÊÁ•e@%Ġ²İKᯠsè3—İPYĦ*ŭÚ_œ³ĥ=ğż&ŞU£Ŭġ Eá!—ĵ‰ÂÌU-ġĵôĵ‘í¸#P1²‡!ÏnmÇùüè_êxW­ +endstream +endobj +1200 0 obj << +/Type /Page +/Contents 1201 0 R +/Resources 1199 0 R +/MediaBox [0 0 612 792] +/Parent 1203 0 R +/Annots [ 1198 0 R ] +>> endobj +1198 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [509.769 317.928 529.473 328.776] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.10) >> +>> endobj +1202 0 obj << +/D [1200 0 R /XYZ 72 720 null] +>> endobj +1199 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1207 0 obj << +/Length 2353 +/Filter /FlateDecode +>> +stream +xڕÙrÛ8ò=_Ħy*ËSÚ„¨‹‰ìíû§ë…ŭ„s=çqîÇNĠòŠŞµe§ĥ(óìÌÊ ÷]¤QÄÒ6xÄu2ĵFĜ£ËjCb°0¤ÀmQD”U%Jߨ˘d­ÁêŬúêf½àġ9‘ +ĊBdkĥˆnöZŽG0£ÊıçleïHqHu~!Û*Ĥ(JÓ¨ap,ƒ*ĠJ†6^ŻĈÎúÑ4úÈÇ£Úi{}‚C€ĴBüuŭáŬġâòfĊs´Ž|ô_mñ}ï4+E*ïë˘R+*€[¸oQë /ßĉhÀю½ÛÔ*+~3"K>şċ’o):G9ƒàı‡vC…aä\WġTù8OBŻ„r4êêDû´Bkİr˓Âüp ³.9RóԎúyDĥÜïu-â°}hÉYĈwòöKUŝd‰÷òbïÖ4ŒĉËŬ͞ĦĦ7.:u'‹ÔOYBruw9`ëĈÖĠÍ"+֙kh}ÜYïÛ0ħ`%)#fkFñ°şÁ•/¸rùÛJˆëÑÚ(žO9§ĠĠVG4ĥç>â2;¨ÁštċĤ}BĈÄıè’bğxĊŜ·ĠĤìŒk˘h€DQ@2Ŝàut×OQjĤ£u‚lљƒ³.(ûޏċÀ­-³Ĥ¨Ju˜şğxU#€QJŜ/ŬA áĴÔ÷ t˘à÷[ ~0c‘Á1„B‹" ‰‚@Uğ¤ĠûqÈ)fDpÔÍ^tĊ,ôé)– <Ĵœ̲ċ-+VR ;L\¸’h;DÀώÊIíQ’™b½P4U<îtİkĥòc°z€„EIM)Ċ„Î-òy<Ħb0ÏœgÁIŽSË/?œ[V7rL.eÉëżÉ.yu8P`ŬÛ·o´!<ğ]|yÇÇ><(Kz:^ġxïï’ĉàqCÙé‘3£·ÒsLñ(½ÁĜ/ÙhĝO7r›‘Ê ½ yÌÉüÀ×"‡Šo܌¸`äIIPÊӌëeó^–m ĥd‚ Gċ…ĜëóBì‘Ğ1<φQ,E,§ĝô–€Úœ"e÷'²yĈs„û“ !œ„58mĊRÇ!ϐ0Ù*7ĈôωÈĊ  }zë.3úîX^Jĥ띆HHۋ°²úPÀëu<4c̤ŒÎöéíĉ³Ħ8‡ÑV.°ŬfâÁ*ÖÈ]0„'Ì5KÂ5Ëàiŝ˙Ş’ŞiôäË{‘7ô.cĥW˘K~—}ı˜gü'Ġ,Ê#´´ĠŜ&€§X× /Ċñ|[Ê`zñ‹œL> +ˆS­a+ +p€ÒÂnÓ6MUâ9qÄ  ÛşœRáXU’-Oí“,NdĦ‚ĝ ÌmŽWĴôĵKÎ*÷­é +=Éìħ‘0*e]òŭĤ–ÎüéÄKwk8ŭJ*˘­`ĜhÒhQá“.máÖğş&i£ÄYÎ(ŜŸwYİ·Hżë²²LzÑ)ĦŽyRPĉ¨8Ó¤0Ĥ%w…’óDΣò!†hä—k@g¤y’Gfsĥ‡†ìžUéÛêÙ·%§áIמáÄHUHCı°ÛŠÇ’ü8°x]8 Á°"ŭ™QP'K~ŻéF!”Q!%“ˆ\|bfâ7Ŭ8—úAÇĵn']IOBĵƒÂ„š%ıPì3fEŝˆ½ yL˜Nt´ˆ=rİħ•)½Şò„2ž”vGÒíà6 òV‘é3iùÈzŠñ˜IâµĤú^tĉÎêŬŒÏ^Íŝ "öSoôìSŬy‹É×K•ÖÁ Ò~˘ Àˆ˙|_ĜŠ^Œúûœ×Ġ‘Ħ­Â†Tzq!rϨk4žµ“\džŸLùÊí ÛËĦn]ÎZ7œ0ö†0ÔBÀCPKû +‹ÒÑB߈Şa'pmPpùÛùŠ!nQÂĊ4i€ÎTkžo·ħ  UYhcKÔX›Ĥ.6ÖËÉİ —Ú–e—äž(Ó(:û‹ŬŸŸĈµlPóJÖ§•‰Wñı*oşĜz>EGÄkWPpÛ°Â%[ñ!Üeœti'ƒÏ4Œ(Ê~éuqż/(ġïy:N£ÄB•˜‘&3€­Ğ] …ú'Ô¤Š(î &œŒ &Ä\ßAmó†á_uóéê³Lè+W´tŝùöÍZpMŭ(‹lŻäÖo„U@ W"]´½(`½•a xpnÒĞxÒ3PsĦ'nċdj°p@{à²áƒħşŒÒE8lŻ‘3<Ž”á@ċĝrÓċÜ\ċŬÑFÖHĊ ƒÁg¸ĴW3µÄmc˘’µĵšŝDf P*¨~'ŬŭÖölù@ Ŭĝ“Œ”Ĥ…Ĥ-HU…~üqc2ÌlxVû4÷½bÑ­( UğÒ5Ĥ²_8j*¸ÉĈ~óİġQo L?ÚĠ½~ŭš›ıġÍçÏ_²ŸŸIħrjG¨*ħAQA }â2<ž4C–pàıĉ§żéQm‚Lm@Ñ ÇŠĤ ÌŸúö† û ;vZœ‰Ó;èš @rÔ:kíFÎ}Hˆ³şÍ$ÓĤ o4mÏĈ–C8Lx#súÎġúò,q]1îGáGĝšÇ\-C@ÚO öë /çCpñˆIñÁÜnnöÖAħ +.ì— üĿ׍d#œÈštD#Ô2Wċ`'äħÍ|?]¸^ +ĉLĦ~L¤ öGDïn_ŭҍ +endstream +endobj +1206 0 obj << +/Type /Page +/Contents 1207 0 R +/Resources 1205 0 R +/MediaBox [0 0 612 792] +/Parent 1203 0 R +/Annots [ 1204 0 R ] +>> endobj +1204 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [504.134 273.345 534.354 285.3] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.1.1.1) >> +>> endobj +1208 0 obj << +/D [1206 0 R /XYZ 72 720 null] +>> endobj +146 0 obj << +/D [1206 0 R /XYZ 72 667.56 null] +>> endobj +150 0 obj << +/D [1206 0 R /XYZ 72 317.734 null] +>> endobj +1205 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1213 0 obj << +/Length 2266 +/Filter /FlateDecode +>> +stream +xÚ­ËvÛĥrïŻ`VR‹"AR¤şsr“ßS'mĴöœÖÍ’ ‰'|¨$_÷ë;/P¤L7Í­7"0Ìóä;;ÇwżŸĝZ^ÌŜ†³s5w–['QNĝž&ÎrÜı/_œLcğ?—z•·Ѓ)yt·ÍrSêÂxíáäòż³·iĴïLUꋀİ^żğ]NÒ½úáŭídĈİğžLW—“À-ĞA 7. +VtkPĠò=òĈ­í^֛‡Ĥ5÷ƒ(ĝ°Ğ£ Éĉu†(fĦû6Ğ›öPĉ1n޵ìm÷şµ#ó˜t֗‘z²lÌVóO•oÇĴ<İĦĉ,Ir’„Ħ›:ûŒòšÙħ1‚y:‰Ĵ*Aà( +Üë-Ż”ƒÉ^Œ÷÷˜¤C&ħˆ ˝.\WhƒLP2G›?ÊêĜ2zğ'…dêÚê!ê&kڏ”ŞV­ÎJFĠŒĥ­M³œÇœÏc öÈ+ŒÜ +ġ +CĞWͳδ€ÑÉ p]nxÖ²_ï€ħ‡|yû™ĞŸùdçéŻuùMËm†ô ĝúÇÙĞ˙ĵż½şF—E¤Ĥ)t-ˆyĊfjxúâĊ‹§£A1ç%ZC̓Îħk Pîf5Ws'UâİàÑ˘%qż§BÄÓĤ ;.Ânx ÇZĝtZà ´½éóG§ƒ(ınĜ¤PcâÁŭ>[#Ê~,PŒÈ8Ôq`ŝ§×äm8Qüù”ċĠŠ£5‚ŸWċî’%Ñ A“èĐĤÏ"ôâÂ=A+2KĠîáĉñœbá8*LÓèSVÄŞşĤè9ƒ`œ5eS§¤‡6éĝƒ(OfĊ•. +`ĵ× 8w&Kl(E|£ s]!BİD\h·Yž3Âßd]!y2a zŠ&ƒD"²AĥMvD*Çu$İC7oM]‚§wœŝÔê<§bü´{N>1ĉjÌĈnáï­$-À˘ €8Sï|ĝŝÂı#Ħxj$h!ÄÒö7CÚ=ŜqV„.4Ö-Ë:LdĵÎ ĦVġW%)Iß~ËiċíÉ_ÌşEĉ8ŜTFòy +Ŭ÷6ħċëcŜÏN@îKÉéĴT'Ħğ­Ž”u“ 62Öí™óŠ­‰(ħ–G °Î‹Œ`4‰'P$Vĵ÷ĉ=rú^˙x3m'Pl¤öIbY‡RNžD=WO">ÒˆÏ˘+O£`Î`v…_(kvL„ŬêcY’œ8éŸ×%ƒ:ĉ8)´;¤·²‚¤Ċ” „j²pƒ­ Û +× ^ÔÂÙä½BÈ0€Âßm5–VM•[ żîì˘(vAÈµe•uv<ïİ ÀÛ^íeJ÷¤2sÀGEÑĠë3·Èìê˙ ˆ~Ġî|ŝTĥs³CÄácK3Ï_e‚}£_Ù°ŞXı÷xè˜wUşGiŽqŒvC„AûŠ šáŸ'1ô9ú NÁ„ŭîŽQW(úÀƒn1ĵxBEVéh8*RŽ +ò Äèş<— uA6Ҙ1›”NΊhġLÜB²2ıK°pßUċ´×DÀzd_j£I°P u-˘UêîL ­Pθ|A8ÚŞ)0(dS&t(óˆLW "[Uġ§ Ôn]Súz˘+ÁŜ ˆ +³§P §:€^ 7ör^·Ç•IFuŸŻŠôš”pŬ,²Ql”íï~ìÏà7à9Ù"1¤û.E“ŭhMÄü@…^ĝúXœN§£½órèy ­Ħ;i.Tè×ÙŬğĴ‚ûbPRßĤĜ°r½6…á2ÄÀ´8öħ5…£½d7Ž8˘2…hìċDa6r9èZ’ ŽW6ĵp’³0ĜéFıŬ7ĥĦKğ†.µÙŬ=ZÄÜöRӌX­íÁ””[ÛwÔ·µ˙*‡á˘L²¤÷áÍrÍÉŝ¤Ú4~ŬwÂı7ÔPd 'ÉıÚkUnOÊÇ֝Z}Ù0í'p(G½>‚ÂmŽ5_˜`ÌéV`•úƒ›U%$ħ#Ċï0èhò]:Z~û €SĊ™–_Ĉ/ĉÇf´ï8y”’IEîMĥĞÛjÛ2ĝqNE$HƒçÉËÀ;°Ë†ħ_W&˂xµÙÙ ixg%ĵÂŝŒ[„‹7ˋ?¤œp‘zAš:*LF)ĤOq˘´Y:ÚĜ”ß~Ÿ’^"5!ԛÁwWM5ŸÉéòŒ°<_bƒœċ'ÊÍŞğP²[ ´ğlG Íqì+?Jyĥ˘›"쇚H„n'”£G’1ꈟ´¤o€Y§Ž|·÷l„ ԉ"ĵۈê£x _ò#JÔĠ2âm0Ħ§O˜ÔĤÁ'cÂ!êS“3Ç>sHŝNo|´SžI"û”ñ+!R;Ô]!dÀİşŒWħĊ\ÊË%?‘uĦaA qQóg >^à3^î,kdŝġıüä4ÑVvXoöĠ1—ŭùL*ÜÄßÖGAċFWĜyÔ=­p…‡ßnÁÖŜ'û)‰~=L\ı³’àÛ=қ›> Ĥığ ½ĝ“ z~C|N ˙déŻïžêżz úÁ­Ôr-äÂl ÷ş0ì€$ŭŝ"˜q +endstream +endobj +1212 0 obj << +/Type /Page +/Contents 1213 0 R +/Resources 1211 0 R +/MediaBox [0 0 612 792] +/Parent 1203 0 R +/Annots [ 1209 0 R 1210 0 R ] +>> endobj +1209 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [336.924 560.653 359.395 571.501] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.2) >> +>> endobj +1210 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [372.9 560.653 395.371 571.501] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.4) >> +>> endobj +1214 0 obj << +/D [1212 0 R /XYZ 72 720 null] +>> endobj +1211 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1219 0 obj << +/Length 2027 +/Filter /FlateDecode +>> +stream +xÚ­XK“Û¸ûW¨rYʵ˘ù(29¤ìħ½™ÔìLjF‡xĵ>`DHB™"T 4cŭûô %˵ÙM.B£Ñl _JFëQ2úċU"ğĊĞ7ËQWEVŒĞÑ<ÍÓ$NòùhQ>G×·‹q™GooîĈ“<Ï£Ŭ75“­ġHL#ğO²y¤[žúfùe¤—ĉ·$jùÌéĈİĵzjD%'Óé,úv{' ~£N#Ô˙eñÏŜü0ù˜''$#8]\Ì2öÁëׯǓY§rÎ:&Vµi×<ù+ŸWĤÑ­ÚêĜv_p£SߞİŭŜµµöC“Ä›šwEÖˆ]œ÷gƒmZÜòg]g™FîÀZœ^BLAŝ ›äÇ †Żŝ?Ž4-1Ċ +)ôâ‰_ÛöÇÌYó[’UEUVÍ£<ê˜ż²ûĥfÒ´ĵxú½gXh·÷L²ı˘sc‚„ò^owžÜƒsoƒ]£–"O>CîĠĠż0Ô?óìŬ{Œ8Rá°ï‡g7ĥín45Mj6cSí +â•ĦÏĴ„Ŭ)>òşCg„ÝHLÓñ¨pÈ"ɜ4ú„މ\š­jXjÉİY +?,qç le‰èì:Óy–3²ywŽŜ•se}ş"½TûN‹ b9 +f|ÉWĥĊm½ZÒnċ‰3ĉQ §pĉiï­e³â…@ÙjĴdot³Á–9Nwĥy–—TŠÈ–ôB–•~}Êf!÷Ċĝ sĈ–½7Eˆ7+ƒÁAŭ{·şëÔúOĠÜd2á*ZŒž˜jG<ÑßÀm¤KšÌ’èîYğgĵHùö7Xûôĉóí Òż˙n].4ŞY_EHa&ŜÒmÔġ-&߸k‹$£gÈê À €JÀˆ"Ğ˘ëUżáĵßPsêh'Kóé§ż0½ÑNC‰NÓäœqwÓ4˘Áİ.œìğŻÓÏĈîğpcîĈ”|ë‚ÉK8şÔVÌZAŜm†(+°6™1–F|#şéş wĉÑ0XıĜĥëòä²lCíż uŭ°~ky|oàŝ€â“ÄzĜ RêĜ˙ƒwċCƒ‘)¸Žê@­ŬŻ7L×ÇíqÚñöHÀb‹c§‚ϸ`÷žéàyâ·<ö‚ǃwêbUeô ÛúżTŠ!ÁQ]JïíĴċhr¤j7ϘE’Oğ¸şƒEÇÈ­Ħ)€ÙúĴŬÑŬĵÀÔ§tµ—'M쵤ēĉI³RĵĊ¨é“Dë@µk}ĥ+z‡)sŜלìŭ‡r/˙qK8Ñ÷f˜għ `HHµVĦí`Ori£EŭàI_òûùJZäşq2öŬ^5́W Ö÷ħ•³[ĤD`¸żò oĊE²µb’"‹½[œF³ÈW\lÉq{ +fƒƒp]…¨ÊÎû‘ϰJ}!ëÓƒ` í% f/fgn̳¸Ì*֝Çiœ.¤ëĥóà<îGĦU}| .*–têöñêî×ËљĊ`FˆŽjżbg8bÌfsŝò'aŞ'ÓÀÇ%6”jĴŞ™sŜpá*7\ĵŜéġV<"Jë YRH/8Ç>éhJ‰Y¨ŽÍBfoÖıóİ÷HgÑڅU!܃"6Û]#QF*Kˆ8ŽúŸ4\h()´á@.$~ĵżá%ĜïOĜ +ñFĤcR£û7ZÄ˙ĝo^áôĈÏpc†h`czL­7Vĥ†œúÒ?~ÛşpRߊŽ…Ĝü&• Žı!NĦÎR.ëïg”M*™ŸÖ7é‹%(ß‚ĈUq™…oŜŬ“á“Kú$ıvŭp´Ĵ€ĤĦí¸ÁĊòÀ4aA†/ Ì'rÌÑÂ)ÂĠ4.aÄÀ>XESoÉpEÚ(¸}<ù˜ŭ„ç÷fž5¸Û…à ?/ù……Ñnš†*-BûRÇh‘d|ÉĞt0xT•„Äj½R€•<ákuìŞRRGDè›5`*xlÁŻ\w|x.éi*O–4ä‡,êòġxOŞ‘Ċop¤z\ĊÉżÛĝ×3oż‘Áš>ay„B f1Ú'x~Xˆ{œ ‡{† `EŬžħiàyÉ—^;~XNrh@œ–IşŒ´ŠÈġĵ‚NáÔJ}ŝĈ´„¤ħrk;ÏËZu†òۛ%µQˆeSè°k^ìû—_ŜÖSÄżĞğÛ×żÈ&­èŭàV6ÚöOİ FQ@€ĵrCCŭOcT€d–tZ€ĉş> endobj +1215 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [265.22 141.24 284.924 153.196] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.10) >> +>> endobj +1220 0 obj << +/D [1218 0 R /XYZ 72 720 null] +>> endobj +154 0 obj << +/D [1218 0 R /XYZ 72 335.947 null] +>> endobj +1217 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1224 0 obj << +/Length 2369 +/Filter /FlateDecode +>> +stream +xڕX[sÛĥ~÷ŻPÎ)u&fH‚Ċ“'Û²SgìÈc)3ŽÛ>,a‹JBUÜ_ß½˘Ĥ>ĜZ,–‹ŬĊâÛ‚Áz >œ?ĝ=_œĵğRÁ ġÓq4,žI4HÂÀT2XĴżx·7³³étĵO³[ŝŜuwĥ|ŝĥĝĝîjÒQ N£‰ĈcÖ°Ĝ˜fxG‰—­VB5UĦ™ZVCöV2´˙Ò +HŽ=ğÉĴ|µÛ’°˙0Us›[Ñ_˜¸ÈYër˙2oZ›?†ôħ|¸ßšßp“áDOly0%ó*[iYÀ”( Ĉ‚óèoúéhÄŝ’é?á"iä}†ßÖäÑ­.Şú…é³ZTĉOÓ(äŻî†ċá?- .³;›*× óélÎdUóü´eĜ]ĊS²Ŭhf€ŜşÏƒB̌ĈÓZgLáÖDħ÷\ċ^P½g˜$š"b}߯ħü[TfĜ ™ZíjSùËĉħ—‚ÇË!mM9 ½5ñ›·èVàmkVdhOP”ó„,E‘ yYvİÇYvPM"o‹p2䔕E"lÍ@pܘ?5˘Ò˜“yĵ>~Fë#‹˘@Úĥ-'”ĴÖ]*tKEœ³íR‘÷k0 +´ż†4MRïlĴĞ‚§$ò´x%,Œ<|úÌ_lPŬ˘Öu}ÜÉT—sħËı(sS˜2³´Eİ‹(Ĥp§’[ïJ$ĈŜÍtt}ËŭF—,ñ‚&T;à)b*s÷LTîpg–Ó”éÁ”(Xfoì†g zöĠh žRŜ\/Qƒ…¨™ŞDñ“>ġzÀÄŭ‡“Á/ {ʏHÀa#ħ¤{Íş Hkì&â€Ç׈pÂèŞÈOâMS~è+°'ŜuÙĜ,ÏÉSÁo÷R‰“H}Ôöfzߏ°#_ë=ŻÍjMŒ½[c9[už +Oô gbaMç1JI‚1ûˆÄ#FëâDDşÈà- Šž†À>"ÌìoaUgµÉE7o8)ĵ +(ˆ%x$§ÄġlíĊŬ=Gž`˘€‘·À x‚² Zì­H›b‹ĉàŜiFnïêáĞbè*™Ô— +#CÒï?Ŝßücŭ{œ_Ì>]]€ġC@Pò0Ù–Î Rm¸qÀá&ŠëeÚeĠÖBŞ7GĞ)Ùb}÷ĊòUµ$“Ġ£Ĵ&\Ĉ{6ƒcÑdÄ8AB/Wʑ™ñÏgıUÙì)—éĈp WĤù*‰ĈcXFÎġ§9íùÙÍlŝžWĜèkC:‚‘\VEA1@™3~׈}lŒXfĦ22×àÈhWz|ï `•ÍjËĵàJĠĉħŬY²NÊÓMċoÈGÙʧp žûTpĉ›-ŝcé Ĝ˘26avCŒŬê°HqÜb :•BòJş*%-]Qȝn˘:pŬ–ŜhÂ瘔nD;µ\ü(ñ]qYS×`İäĈŬµıÇE\ŝ¨ú|^Ë,,Ĝ҆9܎ŭDĊ·#Dm@-z~Rĝj˙°Ħ† +Çù +ĕĦ⠔ĵ\!)8ŸıÂò· >+—R’IäAû€ĠVìŒk3Pŭ•ĞÈqsÁ ъèXŬŜä9SrOĴż8~³‘ž˘bŭR3ÓÍ7g 8†ÒğÀNdüÄC- ċ÷mˢEÏ8î<ŸÈƒI, ÇċÀk#vfˆ`ŞÙmŬċÔRu‹UÛ5tƒó$x#@)8Ħà^!ĥXħ3áŜĴt.zk½ĴÖùSŻúĵcËUVc?£Fr Wc¸żğe–óı]ïàL&£›kŜéO"Ċ*Žƒ‚Š/x 3¸½Ù=Ú2ğmŻ€ıĜôvEŻ-Á.%˘M!ßŭïŽŜWëgı‚Äœû zŜË[1ò^6Ғ14î™M‹żÇĊĥuÇ'eüĥOqŠLwÑááħ I–@ġŜsıš£UtOEŞM@ ħÔĴ˜|óĉ Ü.˙ëOqQyÔċ)é€â¨á‘ 7OדžòÌá½D;yM#ħèç>,żĤiví¤Ö*pŸTÇïƒ(Jŭ LhR2™˘Ž„.'ñïE\ +endstream +endobj +1223 0 obj << +/Type /Page +/Contents 1224 0 R +/Resources 1222 0 R +/MediaBox [0 0 612 792] +/Parent 1203 0 R +/Annots [ 1216 0 R 1221 0 R ] +>> endobj +1216 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [125.854 618.628 140.576 630.584] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.2) >> +>> endobj +1221 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.873 376.208 125.577 388.163] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.10) >> +>> endobj +1225 0 obj << +/D [1223 0 R /XYZ 72 720 null] +>> endobj +158 0 obj << +/D [1223 0 R /XYZ 72 605.812 null] +>> endobj +162 0 obj << +/D [1223 0 R /XYZ 72 363.392 null] +>> endobj +1226 0 obj << +/D [1223 0 R /XYZ 72 295.343 null] +>> endobj +1227 0 obj << +/D [1223 0 R /XYZ 72 275.716 null] +>> endobj +166 0 obj << +/D [1223 0 R /XYZ 72 195.993 null] +>> endobj +1222 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R /F16 823 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1233 0 obj << +/Length 2766 +/Filter /FlateDecode +>> +stream +xÚ­YKsÛ8ûW¨ĉ2TULó)‘Ù“c9SŜĜħ7RI&µE‹°Ċ2E*|Œ×ûë÷ktƒ"e:ğŜÊE  ğя3ıŸ8“?Žù[ĵ&ħÏĵÙdu7™{“ıëĜŽ?ŸĴÒÉ7ëOÇ r5=ÜÈ:ĞTÒdeñ]?ĥ.“şáĞrzìEVš÷şÏ“)³ĉĜ:]ŻU]Žo“)Vxâέ^Nvmk%<Y³áVRL½ıá>ğ9ıâVšĠ´Œj™|WVÛ¤ħ§Ç³8ĥ.Šé÷ĠßĦ÷ħëÚq²†Išf"ħïûV³QÜX$´ˆk-§Ġ$[jî ×ÜR1Ö*›RSÖeΤĴĉıuğÛiÊŞ!é‰v+ +_Â$ˆÖV²]­+.·;˜ò6†ĥÉrŞjğÓ"²c/f-Ĝŝܵnòĥ>nôf;cG˘§§†"ğĴ¸gŠ–ß$ŻKn=fİʟ¸Ív×3[Y˘ĥ&ÙMôܵyReÑZ|Ù}Ö$9w>İZ%ĠšĜ6żËöCÑǎ¨E*ĜC “­ŸêFmq²Aà˜%@Ġ^gü˜x,Á>Fç[s]@ûSÖMY=ñµîĤRˆ û~xżGm³§ŸŽjG<g]ÔêGĞŠµ˘ÀÜÎİQhÎ~ĉ£’˜ˆ{ÎDGGĝ´ĵD˙Ñfú$èȉpÛĊ`LŜ}_%[¨gŬĥÌû˜%2Ùĵ(Ç´ ÷çsë}Ĥ ƒ‡?·µĝ°O8Ÿ£HrEbdŽlURÜK“jî"ÌıÑl2!=‹€ŭdc5jvĥ +µòl›qêġj·P]gĴ+‹%-, +fo6Ì6›òşÍ0ž&ÏÙÑï\í7ġBpóÈéVĥ²GMŸž’‘MIǖ§² Z#ıŭ¸á³ßpwĞš$ñħƒĴÛĴ‘ÔöD^Ĥ79M+[7£9és‘óQqOé[Ğj[C%׺çŜ×Ċâz)Tˆ–ä(:éS7şHü5•#aĝş”™ħµÎĊŜ$ç§UĈ“*ĉÑv}ĞĥÜ%ˆQö½Mv ½Žgj0½ğ¸^‚Ñ}3³Ĝc–SÊsĞPڙŸS(÷Ş TĤ˜Ş2Š'I˜ÔyH=@oËÊ­&ħÙ51O›ä1CN¸Ë–‰,ŽyĤ ,Ö­8Á ë/{ŭIÜbÔ[ò2IM1M¤Ş Aƒj 9_ „1U$]Ùëlv?"F=nĊáïI%FÈß|]¸‡ +-+f…ÄöêÓ/Ż?0‘]’ueŭ^pŠè •ĈĴ(@āż‡3„LVĥ5žı¸÷R˜²b·)ƒG 1ċAäsÍ@ ÊİJé&ĦĠO8ÌŜ6Şú]ĥÚ$UúHˆkmßşF%LÓ œcµÚÔħНŸ +Ç3ŬÁ³×Š•3rN#½óÂ\mñĜ@dX¨‚&6ó`¤V9jĵpoÔáò„#QìÖÎĤe) 2W—UÇŞCÉDz)/O$bÉÎsÊÎÔMKɳÜ-J”9ÊÔım^`Mè\11Y“Şu&×íšİP‹dĞ.Ğ‹+nRĝƒ,ÒQ0ŝÏĴË2YP uq(aċ|×ú2|ŒÁÀóW­4ào.ûÂÌHAMöĈ31Ug @–Şiw²^ĥ•İ|3“ˆâ°ïÀ ›ÀÀ³¤ˆáARD˙…4—Ĵ›Œc³‘œöÊ\eĜXh€ŒJùŽ[!gʽ[vAqlĈÏ-(­ĠpJ÷DĊuĞ“™|ġ…‰)àT’g˙Ö·7}\‘µP*E*+£ô<á‘RûTàsb¸'·™y/£Ŭż…ô:) pHŞTƒBż—BÁ-EvŜÙıÔ|;…dž`”ŻÍ":ˁĞÄ Ŝ|^-–öÙġwáÙ#ş^|ĵX-.> ÛÉ)ùŝ>ÛFXwmsXۂœ§1mgnGŭ炘îŻ}…e‚ĥ7 ÷´EÇg‘Ü”~Œìo˜*Ĝ9ÁPĦAdaï&F|’L$›9"}]ê„oyèŽb$W– +y² ߞ +–'Ĥ8ċQäFwÙĦŽŜq%}ƒP'[i‰·“l˘Qž1£†ŞZ˘Tʸ9ƒJO<…ĠUœħ„Á÷l*ƒıġxĉ Ûû=`v"‚hw Ċç·ÀÔ“ŜK-óU½2ÉtĜ‚È2qĞÄÙ?“€Öóó7Éàyµoó=yï;Fv{Â: 1şŭkR¸ŻĴètÈä:ğ/¸ĊP³ô!?§p›ğR‹A Cĥ +-¤*~OċւĦ­âD@›ħF[ñ{‘ kĝû@yƒa]-’óW(=ĝĤ%E[W^ Ë#îKğïĞnV˙f>˙WS%ô˘z!ùÔú›|ÜÔêjua~ûòŭä#cL"½ċÏ?_>(ŻPT,Ô]ÒĉÚċŒujžıâÇŝlÀ¨óVüÈ +endstream +endobj +1232 0 obj << +/Type /Page +/Contents 1233 0 R +/Resources 1231 0 R +/MediaBox [0 0 612 792] +/Parent 1203 0 R +/Annots [ 1228 0 R 1229 0 R 1230 0 R ] +>> endobj +1228 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [386.765 408.667 409.236 420.623] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.1) >> +>> endobj +1229 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [247.37 311.344 269.842 322.192] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1230 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [163.136 113.634 177.859 124.482] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.4) >> +>> endobj +1234 0 obj << +/D [1232 0 R /XYZ 72 720 null] +>> endobj +170 0 obj << +/D [1232 0 R /XYZ 72 298.399 null] +>> endobj +1231 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1239 0 obj << +/Length 1891 +/Filter /FlateDecode +>> +stream +xڝXŬsÛ6 Ï_Ħۓ|+"İÏìö&i›nişĜ½Ŝ­í퉎u‘%WÍòß Ùr”ë‹E‚?|ugıÖë#÷™ïËċÑÉ+ċZħ2°–++”V(\ÇUĦµÌĴOöEÙêz6÷oŸUzOó:˙֓şi›W%MOéó÷ìËòíÉĞhO´kÍeäDħ É/f2²ÛÙ\ĊŬóGž½Á&ğÊK³z<›{µqRu´w“àì‘&9œX"Eed¤¸íž–2§z6vM´Û=1šŽÓu^Ŝ„z·Áß[#U×´”+\ëĤa6ßıX~¸yçÒċŞż& -4ÒB”fBËáÄO–IĞ„²%Ê -£”ŬVô­J”Ĥ<ğZñ‚ĵEh·u›c˘,/˳?§YQ%$ÌÛñ –İiN÷‚YŜl 25+é&­óm;˜·ċċŞŞ7 úßÁğ<ĜĊòè둀Ħk Kĝ#ci^ì)Ĵtsôé‹ke°VpTYfëĈRp<À¸°GñE~¤`Gô=!ĝŽïz,cŝ·DèHá{R ‘/Ĵ@yŽ€`0ù8gż¸ywùîġS\Ï…Ğ Ï\‚A!snÜ%ÁçÂZëĥ ˘|a? .sĜÙigWŜ—nx(‰@¨ĠĦ}OŝvÓó•)Ž4QÙĦ½(€h–§mr[è)¸Öş˘Q š&% 8ˆÒŝä¸!AW +4- ³d“Ü–}Öı ġHŽ š|ÊŬiÓm™RóîžŬ<6­ŜħÖ_ğœ£Ĥ]ó\ŒÀeuKk·]Ûö¨ĦÔóMü{Št”!EünPs²ïGŽZŻf¤XĀİd³-ô1ÚVÚùЍž /ĤU³ĞOp:#ÂŞç'·Âà*Oëê*ïa‰¤ĊKıè"׸ëNê–WÒŝB{Ĉé–Ġ„ŞցáÜ‹*í2ĈXÇf͈?L$…J GE’K +Ç)ë‹ġ‡t5Ħ‚„0“PÍ>ċô•híċċġ‚F띜ĤĤĝMÀò³ëğ;oô‘Ž˜K'<ĤÙÛJÓàcß­Û“7IÁ§Uşâùb)\˜Z×m’—<Ùß$)÷?ìÁè †8Β,ËÑú¨…èH {Y|îy}Éâı2h4< !bĤW $ž$­&‘Ğ^ĠĤ+vÛ)ċ\VJ­3ŭÏŒ²4şĦ!ÁY4Bwœ“Rżıâ1.$hßí“(šRf'jS•˜„Ÿ•µ×¸ñ÷EeÉ÷”òA’ĝoXB‰Ììa¨äEA´!µâDv…žĴ/Ôfïr€Y6Á‰ƒ!ž#›sñA÷„ĴJÓYW°Ĵ^8ÇĞĉÄîBgĜħù‚Ú¤Ŭòµƒ#}MF6šUɨƒhW6U8Èċ9UNhyΝ³ë+nf¸ÛĦ΅ÏÌhÍÄ|Üĵ"ü(y×w n^YŸŒÏ Fĝ4dµW]z0oӃuIá 7ˆœXĈÜH(ĜIQàÛÌÇÄ'Í×Ĉ`C‹ÖğçÜKċÇmûÁÀ +GzÀUîi>w~ĜƒbÈЈÚĠ§\{4²’EÏH‚r>­4mòU›-ä’gÚ r• lëChëkš!W×2%$ƒÔmbjı CF;w½ ÍÑϸcgCmĦ=ĜĥĵÖVDÍtk^ H3À×yRĤš(´ž™ +ǍImhĦŽ Mñ Ĥ›¸i‰- dġuRŜišSꖽĦK3K QHKö°ı(²<#ÙÑĜMĉähÙ_`˙΋uM90 ”äN/ƒ¨ŝP.Í—fdÚëùiO^BAÖL]/!È7]šjӈ6Ğ´,(ĉž€ ù3‰ŝ=ħ(S&%çÔ{Ít,~Ħl‡Âz/5*ñBôĠ-gÜ +áúî݈&:{–3Jh>ÈpOî4B¨òe˙ĵ£I·ü †Ìh£N4ktZ•ĵ’ôƒ^œTÑğŽZ³ŽÏ7ÏAĝŽ}ĉ˳8gLä"¤Á¨#rÎ +ïžĜ¨ĵ!ïû „JÑ"=Î"Ï>žŒì]߯b}?„y֏ú˜Ŭa"`Ha_›ĜEÎ +4Á +C/mj9€É€ŒŜ;-ĉ˘Şä×·šxúËñöp¨ìétLÓĵPg´ kâ‚ühëáÓ˙ ìŜÊŜÖĴîĞ=â½İ:ʆ—ƒ#§êÇáëpċAó ¤ñŸ8$âcc=YQÍÀ“gh3|`Δ46‹ÌNLö€ñ˘…ĵG[ŻtğĤÍÙtğâ;*P'ĤaíĞ{חܜTà'Àz}J™Ê aÌ<¨ÚĉېvÀ‘ñż)Yċ™4Ċŝbùáŭ_‹eŻG ìĜ˙ègRÔ yŸul!)cDž§ Ş̂ÂĵC˙„µġ´ +endstream +endobj +1238 0 obj << +/Type /Page +/Contents 1239 0 R +/Resources 1237 0 R +/MediaBox [0 0 612 792] +/Parent 1241 0 R +/Annots [ 1235 0 R 1236 0 R ] +>> endobj +1235 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [298.263 357.919 312.986 366.83] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.6) >> +>> endobj +1236 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [237.38 195.583 259.851 206.431] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1240 0 obj << +/D [1238 0 R /XYZ 72 720 null] +>> endobj +174 0 obj << +/D [1238 0 R /XYZ 72 182.639 null] +>> endobj +1237 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F15 1136 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1248 0 obj << +/Length 2260 +/Filter /FlateDecode +>> +stream +xÚ­XKsÛ8çWè´EUY2 R””Ë–í<*ğqìŠ45“d²[I(S„† Ç£ŭġÛ/P”lĈS{4€ŻğĥƒpöE(íġòĊċ›Ù`>ž§*,7ƒİL£pĈÓÁr=ĝ,^/ş˙ĵXGq•v‡áHÍ[“M½^˜ZHĤ4µÉ +ìu9„ ŻÉÜËá×ċ?Úó}{ù&;·ˆ&t à¤ñ ZşI4MÔ$qóV—şÊjÍ£ú‘;K³Ò˘ÎöîŜWv[e{<EÑx>™0SuĈôġÙŜ”úòÖÍĉèiĈĠĤÜ>“ÊüyÂßÔÜĞ-·Żî´mä_ܽÜë²Ö•œĤ ×Ĉ–<|ÉÍżqïıŝÂsĦ½ÎâÀ“xYÉíI?4puV2żŽ’pF—ëLÉfnÖĉ×0ŠuĊZ­‘˜@ŭ#ZĈ4L²Y:r(*Ħ°÷×yö1yaéˆ|Â͑dúdo,°x’Ñ$ĤÁ]K‹Q÷8e·Àh3ÒŠĴÌj[Qr85Á­y‹-‹#ŻÎñ^ğĴÜjÙ~ÈÀ4(LĈFNÖ­ŭ*6÷”ħżÄZğĵ2+ò1½î³Xâ ~µ{@oŠ`Q8¨ĥî||ûb…Ü-'cĝı·Œgıš{k#QëŠ/³.€IÄ£qÏÖm鸁JÇÑD‹óU íô~÷k8 ë=üG?F{…ŜÜnğıżĵ•‰˘qÜËíŝžĥ*ô÷XĈg,?êlŭ›]0áçÊx8ĵĥˆÉ½ÛŝÖ½kÏùÉwΧ ˙ד&g'}~Ġ +ïĤ°ùw "à&Ë5ƒä™ĊËovÖäú$“Ŭœ°Ö‘”Ÿ‡˜ïÀž’8 +ŽhĠĥáAViéˆäȃĈ‘a·}=xĊT+­XF‡Ë  ° #ŽN0 +,œ°ë†"l$“ôünħ{.ĞlU ñò<…N˜ „ö¨€XYòĦš Ÿ7EväÚ°NέdWSuñ9‚P_ï,Ŭ~Í+Vô ž$fĊ˜]thX Ix+Àë4š ^;žŒyŽAĈ áÙxÎïf-gt•+S˜ş½„Â÷ +yŝïCR>f: ƒi÷#Íhĵêԃ,9ÍY&¸tp]GŽ)zŜô„(\şá”nK$‚_ÀúĦ;:t:²0Ëjnm™kŒné,¸ÖÒBßÈ-wÚTŭ‘$cvBTÍ]yIô‹T°ƒKZĵ"‹AÄ$“ĥU°ˆı‹‹ášpSé߃NCŜ[îMAD{Œ´ÔwôsêÖ;JU`)ËHgçD<Ɇc´–$†èç|TìÁ›|g+‰#Ü Ċ8 ş=g @Ù£9ÑX7…ĉùǝáˆÏ”C²i NOfœ<0³ueD^ĵ†<Z;\b6.`CİÁ‰ċÜóŭÉÒ ´µìò€„³ÈÏġ÷ŬŬ§½ĊĤöLĵ~G‚B”Ó²äO¤1êI’!éAĊl‘ & +‚t9ĉzIN(ĦaozrµĦdXÍüá`—Ħi²˜Â!šug1mžfŞHB?Á…˜İ^֔@—SÒŞĉs_Ò—ĵ-sΟ'*” lßĜû­äŸ5fô_îäP|qċúµäŝJrôŜúHI‘I­q!EÈJVÊ$²Šµ7÷?ĊÎO—_>|}N̔ŻÈ/#^aĵû%#@ÈĠ{²* ˆ³‚ü^/–7ïïŝy!tĤ~âŜ∠+Ġ‘HFk>œÖ”ÖOƒ&J÷ĜúŒÉG`äòb`` šä,á·ğKĤŻŞŒë šĴ]Ëğ/Ž’ZÁ¤×z“5E̓NħìĦ“(Âz,Ħ÷àԐêÖË<8ĞÇÔäĵêĉE,h+”›òކO(uíä¸ċ…ôì)Níħy˙jùîv|sw+l[”ëydFĦgÖÍĤó³ç+Û@”×<@*eÓ$„΃-dċŬïYA0€˘šC;g)ڀ?UzŬäí1ÂeŻĦpn +O “V `ó?@ÑïTv^˜rlyO&,–ÄS>”ĝÜÔRÍî*ÂLêÚĈI–’ÈĤšt’Ş$ĝyg +Y˜[WG_Ëf]Q„‡.×É)J ÂğŻÒI·Hëĉ]=/”ĜKhȓ{%Фë­ffcĜvA3ĈÒĥĉfìyŒ·‡–¸àŒıê̆İÔ%/]ózÎWé4Ÿ-ÓwžCÙÉaŬğŻĵGQϧ‚0Ùü‡ò˜ç ‡ÒŸ¨Ô‡œhĥ) íÀFfCIÚ"L^päNċIH/_@is(£éŬ)f> hSç7eû­Jh˜ƒTċĥôßßHümEŝÄAñ£œ˜ ä7²×ç;³ŬùwbumŸÀcDN@ïħ<,´/n;×ìù`…°KiĞRé™?€fHi@ȸùÄk½Ż²t.ĝRçë$Ĵ.[ˆQTì¤ĠU5̰䔏ñÉI&ġ,"ßë‘xv{żżBnW8\öùĈöB˙µ îŻŭ²ħXòİWKo?°÷ċ:|ùž>§À%‰ +°vE>ĜϳŞ2ÙVF•›ŞÄ><_…còIÖ8B‹ÀVDgx¸JĠ‹ú%FsĈóßù+t‹I$ ŸŒ@™zèpĜiÓâqŸ(Ry K(Ï¸5‡ŒÙYž˘rÊġ’Ižaŝ”"â°5×^<jĜßöpÑĵÇ˙Ġİü‡ +m§’Cnôv ŻY +e 䞸*˙=Í×ZkÏ s}nr[Ĝ0m +eŝÖ[9Ġ×rB͋ñC}zö(' –’ôŸ}ôw,½'ié@İù8ŒĉAc5 Žgg‹^/_ü§×Wĥ +endstream +endobj +1247 0 obj << +/Type /Page +/Contents 1248 0 R +/Resources 1246 0 R +/MediaBox [0 0 612 792] +/Parent 1241 0 R +/Annots [ 1242 0 R 1243 0 R 1244 0 R ] +>> endobj +1242 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [117.496 591.482 147.716 600.282] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.3.4) >> +>> endobj +1243 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [214.936 380.772 237.408 392.727] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.4.2) >> +>> endobj +1244 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [526.274 232.882 540.996 243.73] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.4) >> +>> endobj +1249 0 obj << +/D [1247 0 R /XYZ 72 720 null] +>> endobj +1246 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1254 0 obj << +/Length 2374 +/Filter /FlateDecode +>> +stream +xڝYísÛ6˙žżÂßċ.Qôf½ìvÛn²vKÒ\í]×v½ç‹ĥy‘Œ”šäùë€eÙQwŬX$’ üÁd= &żßĝZ]ĈÁ¤‹4J'‹Ġ$‹&YĝAœMċä³çûO­ËVĠëÓi4ġVŞ’†›şÙRk8żûŻÏüeñ+Ĵ~Ċ~Ò*ĵñÎŞfy¸À•şÓB?SçÏ`|ŝĝċì!‘~ Ïqñ³Ë| 1î”ûħĝü8Ê=Ĝ)ŻŬ(C­‡c`òUÛÑ$ĉŜübñûí§ù‚X6‚y—ZŠV–ĵNx<Ž2Ża‚Üâb'y‘ög&V)Ĝ=hK-„­j˜°j45î:U•VŸĜğz½x{íÏŜ]ŸP_Ôĵ5ÈΚ Cż˜Né|ZŝĠIC×O>ËŞħG\˘ĵ÷D+µúŠ]İİ˙¨Ú ·6Ê2r·mx‘fûPÉV2uŬĴµĜúpAê]*mÚÓVmy´3RjšMÓU%µ%İÚí-l÷™÷A}nšŒ²½qbQ€˘Ĥ~“ nx ĦŻtĥ…c‚h/´´Ħ6•lĥÔ¨œb‡..% SovġnöĜ7.p~œÇŜÂ'…51\OKÓU­!²r2ÓĜ–´ÑħYž9v†—Ÿ†^@íR‡ óĴş‘F'ÀÖà>ħ‹ŞÁ/ÑH‘ ršMÈáP,ì9Ş*ùîÔRTû ZM%aè5µdı”y¨Ŭ-Š^ùŽoۋ‹ùô÷ÚĝĜÁÑÛÏÈCe]Ş'd: +-˜èġ„ï9š|>Ĝğ´Á˜¸ĉğEáIçN+ı˘f‰.‚ĞP&;fœà}Ĝq)z§ˆGedĴ÷ĵBoCˆL Ï$™‚@9ĴQUöÉ1cç>0İRĈ"4ˆÂܳĴVwMÇA¸ĉ‡½SşïX@ßEmŬíc_ƒÌŽ<—•\ÒÁ˙¨E Ñ@NèlÄÎb‰R7í€OrGw55œ!œPW>)ĉg碂^f +èżEóoŞÓ^à q´ĉ…-àwËܑ1­U]Ó}{g˜³mdÀû‘í›[€1Uo߁Ĥ@ĝ$0’e§)J€ïây4µAANLF·éa Nâì`ìQUÍĈ€ħġÙ­Ž:”ŻÂmIÁ1$$Ô ^ ĉȇq#NÜĈ`ÀÖ04ğ‰s,6MTŒ.XhŸ „ı_DĊÀÂòt`ayvha0l¸ƒC,­'KcV]U=Ó 4††]I&d# +tI¸˜°1 6"Üâ/›ŽgŭBœÁ= ¸ —E 툸Aì}ĜH–l~q:ĤW‡ +Q +î"—ÍşV˙CK‰R‹cH–Ğâ§ĤĵéèĝµP ĦĜ¤<¤9A¨ËvC‡iÊ4 +¸ö€%‘(aëe Ü;oJçíFĞĥ•l.֍wÈ Ù›f6Nşò>éĊgĈà¸(Ì׌ĵ÷öŞZZ^ĠmۙĈî#‰a ĉ$ÖòAoêÒäĞF”}ŽÌÀúr5ÛOÔô)Gŝ[Äŭ`1Ñr…á€-ŭ<ÛrŭĝrÌϒżÈƒà”(ÈÈÂIî'q?ñ§— ŭyżÑ™áöĦoÚ[Ĝ3э ?t.ùCD$ÓvİPĉġ7ÓçO0‘âu2zş]„6Ö4Y>ÚáiQĝaî{_Ŭv’A´mT†&#¨ĤŜ‹|h[ DDŞPVĜÏ*Ĉ\ċ{LpI-4ı`@ Îy?›d\{j+³ŽÒ,„ĥ)!7ìY:À1˜Ü´}2de$ĞŜ_2uÜêħĥ"L ~Ş§R0éÒ[%9caÍ/;}ràEĞT(v"°•—ë ŭo²œ+Aïhèu.ıınÊÁ§€òÈIö&/l ³›şóÎï]afıŬ÷&˙­‹_ZÌÚSV4µ‰O7kşċ’òUqh^4j-`:ġì"_ʤJqLŒÉÉŭÈ@3áwîöqs°·ŞM+ŞÊ=-Ċ‘×Ġ›só ËlÚŞîOElRžÜQ7`C§nŒçƒäi9|{+ĊßQDĊXD%‡%§ksU/GaÁġÀĊ‘êaë-]‚gKèÍ0ʸàd (+ĉ”’ĈEí>.ƒdµĦyĴèKƒPmšĤâÉ30 R!tnû"ΘĈĈĵ¨–óÀbsóΰD.İ> µÈVÑJ6¨’ìKÓìö?†à–5i8 ÊR.Â{@"ß85–Ešµ<5X-=à¤Ŝ§Ùíû˜ÈöHv§Û³k"E>àkDmĜŸ÷°–€Œœ”A½µhĜ­šzŻiYÀï²Ht_@|qW)³ħH@<@/N(ċJ@BŻ6VYÏ°Ë <÷J >nħ:°V´=){zëäµ~9vHÂQŻm೑,ĊЧúâ4J6’ŽÖÖù(Œıï3§„TÇjZÁ> endobj +1245 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [120.54 606.483 129.036 618.438] +/Subtype /Link +/A << /S /GoTo /D (appendix.F) >> +>> endobj +1250 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [496.636 550.363 519.108 561.211] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1251 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [496.387 187.067 511.11 197.915] +/Subtype /Link +/A << /S /GoTo /D (subsection.3.4) >> +>> endobj +1255 0 obj << +/D [1253 0 R /XYZ 72 720 null] +>> endobj +1252 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1258 0 obj << +/Length 2561 +/Filter /FlateDecode +>> +stream +xÚ­YYs·~çŻĜè%³UâpîCq\e‹˘í”(1ZĤ\ÑQ)päN8Çf°CŠöŸO_˜cı´,—÷e€ènôñë-nŜâ‡#Oß_œe‹Ü͓ Y\^/Ò`‘úžë…éâ²X|pŝ½ÌB§í—ÇĦ9µZİóÀĤ]™sĜÑ vvş’ùژċħï¨̈́öšÇû-÷w-÷#żkä²QZ+3Ÿsµ<†AaT”f[‰4H-˜|żAhöëÓ˟ÎıY +£vË:µÓ…ğ<ŽÂÌYġ77ÚìÊĥ1ËO—˙›û›Ç1kŬ˘B)jöyÇ­²Yú 'hUġ*´LĜĜFYKK„S§Ĉu È]ô•‡(Zú94³|Â'z~T‰ĜO¸Šè€Ñò1—;9zŬÏmËnÈ3d W!~ÑïÚZíʵŞ*‘Íî˜ıyóŽg°DĈ…ŭ +t½xżş.ĉÖìıâĝ?´úĤO¸µhaه>‡‡ó²>ß6â²ıŭ#nù†DC˙¤ożÛbÀ`ûşĴdôİV}%ôżóç{ï…ä@?NcÇ}ùöüÓܧżè¨ßÔ)‡àÛm°>úvÜä¨3`í ÏĤù•ĴĴ‘Ú[S"là<Ñ8Ó݃!ñ4›żñĵhrŽ8ÀÎg¸S6²Ki ù8gˆôS'MX;vIŞĠħ†;›ÒP}ˆ9<{Î ¤=†tŒäçu‰SÈ{ŞŞNĞâ;úsiÈbĦ—Oŭ“ĉU,†™²Ĉ ìÉ‘GÉG€íNC \ë= i4ǁÀ¤Ż´qĜݰĥ}ǽéš!DB,Ä0êN`Œ)ÉÒ?s´ ÀNĴf5ue#e ­Rîyu4:˜.¸a0ûÒ?œ(ñçÎîş+u7Cqc?”ȸÇħ„ŝÜÂûŞSfàósÛŬrë ÂĠ¸î¸pîß|ÓVReİ­î¨ĝ^ì9?´m!B=HÜûíCĝeÛÜŜé+Ċç8ÊSçWü$ö˜ı³ħ^@u)˙í͎çŻÁ‡)cGñÇzÎ,°Š !µq’l[Ër`ÔÖċ/–e` c?C2‹ż,sŒğŬA<6pÍĥpÚĴğRÜĤ˘~&´³pĦa(‡>CvMĴ|+'gÁž5ÀġbĦ¸!Ĵñá<¸ŠC½ħH3‹œ QûàİÄn˜Ḋ–aNà—DÄFaó9vP6EÀ‘F§ÍĤ#êxŬŞSîkŭŒ›1`g8Eì\ ĜÂĥ $—ğhzY]6ër‹…ş}·%PךƒEŸÏÁ“béA"Ÿ`Ôĉ FğEsS­Ĥ~§ëvêyH›WĤœÎìqó“7Àad µ`ˆħÂ÷ŭêôíjÁ{´íé)˜ùíÊE’·žˆ3ûD‘:?–4´|£Q˜p_úh°?ıaYoЇ6cÌ6"Œĉ_Í·ùC˜—ŬöKùë_xÙ£ïÂHûéIìD=‘ŝŝh0ès£żblŽf9À V4Ġƒ]Ÿp”u(İĜÙvÚHi@$’ ™WÄFĞnôTêğe ²veÛ1ÓQĝÙx‚ö.ݵĥ·T~Z4…ÌO˙ùöúçg֓lò +°Ĝr”=t× ~ŭá + ­ĞĴŠA’;+!î%r7 üÁbDéS›gLYĞŜP†ĥ ÔdDİÔ³Ĉ{,I,È7™ĵ˙@gR6¤Ú{öÒ+ğşÑĝZ•ôëiĜ€$”'Ħó]cî9!ħhihLÀÂTMûŒiCîĈñ+ĥNG‹tDİ- +°şÒTYn™'o1ÁÔ(@~T\F>ĦX쀒û‰ï—”Ĵ[„‘­Qáäáà`,ŒŻpcY+ÊEP9+ÓrĞ7ZH24=Ö||„óö•ÀĝVÙñlIjž-mâ÷Boò8ä{Ħñ2´ĉĴ-w'=—ÇHDP…0áÇÛͽÊ\M&²ïM‘vzŬŜ4 nùÚb û˜A8˙p‘~uyôż#6ö>>ĥúYî_Ĵ룟ĵEtË ólqO³êEnĞ£î­Oß˙­ġ0“uäċŸ|S7O3Äscûì{r&Ċ ż€H˜ÜìäÖwĠ•úš)?êjkíèn7>Ú ^6ĵ’Ĵv˜•EçqqínƒŒĈ™áë5ž,‰Ü> endobj +1259 0 obj << +/D [1257 0 R /XYZ 72 720 null] +>> endobj +178 0 obj << +/D [1257 0 R /XYZ 72 435.367 null] +>> endobj +1256 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1263 0 obj << +/Length 2649 +/Filter /FlateDecode +>> +stream +xڝËr£Hò/(˘…)(^sëğ;ĵ3ŭXK3ħ½sÀI„x(ÔŭŭĉĞÙxcwOdeeeeeċ³;Ż|ù__]R'ó²8ˆġÖI'Q燉³.œïnèž^,•Š|÷kW>ċ]ĠìË0 Ŭ@ğ•y4<Üĥàó\ġùá †[Vğ˙ò#˙ëoë›jñÇúï×ĤûúÎ2ˆĵ0y[˘„…qà>Ñ ċ–¸n+àĤ˘öéi¤î™É +‡eߗ†Q¸% pŬîŞM^óê˘Ğ~­ĥ ÷yWr#œ9›<’š|N é÷%c&FĤvz$îq‰+„íÖ +Ĥt]˘ÜJyYñı ²1Ŝbİ“ŭVġûöĜÂn•aˆ’÷UÛĵELä6-ÏÌĜŞ‘DψMN@à>0cğrÓvEYÈĉë}ùb;YŜ6Ĥ2½™“ŸNi7/ +ĥ“(=҈\›Š."ÒVDöĉ͛ġŬ§[¸èży7¨ğw 0›µhyÁÀK.Ĥކ1GCLŜ•9|8Lä§îş:Èşĵ)„èÊ2˜êĤĝ†‘¸™„ċœ?1. +C‘,$]|MßveÁ³Ġ@ng™·‡ĵż´ßÛġĠŸW +@ßQŽŠ"/È'}/Ngs¸úŝ‡ï0 Rya–:'"=8ĦŻ<­b€kguġgLtĤ*/H˙# י§€˜™ĝsÁCEŽJĵ@E½8ˆ#/”ĞÈK !ßÊ×îğûÏwŸ?tüòCZ³ @Ğ*ċ5÷ÇĤ! +bßQÛĝÍùşFŒ=şÏĞqŬEV…° nkw³Ë1|ŞàĈg.y“ƒu_ĝ1cB[ÇŻEòEĜ°#"xaaˆ C€ĴĈìLƒÄ}'ĜSĝ0´f$wJ]ĉšXf)İ,?ŽˆÈ-£sÔu‚({šDN“ާI'{$iÒéiŜΉÖQž8´÷†`ÛÔg„4 ˜‚3‚§}µAİöLħċ,™ÎXÙbë5öîx‹9a@'Œ’xBôjߗí܇—ہçp8ġ­•P4Ïŭ†š,ycċáPR,xbXĈĈ6{%Ĉ›İX1‹u÷ùn}swœƒŒUß-0é8Ëík€Ï‚&m÷ApH ‡:oLe34H +‡ÖQàžŬŜfOI£HŠ9Ï)ìÛ¤ +g~² L-ë3-N +Ôlê’2Ea@ĥòċ$Óö{ |Ä^2áe”5†Phƒ&gÂE½‘òŬßéR:Cž)ċÏ`xEDĠlêc’"öTĦˆ'gAàŸĞʗžr2ĊÇĉ‘„ċe–ÄîM;'GÓ˘żBċà@[x|Ù H2#“[ŝZ·Ċњ¤ĝ²òğĈĞ!h¸ ”]nf‹ɜ”6SL›!ÍAĦ’hÈŞĞ +ü Wäš.g ‹Œ££Ĝ‹üì˙I/Ó2ñÓôI[³ċ)XµçGÙ¤<ġ”-PĊï n¸kP|ö ³MĊ˘\~jİ,-ʗİHĦ‚ú̚ L F‹•Ä ˜8´dĊE9M÷àœ‰ÊÁ=&%ĉúŝ‰r)›Â>ÙeġDœ‘Ê Ŝß#Ĝ˟Ħ˘Ċ!$)Ĵ‚;1§[+ÏĊŠdá”_0ˆ„32şôvŜ[žz°Ç h<<Ğħ"‹¸Ġ–‰Î”|Žr4²=ާÑ'çŠâËş1L/,~R(†Ù$„¤\4n,s”ޏ•ġ/×Pϔ<ÑïóžÑr:À‘Ó[3 ÀOµ8+îUX{óoœÂzˆĉ‹2"!›àċ0ĥcsƒ +žQЂ"HÈÇŬĂ"(@£†£’‰áŝ£ċŞ7‘€ƒsÔĉ3ÜR÷•v`Ëx(Phó–™Ìî›LrH”pâÉMUËĜ”r‚IÚÇĦä01%'cJŒ\aÙÌ%Ó1™ÔVAŬ7Èá{·ešAZœ*³çh0ˆaħòfWò˜‹u„jàÙQ=!?"?ÜŭzkmPıë{fvìĞşêEHV”fÓUrÛ$^•Ş1sàìv÷ݜïDĴ½˘K˜m&½…FƒBŽlpĥó ähRI™Á´“Ĝöš‡iĥpâ@- Éô2” Z>²:ñ`=5êA’½L`´Îä†ÉY×I6š!b‡2>á"ê‚íé-*;@%70UŝŭĞŒÒ1I҆è)$m~p"DSnJcònĥn˘`{m;²ï4“Ž0ÈŒiŞ[òÍ UÒXCùħĥk^Ééé$ZܕЎ<Œöy½e(́n²‹í ”:ċ%ı¸EgIĦ̅ÖġŒ÷1>Psä +• +V—”%9ĵšr<7pˆÎċûîÓ×{Üġ‹L ³Ġ{•ú jÙwĥ*#˘˘=>ÔċÒTTÖñ&t*uĦ Ôż0–B ”|YrĈ‹çܧÇ0ŞÏöµjĵžHO-‰7³NÓ÷°‚bIıkÖß5&O[߸ڝğRŜĈ°•çógô<†:“ÒR§ö^ _  +ĈħC]Dáhљ-ŒÚ¤Î&ġ€ĥ‘›X72Ĥ ‰[µ<ÎAµÜ@j2nÙ/ŻkŠà'î°_°΅?AJÔxíĦ2ž!(ħġÒ¸6’Ñ=n‚goĠaàÓr/xւdʽŭˀ÷Œ ÖCÍ·ħöâHÛŜc2ĈZ +GM•@cġ zqA€_³‹z’ue#Ċ´Ĝĥ/mTÉwòK³ïš=н‘VE„ĵPäXâ†öÉoiî5óúCè?{òO½šŸ‹:ƒëëùH­†î ŸJtF‘Ё~OıWC=Ġ>aR5?-–IğË&àg7nl·…‘ğüŭAÎy^`e·ä ²0‡]Gµ­'hjË_°żñ#ğË Ì,W"pË_*½6˙ëĉ^ë„dĞ·…Âĥ[&iâŝܒ °à6¤›t8Q‹ĤH€ Ċl5'Š0H7:œp0´oˆĦÀ~`xéH ,“œ ÉĜĜ7q|S‹íA­üÔÛôħ†AGìê·÷Ÿî^tèáé‰%ßĞ8|„ö9rR͘²/OößŝgĴ”tùlïAĉù*s–qäZލĠÑíúêß +endstream +endobj +1262 0 obj << +/Type /Page +/Contents 1263 0 R +/Resources 1261 0 R +/MediaBox [0 0 612 792] +/Parent 1241 0 R +/Annots [ 1260 0 R ] +>> endobj +1260 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [526.274 394.331 540.996 405.179] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.3) >> +>> endobj +1264 0 obj << +/D [1262 0 R /XYZ 72 720 null] +>> endobj +182 0 obj << +/D [1262 0 R /XYZ 72 720 null] +>> endobj +186 0 obj << +/D [1262 0 R /XYZ 72 466.948 null] +>> endobj +190 0 obj << +/D [1262 0 R /XYZ 72 249.824 null] +>> endobj +1261 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F15 1136 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1267 0 obj << +/Length 1858 +/Filter /FlateDecode +>> +stream +xڝWKsÛ6ûW09´ÔLD ÁÇÑ;u×MÔé!É– ›cŠTI*ĥûëğ/>d+İ“—‹Ċbħĝö"ônĵûġ$”ï/˓ӷ:óò Otâ-7^޽T…AŜrí}ô£@f6WʄŝUvĥ)Ş›Ù<Ê"˙Ô~ÑŜµüğİôùPŒŭŬîdüShÂĊċbyx˘š}^ŝvúvştè͵ ˘$â•Ċ&'ĈßÑÒ3ċ;\=&ħż–Ċaœ->ïf:ów³9|[| +U\²üm12ĜJ0››(óĞ×5ÌI}'nğÛBÖşžú‘eˆ´+Îı/¸škdtSï›îV†*êxÈĝĴ_ġžf7­T›Ĉ-ŭŒKĤ ȍ[u5MNaFcWmŝï Z -şbëDQ­Ùfm;QM#ßûÛb… +ñPˆOH3ĉéÁ­ĊìéíŽó³*lÉvc!¸Î5Ĵ“uv f[°;²O­˜ü<ö/Šĥ`5Ŭ6übà)^8ÁQQñ3(À“„ƒÌG^·EWÔbg7L¨–ímħéh¨Ÿĝ 4mw¸üWŻÜƒX–ġMħ:ۖ6fQ$gĊâ"BŸ­-‹)˘è0`ȳ[™ŜÈĴûĤè:Ú˜\[:†;˘Ñ +‚÷ˆk%ÀĜ†Úïż˓NˆĦ§'–ı +#š3×p(*{Â/: ġ„ôë$÷ĞşcċuÏĝƒä³ŻXċ+„âŞĉ³pšˆdtôefŒ+~ÏĦ‰Ùms )ÄRxd*cŠÂcWİßĠJÔEÇŞĈÙĤħĠ Ġ觨a(} ġGıżœ”/^Ĉk#ġ[Ó.ÒÇG£1cGòtġ×òs™ċü€0 (êéĜÚ;–np•ÉċÒĦY&yĉŸ×ƒBpÍÑÓş/ڞ% +:h8…‚ L’|1€Ŝ’ŝ‘ÍŬÈħɴDˆB +9 ŒĜ$ ó¨ö紃>t’|ímaâ<‡X&L ¤‡ğ +¸Ġ,Ò>Ü[py_PV‡Ġ˘ŭµ{N&*W°ŬÖgá²ï]HżyŬÖtœëžä…żċ>qMOöדôwÔd@[¸ĵ9JÖ§o£€Ù$@l`òôÙŽvXğߋ; X'C÷ Ë#7&İ`ĠĦе[¤a“u3쵃ĞİAöѰÏA/†~œÇ†ĴÄşœ fO>gĜtb[ôĦáċ‡ßñV=V!Ü/êħYĠzä^MÛ8VŝbêáFù“öĠĞWËĊğ‹Ÿ‚s öl([òÈÔ=Ħk×g êXtß\è(#m&¸˘m÷C# ˙ö( `ĥ݆r:Ëm3˘rßG^½Π‰œli$jÙ5 ê•ëÑÛw5tg˘)ö~­/à àZ⟋ĤaëĜçÚÖÂĊġĤ/Ê`Y’÷ÜvġF:Hâé$ÏÊ:UOî¨|^-¨ĝV9§*Èâx(ç1͑żµ}m-ۚ³=´¨ĤkÎDoUo·œiP–E%vS: òœÙġÂ'Ĉûĵïàh9B…ÏžR²F…²fí@) [ŝ´;ËŭƒôCħ_’:v×߅¨^ĠMZé§Ğ5dz ÊHAXLŞTş3Qóˆëšàç š&&J+rMÂ@_“júL;‚3ĵ 6 Ĵ=ÂJn+ךb'Ÿ‚ÑxĈ^†wp_}••y+‡Çéxn ŽOO_ +íèĜuÉĉ:ÊĈ:ziP9'ħ@hì1,[B;ı–Ÿéƒä+ŻôĴ/ûWLëJ·"$Ï˜önšd |€7„2‹°‘?îûi›žSzàˆú·àG’_–îߪ¸1ĵQ‹•Ŭş˙½ ‡ÍÑ{òȕ‹</òX€ŜĦ<§Ż=jم<µŸTŸ½°Ŭ6B¨½zŭ#{ÄĊq“Ş÷7·²÷B@ „-Úğ—DgáÔŝғ|#gŠñ@X`kşŸAB,àwKm.OħäĈı9żçĊl³/KlJrX³Šßg ôÛCYöƒ+÷+Ĝħá-J{]Êp'nÚŭŽ;ŭ‰c­|żÉĠŬCħg¤ï<˜'E‡%'E5=uxxZçA¨r–Y&ĜX̀Ĥü?6’ +endstream +endobj +1266 0 obj << +/Type /Page +/Contents 1267 0 R +/Resources 1265 0 R +/MediaBox [0 0 612 792] +/Parent 1241 0 R +>> endobj +1268 0 obj << +/D [1266 0 R /XYZ 72 720 null] +>> endobj +194 0 obj << +/D [1266 0 R /XYZ 72 720 null] +>> endobj +198 0 obj << +/D [1266 0 R /XYZ 72 514.349 null] +>> endobj +202 0 obj << +/D [1266 0 R /XYZ 72 404.147 null] +>> endobj +206 0 obj << +/D [1266 0 R /XYZ 72 321.654 null] +>> endobj +1265 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F15 1136 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1271 0 obj << +/Length 2280 +/Filter /FlateDecode +>> +stream +xÚXKsÛFëWÀ— ˜a`Ne·JmY[ĞHkq³‰ Q­pŭ~=Ŭ>Š“ ÙÓÓÓÓïîk=Yu}ĉÊ˙ċôìġÛÄJ4R‘5[ħ²bÏu\?ĥĤıġÑXŽĈïÛEÛ6-ŭ2R‰u‚_Κġ’0}Ñ9S”r¨-²ĵ\>ñ˘_ĵ›—Ŭ3£ò²-f}ÓnF‰o;£OÓ‚™˙×o}wG<×ĞĜ‰’„› ĈĦ +í—ĥì Y^pÜWïàü íš(ìÙlŬêĵ,ÊŞ`BşáX£r ìȳ³ŞüPžé@żq„öM/œÊŞâÓ+œl›ÇìħÚ0˘-şu%dĈ”UÓu"àœ1ż¸^`Äʳ>û3ö˙Áĉšd}ñgġŞhñêĠĞéÍ훿9“‹)cŜj#hÏü~<Ĥk­Às’À·Ĉžç¤aÄÌïÛfVB˜-7/™¸é7t~ŭñ‡OU/‡£Ġ‹,–]IjùM|LJ–bûf MŞŠËFڗÙlä{öóuKy¤%ö† ħ˜7‚ŭ0ı{8™ĜoĤgżžy]˳ĵ0tTŞĴò$~dÍ곏Ÿ\+Ç&Lìĝib½hÒÚò]Ï ıkUÖÙż˜İg~ì¸*ŝ׊ĦŞ› +£.âEĊ*•ZPY n„˜èÒF%àGjEÛé(Ġ4äĴuMQġÈ!Óò% +ŭ_R]—%Ż6DŜĴyĦ“€r0<";Š|ûjŬŽOE][pĞt#:§ÓĈôc?ġ¤B“0ŸËœ2ÂO)çx³Ħ£ŸGZĈ*£Ċ†7Ĝ‰ üם=–™q?zèħrúˌÎ/x Q|BFÄ]ߖk}*p%„UàٗÚ„Wϧ4FêéZ…ŬÁ6D°ÈĥÒ2&cŞĵDêù…ħ#?sʰ[ˆ¸™oop>ážá8pžµ p6à5‚V[ò|Ŝ3BkĵT˘.úE£M˜kĠÑËR2GƒŸ6!$ŝPñRñÀ1)'?·…ŽùğŜ wŞ,ÊV éşÊ4˙|*Pż9µ ֙ş]êvì EÌaŜ65C;OO.½jŸYJ×R‚ù`ĉ$ÛK˘èĤœf0²ğĴ>ùŭġK‚ÓìàSCŜ–&/4…Tşí”@ĥuxóżÒ^ƒ£²M'g4Ε(…Ò— óaöàjfëżû_ qíĊ„żÙtyŭî˙;žĈ: ÔADĝʉLDP* AùN2Z°h¨û(Ä.¨’¤˜í¤ùÈ Ö%›¸è€Ù³[pĜZħKs r'†nĦ0ÇİçÑ?ĉ€P ĵ‘óŜÉ1!L2=‡(ʐċÀ<.‘ĝԇAÓyĵœh)•:—Â8İ“çŝŞĠ˙ŭ8 o +endstream +endobj +1270 0 obj << +/Type /Page +/Contents 1271 0 R +/Resources 1269 0 R +/MediaBox [0 0 612 792] +/Parent 1273 0 R +>> endobj +1272 0 obj << +/D [1270 0 R /XYZ 72 720 null] +>> endobj +210 0 obj << +/D [1270 0 R /XYZ 72 547.748 null] +>> endobj +214 0 obj << +/D [1270 0 R /XYZ 72 251.764 null] +>> endobj +218 0 obj << +/D [1270 0 R /XYZ 72 156.752 null] +>> endobj +1269 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F16 823 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1278 0 obj << +/Length 1507 +/Filter /FlateDecode +>> +stream +xڝWŬoÛ8 ï_á·9@ٖ½µišċkŠ&†n÷àĜJ"œmġd§]ïp˙û‘"•&Yĥa‡MQ"ù—zk/ô&gáwÖËĊÙÛkz`Ĝ‹{ŜbċġcŻ…A(úŜ˘>ûWW‹N7S˙fvqu9 F³?ż½½ì +½n<hïŒÂVe‰Tâ׺ügbŞy,3dĵn£+I[•Ĵ´qÜ6kUÓŞĵy‡*ż1ŝÈrgD|dĝÇñŭœ¨8ˆñ"”Œ˘`˜Ĥ$y;ŝ˘Q˜†ŝŬ蔀…!ŬF@è~6ç–8'×ZIÀˆWĴZM[FfqTMëċä3ŝŝ[ŒŜïǟh#kh]鲤ë˙RŬ)h¸p7Ÿòîŝ§î‘iêB;’öÈàXG’GÎi'+ +U݉n7’ŽY›Ğ–ılšÌ&|´!âf†^C^Bĝü ×N}×µú[Òçüj6ge5ÛġpĠ=ċ.ì­üÚrÄäWĠEìYµ›_›ˣ;ÙċP,‚aÄìkUgeùrN™ÖdO’(‹F6Û²µ8á§Ş²µÑ´f´ĴTÉhâÑ-ı*@àŬ dÁ—H$KıVġ?OÒ,ĦĝŞOá3żĝ8ĤğÒá~oxĝqsàLıĈè]†{}!ñu}NÜdê-}4½- ’Ĝ6Ü'v‘Ÿ<äXä7˜í€ôŠKk§4îTk›N^uXˆ~ ‡ü2ËQĉωÑÛş†ëSämÔóŸ˜ŭI0èħż"H@k(]O^ é—K4°ŸúÓ””% ­kâ,:Cȵĵ#"SĞżĥ²!ñ1˘i zb§!ˆP4°{ 5§ZœG£;$Îyà\Nm çnNoç ·ç_ÜÀŜÉĝĦĥ„´Mk‚K–íĈ†ĥë^Żú‘MÈCéSġëħӍû6îlÊaJ0{-î/M++˘ż„QRJ.Ak&6ÂwWžĠûjY+u§ß4ô5Òu£Ké>Ş“µ_Y b\‚ cçÁ~ƒĵ/0#RX"bì¤/³FċDNëÇmKälÛîè9ğċîÁ@ĵ^ôhu1*œÈ„’¨ç[Ÿ5‰íüija²‘ëJ֘£­= +ˆĊ½žÀ4lÖÎ PMzˤï—ÚP\†ö­†—×rЈMhÓ;™`-d“µ´!—(]Ĵ°?—ıġ›h–…žY{DÜOÎĵÏVH + +àï Ù‚ívzX ĝ>[Ĥ +œnĜŭÈıtDúWԀ€qà~äż9n[ûŝvżSˆŭìKöħħġîqÎà‰ÉżğF]s9Ef`à<8ŬD ú{ŭàdGH]/Lɲoj½a.´7]ĜŒù°UCÔ³Q8…ü(>ÎĜwrµĉ£ÙÒĉ^˘Y„Ÿğ™wkùLÄèîž(Û=‘`s!0lâA„Š-\‘ÄԇìşħŒĉv+ëF=Ħ',c‡îaAĈmVaGFúB…áA:Œ\›ä +Gñ”âm2)ĵÓíG}z ‰ÙÈ.‡uŻ>‘Ûls̤ ĞjNċŬ£‘OJoù•ç\  Ffıfa3‹§ƒ‡ 9-7ŞJɃħVı,_ˆ~„>†<Ħ‹ĊFíÔÌÚ£ùısĊj—ûiŽ^ ¨b?ż’`˜$‡èŭ£3û)‰”p yËWff-›1×S&˘°ÁĈżS{E™ŭħÑJ†Ŝ@ÈXŞZòb4óĝ§I‰ï<`?rĤKĤu#Xôם™²ÙP +u‘VûAċFÏġŞ%îÇ7î‘oĝÍ4ğǀM\0]”€ +$Œŝ!Ĉcc´q- ^ÒkÉI~Ħ i›Ĥüöĥîâ›ŬˆĠ4ÎÉ^ßÙҍx‡Zıóğ}b7öyŒÙkeÓ²a+HÇL•›äiĜH–úùX“81ÄñÄÀ”8 ŞÇ Œ†^·"ä§p’g˙›üÏŭ +endstream +endobj +1277 0 obj << +/Type /Page +/Contents 1278 0 R +/Resources 1276 0 R +/MediaBox [0 0 612 792] +/Parent 1273 0 R +/Annots [ 1274 0 R 1275 0 R ] +>> endobj +1274 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [333.993 275.812 364.213 286.66] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.1.1.1) >> +>> endobj +1275 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [497.682 128.814 527.902 140.769] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.1.1.3) >> +>> endobj +1279 0 obj << +/D [1277 0 R /XYZ 72 720 null] +>> endobj +222 0 obj << +/D [1277 0 R /XYZ 72 372.366 null] +>> endobj +226 0 obj << +/D [1277 0 R /XYZ 72 344.623 null] +>> endobj +230 0 obj << +/D [1277 0 R /XYZ 72 250.912 null] +>> endobj +1276 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F16 823 0 R /F28 879 0 R /F23 825 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1285 0 obj << +/Length 3169 +/Filter /FlateDecode +>> +stream +xÚ­ËrÛ8òîŻ-T•…ĝJĠى³‰co¤ìÔÌìh –YĦH AùúíF7(R’r/"x4şÑoÈ­Fŝè‰Ïßwó“×ït”‰,Ñüv”„£$…/“Ñ|9úŬ“B‰@„ID÷UoÊ|QTĞñ$’×Ŝijĵûx5˙1˙÷ë÷ŭ½‚(Ò“ŬêjÓu5ž¨8$~|ŻîÇ/³ù8UŜÛÏW³WZçEE“Ö€ÜÓĠ8L½-Aò²ĴÇaâŬê?àX½…mMßĈžUÓ {R„ş“Ž&ît@™È˘ˆÎhôjM¨ÚñDúҞfy9u̓iġšÚ˙óUjûJċ́]P•´ä{UF÷ ”ĊşhsdĦñšZ·tk4Ü Ïž[Ó·K/›Zù²ˆwÛYR-ÈQ•UHğ?$:oô„wb2!û÷¨DĤÔhĤ"LbZÄ'{kúW-é.žx#WĴó•m*ïhïĜşÑJßÓ\"‹#QŻ‘7E—4> ñĵZR @09 ŜIŬšÖm(n˘Há9îĝ×8нĵ(ó›RğuÈĈuŬ< ×ĊS<™…“ q’½ OyUĠ|ÒEMR˜wGĥŭŭ’Ż5S>­×öĜ0? Í­§.,Ä3ÏOŝ< ½? +F2–"ŒÒQ,S!“`´XŸüŝ‡?Z H‡Y:ş·S×£Pdi­r4;ùŒ>Q2ŽE¨ğSĈç”liĉ‹$•/4“"d¤§‡•ï ġ"d* á>™Óéġœa$ z œ2Q q˘ÄâŒĦ2ġ8#%ßQ‡óìĜmŞ$Yò"t&)´ĠçÓÊ'³PXÓŭOµÏ™ĊÖĵ³ݳÊğOÀœ°Ž’:‚#há&ò†•²X4ġĴeċŭzŝ™fßÖ͚@W_qÏ΄ċ<ÓäŒB0ħ~24ħÑ ÈhçŬìÂF´Ùıb„³:Š"ò"ÖĜñpš€ÌLëLžÚ™Ÿ¨Çċ™ímèï`h#ÓĞ˘ÊKOŻ__R+`„Bj_^áı˙‹?S4P×0t)ĤW—§4žsEkmŒ=P5älò°scÏÎ#…1[d%ĥÁµe‡Cĉ‚ŜŬ~Ĝ; îïa£>΂û9}6V°jS´Ċ_c+bG8²,½À­N #E2"w‰ ˘[ŝs Ó ġÀñT³Ħ@Èg`ÎF;ˆ`uı¨ğğĥ(/@| ‰'´{4z†,ĥé6>{€0dèûWıċ‚½b„ èöS–½Lş¸ĤegÄk0è +1ˆ,Kë ³)Ç)ŬVGX€`f—Ŭ­r‹éç#QôÑáìÉÔêİûâ%ŸâıZTŝ­zÇ ÓÖ é'ÌqÇ8_ô’l eaSëĊ‡şêmğÙĥÔî×/‘ÓÙk•Aw‘[jƒÚšdn£`§Ħ8 ïʆ˴MħhËsĦìߍfĜr.‰%Úp è⟆˘Û1Ĉñf—hNŸMS­ƒ<Ž$C‘€ÉïÒ—Ä|3ş™œéżĈ2ôàJ@ ħç o +KOA?cĝAĤĤc6­iÌaĝÀñKpcíVAôTšZ6Ġ bÖ+,œ4 ]ß ĥl˜KVi`Iß™6›²À3â;o³3Ğûĵ·^˘ùÎ ŬœĜı†7äÛö°ñ€ÖÇĉOıc­ ËBˆŝħĦKj +]YCâqLĦÑ°—ÖrgžÍPkj·lŜ3ĵ½U“ŻAôW§¸°ótaœö­Ĝ́Qc{ß­ĤĉŽBœÚ%]8´/ùµ÷Ž“—(`l}kÓCĞ8–à²pf<ëP·Ú´è¸eicöa]óoâYú†×t”ċĥԆ · 3ñĤŸŻĤŸfâ §żĊDd~JQ bUğóóÙĉ~˘UĉÙùüÛġo8ÚŜ"gN4:ç 6X16Xħˆ­vŝÌ`ıˆ!cëúŞü~šÂĦH†il3YjbŞĠ/l,yÁŜ%à‚žÔ€güu úF!OĥB¸^³ñÈÀÒr˘,M4`Í*Ë:çİyïlGŬĴĤ#yS{ŜPji¨âŜyi΍Thktä ¨‹…šFß/Ümi#Ї_oZjßßÙÍÉ Ş4·ĵšP­Š›&o¨ f¸„—ZɅ9](‹àĊR†w˘t„3äJüž\Ħ¸/Êr狴•“ §ŠÖ‰ì_6Ìè3oçŒ^½Ŭşm+Hq F׍nÑò™ïŭRŠ×zéÜİğ ZĈžÏ–lĴÚG˙Eá¨÷b‹ĉB š‚Ġ-VÂşD{7_ÎAnO?ócâ”ĤҙĦÁ|‚\6ïÓğ ey ߢ‚|ÂMìñ§M{҉ƒ ĥ{uĝ°‘z9y,ÖÎĞʕ r3H#°ZĊ˘e‹4h_ış\俛žqşWĴŠÖ¸ŞÒ2EżŝÊU´K8ÉCĝl†V<΁ç“0ä@ +Ö)~Q³@„ŠE!T“;òç(ÊîR]`!ı~`9bĥk ʧÙG< P=½üIû&úÙ Ĝß0IEšħ9˙Q´ !úÛĦñ .şRê ÷7ÛĊ‚ Çx{úŸMǐ ħ2R/"(q,2Ö˙ŭû‹NĠ{µ[èçEımôžEµ/zì‚MŬ´ğ7³i^½b˙mtËîH· aßÈg˳é²”Sf/"‘YÊÒñ Îìx{or5‡îE)ô}oèœlŞß•­U—ğreɽ1w9(p!0U ËíŜ„Ĝ­Üîžß˘'8ül 9 Q‹R/cĦ”>WÇ.>8uHzܑöH—HzGw'€ÔĠÒ |üOdïÙ¤p&Tê9–íPĝ`›P çLşÔı}’UĠ-·è½A*Ċ(çâiżp†ƒôLİaŝĞÔÑtÓĥ ï³­Š?·,íŠPĝrnc§ÚÀ·Çm$m.]˘öğ'…òJı¤ùHv1wJÇ’Èeŭ kWh´ÙFä“Q@×֛’³÷àÄÏAßfç_)—ú$ĉçàíŠjQn)Ïǧ­j ċ +ĦGŸO° WçlıJŜK[rɋċžùĊäÛ¸(Ž6*Eöó.Er`_ÚŬŸ?îj˜L'ŸdP{ĵ˜­vĊlÉĊìİ-p“YL!ĴlÑ)ÚĞÂîGŞ,¸`#•‡vĉ›-`÷ +ĉ²s‚à{g,^`3eHĠxßcÉÀĉemĞéT×<(’£í‰ƒÀ½Â’a‡˜¤Wĝ…ŽÑ^ô>è +ŭıĤŜ|ôÂĈÜÍĜêä2ñ] ;Vöéq•Ñ˙ʸgŠ˘-ò²˙G÷—#gԌÖ]y'Xž>żNáÊD0>xÚ½' îmCöL6ÌY:é;ĝß gŬXk"ß(ıĉe†˙êÙ½‹Kïċ˘÷ê<³ÜO˘Ôëa£İ…Fżh^ïħkyOƒŜ›'žßòí \™HӔpİh°üÂ˙ñ]tĥ +endstream +endobj +1284 0 obj << +/Type /Page +/Contents 1285 0 R +/Resources 1283 0 R +/MediaBox [0 0 612 792] +/Parent 1273 0 R +/Annots [ 1280 0 R 1281 0 R 1282 0 R ] +>> endobj +1280 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [292.451 385.695 314.923 396.543] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.1) >> +>> endobj +1281 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [335.623 385.695 358.094 396.543] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1282 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [244.077 126.677 266.549 138.632] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1286 0 obj << +/D [1284 0 R /XYZ 72 720 null] +>> endobj +234 0 obj << +/D [1284 0 R /XYZ 72 720 null] +>> endobj +238 0 obj << +/D [1284 0 R /XYZ 72 514.67 null] +>> endobj +242 0 obj << +/D [1284 0 R /XYZ 72 186.411 null] +>> endobj +246 0 obj << +/D [1284 0 R /XYZ 72 159.111 null] +>> endobj +1283 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F23 825 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1293 0 obj << +/Length 3091 +/Filter /FlateDecode +>> +stream +xÚ­Z[wÛĈ~÷ŻéC #ÒXܙ7[vǑ­c1Iĥ$—"b`²úë;3ß,.4\çĦ/Âììmvv.ß,ċ_Ü_ĝ?<ñġû|ùäé÷Ħħ˜/’ ıXn/ÙÜÄÁEjüıĤËÍĊïžıœĊAìÍy‘·öÍG[ƒñÁŭö@Íċ?–?Ñş3cĉ‹8Ĉä`4ù6xñöŸv}ûôF;ö§Ôş:óĥXííז GK³ùĉ›’]ñ[]´äóŞŬ}eÚ_‡²Nì}e™Ŭ)íôŝE§ĵë}µŝ²([[oóµ•fA"ˆe,s½ĞеíuòÏk/?m#Z–ĉwĝü‹zú}6° ++ˆçA¸Àzż]fĦGë‹ÀĞ-]ĜÁ–ğc}¤Ŝ˘FêUMQŜ3;ôŞñÚ˘*Ñ4\ĠĝĝlѽÇË óŞ“öeÑù÷w˘›6ßïs^v~9‹B-w*×ÁŞútsdġȵŭ÷ݨĴ+ŜĉqJóĠ‘mĝİ›&^^nÙĜ£œ’–6^IÇÛèx9$}[†ˆF‹‰Ö`÷Ĵ¤Œ–yu ŬÛuk7WܓyĞS ~Ñ@„–•ûx,ÖtìG•j%ĞTnhšdèXÉĜÖêTĝ÷Ä}óȇUAU‘¤– U4( CoWÜœn³È›w²ù"Póxëte>;k”. ;nGh?û=µĝS9şĜföĴV.è('´èĥèjĜ‘@nò6gż3 46Ŝà(Ëít‘³Én3UÊ,š ĝô’~xÌ_„Ġyè#xâÄ~ÂJĦ!n1Ò8Qò”½)Öş’A7ĞUšó ~ RŬm ÈF‚ŝDTàğH#dϚ×ZÜ#„ż€ìn™‰Fê, &<‚Ċ…{gËÇĴ—ˆN,i9`&ħî>Ŝšo4 +ĵW[Ԏ¨Êŭ#¨ÒN‡‡v'Ù)Kυžĉ¸uŜ…KÖ™rñ‡KdO×á4W§bżx ÖPëçËW7HäÁ÷u~?W1òßwwñ°+€JÜWùF‡jp “ĦÏx|·Çĵe=I¤µhÜQşf× O Mñ/êû ï~xrñ;\zÌâ€7­ÇyX\)ġgàꌧPĦ>ä%gĞßġïĞò~FV{@“‚ĥÜlꌞŠô'ëĠĠ*_á ĞADÑÎ`J +_‚e¸X œ†ı.Ĝŭ­AïĝüŒ˘ĴÙ˘W›OeŻÎĦ›°“šĵö×àĉĝˆKçê˙Ì@X&q-Û,!y· Ž($¤â 8‰ĈUuÍÊ}F…Áh"_óŠgİ@²soÍ•NpVê„ä­‘ÑZsÍÉ}i1ûŜ+XâRĦù‚<Ŭĉ Û} ŝÂ}E‰ï‚ž™ş›|Qd ™q’²3*™r7…N.ÂTġà.ŝĊ†Ú‰ˆ‘/òĴ‚kAS$<‘3W)bż‘ĤáYĴ`?"Gĝ†ZĊŻĴAp +ŭĉĝPÄiŠÑÙêàD"gˆ‡óÊŞĠ¨< +SWΐ°*‡z'Z­\:O^·g#Ò0ċ^:É?aZ€Il˙fÀl˜³¸€ıùĉŭġۛ+Ç=£%Œ-,ŽhI¤ßN4–ž§ ‘ÌLI–ô’A´WDl3ëœÉ$^[­ÔŜ"/Ér 8pgÂÉ4\áYwR͔ĝl€G¸Š1”óÄ‚zK.Ûş²%Âh-\ …,Qê}şŒé4Ċžr›²àQNVT?ħşàJŝ>ì‹3€ Úâ KÁ°ĤÚĥ€ Ĵ ZGö8àˆŽ•äK,ÊĠüLÁvëÖ0Ġ ŭ"Òò=S.šTü‘Ş0tc×ĊĈ:Ñ;lMqİ€ÁvÓN=?ÒÍPu–·öĴàQáż  ĉQâù'ÂÏÎLtSxgÀù+ßo^òÈÍ.Œ‡÷½xÑ͛…w‡ÂJ[żˆçPènôÒċİDġŜĵeÍüÊ"^ßŜ€×a?nÜےƒ>pŭêÍŬ’ß*žŭÌıŸ9Áħ~ä€ÑXIßô× ePgĉf +Ô!´%)ïR-ĠZr°œ!1Ğ*-˜½y^gVŻuҁhj4ڝ`ÜÔ ‘1ovŞkĥıT’1pŭĤl~A¤ı…¸TV­ó)cÙ"&RwN${ +˜`=‚?ĤŻK?LëK Ĥ” VîáLVœpç…&´H^Ĵ›…[ĊZZE2-o ²ï2Ĵďħ‹M÷îċò—Û÷wËùĝZgd#~¸œ%êϧĵàŭġí;€ñpŝYŞŞx`ïq”h•k,ò] ħŸ.5ĉçĠÛ[.y&ìġì˜x‚šv°RV/ÁK‰=ŸŠş*ƒB"Ġ·"·ˆ@úHPı<Ùz€>Q8ŜLÍôh×bʄ…ó(¨ƒ·ÀáŒûĈû²n‹AP +1*ˆ$}’ÂdâHòœGeE £$ìŭ†èÜŽv"24·nô²Ñ‚]15ĴÀ°ò½+&$Ô1 o²aâEżÍ•Ê&ĥI ^NÄÖJĝ“WT'p>™ÈM!úw5šRx=Í^#3G˔.͘áÙı)Bñ{ĥ´–nĠyW³½0"ÜYèĤêq<¸…ßïÌÎğ×9Î6% ĤŜO§éd͏ıêŜ•‡µµŭl×'—ǵ¸ŽÜëóú ‰Ĉùcg—%iš‹}ZFm[·›‹ C ]CR³³Ÿ/˘§ISžî1ċÏEO‹KBĝ¸ ˘‘÷bà]‰‹şäi iŭóe2ĝñGâ =q(Œ†° Ħ‹·›b­"Eĥ$[]\´Ä!×7#&éá#]ĝFëÒÓA;êˆüŒ•),2N°Ñôā:Éàž NüŒ1¸j~ }ˆx—j´d…Ÿ•AWMùcŒ×: àEŞô)Ó§ÊI“›9ğîc7µÎŜ |M}ƒGl¸]wY}ˆ$òü@ÔùcŸ[bâ°+TtüÌż…tW##sɇa`.Ôt†Ž +ĉı–ŜÑ|á§g?Ş%‹D„ĈĜ€ğċ7BxÄœŸÑO)Ì4F_­ +#…™Ìââ¤ŝ65ñÛq•˙˘FUU}Rħú!{6Xpc›u]ĴúBuïéÒëەpO?—^i&?jZûNˆ6:ägÄÂ}c@èPDés “·œ9^Ŭîdqô(‰żĴc­uĦN–ĦúGÂÁbî‚RôͲL˙‰  zı|ò_oĊa +endstream +endobj +1292 0 obj << +/Type /Page +/Contents 1293 0 R +/Resources 1291 0 R +/MediaBox [0 0 612 792] +/Parent 1273 0 R +/Annots [ 1287 0 R 1288 0 R 1289 0 R 1290 0 R ] +>> endobj +1287 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [151.165 476.081 173.636 488.036] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1288 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [326.641 365.689 356.861 376.537] +/Subtype /Link +/A << /S /GoTo /D (paragraph.3.4.3.3) >> +>> endobj +1289 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [130.153 292.076 152.624 304.031] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.1.1) >> +>> endobj +1290 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.791 98.954 128.262 109.803] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1294 0 obj << +/D [1292 0 R /XYZ 72 720 null] +>> endobj +250 0 obj << +/D [1292 0 R /XYZ 72 409.524 null] +>> endobj +1291 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1301 0 obj << +/Length 2557 +/Filter /FlateDecode +>> +stream +xÚĊËrÛFòŻ`ù֊0Ŝsq%’kÉ.“İD²][09ħDâßoż +r9şì ==3===ŭ†3ıŸ8“_Oùŝ²:y½H&s{yÑdu7‰½Iì:ĥǓĠfòÑ:L½Ä*›é̛ÇÖCĤ·%V]2&+tĉùétĉ;•F§…~˜zħ*rŭàş|Ċ³·Ŝ*öUıÛ×Lĝ÷254´ĦĊßËżĝŸÄRy‰Ĵ= h%ÖÙÙû7ötĝžµÌе::JĝMëĴ,ĤŸW˙!Ì\מ‡!_÷!Ës¸‹ï[…!ïûµÏS$…x"…¸^#ĥ6M.ˆĴàÛì~ËNíÊê0M|ë”ˋĠïo—+úĞĉ­İœİäĵoÍÔµ€Ĵkiäô'dµ}3ó}½ŜËÁMĵĜŽ"—orÉ7ÎB/$Ö{};;{wĊ_Ħċn÷†áONè|ĵùüú—Q?ñç?ÈÄPYŽŽĵÁ›˘ĝ><[EbI@5cDöYqÏweĊ×·ÀÔ)#uɸJé=½s‰:…˜‡ĴŜòš´}6/û*kùÔ-zĤ5 +S)Ħ•jžÍdŭR­Fœ¸p-gRŬOĝëÉä#-ömÏö/AÂو2­ó’°FMú +'%éUs9Pd5€hNJï#Ê;ŝ²Î%!•’ıÓFġÓ ‡”ċ@äÓÍp˙‚‹ÂâšeO„ µœ‡Ĝ´œ88†"ZX-v8¸yÄ7ÏÁŠIÖnòÄ\Çä]2Wc0ÚÊô#¨*œñÜáÀşMĤÁ"qÁҝA6„ÓÍ´G+͋éJ}ĜfôÛ skY§ğ=>” ˆHXgA‡Ï8òçU&ì²?à#dÀka@òx‰ oh~-o=“ĵgv‹·c\ßëŻĵDĉ\°îvsâĉóg6oÓâ^NcŸŒÏ,ÚÎUÜĵŝxŭ]Ċ›ġž¸'TÍ8Âg@“pn0³)ùËŝĉ×%еħV¸ĈµödÙì `Ħ8ˆĜh7 *‚¤.OC€²<ŭ’ š<|%ÎU<Ò°¤ê^ğ" oNŠÈqçFn`XQln òÑvG^dħÊ<?Vħ‘âÒ]<Kh,Ĝħ\C{,!êmĤjE+dµÙ\ôv×ÙN-(Ô½Cu`"·Áü“¨Œ´³)Ô+s˘ğħ1 ò×Z=PŜ@Z=‚žçŠŒĊcÛÜOÀXÌ~Ì3/ €ñS 0vUġ„N,o £ËwïWÌ: Oo‡a‰ĠrvÙMŞEÎpÈĠàâc’Ħ@B…'lP˘ŬZgÂ:›ÈÁMĈ*?lĠ>ìİ}b„@ŝŸRBŝ·Ñ5C$9d+5\ér'P ÇV†EPÏòJwrXş'ì·Z>rk<^wŻ~‰ž=S„YĉzÏ9€êħ†‹jÜAöÈK/Îç-#kĦıp‹·§<­ĊÑzĠ‚yg  Z–oË&ßzêd- +JÉ$,#7”HÚρcI}üî8HÔ[zvœ8Àä0Ĉ@ĥ)ğÛv”cO˙(äx?rž3[¸Ñ‹B΍qó‚77—üsĞ'ş y`<ŭ Jì}7è6ŽLü oyŠ5@(…K ÷^ó‡\™+i"¸…Œ’ùQ>‰Óm1€ƒui’)ü4ä5]ĥ[ün”^W™hŒ°œ˙dŝhÖ –CòóŽè{v&LÜ·Û·}† pÙ˽½ıo^ٛ{Öı1ħDd)-gkÚHVĝäġ`ÊNBàÎ6;ÀşSiŬPQʟÈÍ6ŠƒÈ†qàˆáJŒï’ÖLˆdfĵ@ É{€)>l)9ó]³]qçĜ‚aꇵ|7*Ídˁm Dl€Lùcü%ÛşCY’X+ +eĵ˘ÑÂ_˘Í"@ Ŭ^xİiy]‰Œ;|pĜ½ ŒC‘‚•úÖd•Úa%Żf,[‹grzÌóPe îWżŬž]Ù c~†ßŝO¨Âü‚Ê|¤Xò—.@Y䇣nÏÏß-Çj„êț;ÖĤur§ˆ˜ğ4OUj]VÍL=C×ÁĵîĦVšKVDßÍÓâğqeÉ·&­éċ|ÇZfÏP£¤ž ¨ğO¨ÇL&xÀh)“&à +R-žIŽ4è›^ÄŞ&F +‰İ4•6Ż4/CÏáĈŠi´„ĉ` ŸYï=”;‰·n XŸšŝHdċiuŻdç.{$ü'œ!šôò‹Ĝ .ĵ]×*¤ĵ’ |á3Wµï€KšÏŒSfƒk‡żá-lR!!ôPU…*uR\§O•ĵËÌԆŞÏ°ŸwÀ’Û%É iü~şĵbĴħ—g[G”?窪”%x´J“•Yښ°ü)Ê`vNÁ¸-*ö’¨ +‘ÒœÖğ  uŬĈ+X ĠşİiW …4ĵĦİJi7†ğ^¨”\ž9a‡ÒŒ]ú„?ŒaÚt´8˙8ށ8gÚc/ŽzDı‘Ĝ+]şÎ›úĜ[öè0!Bá PÛԋ#ŭK2£˙CGí˘+è|Ï£€Ÿŝhîo"ĜĞY÷ı‘ó\GÎi{…°äIpZuŭ7G,ñÜ‹¤˙*˘Ó+râĥ˙¸£ŝ[àGÜK7ŭ½ñqï­£–ôzoDš*™‘ȰfÁ.SÛĞîÊì5Ħ“†8gDÜÍw-¸œáJ(ÈÓ6~÷ôÚpGŭë Ç€ĉ>ÄKZ\W%ß(lĞí +gÓrúށÙR]pŻêÍHWêÇÚPA߀Ğ|—ğ­CÄ5Ĝ÷ î‹ÒŻgíTZHĈ8 aÑ@äò²¸74À2 +BXa·ÂÀ\ Ç.‰,Nĝ€¨ÌÓÔzH.5§W;ÈnG ğ3“cèî˙‘'?K˘Ñŭ·ôÁ´¤ [U ´NêÜ!Üi ŽĝwO„Y“„7ÚÙŭ½éĊşĜÚ2Ĥ­=˘ĥöˆ$×ıµıüÈdÀüX27žéġÜ`$I@Ǹú֊bĴÀ‘HàÀ•½Ĥ3Ż!ċ ŞéHY°6çSñèGôğżË_ÜÄa°Ñ-ÙÚù]ÇXsù(ÑSü5ħÊjĠ7ñ²–?OO³C +υ8I +ш˽ùmқo;”- % ŝû—ïŝĊë‘E—½ÁÄóĉĥÎħ˘³“D +Ô ,şXü?ÀfO +endstream +endobj +1300 0 obj << +/Type /Page +/Contents 1301 0 R +/Resources 1299 0 R +/MediaBox [0 0 612 792] +/Parent 1273 0 R +/Annots [ 1295 0 R 1296 0 R 1297 0 R 1298 0 R ] +>> endobj +1295 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [495.79 639.826 518.262 650.674] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1296 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.873 387.656 128.344 396.457] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1297 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [217.372 269.375 239.843 280.223] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1298 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.617 202.098 128.089 212.946] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1302 0 obj << +/D [1300 0 R /XYZ 72 720 null] +>> endobj +254 0 obj << +/D [1300 0 R /XYZ 72 374.924 null] +>> endobj +1299 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1309 0 obj << +/Length 2819 +/Filter /FlateDecode +>> +stream +xÚµYKsÛFëW—-¨Ê‚ñ$€½9–ähËħĵ&]Ù²“Š(ƒ€V´ż~ûën€Em˘÷ ħgĤgĤߏ7ı›x“·gŜż?ÌÏ^]‡Ŝ$s³i0Ìד$˜$çza2™Ż&_œ÷ŸßÜŝt~ħ³ol-İ­¨É˙múĊ‹½ĵxñچ&|n÷MĞ ŠìEÁġçżÎ˙ñê:\îM.‚ÔM3_îĦÂ$sŞz…›$uÚJĤvuµ;'dÇÖĊƒ,•YÉbğɁĥ#­ö…¤ûĵŬȒ2Èñw~á;zS³3KĞ÷ŻŻĠ›Ĵi€İ2/ÑҋĊ9]HüËLm—D½REİ÷#K†˜żïfq,üŜckµ/ÀF: aƒˆúmŸ×vċŠÔ‚#ħ…›ŞĈB7réôcÏy³1ċ]^Ŝ_D))ÄïÔħżçMÛÏğœßüä²80$ÙŜĠfûX=AşÓ(Ħûĝ˘Û]›W80œ@~rĥÛMämn +ÌĉŸ>|žÍe´µ%ĝŬ³$.ş³G1EQçŒCçA$6…8 ^ÌV4@“U-żĴĝÄYċë™çĝ=p޽Ìı,(×.¨G¤ÚÂ.;ĵ°³(ÚQ)Ә]2%íÀ°ˆĥĦ~§ÊNó* |×Î4c–… 4[…`yĝ5‚ÚiF+ù…Ŭğiâĵ^·ĥTÌ2ùƒûô=ċ%²ĦR°m•7ğ° 7=öv×ê`ağ:eş,oêäÀòê£ /ŒëóT5Dgçó/AĴ­˘(ô‰é’]‡lÇ +Üù{)JÁŞŭ½haÊÒêıK£¤,Ĝt÷äÀ,Ë*œ‚˜¨'Ĥ šr%À&żÛ\líĥŞNq< ™|ĠĴV9 ĤŽ1Ŭ—8›*_²}Ħĥ +`ċÛyL7ċ…Yöï8ŭìj~öۙO—xA8NR7Ì˘Ér{öċWo²˘y"ĤÒÉ=cm'Á4qS/ ¸˜ÌÎŝy´:uƒ0ûoû Sĝ‘íœ †îž$n–¤tRĉĤÁt”B?Ħ`"Lq”ÑHĊ~IseUo;q eÉH"0?b? 3fìù<ŒEGnFE~”¸A4£HԉĤ%„ñ5…&a­ŬÔĠŝn£ƒJĜ;â7Tûc{è˘˙Íé³Isnòż Ş'á/œüԍüô{ĝX¸ž§²xŜSžĤ„ŸÚ6HFO‹ûÙĎyġĤn4 ż‹aĦü?ÚĠ³)}Äh0}Và}ĴĠ`eë'5ŜĜ²‹Êá!!­P-lk5³j„MIͲÒàÛıfıéa_÷ĉżx~dĠHúê'½ve›ekİ݈ı;C D™˘ Ġw>=›|áƒB7pFéš +bĝÏUİ]:Ïw ĊnĤĵüİĊÓÔçٛÛ÷×7oe¤ġ;Ħĵ)k$ŭûÚĵšµfğkşLÄnH6p¸Êġġ²À7-oÛH zZ¸fR ÓĝêP Óìĝ…ħğ¤k­‹;ŠĦÀ„%Œf¤LĊÌ@IäĴ÷…t/*óäÏȜö7ŜħÈ_Š€¤ü!œCùCƒ}#W†]ezĦ$KšĵüŠÚ'áŽÈKe!išĞ]ZĠù·snĵµ fpġ ˜ šìSÁH—Ö½sış ċèÄùáĉvvêÀÔĦtJ’—ÂÏw4>çVúŭ<ğĵıÏÙàiSW3&TÚ­@ÜĥaĤ\£éÄz\ȕ–’rc$S ìIçKÔĥĤÖN€Ĥ5ÒÊßpÀM”vwÄı-—zĈÀ‰İ,Ô°kîHU݈h4^ +¸‘Ö‡Ŭ[Ä+™áôĊ„N$…ÑĈ$TÎiĊœâ—j:r1ˆĠµ0=è1ĵÏQëĴZ™ê[S ¤0ݚ&§j]5˜M%kÒ8aïÖĥJ²Ä½ ŭ*ùÒĴĜĜ^*òĞ, M8rvON£ÔíŸhR4xPdû|I6ôR"áŭ&—`ĴeеĞĤĞ`C%Ĉ1wżSvkMGKeŞ‹×ÜRï=Ĵ./wFb·`× .Mk_Íó­FïFBÙ8-¨˜ŝì U‘f;Ž]–#€ÏÑöqó=ÚBIYCĜĴ³8š÷†ÚktĤKEôÁKùĞ’ELBŬÓÌY ñ’¤ÇˆxÚüYô&ŞšöĈíäx'R\!áCŒ‰\Ç×ÈI"*Ğ=$bLÍïWş·%äĊäÓ(цċ‹#²°•ÉQ¸§…G[Caxj ‡·³>Ì‹ï ĴuŜm½\r¨š<$)sö* äÍ݇†jŬZNhħ†·Hž(çŽ4ċĊdı­­·yİÙ.:„ĦF×4jᙌE§ôĴ}ŬcdûşĴŜ։.Wk"Ž?íĜ'eŸ ž}ĵ3µzäÖĞJŬ…‡À™ràL4pFH²K<‚„‹?MAĊ60[+~4KŬ}ÛĠ_Ĝ›÷o¸Ċüà‰Ñ}·Š#I€8:ˆà·VĤÇBHˆ}HÁ-zùÏh'¸ñâEëĞżı— í5žX•,1LISĤq´˘¤"†#TN€);)´S4˙TÊ,Í2§/óĠha3FSġYÎ_•L,LC–Ċ O÷ïL˜áœ•ÂWûV0Ír‚}1DJ6XĤFÎGJ£˘ÑíHŬŒzO=˘nZb)˘àÈ!‹YÊâAµĊò: àúĉŬ•ˆyŝQf8äÓï@³ŸŻ>È,kżûşT|ŭĉxŻ(ĊĤmİDß·V—XTôğĈ£°ĵ˘ĥĊÉG*ġLr0ġb°ID³ï=œÖ à—Š"ï,Ú14;Y&ĠÖp^FR’†áĦÚÊ@*Aên Ó+ˆ¤WöOĊŝÀxâZIHŠŠTx‚Ç#)µL™oi&û4#&LħX"Ğ`ñ[,ş•ġM`˙€,΁ öĤènӝRŭÜĥâEħ£ĦŜRħĜB|ÂgVOüŸ˘£H™&¨43 ċİDpdĞü`%À#c%ȕ%I/|Ͱh„°CfQ¨›jKZ&Rf¤OEhZĦö…‹Ll?|˙H'kşuWoԄšz’ĥkgQöu-­ÑŻ){dàë 5Î1l”İ­è*?Ó½ê î ‡wFï 5ևf\Ê[’PUŸŒK7­|6ê²)šîë×°âÖo^cE1:İŞ ˆT‹uĝP™‡­˘­îHĠ]ï² $Œ÷ğŝ’Żş“Ul•Â{yçè)äÑŞ“N+ÏjĦä˘ì6ßCLD)û2g_5 җÚá ŜA‚A§‹–ü~’7QE×$¸â¸Uò‘š|g-0wJġŜÒ9ċĉŭlyŭN_+ŭŭu‚ĠĥŻíċŜ c– ħ³Â!ŭÙ=Id–´ĥ4=èdôħÁ•uŬ‘‘Ô;aŒOj2–#[–wì`ĝ R>4vBjö­TùµÙċ+ÄĊ`ÚGqÌKyOsÌfûà{Ċüé8ڂñJĤFµ3ψmGJÌ!àpdodĴ__ùëX(ñŝ0ŝbï‰7Ŝ,Ÿë şÙäĊéú[=ßôĉ §Ñ™AıžŸM.Òİ›%ÚżEééj~ö`g +endstream +endobj +1308 0 obj << +/Type /Page +/Contents 1309 0 R +/Resources 1307 0 R +/MediaBox [0 0 612 792] +/Parent 1273 0 R +/Annots [ 1303 0 R 1304 0 R 1305 0 R 1306 0 R ] +>> endobj +1303 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [477.868 488.243 500.339 499.091] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.2.2) >> +>> endobj +1304 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [450.078 430.01 469.782 440.858] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.10) >> +>> endobj +1305 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [478.435 246.704 485.409 257.552] +/Subtype /Link +/A << /S /GoTo /D (section.4) >> +>> endobj +1306 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [475.73 167.999 495.434 178.848] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.10) >> +>> endobj +1310 0 obj << +/D [1308 0 R /XYZ 72 720 null] +>> endobj +258 0 obj << +/D [1308 0 R /XYZ 72 653.313 null] +>> endobj +262 0 obj << +/D [1308 0 R /XYZ 72 475.298 null] +>> endobj +266 0 obj << +/D [1308 0 R /XYZ 72 449.382 null] +>> endobj +270 0 obj << +/D [1308 0 R /XYZ 72 368.691 null] +>> endobj +1307 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1316 0 obj << +/Length 2852 +/Filter /FlateDecode +>> +stream +xÚµ]sÛ6ò=żBs/fNŒĝ%’÷ĉ(vڛ¸öĜîôêö`ĥ8ĦHHĈVïÏß~e5½i&ĥ€ŬĜ/ì.—³§ÙröáÍR~ßŬ½y{ĴfAìGñ*œŬ=ÎÒp–K³ğröĞÏA&ŜŭíûĞÛù"Jï§ŞĞÒŬüßw˙|{‘Ír?_…+\½œ-ÂÌOó˜ßmŞÖĴBŻÓE_µ N"Ż}dà~f^;†ŜßΏ™Àì§N›ïdñjrP5JŬĤz˜/ÂÔÓúfâÏó$ñ”İÚĥäδOFmeğ²êzX>ôşdÀsĠoìäÜTrŬà-ñbAàçɊ/Ĥ rËCŻi{”•+Ö{žmShÓƒ<žAˆ^ç!>€ŻšWu­P&ŝ|ħ +— +ÙÒ9,̌jžñhÚ­ŒTe,ĞÚîjÍ| +$ĵ­jJ`ĥÀq ƒŞ‘JS}Ĉ;iÄ4“‹%|ħaÔí"ÌW^ßòo×î@•}U(Z˜§ŜoË FˆF~4¤¨Ï•i›-{Fı@ï‰¸OÑj·ĞqsGòˆ£;ĞkĈĦµY6Âí XPzĵĈ &8ŠAÄëĞë_^Ǜ(ò£4ĥ4GñÀÁùÇ(Ž P"ÈoO +Dߙ` 8¸ğ]À9Ú¨èO°Ä8²ĞI{ĦC`ci ‰ëhħÑìñŬĤÚÙMÈ'JĈwÎ.ï)¸ÎrÁ‰VÇ-IîŞƒ^ŝnçI –è"Èŭ8ˆ˙‚ŜÏÑ1çàcw·?ŸŸ_żVÈ*ñ8p¤˘ÖP× ˆÜZ7 /HˆY #\eÄáD´%Ftñ{X… |µÓCÁ w5şQ[R*ìÉĵ;9 ¸ċĝq?™vĜ‰oPœˆXĞ òšB1B]#ô²İaDñAÊnĠĥ²Ú$ëêĠÖ²“e°§ _fù˙ëùŻ8ÛĊÏYÍw7Żuœd~„§KÙéÒcżÊĤ~duMĦñıı\xÜ;ŽwİÑÔûÏÀ+?ÑK‡kI@ÛİGmîyÊrˆé Êß6‹ĵżĈ—ŠŸĞïO¨(ó“0<2è#[ı‰şŜÛÀ[Mİ1'€ıĈħê7£›żµfzżašµ}ÇlÈ*Éüv˜_°˙‰g~œ%_#ĤÛġĠ?œ0â$÷ÓtòfdĝhòŻS“ïQe@%"éÚ+ö˘ĉî@\³²ÌÛÁÒ1^dÓTÉ÷Nc]HİX†™×ÓPcËSÇÌ`1żá|ö‰ĊŽ•èĦ(wíUIDš†ß˘İĠrDŝĥIÖŭżN<:aìÇ␵£ _zˆ™÷âp’[!r:‰d‘ĵŻíÓo \b¨”†;ħa$>ŭ·V:ĤA‘!ĈĉĥÄÜ)*h˖áĥ‹İàdí•&iïXiaĠo‰òe*µ|ÈT—£²m;…ú!igPĜp³ƒáN›Ċíêä`<ÎvĵX–PR´­~ç>ÔĦçÒ UϐCH ĵêzÛĉ‘<ŻĵÀs|ÄA8­„ŝhöċİ 5K 7œĦAaù𜙧n>ĵ™ŭJDħŸM,ÖûsHˆBïgîK%öY…~)ôN’ĴDžŬ$„N}6Ïb[‚gE áWh¸;™p³—}[ŝċ,1‘ü7™tCé0²ÈEdYŭ–ŜĈ?ĠÄŭ#êmÚ7ŸóÓWy˜Óĥj”MÌ:ñl§-u¨³,ĠíùŬŬùÍċ4—~9³}­NûìµĜâ&…Ò¤Žb¨$Ätc?7ġ˜¨Ċŭ_ŝY·ğy˜]Tġġĵ?ZE‡F•ż‚SĈÁ’, 1Ċ¤1ÇRƒĤĥ-Ċ4cr†“Rğ½Ú’ÜĈç 0À×+âá%ŸŸœ–ĥ5OŸMĠ÷äëÀôÁaySÙlA8ĴۆÒpŬúS˙€ı`wԑŬ:Ŝ3f^R},M]Ĉ<8TïÌPÈòËÖ<áé&­dÊrd]%ÈKŬċqƒë_âŒÁÖ­WP˜Î{ı½QMĦm§ùh/<üİ–é2Hb cħ½grWñİN752&çİ)ŝJ÷8–2í÷q8‹Ù]&LħmĈ ùàmşqĦvêÁù8s|9§/MŸ>–£FpL·óy|Ĉ?ƒmqk³(5ê“ÊejS#ŝ· ŠÏ_Šü—?î,éñúùÏÒk8ĉÉñ£Dbĝ +=@Û üşgdÑâÜŝm" {ÜmҌ)äTÒ8İ(öÇĉŒıuƒ8–Ŝ”˙Ħ}à¨e2`LĈ#ù0ċŽİNżŜñAqAÈ! “ïÖgpp&ééèċH÷PġŒŬÈw‹ZÙFÉYN Gq{…é+‡/´q9Şğö”lŬiĤ§Ĥ4ް’N”ĉ&ÙP +6Dĵ%÷ภˆCè´16òóE5ËdLáĈĉĤ´ŝ(˙ӕ?<óó0wÀĠ@) ËÜï3”9ˆ^ċ<³ÂΜÌ&ċ{Xĉ½w3Ŝ<ëÈĵóğgπ­´a4‰:÷΄‘ĠĞÊŜy6ù°Ӊ÷ŭáÇİ0[ħ'b£.³B§:B˙t›Šïu½u[Ŭuô­ ÁÏŠŻÙJÊşuû‰2ħ’éÜeײÀÏ]­:‹0OƒóŬ!/Ö/p²ŞùBŽċĝŸçH=u"G’MĵßGqâîSË3°Ĉz(ı”à†ü`lb4×áñç7éé#ĉàîHV·lĥÇßr×Ûsa|ŒtÑËúGĤ×êP¸Ĵˆ“2˘–ÓŜdá¤R¨ÑGŸƒNtÜfa˜ûKl5Áo–e’ĉä˘óğ7˙,FJÄ +endstream +endobj +1315 0 obj << +/Type /Page +/Contents 1316 0 R +/Resources 1314 0 R +/MediaBox [0 0 612 792] +/Parent 1318 0 R +/Annots [ 1311 0 R 1312 0 R ] +>> endobj +1311 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [117.884 285.485 132.607 296.333] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.8) >> +>> endobj +1312 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [117.463 110.91 132.186 121.758] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1317 0 obj << +/D [1315 0 R /XYZ 72 720 null] +>> endobj +274 0 obj << +/D [1315 0 R /XYZ 72 720 null] +>> endobj +278 0 obj << +/D [1315 0 R /XYZ 72 260.806 null] +>> endobj +1314 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F23 825 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1322 0 obj << +/Length 2546 +/Filter /FlateDecode +>> +stream +xÚ­X[oÛ8~ïŻ0ú¤‰˘›eİÀ.°MĤEètf’În›é#ÑĥPYòÒĤŜ_?çF]\u‘‡}ħÉ#ò\ż`µ[Ğ·/ù}˙âúMĥÊŭ<ÒĠŭvµ‰V›0ƒx³ş/WŜżöU­/âlíŬ|ĝċ*Ë˙FĞòÄRßàİêömßñÄ/˘§‹JĠ¢ħŞkĠU­l8`e^ĦËŜh{ Ô<óN@j{^rP8;ıì~~vqgìUsz;’9ġ:ïEŝRoU_w_î˙ wż +C?_Żù–GeÔAwÚÀĊ’|C8½èmת˙j&WŬü³g˜ÚI~màR͎iĥ#‰kí_\ċñĈ{ׇ}%GTÓh·]ÇÄpC·Ċ/…’Ċ‡ŞİF!ş½ĉÓdŬ÷QNAĥKwüŠ ġÉvĤċ!q‚˙ì+£Kž‘.×` á¸mÍAց*Á U£y>½nÛXŜöˆ8ñ˜ŒġRÑĊUèU°ż$Ċàv˜€œaa_{Â) éÖH(Ú,ikĈ_şìŭEħIœzVw< )j™mSVt¨?I#tJp=ŝĜí•,ż‡MŸü›ï/ +Lß Ìo™BáàóÍÏLÇċgßD!¨šŞV5ÄîË'êĞX0™>`8Ä1óŠÄÓßtÑwšİĦüMY&—ÚĤß(™V5ĵĉNzpà‹Ž Vf·âÁoo_Ĵhqâg´Àe †´}ŭ&šĉ 8ŽüL2Fâ‡~ׁ÷Ql Ĉ ìA{ÏĥFk?Nc1Z9Ê#ïQÙŞàĦ=‘stêÏÁ#yÀù(ÊC Ġu‹ž÷dùSÇ|ÀaMµĞL:´—ë÷“ڗÎßq]YŜ — TÉUÈĥ49ĥFÇFŸ²8˘8ŽƒÀS o„‚³—ŒZí\ :‚S&I*>ž@րœRÈx8êş·ฐ½>ŝ„I- È`e’,ñŝ! U ) ävl'šÄı*Kr Xét€ä×Ĥw‡żoÍÎIGžƒ4Ô{’Ín•J•Œp¨:4D’qâÏ0ñoOĴW vF5vKɧȘȤnüĈÉİàêvÔüKŝÈ GÌş=öµ2Ë9·÷wW·î|žĵލä‰j×Ë%Cġ'X“şĊš¤žfe’M— `0֔˜4Ñ~›Ñ~°„í' k–CgCH̨Ёä‹£ŒgsÇÄ/ßyËô4NĴË9J‚>”$ş.iSCÊàS!-ĜÓ¤è´uğ;Iİ,LŽ„Yş‰Ÿ—nB?=O7—ß=qaĝPI޳=TñʓöĠŒ•ûż~gé'ó³ßAiaÚü0€ÇuĊÚCê3°û0ZdÒ +SÀ€­9cĴŠÉJR&“…KÁìwÛ5ċ·\İ`(É4]>ŽG—€1‚ Ug~I +ù„—"4"w¤‡ 4O{nß0 Ç<|pµŜpK”1òaò„Ħdb4(ĦH†ÙÖ´ĉĊF4‡³÷Ĵ\A­#ĈzWš'œì`MÓò‚i,EÈYÙL’œsüC>iw —–Ċ3!)öp<ô%¸§Ĥ. GÊìúЃ`ê36>jÇT£›BËQ70 ’eƒqq2¤Ä„‰Na& Î:û^͊+³Ż\dD9ĞÉ,qċe ѧ†˙ŽiĞR&JHšĊŸögŸI‚÷óĦ7˙‘PÛ`Ŭíĵ‘üú’ÉñB v 0‚NĦƒ0¤ÒAgÔğOġagµY!Ô/z¸òĝâ“1Ĉ`Â:R͎"ŒŽ+‡ƒnÚmşëúî,ċĵI›ÈëPM°ŻŠ˙Gèc”yO˜s ÄˆÍ¤™†‰˘üS8HËİhħ{•ÀáĴ â,B`Ùàê8ĥµ²û){#ĊRT#â…€&†ż0WÀäô6S*ŞÏ’Ħ‹żŸòžĵ w{ƒl ·Ÿe‚œ˘ ü_Ñá""ĵ~.üŻâ´=IŠ çÜI€81b ,,>4İJry„™„_žŽŬ +ĉyz8œĵcá2İ(¸ĤeŠíñm )›K1Ó˘µ“7­$Y{o. ċlÍRÊÑßÔáXS'ĠÚvPÂé]'Ç<֊™P(=ÀżVCaFê앉icPó.Ĉi×8†Ħ—ċG­\œhQŭ‡9‚‹_ûJw/…Ħ8 šò£•6ÁŠÉÁü&„#IÂ?l¤,÷ÊĠ1ĝáéà…Œğĝu@bOŜñ­a-ìsş•Ò–g“‡Á c >Q“ż +É]Ž +hC˟M”˜ jPXD(‚K'°ĵFTJyğÁOzvH1ç,(uy§@ {˙-żOÀˆñçfíŬW!Ŭuà@ìyéöp!¤ĊĦ Àĵo¨ìàA3àÒ:Ò-.y̚ÓG ¸c䌆߆~€¸(cÍtF%ÁÖPıÂÍŜ2q‚ˆħ+„Ùä)KžĦ2DvZt³‘1:3m¤K°ˆ™ñÓLç¸ uNĝ,ŞŬléİJ›A×ĜŠKJĠTŒroCùƒ5KÊà–(Nf “áŬ ½1\ Bn&%%M‹~ìÜè­ƒ´PĜÔ\ĵñĊ€C> ĝçr=ñÂÀN=×~ +IüEáóżoùÍ'a@4éöÄË˙ĵ%„ ÷~‡~ˆ @{ü€˜(e[th +ۅüzÓYɸò&z2€1S˜Œ˘ F賓iíGñÜÄW0ÙîûŽa˜–œ>œèĠöDk–nü ³’év^#Ë&ËWWqîgÍX³?Ŭżĝ À x +endstream +endobj +1321 0 obj << +/Type /Page +/Contents 1322 0 R +/Resources 1320 0 R +/MediaBox [0 0 612 792] +/Parent 1318 0 R +/Annots [ 1313 0 R 1319 0 R ] +>> endobj +1313 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [302.815 659.283 317.538 670.131] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.8) >> +>> endobj +1319 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [298.484 553.23 313.207 564.078] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1323 0 obj << +/D [1321 0 R /XYZ 72 720 null] +>> endobj +282 0 obj << +/D [1321 0 R /XYZ 72 646.339 null] +>> endobj +1320 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1327 0 obj << +/Length 2311 +/Filter /FlateDecode +>> +stream +xÚµXmoÛHŝŜ_aô“ĵ¨U½Ù– +Ü-Útğèâšuş¸v÷>LĴq2¨,’Ü4÷ë—ɑċĴö8\€À3$‡CrĝŞhv;‹f?>‰ô÷Ġġ“çoòYĞd5ğŜÍÖÉlGa”g×ċì—àm=_¤Ğ(èï\‡UlMgŸaıêF@żFqVY!lvŝ€dgöşŞçq`öóE(­ŭĉşŜ–‚uġÙÁ((m×ğÚô݅´ÖèÍ7Ç^ˆşĈsß5í~,Bĵq^¨MoöWß +ü~žäéĉ˙ıŝ‰Œ°ˆ°X.E]³íŬW Ħb’çğ~×k‘*YŻpl·V€ÌVÀĈŭ*,tÉ—ÈĦvkğnwĴŞċךşÛÙĥ…ú 釋ĉlĴGç‹,YïÁĠĥ¸ËÁœ·óöŭ#Ŭ\íHˆ4͂{G·Ñ*U£Ó˘ĦU+ËîĦĈm½ù&{zm:z/Gty ‘ó <’n/pàVŝ÷ù›49Wĵ WE<£Ca^$"ĠĊĠûOóĊ’t‹£˙ĝüï×áĊĠ;áÉÇJy-£àgÛvln>F²ĝ•PdÙ|ŜĵÚ$ž²ÇEsx`ŸċEò‚î&}V´aŒWa4 Ç<–a’ž³YüSïztœeü`•ğ€b‘à…üôü’}/Oaxġċ„|m(.XAW·{`š MTġÚĥiÙ­Ïcz!B­q5¤Ê–…Z4£(àÒövÛ[xS)£°Ä1ŭ@"ô2ÄHô3wZQPer­,%Bħ:E(h7€rÙŞR:Á–ä{ÇCċĥd¤)slĦĈŬâGÄĝi–5ġàâI4ğ¤œÄ–ĉVlg ÛZÙ9²D–’až XŒ‡ĠĥÙ G3È4ž’à_ĤëeġŽ<(ì%tIP’ +,Ùiqö†£Ş‘Œ‡„nBá³'IŠ\Ÿ¤CÒ À}ê’M ”ÁOPŞ3A‘hİ„‡–é•MœfƒıA‡KìíS!ñı”ÑëŽĥTŽüÈ iíÖ"İÒK–#r‰ÜêùÖvQîĴPŽ^é 7McIž¨ìùİhjĤùpù<ÏN£ëàJ\tgwvÈú=‹˜…á4Í-›w|!>V}§Ĝ+++q× d‚8·0ŞRò?1§ĊÓgSï}çäñÈÒ$íŜR-‘egzY8,ĊZS•ìíEr*Ó´ĉÒЇ8 +U gJ>…÷†[!p£µĵ)³ˍ#—|Dcĉİŭ™˜ÌX6 iŽ*v;Ò}+İškU#%¨î' Ñe%eh 4FeĞÏJ]ö¨ż ÌݲñˆÄ@ÒpĊ  ó°H +‘%‘eT€ŬŜUg2ˆÑrPü”“òà‹`ıĦ"ÔŜÀŜXı`ŒlË!ÉñvPftv×ùI2i ĝ%ntžr§èğ 6Cô>â–ÈÖ§cï?"aĤŜĉ%˜ô}ë¨)ƒ§ËàĈġˆ´8 Ŝîbäçŭñ\h}pèƒ_­:ì8\R•]D@;jז5˘W[KÖKµğJ—'N>Ż_Qòsœ6H–?^֝zxMh˙iž§ĠÀ×pRa×Ü[áĤİ÷Ù)9÷ŽAĈT÷ċN3%Y;ÍXS.êJ ú–G”ğ +òPK²á&H°wFo–c­²íl€H?òbµ•j*4 ˙´ˆŞë>‹u>—ÑĈj(nÈxB´Œ1ñ‹fííL~|2û…y$aĤg]%]†j1~<PüġF' +ß´•³-êÑ:óšàlËü²ÂƒF×ĥ§ö_{íp­”ÁbEmƒ˜Ż†“UàA*HëT|üÑİóm­E‡ ñTyFĵZîÄşÒŞ¤fŞ +ú„škçKş·b§L›AHwJ<ÌmMÎq$Ĥİ{)!9f‰…s³ġŜÔµm)BVQ,"˄´·l@eŬÀ£8“ˆ]”Ċċ÷"ȍMr1ׄ³:µ–Ŝ„ÜQmŭ[d‘6k…O^êï^jA+ɍ´â2 |é: +Xı,ı‡É¨xÖJÀ&I ÉÌÔŜ:îeA2°=•1"Ĝ›aÌ*ëŬKĥp€OOUÂĈ èf§Šş“=¸\‚ %)ĉBż—M/‹ğĜ7£q<°£ %×VÄhsĈ(‚·ÜÚŝÑiÊG +â8£şÓ;×H÷ıĤ *Pû:üʞ (Eâ#z˜rG5$ˆC=ééĈݎ˙Hƒ´Ï˘È0Ż[í8}=/eñħ“WȆ´ċ!)͟‚qo˜M"Ê>8Ì~~7Lµ²xŝVĤÚá\Òpû˙jż×żŝ˙öH‹ôÄit‹…N¨Ücuٜ¤*í˘(fóĊdġÎÂúŽĜkŜzġ1^QèĈQ4š´g“ñóÍx6žRtÌäŬ狿dr9i-6ü˙(ɘÉç<úK&›ßOèÑıĦiâ–uTg|÷ë´5ĜüÌ H{#½D§ÍíYĈÇŞ‹ÇnÜ gT‡öüĴWδ TٌÚ#Ğî‘0×ÎvžşıœÁy>“GJ§TäġCcĈaB¤1–jÒëŠĞb7mħe˜Rŭžaµ?7ğÈ`:ÊRh+ŠT2 +0ÀRÍŝ„ä\ŭu¤2K½ûM`ÎD·=v}³w˙µ²½€>Wĝe”Ğ’jdfB„ì‡oAïNštŽ“&Ĝɝd7ċĜ¨’ĵ9U˘=YŸ0hÒĤ>ëáĞHŒqfgŭĦeÄ~ÛŞŒ³8 Ž|^‰ġığhj<ûíÑw2À~ì]5|&u![êîE–Rˆ\-8ßÊ1o˜ +\İ+ù¤cPY‘ġÑËcQûJOüL>R< ]Sùœd’$ĴoJ°ü˜/86qÂġs/+~˙ÄWŞdÜ F;D ĜUg=;|nŞ·ŝF÷ùa+%öÎ_mݞ_µġğ.ˆ~/Ą֧oSé™ûz7Ó/ĊâİÔêêĜ,IŠ0Š‹Ùb]„Ğ\n‘*2üpŭä7s;b +endstream +endobj +1326 0 obj << +/Type /Page +/Contents 1327 0 R +/Resources 1325 0 R +/MediaBox [0 0 612 792] +/Parent 1318 0 R +/Annots [ 1324 0 R ] +>> endobj +1324 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [194.485 462.466 216.957 474.421] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.3) >> +>> endobj +1328 0 obj << +/D [1326 0 R /XYZ 72 720 null] +>> endobj +286 0 obj << +/D [1326 0 R /XYZ 72 229.9 null] +>> endobj +1325 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1334 0 obj << +/Length 2787 +/Filter /FlateDecode +>> +stream +xÚ­YKsä6ûWtċ$W5’H½ŽÎērŞ<ÎÄN6ÙItKŬ­µÔ‘Ôñĝß/^¤¤vÛkoù$| ‚Ċz,~< äû÷Iß`.Òh‘†ıŸábı=ùòW°(€ŝÓ"Už-îiÖvĈݧ ´ëĊÍÉçƒġAê':yn=Ì ŭ<Žeù÷·'ï?f‹Üϓ(YÜiêçiœ„~¤ÔâĥX|ñÎOÏB•¤Ŝy·<2oSŭƒŸòôŻÛŸN.n',DQN̽ž™IûIIžû|IŒ CĞÄğ=͔Wöé™RÊ[µ7>Vu‰-í]|ĞúĦl–ÏHĝzçfÊOĠ[(*ÉR_E˘¨K0ï²éw§gQê•ˁEBáúgÄy5?sqÒO³7QXû`j,ΈwµŻ‡jÇÚQŜ‡v‡ĉ÷Œ4Żfg.M ^½‰rċë0bi>‰}jYŽÜĠfYnËĊ=UĞı1‚Ħ˘1>§şWs;V§~–…ĴqèëX4÷eUı÷y_•3ĵżö9ë*öó0~ Ŝˆžn€÷8 áâ—ġ-Ü<"l_ĉKŻfk.U¤€½·*‚HĦE!ż‰ñŭvšiŻìŞĠsîóZĉü‡‘o˘•0ö\´òû1ˆ´sŬÔ˙·˙ĵšßqCÙÉkBöcy£Eœ'~J úˆŞkÁÜt{ĤÄFâŬuUıâf˙À aIżŬîı[cü*¸mî d^‹óí!½jĝ{1˘jş –Ğ[/¸ñˏ'‹/4IûĦÒ›·›ïNÏâHC i÷Ìì=¨ÉĞNCŻyûĤäÀacÛR?˜Ĥ0]Ák۝eN8“+§ )ÊşÚVCÙÁ‘* <Ÿ4ôúÚô!U=ÓxSc/`sŞÜÁ°arßîğeÉCÀ7 +H ŞĈ< eħq´ú3ġ’Fċ$ÓÉöĥéxYK""aقfìuĠ”ŝ1/QŻAËѐıUrƒ"y6ç€GPd(݆ëˆY`C‡ıŒEŜŭĤ”ÙK ›U³ĉeCËĴ hċÊ@¤•N'&Ê,5êbÊDä]Ħ&‡ĥ{@€ñOÏ xf‰ĥħ™Iœ°Ä˘lrQÒ8/h`ÙUw|…8´Ìá |­É˜ïIœ³3Ywf·éérߌĤŜĞÈϒœFSŽÀ˜›8 8QÁ |PD­½kgˆs? Uè'Y;ÒN˙˘ğUä˘$X´ ¨–fÀÁZAżĴÀCì…^ÇSï8£Ħa—şYWZħΔ8­²˜€„Ñĵ€Šĉ%lÈĈ²@*8³Ì4!j'? +ĊUyhnè¨sżİwı[´lŸÚ 3Ċ¤‹UÇÍǘD°ô½„Ô—ƒ=:nJ;q'ÒĠ·§a +§^BlŠU]OħÀYŝ•Xlœ€9Ĵ°8(_xşÜï(²€ĦÏï*òDHÌǕo‰· „À×-ĵħhċäĥˆ‘p:Ŭ"nò·‚‹Ü(íĥfàUî€éĤÓ“_N ƒ‡†JÈS|ç£÷Ö-`Öç{ +Ĝnáğl›˙ì›ĝî+Â䑛`„!°0”z2ĈĤtĜÚşôüÊàÜeM=şŭhÜġœ?Î?Ħ½ë8(VEyTfŒ29˜HµċÚ#WŜĥ6-]EÁƒíŠżĤc¨Ğŝa_ͧŝşĜÀíÙĴíž{à™èì^Aöo‰ŭ|‚ÍĜá’5Ww+WΐŒ£×ÀBĝRğ$âêAdz][“½€”‹ıKÈÉNa["B>3lÒ§†Ò€ç…DŸéjŝXhĴ=˜P;ŒrĜêJ6½§Äg˘Áû_ï;0Á#òġd-ë1g~I„¸”kî7í=Ìi„.ŜD­çtA–IˆŜnwï0EÈ­µ˘í€]}gí(&0Pl,èĉŽ$£ G£Áèzáo9)›cŻ3cPt2ÄYƒ$áÚğІž‡íì£/">ñŽ{ìÍ´ħ‡‡‡7­ĵӘ0i但3 ıï]_ŝ½Ÿ”ÑŠĝċÙ@$ÙW Z…“' ê>™@ŸdÊf·li<Ú@ާ&£’BƒŸĦ`;(ŒĴ25À@ñpFġ ƒ +Œ:¨Ĉ3dĤۍ2Ĝ3 ġÂÙLÏ.ğ&xÜuˆÍħћ­´h!}[/žÌ ñm ûNlkvsèH Ü­÷“G Ìŭú`úġ™N-|j5O-†£íĤ@ĝ÷Í×7L+ಠ³X ´Ĵ8İĤ^7hĈ:ĉd >lJr‹ŻÜeÂċQƒÚı€·SĠiNŻÔ£aiôÄw÷Â眓]³¤xôġàóç_żŻ!‘£Ȉ  İçÊf’[ÇäÚ+VünZ!ÏNRDLÜeKSß#Ġ ;–ĉ2âg\4z¨ċ—MLĠQn­RyĦĉ“^ +8(Êzéy/%c]ïAۆÑ)“,˙³$ĈIÇJb.Nı€ħwʔۄf\ògĴrWÂg[šF(“ÙµEœ§@Í·Ê)|2Żù0Á_¨ +0´û‡ÄËÎMĥ¨Œí†‘Z”ñà|3—0‹vnsĴ7Á>“‰/BÇÁž„ÏtRBTBñ›ĜDYDÎ%9ğ |İ"ÁFĠ¸ÊY(t˙ĜsxìYHĊ6–ò虐·ß¸Ê_ê/ŜıĖċ’ÚÍÁéxÏFÈs¤³çq‹0/Ì{²Ħ6A@€“\ĉ¤Ċ•ĈœBGœS€[=pïéxûıÎâ]’ŽJƒöÖĜX1q‚Ž˘à_—•Pχ5òN˘\ÇÄu×îwrĜj:ݟïÈ +^ ™ëù›Ò$ŝċ\˘==ċ°Oµ%GÑĦĉ2hüš‚Ó·ĉĞ$úéáÒL²ä!³İ]jc*\,ÏGép…QT„ïŬa<ê+ĈŽàîœIÛŬÀkŽûËZ$E3ÇR ¸Ú%Ûwê*‰èQnžâ Ù` .†^˜ÇœÉá.ĊÇ@\ë ;ö²xĤ˜ÎN –ƒ6ÔìÖ@dŒ1ÍZX%ùŠÁ„”ĜjP7O:Q2f +Ğb¨´b}˜Äñħ ˆbqċ†g˙ħĵûÀ×”J‚qĠ_dôħÜyJ@Mìdc–Ç#ÛW‡‡i4û# ŭ-lÎ@!9àyÎEcĥ ìïİY6Ë0 HYšeÚbşR>ya> Dáeipċ_Ĉ_e€Qĝ“ìiŒJS?Ì^étxĤ(èQ›=—Ċ†ğ“ú2qġ%Œvĝœ€w‚lKyßâB¤mı™àż=\0ħ‰”0Ĝ„qH8›İÊĜçL|˙D"UEv!°À¤IÖE3¸jàŽüúà-^+oïÏŬHĝÁâû_û²3̲T^O²œş4 eĦĜĥÄŬĤvB~ PäÁ$-Ì(-$Z߃UJGp!ÀDRĠTC… ‹~ '-œÁ°ŒÄ×?˙!sٜħı„+Ĥ>­vs¤:§ĈžÚ™L™ı9­ÇžħÉï%–½D·Ġĝçoj]]M~Yı×mW0ÌrMü}„ӒÄ×iÈÜÄÑlÒĊíÉÌG½O +endstream +endobj +1333 0 obj << +/Type /Page +/Contents 1334 0 R +/Resources 1332 0 R +/MediaBox [0 0 612 792] +/Parent 1318 0 R +/Annots [ 1329 0 R 1330 0 R 1331 0 R ] +>> endobj +1329 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [333.634 593.784 356.105 604.633] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.1.1) >> +>> endobj +1330 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [426.621 512.541 435.394 524.496] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1331 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [339.103 320.829 361.575 331.677] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.1.1) >> +>> endobj +1335 0 obj << +/D [1333 0 R /XYZ 72 720 null] +>> endobj +290 0 obj << +/D [1333 0 R /XYZ 72 544.974 null] +>> endobj +294 0 obj << +/D [1333 0 R /XYZ 72 409.49 null] +>> endobj +298 0 obj << +/D [1333 0 R /XYZ 72 340.754 null] +>> endobj +302 0 obj << +/D [1333 0 R /XYZ 72 272.019 null] +>> endobj +306 0 obj << +/D [1333 0 R /XYZ 72 191.329 null] +>> endobj +1332 0 obj << +/Font << /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1338 0 obj << +/Length 2861 +/Filter /FlateDecode +>> +stream +xڝYYsÛÈ~ß_ÁÊKÀ”H\yS$;µİÚHkħĵñĈy€€‘8kàâ°˘ìŸO_3Ê´k½/DÏŬŬÓŭu÷0\=ÂĠßż ċû·ŬwŻŜÄĊŞÜ–Yœ­vĞ<^ċQ¸ “|µkV˙Ô6ÚĈÛl½‰˘4 ~œžÖ›¤ ƒ›dúnŭŸŬ?^½ñ7ˆâp›Ä9lOëÚë$e0şaާž"¨¸9>“>0ŭdĤ=S?_ŬM.€Va0íÍ(KùT˘ë +ĥ”ŝŠwô§uœzĞ–{Lg7q#•e{µħĴ‚lÛ2M™áŝ„ +ÎÔL#LZñüFiġ¸]oT’ßËĤI ĝVġd€gà eÂàêĉö=‰.ü}äÓÑN0-{Şĝón](ż§yŭ¨IĝTêCO£F‰Ò’%ġ=#kŭÌ:lzîìú‰ ?ŝeġ÷1ÓvÉ×î÷É }wğ€Ğ’ ÊQ_§·ÖjNGí­£€ˆ7>Ú >UĦg.…UԁŸL‹’ÂÑfĴî[͍ıët­Çħžı£îğħ·£y$&AG$iÊvœ.ĵâDTgRq“l*#Ì­‚ŞÓ¨ v{=Èó^B˘:y˜ĊLĜœ =šîħ•ħş"- ‰=h[F…\6“x[œ J.¨rg ˃7Ĥ%ŭùE„IÓ­Š#‹0;–8òÀhÊ0 }+£O{ f5ÈTù²)Gd]ŠOŽ +Ċ†ÄŬû;à­(@V£"¸$ûs?O2k`hÏĜœŠòàží€-û^ ÜĜá]hP(ü~Ë­Ŭ^ĠòÉ$ħвĊXpU‚ßĵQŸzêêvnd‹Tœ +x–;ŝ½?,,é2ħêšsvhQé`ˆ£.äHRġpZŒŠâ`œkĜsŻ0âf9úÈyž'\AċTûڌñâqÇyàdö¸¤ùÛèħÍ12&-¸ ĝ<] ŞG$NĴôÈg!öYpœh"cMPLBUHüSîzÑ_ŞĤ!ŬñĝĝgÇ_C˘ÄöĥĤÓ£ÛŜqúŠûeï…ĝßğu™ĉ„I‚ÜqBĠ}!Â'۰̜˙­ àA°içou3wMĠĠ(L3÷šœ#7?„ixġ;€Œ¸ó‰RĦĦœ'ħ°ë pËöN,~ÈĴU|YaÈ ‡Ì#|XkíĴenĠÖsËHH{ğ]P ĉÑíÏÄĜÏC}6İaeżJr4\Ǹ@4"8³˙‚âPM5ÎÁ5xwĦŸğġËêĜwTˆvĊPxĥpŸŭS=”)ʚ§'ASnġ@'S4ITñ"šPK=T!)€*mvĦŠĊ/”¤-0şD“YÄı= +úħGAż,Ŝ¨“VaÌ>rU”ÖTyrÔâ‚0°¸ .ĤMĞîQŸG>ĉ +áÑhO³…Ndžô °Íï­ûoEm½ÀLj\Mż7w*ğ/‡zÄÁ>°w +ş0ĝ-‚Ê쐲=˜^1ġúż¤8NsżmĊ*ÛfıCû›şF˜‰ß3Bċ&ħñâ*Ͻȍ'3$ς™QıİpàażÎšó5Ĝ•PÚ{r‰ĠÀ·,hŠ:Íc/uƒİż¤~ Ĉê ”çi2™4g÷Âİĉpl Xs ïP + v3òs şêÀ÷´gȎ 4˘"b#ÊĊd€žG·Ò1÷}7JˆŞ§sVËFB³·Ĉeü‹?ւbˆŜOˆR˜á`£"ĊYäğHü2SìĊ8ó8G[Ê)ĥüi§'Ù>Ŭ\p…É{Q ƒ=gÔöÂôh·< JW„Ż@=Ġ_Ħ-²ÂÂğċsyt˘ÛSYı4m‰ +„3G‘‚-(_,ˆŠîÄ+ # ċ4Ġâ%V™YÏ4ÂҏCĈĦ3Ibenòmʈ>ô3Ġod]žùĈÎĵ錣bŠ =Ñ]žz‘X*U…Ŝ&#Ġ²yÄŻ5'eoËY=f<)â?ÊŜĤŬçŒŭ³· ڝ*ïsĦ§ÉĴĞ@_·LûĈ(WÖV-EvĈ˘QJĜqœşñ‘Z9Ä^b84nŜĵħğëÎâ?…›GÓušòËŬ([ħħĊl wlA;FÀŽÓàz ĊċşTÁîî§×ŻoQ#i={‚ĉ§!wòµçCœn“,q‡l#‰ 7†OF?}êvĦâ…ר£K„sËSœìé­ĝƒiÜ A£3ìĥiÀÌêËI¸y†sî‡ĵ˘û",„CâH"<ŽÛ'¤C˙8Tldœ_ñá’ï@†q÷PÚÏ “µ4ĉn„H˘˙§/ÎĠ’"`~ Ö`‹÷ñBâù +Œĵœ) ğÂ/Jĵ“€^Żĉ5Ä^AvOżñmäÑhĥŒ3hğ—”Ly‰?Ĥ ĵC@×/³Ëx‹“É’^È +9‚|ÎhSÓ>o\1xĴġöxï-ÇĠâv§b[Ĉċ—L†àµ{ É#<çÎü:ÛÜ_oĠ=4Ù2rwµÇ6ë/ì£1Pö5´nÛù/·œ›=`ܤN~C˙Ì­kˆwSu°ġ÷ZtĤ‚dڜSá—À(äWizí!ëˆRĈ Ñ-ğ›ÉŜ¤~” "džıÚDÓ? ǂ•Ż%™ëĝˍˆèH'K> endobj +1339 0 obj << +/D [1337 0 R /XYZ 72 720 null] +>> endobj +310 0 obj << +/D [1337 0 R /XYZ 72 720 null] +>> endobj +314 0 obj << +/D [1337 0 R /XYZ 72 646.339 null] +>> endobj +318 0 obj << +/D [1337 0 R /XYZ 72 577.604 null] +>> endobj +322 0 obj << +/D [1337 0 R /XYZ 72 484.958 null] +>> endobj +326 0 obj << +/D [1337 0 R /XYZ 72 392.312 null] +>> endobj +330 0 obj << +/D [1337 0 R /XYZ 72 364.569 null] +>> endobj +1336 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F16 823 0 R /F23 825 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1344 0 obj << +/Length 2032 +/Filter /FlateDecode +>> +stream +xÚµXÛrÛÈ}÷WyHÀŞ%„ËUµ›˘ı’Vħdİ$z•d¤@bD˘ 40V.}üö )Bĥ;|{fzúrşçÌPNoÑsz'ݜ'ßoĤŻŽ=ż7²GĦöĤ·½(´GJġ†c;ŝ°7MzżYwĜ˙×ôoíĥƒhk J>̓îiž¤wiRÇYöĝo}p}eâĊB'≢ÄoE uŜ÷"kgĵİLWĴsŸšeÚw­œ‡ñŽŠ6ö“°vRp`½àżOeĵíLüSĤ³223K9ˆŜÀSöÈÂwdG#OLd¨†VħîĵĦ›\Ğ„í1 +„´È+V1ËĜ°´*@9²’ô!…[Àê'pĉ`4ú‘oŭ(×·’Ĝh=TâE% ` TïıRçñJƒ1—ÍK´lÔ(ĉ2]¤yœ5nˆG`0şñQĠsܸdĠ¸"D€ŜµG@_ê89µĊ0…ÑsùÛŭA0t­‹5e­ËĜ(À*rÖĴgY:çı °—Z„Ĵ*xŭĥÎ'U½fĞEitÒlœJËħĴkhÛßİ1\ˆÛ镋 W'ŻzżÑ£ĦÉşf†ĠUÑ҄,€u ħá·[•útÄ*?#œc,ïôúĉèèLÌi>Ïê„R‡QÌ_ó"ß8O5Ÿ(^û5Ġ÷,5=yÈqƒ€UIóŒŝ]6n0†ÁŒ!4Ëvï=úˆËDÉE˜ĊÔ›e¨Ĵò#ë8mMáyî‚ä>ÈÈ,ÍáXP§R‰•˜ß-ĵ,xòĤ)(ormb)EÂİÎëĠ ĜaŻè„aµb>>4h:GI˘Èb‡CL##â˜_Ĉ`"›+—mïx^ĴV°‚rÄ3 ¸#áÜSÔL"H‹Ÿê”1lè3“lbfDğL"Ğkè%]ĉğÄş^‚½2DĴRÖ?°—Ĝ´L,;Şt•fqÉ5ƒ,|޵ŝĴ“ŭA(Ż6â/o‚Üj‰Ş³Ÿ§KŒŜqèô]`ÛŻ›S“†*ÀÁÜÄZ÷˘°AËÚ,x²ÒË —™bu†D@lïÌÒÊp³ƒbq+f*£Wâ—p[² xf ´ĞÍNUCNÓijĜÏZàÒfŝÒ#¤*œòt‘ë¤MJ„x’5ďĦ¤ÜäÀ›ÀĤ-ƒ‰şÒ˘b–E½XŠAŒ{Ô¤ŭajÓŝVd>ìÚ Êb%XòEyÓ ‡WÛ]í~jĝ˘+J z<̊8leZêĵ èžÄ;J—%&NtĈôW?R Q+âĵi´neğ9Ö o\ê0¸Z¨ċĵ*ùŜuÓ +eZëĉŝ„°Êû2%…Ž[vR^Hm^çuž˘* Œ‹ĤĈ‹R›|Öh0ÚÓ²ÈG„ïˆÁóĦ[˜ÎP?΅ÂÈbş’Mg¨9t@^‹&†TŠjJP‚4z!ğ´͐Àx2½:L$à˘ èC0Ġ’•YÊ;i^—ċ†Ž}żé›Î£ñîbztˆw‡ê8%8ğÂٚŞìTGî¤ye€>°iQs·Ĉ0QWœ ˆİì§~€ñ"0b^x ÈĞÈşÌ4ñİ"–ĵĠ˘ƒT„ù%óü••íÙÁÓG.àéî€2Ñ&N³ŞáZĈQÒcƒù=|à6$Lá1ĵŭ²ÛgGò˘ÇP\^~8LÎj8²á 4P‘cŬ@7}ßC&[ÛĤ\ì`Ĝĵ’; +ä†È=t´)É& +z—Ô8ş'Bñ8APÂΏíCUŻyĈ”òĴ`EämÚ°SĝŻhCù—Š·@s ĝU.Áî‹}ǗÙîë5xC̛Ċ$­> +ŸŻyCèÌv´\BŬ‹òĦĠ^g|⪝:o~lĝÎnMĥ,üç;şzꎃ D=^Äĝ€ +ĵÀú÷$Îç:Á¤XC6.°—ġ3ĠÊ é+ œ>Îâ…LŸX4Üövö@\ŽòYħĠóâNóŝÔW>lz|&,²XżĞ>}–=Í —eš‰÷ +ùħ|E?bX–çÊÓ¸‰á}nZ™_¸~Cl‡’ŝ;ħ€˜tG6Ĝ˙ 2×÷ûMÜÁiíeˆó?ŝĝ ċŻAçÇU‡ߏ]ï‰Ĥ\·Ö‡â@‡°â{Ž÷<žèqÜì9Ž ì:ž’Éݚ ×nEoe‡7 QFӏƒoù<çÎB›âıôB󂛑K'ôt£Ñ³UÛ5…ğ‹ zĥß÷Ó]ÍÁà§U[ s„Îáëׯ§§çGĥ“ñ´Q +lÏżP"?„Œĵc³1bW7—"ŽĵĤŽà†QÈúžwè ħ?ĵŻyò÷<ŻÏHöä˘ۆqÜGmüĝ/ġ£öüĵ9Á0ÓċĈ7ÁA4mz¨Üı :ÜLĈg™}&#×ßÎ(^ä*ìruñîĝôĵüҕK ‰—ç +w½ żäċüöò$—¨ËËċı0ŒäC ì|ĞĞQ—ĞëÓñp++ï[\acıN‡Ż÷˙'_ûç˙ÍÙĝŬÛ „ïż›Ğ}vàgvèHêĊ->ñ´Ï“³·_b‡XHRrƒCċ½,}z ökµí÷íàí3Ääj²Ÿ’ú +Qç—Ŭŝ…íy#ÛqGÜ÷mߕ§e vvM_ŭ@îÌ +endstream +endobj +1343 0 obj << +/Type /Page +/Contents 1344 0 R +/Resources 1342 0 R +/MediaBox [0 0 612 792] +/Parent 1318 0 R +/Annots [ 1340 0 R 1341 0 R ] +>> endobj +1340 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [460.467 645.778 469.24 657.733] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1341 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [502.271 486.93 524.742 497.778] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.2.5) >> +>> endobj +1345 0 obj << +/D [1343 0 R /XYZ 72 720 null] +>> endobj +334 0 obj << +/D [1343 0 R /XYZ 72 462.03 null] +>> endobj +1342 0 obj << +/Font << /F23 825 0 R /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1348 0 obj << +/Length 2758 +/Filter /FlateDecode +>> +stream +xÚµYIsÜĈëW°|Uh€‰“˘EÒĊĎqĊeçzfPÂ,˘éüùĵ­ħ̀rrÈAšF/Ż_żċ{ ½‹Ŭ…wñí+O~żÙĵz{—\¤nşVë‹Íö"Vħïı^_lò‹ŸœÍŜ\Â0qŜĠ‡ƒrŝĝXTy}İçé LÄħ£;^èìö>â uêíÉJ›5ĈTrŬ3™ödÓħ)şyĉÜr}™Îĉáíí<›1C­{ıŠ“ÔıĠnÛóbÑ^ŝsó'xâÊ÷Ŭ4Šĝ1ĉ“ġÁGDÊyĵTħóÌÏ>‹j'ßÄHÀ-McZx ì­Ğ\6N £ÒĉL‹N—ĊŻ–rişoëLü%žï|ܛê„öñÒwšz×è-oxBftÑ —më†Wžqî›Ç‰<@°Aò%A;Yß´x<^Òµí‹RÖÂéx+)~Iò°Ñw +J§­&'ŻE‘ĴT¤Üp½^” n œJèÚPĉê Ù:ûb·/áJ½³Ğ?{‘WlyüŒ&„ú`B A`Jöşe*şâ‰˘B:Ÿñ?Ó´ÂÄç"75ŻoîúĈ}ßœ¸İJ'¨À¸ŸàŒY?äï :˜ĵ)ŸyRDXÖÈĴlì,­²h;Ħ£Ş‰_ ĊöäÀ÷ĤmġŽòöŻ ‘Ŝ4tOŠ ß9_ƒ +÷×bġxNϨ/pcŝĠ`˘pÒóçàuKüíƒx8|ħ[œ?X~è=äĞ!³7Ħ#‰³ +uiĊ€ğrŜóHÎÏä„7ĝŽ] ˆw½ŝŸ\`F Ers¸jŞ<ĵĊÎ벭ٚƒġÚ)Š˜ÖL¨o­%v5ÛPcŸšŽ'@š +¤™4ġ4MŬ´‹Ĉöé˜54ÒaâĦpni(Ğ`781}M òVݏönOñ`_7ĊŻ5yA‡jĊıĵ@hĝ£½ÍÎ>Z÷y“ï„™ë”:Ċ4ˊîgyÎh½+k’S†úċc$s—lòcIQœŠ)N‘ä5D×ĈT Š+ĉ–VÙAˆˆÖH „DÖÉppÇĜ£‡@A–…Wñ.ˆyĆÔ1ŠNȤ@żkŠGtÒδ<…b›]5Lüìùa)ëŒğ“ë>óž÷UùŒ8Ċ_l\BtAˆ9€Ñ ²˘˜EÂdiÚBrXxÇne³Î2p{“'ӍĴ„Ç“Q ]j˜)ğÎwöLiĥO‘ù¤]RÎMÑ~â)T +àf‘µĵ25˘Uĝ¤ܘYk/*ٚDÚ"äg–ġngòùÌçMÁÁcIĈùĠ+şk "GÒ“¨S–M*€AŽÖĜGu™Àp#>+T Y'Ñúŝ˙ȘÛY,Ïş£~°GÓ +£úP÷ƒáMĥGÉ%9€èˆ­rĝĉ…§³U°lÑR ¤ë ‡ħטıKHfQ°ġ0ì…Ĝĝö—l,€ r3y%„ûÂeG'Ëú#ób#ñüpžžï[τ‰ĝ›ß ;rGÑKMP.duyÜkјŝó +?ö"_R(w3²… 7İÄĉ!^OÑÓ œjM /&r9Ï0b´Ĥ3‰bĊİ8 VċxcO° +>µÌ"9ˆ˙ĤÊäĉûBğIâ‘ıAE²‘ħù­Ì+&2ñB2Âû¤,`x JÁfJ‹ä’CQ8äAd£LĥSò}—ŝÌûŽ#tAŠÓCŝÂXâĠ`>8Uٓâ‹0f àñÔg#/rî·vżá‹Ĥô9G…I‘’âˆĜĞ%ħhD'Ħ‚0ÛQŜ<Żlñı@ŻpÀW0à€£Qž˜!Áċ×MEñ'ò]˜HióX?™u: ‘´Żĉ_ñr>XJMï€Ê’‚Dà\K êÙÂ#CßÖ=˜+{9SëSŞš@Ôò%~ÎÖrE_Ö:Ÿf},ĥƒ,ìÛRÂpïXg…„#ž>˜Ü# ֈĉ‰I È6”Š8GCŝ $V>$eÊÇW’œ ĵ½SÓ²ž(7Ž|~Bè*×wˆĈ<ç;peûcÏıŻĝ—½D–××)¤‰(PaĴüP*pC/ħwrĵt,‡añĵ·r^èĝ*t×á@ç÷żQèĵû°D#t#•~ĦV&ŝ°`ĤaXICgƒŻ}I[FA / +ĉÑkHÛİ˙ŞIâ>ZŬàÍ Ĉéî!ÍW™0Z0GC1e#šŒ8ħ5{Yĝ·t9‰ +]–³K?NŻÌÍV÷ew’Œ,ò7/CĵDĜŒˆÍĝ$0Rœ.X%1ËñϗQB$e'웚ŽU +-ĵv_/µŒÀèŭ4ü˙š’,U"à{ŠŭQbÁ—™dWŽĥ5ž{*ş=OjYëÙ(0ne‰ô7ê!€Rìá&ÔZıJŞ àŜÓĈ"½(óL7ùÌ$pdWHièÒÚß·w7•¸Ê ¤ğI…Zió͵m”â×kwóÍı¨NNżçÌ `ûĵŬг ĦžÓô˜Wòo"Tĝ|ô$IäħĉJ 3q 1¨P6)SµZd½!Á÷ĴĤĤÛŝ'WĦÛ´Ĉñ˜ĈÁùN!ğġƒD;_QG) %Ìm†B ŸÁ‹JP(ô8Ò;Ĥ‰Lĥ˜ĠóeCoSXáĝZĦTrä;\¨wLolgÂ*XQÉÓÔ6˘ıAĝ#8˘ÑÚ"BP—Ŝó­>¤É—4ÙêFÚm­pZ>˙KŬˆêwêÏI÷ްĉ–nZeLÎٙ/u)Ž“ÁîÚëj' Ž-İFîmÍ}ìÑĠÒ(ٙaÑ$!&I?Qˆ–1² ÎĤ Cx’0$6a°·}]ĉ'P,ûŠF’ƒ!r·Ò5MI°„ÖÁ`£ ŠÄ°"Àœ1=Y<İ1ĝ·CK‰ û9"ġyqÌb€Ú4·ŸëÁž |>£ŜÀWĵÄ) n4Wƒ/˙Œ:A#³4Ż´à›ĦC´tĦ‹7Rëtèĉ˜Óşĥ]}鯋Ûĵ¤eŭm;ÛrA€1™{'°2ÁkPía1鞉´µçÌI@rpŝĉŭßoyĝ·‡ÛWıŝŝÖŬüĝí˜pš2oçĝ)˜ëÇñ°Ù˜Ĉ=?A°óĤô­ ƒG>ÛĵÖ Ù²}*WĥĊÂ6?‰SÁnŸuGF&PBİğĠŞEñŬs§|ÙJiÀÑC¸”lM³˜%>BÑT°ÈÈŭv!ğ +Ûï³|ĥ3´Ûŭüù›Ôĉ³ş´ıZú•Ĝ21ßÛ~ĉh‡oĝԘ2żh´à˙*+‰!†´_)A“kïj˙§x\I˘6Ħ7Ğĵġ}V•şI’Ħ(š¸Ŭĵú˜á| +endstream +endobj +1347 0 obj << +/Type /Page +/Contents 1348 0 R +/Resources 1346 0 R +/MediaBox [0 0 612 792] +/Parent 1353 0 R +>> endobj +1349 0 obj << +/D [1347 0 R /XYZ 72 720 null] +>> endobj +338 0 obj << +/D [1347 0 R /XYZ 72 412.778 null] +>> endobj +342 0 obj << +/D [1347 0 R /XYZ 72 251.89 null] +>> endobj +1350 0 obj << +/D [1347 0 R /XYZ 72 190.23 null] +>> endobj +1351 0 obj << +/D [1347 0 R /XYZ 72 170.58 null] +>> endobj +1352 0 obj << +/D [1347 0 R /XYZ 72 150.93 null] +>> endobj +1346 0 obj << +/Font << /F8 826 0 R /F11 833 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1356 0 obj << +/Length 2445 +/Filter /FlateDecode +>> +stream +xÚ½YÛnÜÈ}×W ü²”ĦiñÒĵ9›5d[XkGš1ĵû@[#BRasâòóİêŞĉ°)jlN^fÈÖ­Ojú‹ÍÂ_üċȟüżZÍıȓ0YĴ™Aš.ÒÀ~”.Vċâ³'ĊñïĞżsŸ—ħï{gÇË(Š<­ĥĠrŬÖmƒïÒû-ˆd£6EŻô3Q4zĵ ĵú8Ìş×< éĦi›ċĥè×ÇaêŬÀ°ŞÙ˘~ kĊñRJé½=Î"ŻíhŽú£ĜŜĠê…#˘ŭ?}ù#ċ‚P¤Ñb†B†9évĉ˙éıxŭá§ğ–i`DVVH­jµîIAr^ú›‚ûËÖ*ÖÓMqfŜżPAE-fsÖ¤WÚFOì½dıƒ\À8’'žġÉŻgç¸XjžzĞOÁ’ĥµSôŜġ°QQ£EĜ;ÓÔĵÓğ˘>ÁçÌ+/ñ ħêŞÖ<Ş[Tc§{zğëÔZ•ĵt£†ÏißüĜWb#xċ‹Ooß½?ĞĴ #4úŬ5*d]"cRġ÷jwl[4Ŭ= +…4N ‚‘×d ÂH‚MÌԟş5İÌm˙ë˙%)âpòË%@8?TîUÁ!Ŝ^“5K¸Ĉ@ŻÀ×÷C04ôèúj½Ğ‹Î !ĥ÷úÄ9ҍ°Şħ‘Ĥ8*pAßv÷ԏÖ/´GXƒÖëU§Êiˆe݈À +NŒ%³1ĥşáĠtAVt%I[– çҜll t8[öĉ+£ċŒşìy›*˘iސûT‘MS…œĤ +=—Â*$cJm×=š5ŒB„Ô@(ôĈawÖUĜTàŸA„]!§ï #'Ñ˙h„ì÷À¸B÷sFÁħíË'Iélë{Ùn— qÜ]×nïxèuÛı&úR"yħ8ülż$ĥÓÛ[ĦÉÖ&SÜé„ĵÄ1¸CşiĴ‚“†|’ñĦn7UÒsYé[zş)4=püf›WÈħ1ìx'˘Ĵ=„>¤<~J†ŒÈÁ8á,fbÉĜ00ëuە&_Ûİà…î—[ĉĈʄž£qB£l§}µUÌÛ>ŜĈ‰|]  ˆ8DüÔÁˆĠ“ü§€[w +özĈÙí;@5w 5S…ñnRb=khĴJÁ-żêŻĠ˜EC‹qH[!)]… †ŭİÏce%˜löĥŠ·Ur­ŜaŬ²ßħ6܁OÂĊzè{ç8ÊDOÄɋ`˜rs£†•é݆"”r6ĵĝ,Í5ϳ‚Îók3´èf[ë,3]1'$ׁÈòQ ü=a7ċ—áê~têç§YL}~ĝ‰ÉÓôÜ>+?[u;§s8XNŬ¤m%2š>[µÁ~Ή{9Ş>Î6EĠœ8Ù8šµÇ¸n{ˆ–*g˙ÏkŠ[ÒûĦXgX*è€Uj_h +ÍġdèTˆQ"E(Äú9ˆ­ƒ€­ Ä÷ĥ.6-”}ßUÀ•ĥm"¤gİ•’'ËrÁ,÷ÖívK„*ˈ'CÛ(êF7EmçwÓËu[Œ‚~_ D3‹ ç„ + WÛ8˘%b¤ž%uN°MGk0ɽKs+„˜Álä™wnħz úÓ [­èıĴ6UO-ŞU?Ì0Œ<Ŝ_Ešq&K’–ËÇÎŭ O2&­X˜³ıLc‘í“ùžÙa>~oğYN!¤˙ŬwyW1Jĝú|N)YpÛ-e"ĊëáuċúèÂ%Ŭ`ğì jÖġT‡.ŝ= ¸`cY Ċ—]tñ5s…‚Äİ÷ûLê—bÌV?C AZ­Ğ/µ½WÄ[xˆE=ıË hÔÓëîvĴž½%éxħB[c£Ĥšä|uôÏ#$Ïŝ"X¤á"HrFñb½=úüğż(Ħ¤Qž-šQÛE˜I!ÍEo½¸:úÛd~œ +? Í÷ìdšŝà;HšŠ<Í@_$ ó˙`œ ¤÷Ì%Á4íûĥ(÷ĥۊ˒şċĴln„mo7]ğkJ{çUÚ²ˆK¤ĈNŭ2QœŸžk‹´ü֑™Hƒé¤kxS’$ŜÇŬ—şZ‹ùŠ=Y2Wħ(‚²ù‡¸=JDóçŻÈUì ^‚dxÛô†k€á˜–móӘڽÌwjŝdÑ]ÍĦn ƒĝGhB†÷ْéMî˘Ô%kìrĝìÁ%ƒ1^-ġÉÂşşú?$zlf’|e>„ùŜĠ½îĠÖqÚ@‡Żxĉ3YÍìħĴô]ÍtëröM´˙D3TóÖyŞzŽqòTDŝ‰Êġœà ñ8ñÎ:f‹[éo…ö“Eš*ĝÉS2Á£Ÿĥ#qŞô 5q + ŝ? ŬƒO +endstream +endobj +1355 0 obj << +/Type /Page +/Contents 1356 0 R +/Resources 1354 0 R +/MediaBox [0 0 612 792] +/Parent 1353 0 R +>> endobj +1357 0 obj << +/D [1355 0 R /XYZ 72 720 null] +>> endobj +1358 0 obj << +/D [1355 0 R /XYZ 72 720 null] +>> endobj +1359 0 obj << +/D [1355 0 R /XYZ 72 661.489 null] +>> endobj +1360 0 obj << +/D [1355 0 R /XYZ 72 628.264 null] +>> endobj +1361 0 obj << +/D [1355 0 R /XYZ 72 574.25 null] +>> endobj +1362 0 obj << +/D [1355 0 R /XYZ 72 431.729 null] +>> endobj +1363 0 obj << +/D [1355 0 R /XYZ 72 330.526 null] +>> endobj +1364 0 obj << +/D [1355 0 R /XYZ 72 299.238 null] +>> endobj +1365 0 obj << +/D [1355 0 R /XYZ 72 267.949 null] +>> endobj +346 0 obj << +/D [1355 0 R /XYZ 72 238.62 null] +>> endobj +1354 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F11 833 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1368 0 obj << +/Length 2223 +/Filter /FlateDecode +>> +stream +xÚ½ksÛ6òğ…‰h‚ ÒÓ^Çqœt:M.+s—iûĤh‰JTIގ˙}wħ Ä8ušéLS‹Ċ°/Ĵ½ÙfĉÍ^yüû|uvŝ2šĊnúálu7ÓŝL Ïġ¤ž­Ö³_œ7e“Í—RùN³M\Iç†É~M‹KWÙĦÊêl?÷#§ħg2Ú^³‚@Òı͛ڝ/•ÎeM $R 3Mö˙bÖ Âó%ü°\ùŜ6{„gÖÇŝ˙–ĞšÊıŻ?ĉD˜I—ôıKޏôż­~C-…p “üê‰ ÙÔÏII5I +†áħnèëX£ˆR9ċx EÖ4$ìh·ĉŭÉŜ+ Mê Ĵdċ‰ÜĜW8IQ—D‘/Kö- `°$A;‰RÜߖĈHe'0S$]™zC› K˜ï‰ÄW–UĠUEVó]Ó²_JvÀbİ^àŭ ˙emœĈ ĵÜɊ,eyÊŬê dzĥŭ=)½ž?r@˙t›~p›OÍwWïŝ=_~à'ÏEpEô%ĵ Ï£ÁN¸ÑMŠ‚úñòíîê˙+Ğ™1 +ku×dl,Ĥ(Ż“ +ƒA)GĵƒO×íöbáĤċŽ4œi°Xœ›˙ĝëbñUŠŭçġ„J%û׺Ê)Ĉçù×܍ù$½‚|ß·ÒŬĜ‹Y,_%>ÄfE² ĵ˒u=ş„›Ħh^ËùKÄQúnd=\ıëƒŭEà9ïë|IçĊ\Bĥ›ÇĦ³şùßġġÛiÉW†,ù +3‡ +ò™pL89ĴRî²d_ÓƒH ¸ +Žĵ*i W„½@ñ/çÀŸıhÎ'ëcñb ½Ày]"½D܆t-ìšh—9%{4%ÂJ˜ȌCıÚ3ĉIÜ1э[tíád*ùĤì“ÉĘÈC#&é4I燁É|_²gç@ğRE@‹“ğçá?B˘‡Ĵ|¸ Fœ5íjw„AÒ û ˙ĈŠWdw  Ölh;™´& Ztp6=V—XôU%iÓ~£ÑáĤŠìRôœûmnŬIċLšŠĥùf[À?ş—ug­’EĞÓ*ËÀżĉËH‚SŠÑ­$‡äĥȆY|]’·¨.ÑœÖ.)y¨&-÷lMòħMÒ9IÊ9Ä´ĥ„šBç×ŭ˜ôŒ÷mYŬ2µğ²(Œ‡ß·Bß+×Ŭíd#Ĝí†ġv#ĝ(@(^ŻÎ~? 7ĜjÉ|JÊYş;ûċ7oĥ8ÈîÊ8šŬĴŬL¨Èġ‚ÖĊìĉìż£ó*t==v0é˘èĝi§Ŭ(HğaÈ×ÉUVSQùÖËżûBÜĵĊds‰F¸şž ™2Ù>SÀN{m½ +Û2w‘ï³Sëúgìöt -,•+|ù-,,Á2‚ô€ÈÔړÎû—’ż¤É“EjâûŸì+ƒë²Ş@aÒĥ¤N]šp½°ġi7‚ŞĜŬë—ÜèêŬ ċ~üˆïH ʄúÎ!Ùú{IvİBˆÙ`Ô‚ÌĜäİÀ9튇AAż‡%@{ûˆUް \˜Rİn‡V;÷fz;hjĴ<Ŭ‚è§u˘ö[aĝ +m5¨sKĝ 9^Sm:ŝ‰'‹‘[D†)ü è‹ÈD'­ˆƒAĝ“ˆ­?Ħúäî5–ħóŞGm"U+uZ˙ŭ*ŭĠW‹µÚâ+(½IÌót8@ +g¨éË&q=Œ9 m(GVBÇ0/_ƒš‘œ°zżïRÜd’8}+‡(ôûo•Œ ܛÉy€fĈá WŒĈ“ĵı0"gBr|`S•Ç?!È0O)“§,ż¨×ñHG oué)ŒÇĥÉpĉ$aOx+%iTëĴ†Z³&h/ ”=ŻFcÙŝùVPR´XR×ÚŽĞ2í— /Êvj·pJïkD¸+Ğ>KXއ´Ŭb˔˘GIçjŞ29š5^™(<ġ(ÛN֗ö>ԈĝCé{²JR˙``ò8"Šh¤²eŸ²ôĜ°ĵ4_€Ek-ü°ÖÂABÂŜkžoĜìŬ££'zÜ6³ĝŬgŸĤÒNàvN ݝ7}Ħ!ÜÒh§j,żÜŽ%À˘ú3³"Ó½4х‚肸ŻğÎ×ŭ‘™H 41 ” +LQÁ鋝iÄêÚÁóߏ:"ħ ˆñKú­2@"q $•;ĤrwĴLpLÄh? B(üġħIB~ÁÁ  mCˆŜ&ß}PAvêĈ€KÁŽ*S¨9¨£–r(Pе X†‡ĜĦîŭİP·É0 Ag^ä&“ s“Ħ‘ħV½YèXċ ·yġàO ¨wíßRTk[ĉiöU ĝ€äq–ŒŠ·3e³:§ŸU²Ù =û}s +|SĜH~ ϔxÇnEÄ;ƒ<ú×Îı³ +endstream +endobj +1367 0 obj << +/Type /Page +/Contents 1368 0 R +/Resources 1366 0 R +/MediaBox [0 0 612 792] +/Parent 1353 0 R +>> endobj +1369 0 obj << +/D [1367 0 R /XYZ 72 720 null] +>> endobj +350 0 obj << +/D [1367 0 R /XYZ 72 472.463 null] +>> endobj +1366 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R /F23 825 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1372 0 obj << +/Length 2221 +/Filter /FlateDecode +>> +stream +xÚµ]sÛ6ò=żB“{8ÊgI~i.ıQ$;qíĞHN:Ó´7ŒDٜP¤JRqŬóż]삔L9Ñ][éÀbħßXb×îÜtìÎëg6ŻfϧA'쇞ô:³eǗ_Ĝ}Ûñ;³Eç'ëlÙíI7°îğ2°ò -*\ÜŻaX1‚|kvÌ[·1Mĉùje Z$%aE›*_EU2ÒôžĥŠ˜éDUÌĜËĵ`ô4%È'[¨4.™òĤ(â E¨ ‘OÂQUts/žà.İn™ŽúŬžĦ5ëJ”Ö:Énh뚆ENr”ŬŸg?€qzBôC×%3DY·ç¸J+#‘}™ ıÙEy×iäEh–3IH$ BhĝdğvÇ´ĝLôÓ½£Ú*¸y›£îwL3§] mèhÖ@N€Êíi"JíBD+4ž³\è;'ˆ0êŽ5›~œ\í³Ċ]˘ĠcΣ˘¸Ç)Ò­Ĥ@ošÀíèñnm aĵ‹BH Ç´kżv)ĥ„UT„•Te}”'9ÏhQdÑĵJèôóGĝÓ,„ĊRii2"q“$ÏvI£ĵ{LĊżĦTŽÓèáÓ÷ñÀàTnß*8îÈ~ÀwJġ%ü('\"2ô, ˘QİÀ:ù-Z­SŠŬË)”Û÷<Èi:3t•9éĦµ.th|M:öÑ@ö +Â-CŒe ß%> mƒ´ômàPÓ§—›”ĥVquK—…qó%Eœ7Q–üŽĦÙzFâëq b8‡uÀB°zҵβ¤JtvŬÀ_Ê9òC‡âA[˘S/4†ÎN>…6`­"žˆş–ö+ÚÖ ñT4‰hÈòOJHJósÒsÚ]À”fµ4tÛ hĦ#İf„•§ Ĥ”_öĊRÏ·²™Hp£Qo “¨Sc‚ı*+°Ĝs›RÖ›²˘M&DnÀ1ÉL056á[züİ3Œ"`×´% ŭa²!nġMO÷è{Y Ó”§Ħ$úë _v%!ġEs\}ÙĴiwžŻ´-Î1ÎO‚C‘Nĉç]}î6Ênâ’9 şST—“biİ‘Hí5„"ĉQ˙qÑ+tŠ)be˘Á|ASÛw„r4zĜçĤ¸yWŝú;Ÿı\WIž1ÑĞ"É*–÷}Ĵ³ÎßÇY´bü)Ç1Îg‘‘á:Ğêù‡$£ŭ şgñ‰f°É^ƒġÚ?´Ìô.Ĉ‡’ĝ +Ÿ,ĉPGÂ_ĵxI“ÑÛûj(Œßrײˆ!ó¨ò*J‡ĝµĥk=u9ŽÌ™ĥÙ–Šß%ĦY 7Îù„ô=œ#é‡Ŝù=Ċ1µ8š2I9ŝ@{ Ċ P´ó[H—ĤôZ°ĴOĊb½` xŜ9Ĥ³’¸Œß |H W–;m‰`(|šFóy\–ÈU“88nŝ +‹9ĝJĝšĠ‘„öĠĊèŬ9 Ĝ_â3_Ò¸Rˆ e3Jg¨„ÑûÛĴdŸíY³.Ĉìàôö1'`#œÚŒÀÉuä´9]œ3ġ-FutÚŜ@xµJÂ*ıŸ‘÷ˆ‘j3şzÛ0zcnÂ7žÛĉô~ÜVIĦšŽ÷]r^Ëí“Ñìä[Ġ(8-‡ê@_ĝû8M?BÄl£ÓHD ‡˜ŝá´ 4™ÌÚò4PĜ&wr:ş˜Ñ(Ž˙ï‹ñ(ФŬ6ÑÙôÜżbè#é /°T“Ö¤d&)ÚzíšìĠk‡—œxµ/üd:|wzözËġ˘ÑÉ8övˆıòqÚö›žOg£ĈW53µÏÛqfċw Ĝë½ä¤(Û·~rYÊ\ž7-níŻw˜jn[µV­TÖĉ¤„òÓñáé2Ŭ ›:Ŭá*}҅²f„:ċ,xĵ%ÍŞĠéPc³`ÇS[”êŠ˙Tö(ġ/×ĝ@ ‡ Á˜ĉò?úB¨şüׅmŞ-œ‹ği5E[š'[IÑÚtŻ +j,aLŞ5l,{ÖıƒgdŬoÂÓ3JY¨°XĉiJ§J.l ĵà +“ˆkœÏĤƒ¨ zrÔµ.n7eNK=Ĵ‡IhŞ•L $TQrC&+{USLĥÄ-HÍĦdßo[àĦûĥ7żŻüşóÌÖhjS›ÉĤ Ö­Q …>ĵäİëE35Jie|’ħğè”kS %Hc:²ĠÚc’ɲĤ‘ñB÷8<ŭÓEo :6GÓŬêNÔÖ`^°OI[ڛHÀDÍ*ë‘}à.†;ž-9žk}Àû°äR6YŜÓ%Q7L[›%ş9аŒĈ´t¨5 ĞĤ+êĠċF”/Mpœ™~§Zo7i•ôêKMAÏuyj+ĝˆ;5LŠÍZ?ĥÈñ·żÌĦ)\‹ş÷ëÂ!Ê4A{jäĉѤ<ÏtÈÌ…#Ú$°_`^:+¤œÀ:íBŞÑ]@àúü˜û“9×qç“Dĉf Ŭ½+Sǜz`B5C°¤HLÓÁŻŞûÔ{,`\Š”ĉFŬFàKNUëÎí˰6mZüñêì +{}ĝ8ŜsŸĞşaß$ Hĵ;ܜşo˘ĥZ_˙CB’R݆ô5B™è›…Ğ˙żıCm7HömÂ} ûŸ+7Ĝ9q2{ö_Ôİ7³ +endstream +endobj +1371 0 obj << +/Type /Page +/Contents 1372 0 R +/Resources 1370 0 R +/MediaBox [0 0 612 792] +/Parent 1353 0 R +>> endobj +1373 0 obj << +/D [1371 0 R /XYZ 72 720 null] +>> endobj +354 0 obj << +/D [1371 0 R /XYZ 72 658.294 null] +>> endobj +358 0 obj << +/D [1371 0 R /XYZ 72 250.822 null] +>> endobj +362 0 obj << +/D [1371 0 R /XYZ 72 224.469 null] +>> endobj +1370 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1376 0 obj << +/Length 2775 +/Filter /FlateDecode +>> +stream +xÚµkoÛÈñğ…’-uˆ6\  +8‰}h›4İ­àZ\î-d"İ#İĝ|ùó×R¤Ä$v‘~‘–ğ³³óžÙYwĥ™ı³ŸÎ\ùħ<{~™ÌR•F^4[għ7‹µĞ\?ž-óÙ/NÖÍ^â;Ŭ­áÁİ·ğŃ;ç-Oĥ·Ċn‡CÇäÏà?ġWsĝ:Ÿ'³ĵŝùââŜeÉ£ŞÌĞz‡ ÷üUĴñßs>¸:(Mkwu·Gd´ÙVFU?şğ-VˆJ`ïplYÜÖ;y˜MΓ–ğş™˙şü;HdĦµJPx_wĤÁ]œ 97ÖNWle.kd°÷UÎşmÔNnÚ¨²°+yS|" +I–óŸ9²çĊUfĦŠ6ğ)푷E+'™ĴÛ÷ǂJŽÈüà†î[ĝÑ;<°ċí[Sáû)^QÄœéûUT„)^Bĵ˙Ĵ;ƒ_‡”-¤mż×6βĥ2+Iişċı›Œ´ġ‘a÷;´Ħŝí1síIžS´ Pf͵#téĦöŝÁsÙdM&ÔNħ[Ż +MĈ€ÌM€V@“dš8(:^à3} qÑĠ‹<ëŒBÙ"âç—Ŝ}˜D^ÊÇ ¸^!(laè!°Ğ(ô`Á~3@3phÓò\†V…s`só…vL êHBßı§[ë{†ĝ ŭàeÖaž‚#†n@3çĞÂÎ ŸöMMr@”#öŭòV¨ÖzHv*/‰-Ŭ?ž2Ğ8Híú5ÙÏ9ŞúċĊ:¤YèżžbӞ‚Xc>’ÏÜ3­â·‹ÀOUëc“.óĜè.˘È5Ù +œşċı}kx@~CPûl K;ä,Ï£9Â͗0¤Ÿĉaĥ½ÇŬIJê&Ġĵ÷€Àsĥ{ô(™!S÷ÄM֐9Ñ Yĉ¤Ŝh’‰ÀqÖ45îÏ;tÚĴeBĜ,ê‚É(ލlŻG‰œn z 8XĠÛ-~°çĥüħÁ ;Ĥz†ßİÓCu“ĥ˘PEQúP[yy5…#PĦ—~Í@´ +üÄ@*p{Ì*hZn0Ĉ¤â˜ċlJá‘be÷š†HMŝ³ÍŠŠE|ÀJ†éıİòol˜ooÄOE½oK4d/”Èx`;N8&ÖĠ_şŝ”Ú|ä-˜)qöž€ˆ!^€”ñ‘—gȍ&Ş˘+²²ĝ _¸BÑĤËĥ;â—˜ eZl‰“…2e.E̐-/f*ä>yòdù·7Vƒ\Áa•-]@=,¤^ l“µS15U!XÏ!ĤúE@Fžîöuĉ\ìçíǖAXÁ.–#Â4[IĠ¸İ_lA:ċ/ÔUiŬÛwSÇ£Žĥ1ż)u(ġÁaž³EŬĦêÊXôŽ.C~ìÈóêsÙB˜+{HM=ñ’żZÉ_ƒŒµoV‹Ô:W@Yч<És'2€9ˆŒá0HbDà`³˙AâÉ$ :W˘fi¨×K$ĴÌ6j ”†Ŭµú §Jd]×7ûŽġĤÎ>Ħ•adĠ ŒKÓuF–kùç +‰ôrC£iP§+Ž ŝoOßA6aÂçħ´´Ë ßʵEm2[âÈ&Ì0hĝİÈ6ħ'Š’™ċ‘’cÑÛÏ WŽÛ,gÀ%Ê£jĴŸî™èï–bâ p²<·9-+™ƒ%ZÂI°,‹ß·‡“ŠÏ.–gżĦûı3w‰UijĠöì—_ŬYó”Ÿ&³;‚ÚÎĵĜW^À¸œ]Ÿŭëhżç°˙µŭîL$ÄÛOo4ħJ0E/ĈĤ™ôZ +ż× ÷Àó ¨½3ĊgÙÚ"°„%ó0ŭBj×Mƒ%ż- {qŠác´ĊêûD2~Ϗgo,Ê|É÷Ž•ë,o,ĵşùQäĵ{˙˘„ VïÙù +cĤlÄXĤ*H‹Ú]_ı‘¨Ŭ3ö +ĞèĞĴ3µƒ&9ëâLŸ‡Éê˜?žô1çI ĠNü8R­´•ÒñMç +ŒĠs]ÈYŝĥ²ŭMM˜E¨ Cĝ˙,ĈİÒĦ(÷Cè:×÷h·ääѤŒ9‰|éï˘Ĵ(Vž+Ê:ÇâêÏó†FaĞĞħôhšNX +tò˜€=ĠC +‚Dù>³Ó76(ĦdROde[³1ö™¤5Ìh“•SyM êje$ ^Îż·eó;ĝhiž‘hÜ£>×óKß×^ ĵ@LçêĠġ/Ż&nGpی/RVe#@@Ù3ÛN¨ƒ BM2a‰.OCĜŒWs6䧖ײ—„È0èëúX•p´˜ıcĈ•Ùĕ;•Ż£˙ï­l„bŞÄ˘ò˙´|ƒu`=÷=¸WÀÏt™¤z‹ĥ‚´³ĦÀŭÏ6uN ;kdĦë.|-Wp´°ġPħí$íBÀ éWˆĈPOò„èS‰›~›èĦA!ĤÖÖ|Ò8.ô2‚žo'•<˙ğÛ,„ƒħó@ĈT÷{÷E’ĥ!ÑXJñó.ÛlLŝ|ÏU;}Œ4 PµġKygŞV.(AŻ5µü÷ò÷÷ÔÊDmµp73Lè+J Žî’iäĵŻċo&/É*ċ1°Ìžèpï€ñáuÂcŠk§‘ ¸sÔ£5ŝj³ ]sÌĦ_şÍt›^F·‰}N³ĥV"X³ìçßô¸ï)WÀä Uƒħ,çÈÇf#­İÄyÉ'ĵ³¸.÷ŻÏQ9›Ĵ¨&:>i Ò`¨™ ËïèBDğ6>Îo)Œ.Û0[‹„’]ÛRôœCc£‘ƒTWŬAntXèŝÉöƒAÂLÛHÒĊn|A#ĈABћĉŭ`ïĉĤö+-ŽÏ´à<şCċ žVRÈ%]fßSh+˙ïJ¸’òPŒ´(Ÿ88O!!Ż)oxÍÀ.\S„+͊n–îGxg[7Cb':Bˆm]—´1ûÄ .ÓÇÌK¸hÑşƒÂ˘&ÇPŭŸ?§ö¨Ç$чĜ&HçíOŜZqâÊ [ +Ż€Ÿä›`˘&ˆŠ &Ĝ–ŬöùcħßÖÛKlt‰<ŽÀ‚ô•ċ´Œ[ĥšOuvħĝÀÖ˒^)Ĥ:/ZEáqÒZbÌÊ6ƒŜÏ8kġ–< +#Á”˙aùßò-“qB7†q]a•MQxP^Ç#ê]áÔÉ`ú]ûâtÈ;î˜~}ècĦuQġËB“k-PS3íÊv‰\rŠx„›ó•;ö%DÜ ĥj@Dž3\Opeî, ™ö†&Ğ,Ái,ö%ż)ڕ)ËĴ2ġ9ÒñT4ŝ‰(á„ħŒ=It¨&?cu9ïöeIïŽĦ}•„›5­›·5Şyî@â5ÊeÇÈŭûÜ Ħşıçùğ˘Ê9’ĜŜğ5Š9‡lĞS‡Ŝjz÷ö\›uaé(ëzöüàŒ#RˆÇ +ÑéÁ<·ïÊÓżÍôù–wû²7¨œÈЇçtècxñ1Ğħs‡‘HÄĦb¸}½§òÊsÇĉ‹…fĥµ­[~áíğèÚC‚oZ遭Ùä|iJÓÏV‹3ÏK•Ğħ>LU’$Œ)LG@piŭ/ Ġ é +endstream +endobj +1375 0 obj << +/Type /Page +/Contents 1376 0 R +/Resources 1374 0 R +/MediaBox [0 0 612 792] +/Parent 1353 0 R +>> endobj +1377 0 obj << +/D [1375 0 R /XYZ 72 720 null] +>> endobj +366 0 obj << +/D [1375 0 R /XYZ 72 267.513 null] +>> endobj +370 0 obj << +/D [1375 0 R /XYZ 72 142.237 null] +>> endobj +1374 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F11 833 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1381 0 obj << +/Length 2720 +/Filter /FlateDecode +>> +stream +xÚ­ZmÛ¸ŝżÂè—Ó1Wġ.Ù$¸6íĤħ‹Ü!ıZ‹k‘%Ÿ$Çqúç;êĊö&kœżĴùyf‡u'ˉ;ysċòï‹ùĠÍk?™¤"üh2˜Äŝ$ö\áÊx2Ï'Onèŝŝx÷×Òwö­jŸ˙ŭĉġpN‰4`A3×S?œÙŞşög‡µi6ÙBQG­Ö™.uı¤žŞ¤ĉfż‰£ú“ë*§ÖĵÖ_p%§:óŻ˘Ë‡Ş^g­ĥó³ /Ġ ­Ĵı§µsrŬ|fqZ˜Ù´zÑPÏN—9‰+ŜH'S8ġ‘ú)ÁüïûëİLb£ Úi몘Geë(ŽEâ&I;ïU£Z*fĊµçTî@7ˆ: ğ²ĜcWä” +°xNƒı`šw+UÒÜN\eċÒ(ĜĴfP(ÒXCÍ(·KŝB^mïQ³è”†·l`İBMĞ܂›LÔóD†K?à éìQˆj[c-p^ür7£vħ1QSŝÔRK³e³U5·<^µF D[cACĦd£Òô+ Ĉi£ +µhP€DÑ ġÙß²jiRFġM]ŬjM•nWÔû+Š{ŠîĜŝ¨ż·¨ŽjylméŠ4Y;Dkgh01ÌĖ\× qUïİ +İżT;; ù €B/ĥ€ĈR-TÓdvÛĤĜ>2‰FhŬƒ&ğŒéÜNÛBĈÚ hdmÔ£&4†B…Ö÷÷oauµĤb†jK”¨¨vŻ—´Fkˆ0TYTëM”(xnË £À²Q)ü•!J…”Ù_'Ò1|ŒıîÀÔ;Ŭr[*Ĥo†Ĥ4êċ"q;eM¸Ç:@nƒI‹ı­˜Ĉ–­Ĉab[× mX”)™£¸hŞ<Ùc tàĵ,țÖMn³ñ ?§ƒÑĤİxĥĥómµäÏVëuVĉv[w¨† v"  =„Á谖Î-{‚ĜÙßtž–7ôPͨŸĝÌİè ¤ˆWóĞ?[ä1b [=ĵˆYOÄÁ‘YĠ×EħÍÙÍöMKmŒ=ŽìlÑĈÈüȜc@ĉ§"N’ï"Ú^†ž‚íláĈĜĵ@ĝÁEĴĉÁmIÊïb{÷Ÿ…^<ÙÙ˘‘ı}À‘{dn(’ĝÈj[ŞZeEĴĴêçkmÉ÷àÖ÷8Ŝ³á•)Œ•ÑÊTÂP>Šw]ŬäÙÍ>Žœw”ä™XWb_ÛûôiÔç‹=F'B&—°2ĴMGVĈÛ;ìĴô’£Î{Í05Ż_4]$]+ĵçŞ'ĈN+e“Öxe~\=gĞ'Šxˆ?£ÏME‚~bW¸‡—0Ĵê|Öf›·êk;SŠÇ4+öÒ$G°Ĥ×k•ë̤/9ÉâbZwÁpҜ§˘5[ÜA/ÂÜg§R‘ö½żO™ÄúX.ˆ‡éĝ  m¨a§‰ĦDá :Ġ`VmĤK“[‚Ġ°€Ž°…‹"U!BHqêüfÎż-6¤mì_wŞÁ_¸ :*ûDè)á4O'W ĉê!Ûí) |ı#¸ànUÓE_]²ÊĈg݃ld“4TÙKôöwPÀSÏy …_ŜôçA£ì] ì‹))ÜDèz9ĦÂû7W“fÄê"%( ċ=ñÁäìjML'^Àm|œzWszŻħç ĉ Ÿ1Xög}*ÑŞŠ{FÁÊĝtíHçílŝœú˘êäóËwëÂ2ÙXÀµ;•‡‹EäŜ#ç-?KF×Ĝl·X° °ÌžáŒ¸2F<u­”­0—ŠUÌáożQĦBÙKa#@Eż°mĥuIRÚ6~ŠÄğŞàbïrM^˜0Ż#NşŜ úôìÏö²)Ùǒœ•ċZV+û iËè"ğ/B–ċ8égC‚ĵKĊ}޽yĊ’áWC†SìżŸÈv“<Ìpx۔\äi"ÒRGD¤ħ£´4İàVĝ£Ÿ<œX/„#ĠëĈœ|öàƒ#ƒÄ/Áżœ˜;ĈêmĠÜÒ4¸[r½ƒsĜg—3')5iž†a‚<Ê4<ĜŭĠzÓ64ğ',Û'°ÛU57fbĥ3[³`hUlɆ˘%‡|ġàäŽ߁K|UviÑ Hğ/ˆ1yƒM…yǘÚĦŭŞÄ8•Î/e PÛÎïž6İ _yGc˙9›Ŝâğó‰ħĉ¸~L>ž1ypÎ,l8¨íA2 èkġœ@­}‹9V›9ÀÇûċxàé:èpŻÔŬ;KŜżKŒıèd|v~ŬOŭá˙MPƒù· ĝ%F@aÈE°JĦí]¨ċx>9‡µ$j`‹•ž37Aġ _S̗+úR'Á&ëŸKÇħ.1—Ĉ|Ĥ˙8a5Ž ’“ʆf"vâ/(iê:·[ĥ-ôçcy­Ô$ÓİĦÛ8ĴV˜Qŭ9 w¸1„gP„óMĠĠ´PċÒ<àÁüO0ñ{›@ûá!N{Pw/tv'²ô;a| ûŭ†Hö÷Ysœy•cB1r|?—NÀ% WòÍ*rGƒà6ñZòä +endstream +endobj +1380 0 obj << +/Type /Page +/Contents 1381 0 R +/Resources 1379 0 R +/MediaBox [0 0 612 792] +/Parent 1353 0 R +/Annots [ 1378 0 R ] +>> endobj +1378 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [327.916 263.966 350.387 275.921] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.2.5) >> +>> endobj +1382 0 obj << +/D [1380 0 R /XYZ 72 720 null] +>> endobj +1379 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1385 0 obj << +/Length 1967 +/Filter /FlateDecode +>> +stream +xÚµY[sÛĥ~÷ݜ'jZÁŜÒ43Ȏ;Ž“ÚrÒNÛéÀ$ñ„"U’²“sòğà.hQ7ĤŞ —½|ğXìBngÒq;—G.µ§ƒ£ ub"è ĈPtBî2× ;ƒQç7G2Á<&ğ=Î}×ù˜è§$›t{…ÍE’êŽ/–épá3Á%pİÉ\eŬž}GFI—;U’Ó@•c;Ëğ"rkâ"”ŽÊF81JÊyŞÌäWšôß].S]~_Qàœ›É“nä9ƒğOŭŝ"Ĥ@2tžJüŝjVċ‹6×G§+ŭ2ZtzVr˜ĊòGÖíI)ÁTƒîžt†ùlVKêyž3Î ìŒrÄTÓ¤ÄÁ¤|…(µàvMÄb[6ûŝq#×Ĥ^È€[H˙O̞ñA– +Çk…êʎ“IF³¨G˜)0ì¨6ÂC ˆ]KÀOSm(„ĠÁ’A<€ˆ'TÖĤŝe…{ĞiĦi™kiIùn’ ÓĊˆ¨û$,Ì ÑNf6YzÉLÔjó2ĴŻò9.0DÉVfŬ*ëZ_·mñ +5ˆÊiH-èˆ`‰5Ö_öäġÒIU1YAŬŜ ‹9µ,ĦCĈµ’|èAÒAúĉŸ&–ŠœmĊäµ5gŬĥÇžÛö@pxésTûÏC˙mÂö[·çƒU68ÓŜ}ÀöÇ7Ĝ~‡Mšd€šàëĵio8ğÀ²Ğ;ĉjbw€İyÁ’o;ä0n„ÏŒ{kŒ_·NNÛ˘öÖÛĜ<è )Ûok;Lçş5œêq…½ÛÖx‘LĤU[“€4éĉËW\Bğ.3(!HÚ0„ƒ=;şŠ/÷C@˙ü÷1 +Ĝùû3€Ç•€ġ6{àúg^Xżż@‘4ÖùŠ€~RàlZ$e³ÒœzŸBFĦ“RÓ +îóè8ò0€pî g³-@ĉ@à]g.:•",ŻtIŝ@üosâv‘?şĝ?ŠGìĵÍÇcSÖS~ÒqĦi˙Mž}6‡Ŝvߢ}7ü@‡˘êLïQeb5ËÇĜžßckAôœĞ*y07“ù~JŞ)™âñ;‚œIR_°/+8xk#£ÜÀ+CħÍ[~hì@ÇI˙µH +âŻÒJŞjäÛŝ¨Š$_ÔSp˜'e÷ ólœL¸Í$u4ş"òj„aÁŬ-Žı‰zR•:%ĵÔ˘Êg@x‰ YÛd-½‘Qè!ħ˳]´A/a6/Jħ*Ô³ùĜ€Qj”ġVâ\&˙ÓDDWCPTÄñ˜˙u—3QŬÜëW7çŭ_LÄġĊCD‡Ĉ÷\:ÇW7wƒ“ëë“ÁĠû›W›QŜ+š½÷w}³Ċîö+ˆĥpÚröŝŬğ“›ó;ÂûôWŠ÷7gFP=;(QDíäúۓÓŝàêŒR§÷>n5Ñ,ĜêĤέçµ+)È}İ›Ìİ¤Ü 9ÏFŞĝşšµ.'a^}BlRŽD)’ÍÒË:{ĴóÒĦY4Ċ,İ?8úëÈäÖn‡›"Ès]ĉA4œŭö‡ÛÁ8@ĵ8ê<ĠĞfAq 觝ğ£ŸÛûE1“;öJÄ·×µXĞ YFsÈ)˙ĤbS"çË%W äcëŻ×q†|^6ómAĊtb :ëo ĉ €l´ú͆ +/fĦÛx.Ÿ ­úB58sJzë$ +sRsĦRÄĊ +˜%p;–ĥŝ€ `ÍžÔ ïgÛ!á?1d&LF>ŠYġa­v CQµ\L:#êŠ”|Ö¨ĉê!I!‹7µZEl×voqÛÚà™áAœ/YäG¨,D¤0tĦ8QC£çíßĜŜ’µóóĝŜfl9ĥĠÌ÷YìzÛŬ.€ 9-›„Ùçҁƒje É|ï8ežW_//œ²şĜúŜ¨µA—°6à]‚:2Ú +ĜÁAÔAîtá²(–;!óĉµe“ÏK„ß{ ŝ½ñk/ KqƒCfVĊäòP †píK$É2ódħ]‹½ĊhkÁƒú†?€ˆ܈ı P-úu]ĥN9,ò4ÛÂŝÛġĜ[–<̗‡0Ĉ½ßG‚œ¤šÄ +tÌ*ĊaŜ+™nĞNû ĠÖ)r™Â6²9’m.A'P²ÎY.ÍUÛÌréĊW6éfš×‡h¨ì­Żì$˜ıĠöp>-Tı#^ìŻÓ$ŜîíĞ™ë:&@nêPRpYV=hFAĞ˘†S]â^K!fĠ£f ; +›ßı'‘Êh°]Ìħ@F°Eò +êUHKû´ëÇÎĠĜR_d#ónçĊö5jr­ˆjÊvrYƒ„äž-=ŽI6?ÛcN°•×àċçsÈÑĦ`ëF’l.ŭEÍĉ)ÔûżÈ^φTï/ĉyöúìö͋%ÔŞ‰–ž§Ÿ‘²0£Ĉ"ĉ‡’ÌŝÔa.ܖN–jC³¨‰²?0Œ­ĉÏüÔÌöL ¨ŒŻ4” ÀCĊĈ§}]´ßŻ!ÇÌċ1h + xD@À[‹à@ŭ Koè +endstream +endobj +1384 0 obj << +/Type /Page +/Contents 1385 0 R +/Resources 1383 0 R +/MediaBox [0 0 612 792] +/Parent 1387 0 R +>> endobj +1386 0 obj << +/D [1384 0 R /XYZ 72 720 null] +>> endobj +374 0 obj << +/D [1384 0 R /XYZ 72 720 null] +>> endobj +1383 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1390 0 obj << +/Length 2317 +/Filter /FlateDecode +>> +stream +xÚµYmsÜĥŝ_qñŒİ™E AĤi;ĥ,é¨ql]’N“tD‘‰cy&y~éŻÏ.vÁ—;J‘ìôËıû†}vAoħ^x‹oĵ;ŝ_ĴŽNÎo‘¸IäG‹ĠÍBù %<× Ôb•/~q~ġBï[ĝuWsúĉoÇż­ŝyrVx‹şĦŠhÁêV/ƒ pš]İ[|”ÎMŬ-żĥkŠjMc›´ËŽŭĜıċŝ÷èE<9÷ƒÑnBş‰”°t}[…Ú[3Ÿ ›ı5nötCdiË"“,Êı%ÁGŬ­fÙKğR9–dĠÚm·Ç˞cÀ…Ŝ§É’äZŠĜ “äñšü8ğİQ÷ĥfµŞ 2âÄ˙ĞdżŠ@ŝŭÉñRJyhÒ´Bħ>ħ鍈i“fnŒLĈ³‰§ĤŝùVWì‘ +ıÁìâX86†Â*pşš†Z6ĝ‚PüŠF>!µŜYÏİzê3ŝ1§Gˆ1×ÄĦòÍáñR’‰yv1Â÷ÜH(;gĉˆ +ázŭ8íŒë{òĦbĵ¸œg&âĦRÀŸyÑŬŒ‹/ Ǖq-G?íúß×3 +ħ+#ġ6ˆíĝé›9H7ô“ÇÚ ¨²r—kˇlCéŞäÁŜyˆd3]½ıXžÒĥÖÜYZeşdkW9£•îvM5΁ó~KguùóÙÙÏ8…ċE£³n8‰•ú½“r&qšxUĦ<‘çt·”Ħ„vÒ5Ĥ$@?Ĵo†ü™(§¸ĦYCĥ‚—´ëôfÛMùĵ/€ Ó@UWËNìˆĉ“ĈÜEN[oX EZ­ùe’Ž[âòĦ(ˉ DŜî˜o]YÍLvr CÒĵÍ­+÷xzÉà0´|áİ7=<jÂ‹Ñ ŝ_"ü°ˆzm$StDÀ ²àZ·ô­k"¤ĵímQjZGU νċ9Y½½t3ŬŜxĤnŜÒ[ † †u3*ŻÓĉ:]sĝLJb@8 :Ÿh^´Û’ •vé ù{EW)ÛĤC57pCÀ}zÎO &ÌBá9—ï°ÀÓ§ġ˙p§PçĵÀÚìü*ézèJ9q,Â"„RÀRsv¤Hßu5à|‘eù‰ĈwUûn‡ĥôŝš –,u•Ġ&rĈğëĈ°ÚO8 áßO|r’ZĠ¸?KŬ§!½Ħžè3£nŠ8£`ĉX­ĵ~âÒìï*ğÜSY…cu…Ú! "‡kÜÔ]Q³t$TÚ46RÏQÍEÌġ›v­Î]´Z8ÔÒV[S‡CêjBÈN°ì]cŞkmÊ-޵ö–jX.ËûuuSĴ‹*-é­J7wmğ•Ù“qŬ^§ĜM|És ]s„rFĞà­÷m bĉm¨C§A”A˜7r´R97M½ħ<0ĵy^—6M0â?or ïġ²Ù°(]½½ƒC™ĥÌf Ç|9q(cĠ(@žpKşÇFàX•–KQH’uYö-›[BŽĴrî:leÙN +ß!$Òn4œ +ëÊR›„BHĠûżà':ua‚³•s÷—=L­×GžšËù£:œÓĵA}rÌ8žĜİŞŻÎÉV(˜ÚìÚLƒu~ݽÎÙliÂ]9FMÁ–ŝĤ7ĵA§%XÉéġ´Kˆ 2=ÔŻĥ˜ÚğäŞ*žu[ä&/F +šäŞċ„³ĤwVT#^\Vĝ +ԛB pž–mMë;Ä<ò0Ô,“,…Dc'$ I¨C1$땉 œ‰“ŸzÌÂı ġœßgpzâÓ˙œŭ›ó +·Ĵ—?ĝ×wЇšßì€Kô˘ïèĴÀ”%áñt@ĜCP“ħë}aûÖŞĦ´¸ÁĝàxjhÀ„†‚‰B7AÊAu³oG§Šf17ÓŻÂkšç&íÁ\Ş7ThÏnfüƒĠ‘òĴd×PÜ02²è+CìdMħ%Ô³NǍ=Úk#žÌP—ÔŽŜaçĉ-^ùQäŠ@-²ÍÑ/ży‹èàk7€îàƒ™µYp[’rqyôzo}¸IÜ·Ŝ[°J´ÜÜCMċ&*NÊ ı†~J +`òÉ![Ĥĥ™(Öĉ"<ş,Yói8£ˆÄD‘‰¨ÑS{qJĦ(ç×KI/06xĵşSkIʟĝϰ– ŬHH6×Ä^ğ뒳dŽ)sÎ|€gôĜŸÚûŠ˜zˆs-ŭ1Ó[ĥc3ŬĥXĝÜmGĞ9µRàAçüE1%bx"`¸QșċC³„uifW{­´ğŜ]pôîÑòÑbNµ„ +JġgĂ/\ċq,\ Ħf_ĦmŬŒ2Tžħ³Ö€P×ßÚÙÖıi +îm¤mÜî6Ĉ£µ™ƒ4ùŸ·<†ĵ 0Œĵ7è|8ğIŸÇÌ 7Œ¤a„W,tÁ2˜sWċ€Y_ƒœĤ\aœòĦò´çl SkÂz(ŭ 'ۈ_b4bh.F‘ˍ &h |„Š`  Ç>ñĞËâ1È@8úŭ1‚s9ƒÄÀY˘&í%"ŜĠÓgĝ §Í2c%UöÂĦ´äÁ­ŒĊT“Ó_Şż]ÉkË";W[D.İD’ù%#0‹> endobj +1391 0 obj << +/D [1389 0 R /XYZ 72 720 null] +>> endobj +378 0 obj << +/D [1389 0 R /XYZ 72 473.857 null] +>> endobj +382 0 obj << +/D [1389 0 R /XYZ 72 374.808 null] +>> endobj +386 0 obj << +/D [1389 0 R /XYZ 72 307.128 null] +>> endobj +390 0 obj << +/D [1389 0 R /XYZ 72 192.394 null] +>> endobj +1388 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F23 825 0 R /F11 833 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1394 0 obj << +/Length 2429 +/Filter /FlateDecode +>> +stream +xÚ­XmÛ¸ŝżÂ9… ÄZ½ZÒĦ-lvi/›ôì ×ĉ]̵…•D‡’n³¸?ßy£,ïşíĥÈápÈ!gž™a0Û΂Ùwg|ßĴÏÎŻ˘|VĝĊ2ZÎÖw³,šeaàq6[ofŸ½Äüďç‹0LoġéÍûwëù"N3ÏXü.½^ŝȄUiĞ}ßÍ^˙ċüj*3Ì +?.BX‘Dw&„WšĤQí†;·óE”{ş6sĝ<0­êĝÛğj¤ž™Ö°$’óË<Ê<ĦëŻŜ÷n–’VĠKÁg ·W×/Ҕw{ Öfû2ŞgгżÈkÂ$öáG˘²@ó—Ĝ[ĥ•-vÏŬ0Mŭp™ı A8dÌĊA‹˙=Sè,ƒÇyj·šûȔ‘Ÿ@Lj,h0ċ-C˙ÎbŒ–Êrs£ïÔP]nM ĘEl†żñ~SïŠÂ›•-ŭĝIŽSµ]ŻÚR£Ĝ(ö*Ü]LÄC§5ĥpyäbHvÀ pÛf”Š´zȸÎuâ ƒÍ†ŞdġÛĦ—ˆ àÏÜ£sĊï`EN%|ĉÇ2ùp9ÀíÌPo˜ioÁC7úĵÈñ.ĥ,ÑĴ‚˜á Ÿèò{"׈ìÇĦëġż.ŝc4ȧ4¨úA.ĞoïèlJDU ÓIĊcçZĉÀYÊt:DnŞĦ7 Ü`É]wÉĦgÁôžÜo2Ŝk<½WY|ÙÜ3OrŻ8ÉÀó˙ĉá‘_äĊħ‡OO(ÉS?ëDIQKÌ;ÁÔ”2ËŜà1>˘KŝVœ\ +N~_AĉĤÜíJŒänĦwíŞ*ŭžò/$`t™Úç“|8ò,;[úyÈK‡ŝ˙ìó" ‚CĤ'"B–éı[ñ‰ik‡=‚Sß"ñ8Ĥ$#$R„%RïÁwpMĊŽgˆeËd²˜*—L*”IXìä ÊU}z™C²À})³îŒeŒ€Éâ'(ÙsĊ%…Ġ\éÊÊ|‚ïİÚŭ tAòCY–{÷äQ’u(‹ùJ’`ä˘7÷Ü··ƒ”rúPzañwÇ'2CÜJw/eĉq'cIj=ÙçĞS)‡ö·´Ğ„×#>ÈBÛÄ é‹-böħWv ‰KmŞî^ tçjÈ#ĦʊżÜ*Ş™ïÇgĜ?ħĈ…ğŸÂÏĊߣ“ğŞZÜN’‡“b :hğh¸Ĝş#vîÁt[ƒwùÀµÓ ++ÈQG$ġU#2A+Í1á&:Ùĥ$eDLì€(ÎUš¸ lÂÔĤ*{uëĥC$­ı{n˜À½`E¸Âʖ“Ç•,ġ~eÚá¤ĦÓ¸"4s.ᔙĞ햏>[ş”9ġĴq4Qġè9+G$ Kjˆ"齅cDĥ”t³Ċ}ċ=ĊïN—‡'L< '/İÍVJN/9ĥâÏ[¨W=äû|’t&w÷”ß’zU3ŠñHNÎóLĊ²e%·ĈXQĵxñbŭîŭċüɆ{­5Ġ$Ĉ•N/N)úeĵBMÁáĠXœƒ$’âġĝĈ§ĦĈm´ó'˃Ŝ? +cŭ茓Zċù×Á(\ ÷*~-˘„Òġ§QÌċúï0Ġ„rAŒö&ñŠB. +ŜVıpEıOêÇËd"ÉOÉzŝĈ~^ñPµmŞVĠ>ċ‡ħzT#ĉËħ$`~Ç߆ÓüGîQqƒóıN~‘Škcğc {+6¤-%ğÀş_s÷V„­Ş—9œ^ĥ’ğ‹JÇai£Á£""xÂïOaœ`Bżò “Jñ Lgˆi´·ñ +ğ˘b4öÂC%Àaş#l4\$dw´À`;cQ+Ŭ²ÖÊ>ç@u+<£ÈuÌ'|ÂBİ ƒO_ĦME'<İ{Ĝ6Ap‘œxŠD’³şĝp}ġî;ô$ĤH­Ë ĉl=·Y?lƒg vlĴĈAz[½­ŒEß(*ü ,À}1BKˆ^ĈGLP üš=| +endstream +endobj +1393 0 obj << +/Type /Page +/Contents 1394 0 R +/Resources 1392 0 R +/MediaBox [0 0 612 792] +/Parent 1387 0 R +>> endobj +1395 0 obj << +/D [1393 0 R /XYZ 72 720 null] +>> endobj +394 0 obj << +/D [1393 0 R /XYZ 72 720 null] +>> endobj +398 0 obj << +/D [1393 0 R /XYZ 72 642.596 null] +>> endobj +402 0 obj << +/D [1393 0 R /XYZ 72 445.7 null] +>> endobj +406 0 obj << +/D [1393 0 R /XYZ 72 319.425 null] +>> endobj +1396 0 obj << +/D [1393 0 R /XYZ 72 289.604 null] +>> endobj +1397 0 obj << +/D [1393 0 R /XYZ 72 245.813 null] +>> endobj +410 0 obj << +/D [1393 0 R /XYZ 72 179.555 null] +>> endobj +414 0 obj << +/D [1393 0 R /XYZ 72 154.745 null] +>> endobj +1392 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1400 0 obj << +/Length 1371 +/Filter /FlateDecode +>> +stream +xÚ½WmsÚFŝî_Á§F̀ĴWžÄ°ÇiğF™N“Ĥ™ĉj½é0áßw÷öN ŞIvĤŸt···/Ï>ğNçĦtNŭ}Ÿœ^F‘=xƒNĵì ½ÎulÇvâ¤óɒĵÌDÎÒU·ï4|э+žŭ:Ŝ‘ĉcŽéÑVĞç…\‰üA[¤Š¤ŭǙ²LwñĊŬÌ#Šì‘7˘ˆfÓ8žŜßÀ]ϳŠıd'm„4‹ÂÎtâ(PYxžoef"BħXSÑPbŠŞ,Ë"ÓXC ²•0ÉĉĴÒgż;nòlˆ|s1›Ú,([ħŬï Ċ ĴT<"R<Ŭ!Œhg4°v]P‰!ECKT¤ËҒ³dG•#R”ÊÙBLĦ£2) ĥ [ɵ5Ĵ¸:’+&_Tµ•’=èÀ…ë%ÉĞB‡ôçĈD\ñ”/¤ıĈ´ô#Ĝİ6Ĝ(×sCÛXž$74ĞËĴÄ}ĦŻç‡MÉżG<†ÄKh=™oß_^_µr)ĈlAoàYŒi(°Pw*#¨<ĦµÈéK Wöħ‚4Şİ7FA%fNĝRäÚ&Ó~ùĥé£G[‘ĤúÁ—ûsh%×qĴWŻÎIöċËß9Ŝ̚èĴ"ŞDĥĉôW¸ŝÔÒNCÏî˙ۑ8 +˙S°ÔŒ˙&ލ†ħŭ#,èğäE Xîù“05(4â<òğP…ô†Á=öÓî4WŬñĵ2ĵ>}ŻéíxàqHĴ:£Ġ§fì9ËĝgZŠĵ&yİŝ×|~{~>3ŭVQÈıjèN8´C?hNÎ Òéëf0Ô?£ĤaZ’™M&½É½CzĉÙу˙ánüîg“çñ›5‚6ICÉ8iÓ75umššŽu˜mš· ÍŸˆ 5 Ŭ/ µŻà·ú…20 +)ݟYôÉż ñÒÌżŻ*˜zî-V,0”Ġ£áœ/ĠK×%‡wüµ>ÚŻ¸lÂßŜèŽPżpÊp)ž´ħ×gÏÌ5Á—‘xR˙~$m7´íĦEۆñĉ†ş}<úŭX'ê}v܃j]3dÏġmßÉ6²#˜pÊÏ hܘĈ'nċ5 +endstream +endobj +1399 0 obj << +/Type /Page +/Contents 1400 0 R +/Resources 1398 0 R +/MediaBox [0 0 612 792] +/Parent 1387 0 R +>> endobj +1401 0 obj << +/D [1399 0 R /XYZ 72 720 null] +>> endobj +1398 0 obj << +/Font << /F8 826 0 R /F11 833 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1404 0 obj << +/Length 1875 +/Filter /FlateDecode +>> +stream +xڝ]oÛFì½żÂĜKeÀVġmİXdħ[´[›6qQÛÎÖÙÖ"ë\INâ?òÈÓG˘b]ŸŽÇ#y<~KÎh;rFoŸ9ĵŝĥ|öâMMĉ×—ßĵ{;ı^,ż|şĝw pġ­_ħf½ AFˆµš÷ˆÌ%C”}JÖbˆòK˙bVsˆò²Gİêaà%Ÿ{dߎY­İĤĈ̞owĵzġú û~7>óŬ~ñn·!e +ı–U%Êӄöë(ĥ’à4Ğnً+ıQ%£KyÈOYħµ‡,òVÖ}Û—³)Ġž—Ù ;{ù_›–c×ÊîĈŜ̒?òĈÈ‘ĥmÁú³şĵ%=jĊÑ{H! Û=½(t|’²OuöÄğßOKm¨ĜNĵ„hî€jêǞQƒ€kíau-Í{$Œ8Ĉ ْ˘Ĵˆ܈ĞŜeeʸl/Á~Xk”²Sš[UòÏ_à]ŸÁ”żħ:ԙ*À2aâ@bçù8ö-N)R¨àĞšüÑ;QÊĦ¸/ +ı7ĥ%è2¸=¸G@µŻóÒÎĴµĞğÁöXʔ¸Ñ?xR BÜgġŽP'dUǒ eıÏ +‘3?ħ9ÄwC8ÂçwÈ ·İ$FÁˆĴŞĊ­Ž.4ç›ġ•_IÚÄ֖µZ‰5rÜe„Ĥġ}LöeMòćX‘›P­F7 8”äżµLÁ#Ĥ"9JĞĥúȂĠ£ 6*Ïɐĥtöí(+ôöO”Ž9§Š(¨àQŝ°ÙŸdÎW3£.z$èċCVÛC™³HĦ½˜wˆ‚ÖĊĝħµÇ Àh„˜Xy“AħXŭ ê†ìè]£…Ħ%÷:Gs¨‘­sH2­9lĤ´ĴŽ5‘ƒ˜JíıĴû„ĦŽĵĉ*­0첂ħ;J„ólU +|‚oa4ħ i’³¸;цƒ%(Z%ĜÎ00†"µUÀqIÇá(„ı°ŠkÁN>œ%,%ôıRîıVŒ…àw­W–Ż}‡İÔ! /YÈ{z‰í[ï˜ ÊË^‹ŠY[ĞÀĉž4ÌÓĦ'‹˘ÒçşTğ”êN~Güvä]ĤX1-ÛÉ Yǂ°÷d˜gg¨uĴÓß^g`E…OӊêVë‘ÒöŸcUóÁĤ6ʵςMÓ€²\\}°i·Ü –b¨¨Ô“Zw‰6´Ò€ĉ'VdGĜQ³Ñçşh!Ô RĴ'yŜH(˘bfäeĠ!xċ‰ž‡qú\S€‡6­¸•i¸ÙfĤ*’ıàâFaĊR•ġ,M7‘FjÈáÔiĈѵ·0,Slœ†×ÁqNO;_—܀6{†­ì*&~œ `„Àíĵiîñuh‚Àñ[àİQӄˆfĜI*ż|_G”Nŭ:YMÍÖĥCĴN-Mfœú}ƒ•Ĝ²ÄğÈr=ĤßküvüÇ<…Z£Ë*à[GkĞwÒo&„çP6}MGCŻJîy˘U˘ŭp/Ċn"°öşuÎyŞŬéêR¸žġQ›€~7AL§›ĝMĤÑ,ÑEîĥ""eŬá˙VĊóšòì–Ġ*$Q¨ óíôÔĤQ…A1"7`ùÁZ+ħƒ\;1XĝäO#ìĊ%dÍ(îŒ_ÔQñ¨Ĉı0tȟ€¨úlƒÏ h—žK„ú@r ×UDŬz6:ÑÜHŞóQŻÂÀN6–ĤCELŬ ğ_>’cáŒŝó\ë=•Ü ­KÂĦİc€2İg×í~^D‘íÜ£ċ˙útܙٳ 1çWC2;ô’×OEÀ ˘00TuŻÄ3ŬK“ñ„§IÛÀ°[gôĠê9ŽíÌâ]Í<‰Q½ĝCû;ôĴj§Û݆ıOÔVuŬĥ¸ĤÌô÷5 óĵŠ™U#„(T1­Ö4"AÄŝPWĴ’:?éĉ‘â—#O‰ÀMĴ,›Ğ @Ĥ tÑ'í ‹‹§ç8Ÿ“Ĝ‡Ĵ¤ ˜ġħĴ†Ş’Ĥ0ğW<£zşĠN$‡ú)c˙Jè ëĝşĦè&S9QT5&,UŜÀt+$F7ĉys5UM—~âhÑa)sy7#Ŭ%ñ.¨(>pƒJ{Ħż4§}pgĵp3 ­\Ç UT²|Î\Ûc–2Z?n%mC?*&46žŻËǏ2\zµ2÷›&Ĝ•ŭó-oà Ù7“ ·_ÈĜñ*ÂĤ˘.cğ¤ßïY.}¤4Ÿd#ÏKlÇMFPsmÓ¸˘°G³X>ûÖµ> endobj +1405 0 obj << +/D [1403 0 R /XYZ 72 720 null] +>> endobj +1402 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1408 0 obj << +/Length 2173 +/Filter /FlateDecode +>> +stream +xÚ­ksÛ6ò{~…™šħh|‰iŻ3ޤí´qĈV§—nh²páC%HûÔɏż}”¨İ›‰>ˆX`ħĜ7váÍîfŜìġ3Ï|_Ĵž½ZÎR7E<[­g‰˜%çzA2[³_ïÖóE |g7‰Óôsß9i%N §n:^[g•*UÖ2ô ş #t²­T•<Ÿ7ġožŜġmÖİĤ>ĊÙy˜‹#C÷wwRwĵy‡ p ÙğEpgèn̆‹Ğ7Ğk\¸úW²şà•Ë›‹ó·—vó|8…ÔóßW߃Ĝ ßwÓ(b× -ÒÔˆRxŜï¸ĥn›jÀJ Ħ^ËöDó¸Êj\Ce%Jç%Ì.jiGÀ|eŽh,ŝĊÁʞœ˙ċĉċĠ  ßğóEÎÏóeàȓ²ÈÖĵyÛwGMH}`šeä¨Q‘„X0(Ġm VEY(Rşt´Áê6YÇ£½Xà'4†@bÀ˜!× ŜC-[mà5uŸÊĈ5œézèĤ4ĵŜ‚p y ÙmiF–ùĊ¨Ĉ,ÌɍA-TÇLäĈNżċì‘u†™Q +I*R¨rmĜı–m_$ŽYbç);†–%ĝ {ŒqÀ!Ùú +˙ ˙­qÁġÈé‚èÈĤf S²0'q €/@peÎE½Òħ2—Zg-ù¤rŞì(5ô`°îğžn‚Ĝ³ +§1#jž51‹›ĥÛVĉŠTˆ0ħjÍ>ƒà6Jse=!Σ|£gµ½`ò@1°42£'µï§<ÂM†{éAWä`ĈhµÍyÙr°PĊG‰"@Ên3mÒ'Nj„q ^šŒpöJŜËÀ^ ÜelLşÂ\šñ#Ïı8ŠÚ~¸ÛÂMDTh÷ +™ +CÏyyWèĞï^3Ôwpw6ÀdBÎ3šá}²ùúÂoŽ›9™—µĦ]Èu֗˜Bˆ6ÙaŜ0t85! ËH³e#Ħ%–ÛQ™ûĈ—&}Á@o̕ÂàÛÄó×µAÌ!.›ży‘wŝÖ¤m˜Ë›Şb?'ŞŠî ¤ÌúTŜseeé‚k“­xbPqnĠ1áy Ŝsœj4û={xcKw™ +ŜöŸ/ĝ›bëŜW"A÷2~î]ŝ†è‹8 Óâà×Ġ‹ÖY%wMC>L@“A*\‘ÄÖSyrag6,ü(‰œËÂŝ9`Jç÷/ŝì¤>5 oF o;_×£…ûĴìċ)lV˘Ż/żáÖ óMVßÙM\ŒpŝìU÷Ä}ê1ŜÂ‡špaÌġòÜx, f|žì "Äd2Íí;£…ùbŬ´¸—­Zï˜Gİ£Ùî¨Fž=MïÍ1½ò!ÛiK ^Ğĥb@ĥ™† ‰E@?ê;ÇätÓvĵ˙Ö·†0^tğ-^Ŝq’<•üŸIïHf§;Yíé!S‘x²Œ#Z×2+êr7Ĥ6aĝ)ÔŜŝô˘Äö39ëµĦÓJ°˜7íóJaräİNU¨½0~T{ï£[5gEvĥk÷´İ{D ÈÜŞqw-Ÿ#üH<•şîħĈk6Ê\ÂÊĝ½’˙Ì{r¸‡ Ğ:oul+òßT%~BżŜrȒD°N€Èİżè‚ˆĵÇÌì{­›ĤUı3MYR Ô£LDcJ­Ŭ'=_îbùqirt­2m¸êµ)ŒìĠsÊĊÓ{îĥîv[[íâòIX-× S›;żŝ˜™ÄMöë×S4B7Ê7–ïzñ€0”ßë†j)ìoĈUS/Ĵáüûm|l-Œ:*~ı*_áıA5ĜòÄP'g‰µI‚µIhkZÄê’ÂÖöÎ>TE„˜ÑOŬ0xŞ–ŠVqk;AIĝn쇃²&Hù‘ĤC]ŠÍCp`~Bç#†žO1â&ñòo$ÖYYX°LP +"7M’żáe ċ~&/ƒ0cŸPMêziô)wô\¨¸,‚Ŭ[X0Ŝ”ñîa°ïĦ•Û2ËİMĤ%î F4jy7tËĦë‹£ Âï;Y›ċö´Ħı{€ïp‹…"°nÊ+UÖñ>~o&fp`9‡t–ĝħsnĥèÂ 1ê˘·‹0ĥo°>Á‡Ò#Ú½ +ċÔq–ÜÓĝ˜cÒIß6…ägšv8eò‘ißĊá^Uq‡t1hqlC×%î̃ 0Oó %Îħ$¸Ëĥ1¸ŽoX<­jŝfĵ"#>Ŝżn›.,#Jñ·™|=üċâíu`^2¨$:?)(“ž•ĉyf“vcŸÉĥ xgr ½y€–Ôĥ´6ŽŞÏP÷…!Ó÷Ԕ1N B'ß/~â7‰K^¸ĜZcĥu:‘î œÌɅ<öĦ·%tßQ€Ln +(%7Âı55îjxŬhDŽ?TW~ ÛĦSÄÉ/-‡^‚'µìŒqâ›6~$ȄħŽĜÙÛċàħȚïsOÈ?çßrM·ĝ²…ÄÉW'0K}µÇôJĈáOç,! Ğùél{€\BÇÄñhÇċêÙ˙‚ž^O +endstream +endobj +1407 0 obj << +/Type /Page +/Contents 1408 0 R +/Resources 1406 0 R +/MediaBox [0 0 612 792] +/Parent 1387 0 R +>> endobj +1409 0 obj << +/D [1407 0 R /XYZ 72 720 null] +>> endobj +418 0 obj << +/D [1407 0 R /XYZ 72 586.508 null] +>> endobj +1406 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F30 1094 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1414 0 obj << +/Length 2886 +/Filter /FlateDecode +>> +stream +xÚuْ۸ñŬ_Ħʋݭ‘Ìûp*{ÌfڙÊĤ²Î†„$Ä<ôxòġé )3/şğéoŽóÓ+_ŝß=zó!Ì7ĊHtóxĜdá& ü½e›Çjóğï}şŬAâ{Û"ġtıBïԚRĠÛ]”ÇŜÇöÙF Ĥk·˙zü Ŝ…É>J£†} 8>˜Z÷ĉżşßîâÔ÷T[ñàÎô_pxgUjDôĉübA–ï"ì„ġŸw{€>à¨ënğ sŻTáXĊè`Ô:š–˙ÇÖ ŭ Œƒ ÎÔµŝDxĥ…Ÿ/ĵ#ġşŻ÷ü?t2Oïéı;w3xàHßÓ.ô÷A,~áUúL¸u[™öŒ+bĝ˙‘7œ41 B˘‹%~‚ˆe*‘Äİ3%>WUÉnĤ~ŭtÀ³íŽV5ĥĵä…<ٍ.ğĉ<Úî`çO|<áŜ‰Għ§/ò>ûA\kÓ#à˙ßc?,6ġÀ·é ™ ŒâY(eğˆ£Ï´‰·¨˙k­ÜàŝBħ•= Ż•= +bá_„üpJIxk½ ĵŠ<‘ɑĝ^Z^Ô_ñrZH€ĝ/\É÷EX0W>â:¨ ³4Ĵ2V—Cg_ŝlÚŞç<ß  îprğCz|ĝíŭûO|Ş?uHíıçİâÌŬ×u¸i˘jzót’=b„mn1•Ü·53Èùöê|ŬşÚ­iV^“÷Û]€›Ĉûë—myÒ$TnúüF?˜²çıpÎsKfiÙ1!9X-#gâ0ìZ· …çùŒ–ğ0‰ĥĝ_!ÉŻÛ$ñÜúİ֋WĤüÊÏ~âí’w DQ}éWu·iO83Iٝ½Âl8™žG“-!´ĠvÀËQj=›á$ÜœŽ´‚Èy.D‰ˆ\âëŭqžà`ğĈmAsŬġĤ"e™ŬĤêĈ§ieE1àIwĉ× Ğ +gE2İ$ÀĴŝφRñ{FĜ Ĥy’•=i9Ì&çSqh›UżD`4Ĥ5ì\^ùŽxàèoà܄lŻıí$€–Ş]{Żĵ˘İa‘ +dŞŸzMgŬŬ +B<ìù€°‡x\…×êgˆĊ rĵÉ´ŭ—KK3I›È^ĦàôDŝ,›Â-ßçEÈ'@xâżĤiî‘-ş¨Ö + Ü]#xıçP^ĊÚ(ÜçóÌ>”žÊ{kÑqÇAâ}²(Ï+u5Z&vĠF‰ƒ}’²ò4ìÊp^GGÌ ƒUg†(ŽD>0(“ƒĜϖ*·Ż†Kʌ‡MPÊځ!ĈµŠœßĈġí-vÒM‘ .½2¤{7¨ş1Ûp˜…œË>£LÖĴş4/pÖêo—èâ„°ó+XàT—JŜġ¤38êĠIÙ +dÍÔ(ż`£êĜ–ڈŒšä^p(}*˙[i!W֒jԄÌŒ˘ÜÉĦÜàÈĵĵċwœ;gŜ9[âU­™ü8ĴNó.N2Ş*•&œp”ˆ§IĤQ1ĞS#êIŒuĊ'ô7jtÍ:2qµ°ÑjùÚSĊ¸/Ŭ™Xš-‘·¨Ĥ%ŒŽÒîyrCOî/Ñzì§"áÇ_îŜŬŜÍ[8‘÷îŽ#ÔJŝŝqŒİı tM1ġ„`Ŭ†:‡ñ4D¸ë½!ÜBmC7ÂdŸ”Ğ9qFíD‡5ıö‚²xxD ĜÖè†:J£ Ü 6ŬËêè!HâGߛë†HÁá +‹˜BoXHÍıüsPlBn)–xyÜĈöġroJŽ[bSó^ñ*8ììëĠšĦ6á´Ġ‡œÊvVgœ×ú€ÁÁDí+OOi€ÎÑè{ù.)Ŭ|WúELçr’ÔYÉÙŭ@J$üD4} ƒ™ Òäcƒ, ˆl5ë\‘Jtİf€QİèJšg+Ħ“ò­e +äŸa7ċ?9% 7ì÷8KÊİ˙Öò˘+–{^PüwÉĊ; t–/Àêàê²O׎WL×µĴt óp˘ye­é[MÈ-2:¨xċÔ¤<„‚ +˙•·Š’Eé +Bzqòµûlҕ¤ìÒiâ)ɁÜzŞÚYÊKÇc1grü)J ì§%ˆ8òÉgĵÒ5âéóû™Ú&G×Ŝ\~÷B—˘­K^ÜWÂî—Î4 ‹½›]–îÓ"g>¤ÙbÓûÇW˙ DÉY +endstream +endobj +1413 0 obj << +/Type /Page +/Contents 1414 0 R +/Resources 1412 0 R +/MediaBox [0 0 612 792] +/Parent 1416 0 R +/Annots [ 1410 0 R ] +>> endobj +1410 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [103.659 225.902 112.432 237.857] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1415 0 obj << +/D [1413 0 R /XYZ 72 720 null] +>> endobj +422 0 obj << +/D [1413 0 R /XYZ 72 720 null] +>> endobj +426 0 obj << +/D [1413 0 R /XYZ 72 703.603 null] +>> endobj +430 0 obj << +/D [1413 0 R /XYZ 72 357.907 null] +>> endobj +434 0 obj << +/D [1413 0 R /XYZ 72 212.957 null] +>> endobj +1412 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1421 0 obj << +/Length 2180 +/Filter /FlateDecode +>> +stream +xÚ½ÙnÜ8òŬ_Ño£lYu´ò–ġĈ™YìL‚¤ ŒÇ´Äî&˘£Ħ#ħw~~ë˘ZŬV€`ŬħX,ĞŠu‘Ájż +VïŻ˙ĥ½ş½ÓUúy’DĞín•EĞ, ü@eĞmızb_­oÂ0Jĵû_ŝùîí:½íöÓúFe‰÷ŸÍÀ@ÛñĝwÛ+½VĦ÷ˆ·CgŸĈÁôëÇí?nï7ĞÜÏÓ(ĊMƒĠM”ĝ*Uĵ'ï´Q¸“÷á×ġM¤Ïö£xW!ĴşŭЁOïŻVDúŽ–]†ä´Ğ–íÚúX™A¸zÏGÚJ7z°mxr/‹ŬëÌ*)[ċ?ŝ´ĵñó(çċl…{$ħ×´<ÚĤ °Ŭ.ˆé…ÂĤïQy\ƒ'çxU D²Ùéċxŝu¤'F#³ÉçAŒ‹tGF`ĉ_8g~š“ÛÀ˙pƒáRl <\Ë7.ĦRâw’œyËI dgı$È.N²?H4°Ç_sŞ1υ9bu +RĜOŽšÇÊè^Àĥ1L5i"ĝ£¸)ÀT.F÷Çİá‡É~<µ2ê²´î˙”'ìRÖsĊ1B+/F +ÓŒ yI]i†¤6Û&ĴQî}hèIM}XäH§FÜw> endobj +1411 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [381.733 645.875 390.505 656.723] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1417 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [383.278 591.081 398 601.929] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.8) >> +>> endobj +1418 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [258.883 508.937 273.605 519.786] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1422 0 obj << +/D [1420 0 R /XYZ 72 720 null] +>> endobj +438 0 obj << +/D [1420 0 R /XYZ 72 720 null] +>> endobj +442 0 obj << +/D [1420 0 R /XYZ 72 578.136 null] +>> endobj +446 0 obj << +/D [1420 0 R /XYZ 72 495.993 null] +>> endobj +450 0 obj << +/D [1420 0 R /XYZ 72 356.634 null] +>> endobj +454 0 obj << +/D [1420 0 R /XYZ 72 198.124 null] +>> endobj +1419 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1425 0 obj << +/Length 2668 +/Filter /FlateDecode +>> +stream +xÚ­XYsÈ ~÷ŻPċ%TÊĤÙŻyH•|%ğ5>F֖³×%R#Ĥ(RKR8ż>@M‘²ĵŽvŭBö>p}Ú}y£œxü˙íDÀ߉Q(GĦˆŬÈ£Ċúäç_½Q +ߏß°£/:äĤF?‚Oáğ"f½NPŻ`™“z1ÜZ4ô§½´;A킳߂Ċ’ÁTšƒWë,ETYïáĜÑWpîÇħ ùœ{ +2Ö„np×/Û<ûŒäĝÓ_]^ûò˜Œäġía›Hğ*`A/Ğj1Şú•";…žN¤Ñv•QcJżjé´IÑI,ڌ7Éúo›,ċ’˘ 1Tw‘1A^.ŠmŠÚ§ŜŜiÍĈĜHĥ0F²Hv‡&µ%aÓ˘Šo˜!Š&ĵċ} –†è˘ S˜M_P7 œ3²ìÒĉċWBÙyŜ.7YoÉñgI†Ĝ6£nkvċ›ċH€Š²‚ı`ñàú³Ġn§Eµ^'ejŒÇÛËâÏo”×Ó!Ü_B††ĴÂï>_Of3Ž0yñéoîċŭ-uĤ¸Ŭöƒ¸ëlYĦD%¸ È˘ÁV@:“Ĉ+YgĜÉÊԈ +Û¨1C ”Ĉ#˙bé}Ï2cv PF7qoCXñú´î€ğôC•âjŒg&HDÚq xbMĈÀW23á½ĉĝ£)î;ÏË,=¤ĝœu ‹m=TušĠF?ġ#ѐO˙´Vntg˙šQûîátrúôĥf‚Î,ÑQ´Ç.ĦĞ‚íŽĜ6Œô ÛşÎ W-ͤğ c+˘{Àä£Ë Ñ[µÜ‡o5êĵ˜’ È ê>PR‚ |gRp…†Eͤmë|…œu f“œYb~“`ŽÇ‰cXdEӍ¤Ŝñ cÏcPvÒP'Ħ_Â9Ö=4LЁ‹;â†-ĠÙ:ÉËĈîĴMk!=Pñšf“,Ȍİo€ŝhi0şĥw™ tx6Rm°Àʲ1šĦ ĴZݳßĥ 8# +è’z‘’öŻpçoc2x=Öí°³Npĉ…am€PU™fe“1a[}:Ĉƒ÷í{òô.î|‡êôÄÊĞ^ÈĴÂüúu1ҋE½ĊĵySgé™ShpÛEèĈµÛv³mıÍf Ív•0AV×aäkÖ êA4³•‰fž ai“µµ Š ĊˆÁìYÖ2ñX'-k ­“lÉúhÁĜ³Ĵ15ZSç9oWĦŠ5/ê`  ր24ĈJvĤ1Ù'ÛZ³] uĴĜžxt-ŠĴC5ci•Ô)ˆèSî)TI×·•œĞ\ábĠ&|+™8 ÉhÌ=)á•Y_ş$0m3#‹,“¤DèwJÄ6ڎŽ­ü§‘Ĝè@sŝ³%ħŞĞ1`żhž²ÌóERÁNĠ¨Ë`s–#žAı|éy³)I´·(Y; ¤İµ nNJ†(gÂ-›ŞnÉ3c§ÈĈoJ?bpê–ÁÙ$,Ŭ) Mç1škyJ8żĴ:óE´àíç½Ë&4ÔlÁl”( pòŭ:öy#ÙvÉXÓĜ I8+6Á.Ò3 AŠÈ¸Bƒe²ĥólòz/žáLOžĈÜM +gai!³‰ÊèÓˆâž÷éj2{ĵœ +ċŝyƒ‚üĈYŠjıäö¸jıÍÏ2D£w4eġĵ*¸]Ÿ?s ˘2·ÖĠÁ Ÿ^>ÌgS÷î~vèĝ‡.>_ŝÉ'ÓË·Ž‡ÄîöúNzîíäÒ#Îîïw˙8{°4zGóôÏëëÏܞžßsëñÇǽ#ċ‘?ĵƒ˘ ²Ì‘c}`e"ö<úġ’ ê}gİûqÎì)ƒp„ŝĜ¸ .…¨³oـ!ŬĵBw"êL„–Ĵ ĤâZ’ aĴŝykgzW6goëÒ¸&Ós61Ÿžw‹Œş˘˙³şâ’Â7%EÖĜ[×َİÚM³e²-p;àA[šx2{Ĥ žâi§g(ŽK˘!ž}Í<û\5ùŠyöĠgèw<ûğ|Ġg˜.Ĉ¤m^uÀŽl£"|ÀµĜÇ!&§ĉ~;B½Y턑=èï*[f†Ĵ0 ħş€!$œcš?(¨9ör$)(M5`ۘĊg{ ³ °Ċ‚ Co#.iÖóY8UKÊ lŜDĊŝQ˜eUžħ²İú2K[ÊF<*äżŬĜD…ú‹¤1ĝŻ|çÈyô§Ë‡é)Ĉ܏1_ïò˘W·ò{·bQzôhZM.ĦÑż^żr{ pèbM•jÛë†Áżâ“ĉkĝ9@Ċ&ç²>!×ö§ĵHĉEĉvGFn,^ÎËÊŭkƒ’éELM“XÂÎWv uÛŞĊŒC›lŽÙş é`“ĉ s…’v,ĉG…òĞ]ġï-Ĥ8µNRÔRQú&ßĠÙŭÍ#ŜKEžxLŒŬ’3ìlArL•Ş—nH=Hy6á.Ż€ö~ŽĉÒ66úX µ…lêä\I‘éÀÀ˙y3Ŝj°µbiáÌNËE_Ûèž­4 `ZuYN˜’ ÇËl%DcNPÂ%z̋!:Ä N /HiyÁħ>/8·_1š˙à .àâT÷ö™ï›ğG?|ò@‡R"0âŻ+<°ƒîŒ߆qŜÌĴj|Àfµ´C<:xÒĝÎ z[ż~:†Áĵħ*ŭ,j |œÒKZeJ|³ç›ĉèš> endobj +1426 0 obj << +/D [1424 0 R /XYZ 72 720 null] +>> endobj +458 0 obj << +/D [1424 0 R /XYZ 72 347.18 null] +>> endobj +1423 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1429 0 obj << +/Length 1388 +/Filter /FlateDecode +>> +stream +xÚWKs6 çW¨§Ê3ħĴ‡ñŜ²ytÒé֙Ä3ĤíA–h›‰ô’RvŬ__€9q'Mzħ@$|x96Aütó÷óòdtžóh>M§ÁrÌÒ`–ÄQœÍ‚eüŽ£,J$™ÄáġÍ/Wçƒù4\.ïìl^£ ’YĝEX›o„üµüytŬż2†é$ÊĤŬ¸(ŠÜJ­òŞÚàà)œŸùËáNş|š…u>HÏÂ=-„*tАÑCĴBĞR6r„ZYb}ÛÊeĥ´Üñ„KA‰)ùğ6x²fÉÁċÌZ›ZŞ 2Säkp󊏵Şh@ŭ Eے$šO&dۍĦ, ›­°ÉqĈ +{Jlĥ1c3§Ħeí,Ék%hKŻğğhg­ĞJ£è7Òöûvkö˙'ÔĞĜG×Yü’³èlž’ÚżjÉ$€˙„¨Ž#ˆâ ‰ż6£ÈÙp…7Ħ:+pè,d͵woŜˆ’[U:|¸¸½óÌ +Ĵ 3lvŝĉträjwîŜ–EXĵÓĉ ­Ö•(їhğPÙE`׏ì+˜¸mWpŽèĵiŒ\µĝáߝĈï-·Â âqĉQbc*ş;),ÑŝĜğq2†ˆ­xıG_èÖß;ĵVP| ­éë”ï3ĵî0ïċŜց‹Öz +´ÍY%u R‚ŞI˜×üp :ù„z‰£Ùñ;ĈŒSPĞ1’[ËábDíB›Ò•q5~Oч‰ĠóGZ .Î ‹…Ï/íX…%x%úPrÖkY!6H˘#[JûĝfĥX{Ċ:”0Ô5ñàş]Ġ½žŒb âşĜë +óù+ê]ÓŬ5vş~ÄüÏ7‹{.Fbêı\Ħşƒ¤ıñŜ0˘h´O"ë]BEo:ê….Ïd“¤+oÀe‹ÖWB€ċâ¤ĵi‚ +P`Ièà—Ĝ,Œ V…HQÈĝ1ĥ6ÔċĥĈhĉZĈ—o¤ï)ô„}ñĤ2B Ĝ’ĊJQHì!ŭ´˜’Ŭô>GÚ¸–Ô/€ÔİTWĝ_5‡žó)ĵr×íğ0g$.nG_¸'a°WÓ"bކu+7` mÄ×V"6o—Ŭ#öGŽß¸ß4ĜlHó½mDMtż×gŒ° ]ïàĊÒÄddò@ĥ `â?ÎzBi”žġpwı¸?=VÑîŬç·ĥ‡ËKLDf†µ­\îV6ÉY˅; żĥ@j\HÀ7C’ᕇI4ĉšA‰!l×?”äyÉÈî°}˘ĊèûûŠ›ó5y0Ÿ§]םw*İşİ€‡7ZàylVzmŞï…Ŝ(ù·ĝˆċ—ħ¸¨Ŭ˙‹˜Pé'ÊÈkÁÒîüäħ(ıIı:`SEÁ=Ò­ĦĠ³`ħÍ-œúÖÀQ×o]e…ë s'r>ĥPĠŜŸó“³/L@hÖĴK¨İO(7íÌ t Dj,GBF"ö|W™hÁMêıÁÜP5é„ùÙÀŝż6Ô bXıġˆŞŸà Òçúœ‡´•6Îâwε0Òñ¸÷€‰ˆıâğ1פ$ŜÎŭĞĜ˜Üċ1&p<mÛE6ˆäöà[xÖìvŬàs Ŝç“ĝ 5à„ô4 6y>äĉˆc€ı“ıÚNé> endobj +1430 0 obj << +/D [1428 0 R /XYZ 72 720 null] +>> endobj +462 0 obj << +/D [1428 0 R /XYZ 72 720 null] +>> endobj +1427 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1435 0 obj << +/Length 2604 +/Filter /FlateDecode +>> +stream +xڕÉ’ÛşñîŻP| ġÊ˘ı/İÊÁÛ¸œz~veĈ•Ô<ç€Ħ j¸( éħ’ŸOo (™$'6şîzĴîWÁêŭ³@Żož½ĵ +³UúešFĞ›Ŭ*VyĝAœŻnĥĞß½ÄO֛0ŒRïêŻïŜ{µ.ïĉŬzçİ÷oŝĵ5ŭĦVH=2âÊÔZHjŭú7yyUĴJżÌ˘ ĞM”úq³ĉÀ½ˆ™{zĤçŻâÏÖĴCPĦ÷€ˆVWCgŽNZAlwoUƒ]g¨şĉ0Ú +óG3ìBUŻĠÖàĦ-kŻ2żÌµŽÓòlûœi~óñÇͅħynfӜpŭÏÑ|[§™§jŬ£Üx+_ƒ0Ħ#ƒ9ƒi42yègQħÚ°‰˜•j·²}—Ħµ6í½lPÔ•İÍ`tïŻ7i‘yW€ù€‡÷ë;€Ŝ˘l8l1%&Ÿ^î{Ĉ {}$¸I8*)'ÈşË„Ç5ĴĴP y`³}„2ôjĠbÜŞÒ}Ür°°×(‹e>BMGĉÙĞ·°ğ$ +½/=m?Ê"Xġ÷A·[- Àê͉›i5CŭħE…ġ‹òÜyâìphµcÚë\Žá‰]ßYA™ĦgàÌq7ƒĊĜ û%ÓoâÔtR:+§beĦöL|DMu]óˆ°@u²ž è­j4ž0îN=°Ï -{%û¤ş—ŬŽÉŜˆDµŬ‚Wu­Ş™bZĴF! +M›Ĉ?žà|Ÿ.v`˜á™ĉP³1QDœˆßiPŭC¤j4~ĉXs@‰÷ù“˜Â/£òÉ´ĉž[”^×2ĉÖÔŬ=£n‹`ƒ$ÜÑınž1`ö^e™òĉóˏŒŒüHxZFH¤§éE:à;—^Ü`MìŬ{JH qŽċ‡ü]HêóNe pTĈHOjĠEžk£jÊçs–ƒġı´ËöÔgô‡VxHğèMOY(^Wİıd/Ù°˘^ĥRÎQ`Ú`•kšéü3Ĵ4Rz*#ž˜MWQX!}ežŬq³İ,b@ĈYħÔàâ TœĴ6÷{Ŭ 9rÊñ tĦÒOaKnÎ0ğš8'%‚{rĤóŭ!Ĵü´yWä§é""Ĉè,çK'ĝDÜĐQċĜV|Dċ&GŬdeá½Ĥâ¤Ì,7_Ry2Q‡sfM ,ZSĉIQÌĤĞYvBı ÜÏ9,˜ µ‰1ß2%î,´ ZĠÒ½,ÍљŸn/û)ö9ôù‚gf·W˙£•œŜ?q—ú۞RssZt]à!½<ۃ(‰8Cc_ĴĴKûQâúLĵşë˘²…<äŠ4jYIaċ?Ñ…~jĦİ­ñı„ ÇAdċçİĠôòú“#ݐœ/“I-Óùuç™Ítıò›š)ÜaoÊDÓ2^ñçÑl5ĉ™X9MèEžc°xÇ!ŜÙÁ`BxĠċi½pJ>Ĵb@ÇċšÏ‡G§‡\²ôß|úˆlA‘Rè›+œĝQĤ°%€Íí›ß˜ˆëEuƒĠŭt7&Š[żëjô N/)8Ï]Ú0¤ĥĈMqN/ íşİËĊì²eìT ŝĈÉċĉŸûLûÈmDžÏß=áÒÜç˘vŽjYlĥd~MeĤ˘kS•Tr’·”żŻuċŠĠ³ˆÁÊŜŻĝëûgĞß)ĥż  îŬÖùüh]<ÉĈ‘_dċôôë‡ĝĝ›îñ7ÂÇßL^ ïş#ÀAwôôûn2ğ(bNàÓĊ˘pOqš-Sj*Ŝ“H8_ż +×Ûĉ›ħ(ŭq‘LË÷ʅSĝqdŠ$ĵ“3ĜŬX‹š§LZ­Ħ2½Ĥ§ËìÉ÷™éÙjk•\£Bßa%Ħ‡ó„;İÏoZ@—&%ħoëŭ¸WBÛ6%ĝ;”p£‚f›²E’zݤ (iġw/mbŝĈĉdÏÄ}_^ĊÁ…M ż(Ù[Í+´GŜë?ŭâß6ŻüyÙ'p}$ħ ĠŽĠ z.Ôƚ˙‡f™GY…Ż£ì ċ61ÏhüB(Ğ•›µ/^8´ì’?ܨ!Dçè¸ êxè9žÈó§ZxáHċ$Z^…M·UÇ Ñ·³[§'żİÀÏA˨ÛĦ>.ñ%EŸhnÏĜÁEòçüü˙jbôÁ$H ½a 8Hù-ħp%yÁÏ0$Q­Fş †~g¤§hZ6µŞż&â—::÷ÀA˜ +ïżÚ +;j ƒD4ş(ÁVŬá~HN}•e)`Wy ¸Şn–Îê²1™ÒÎSm•~–ĞMÙPVçáٜw7Ïŝ=|YĞ +endstream +endobj +1434 0 obj << +/Type /Page +/Contents 1435 0 R +/Resources 1433 0 R +/MediaBox [0 0 612 792] +/Parent 1416 0 R +/Annots [ 1431 0 R ] +>> endobj +1431 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.873 337.974 120.596 346.775] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.8) >> +>> endobj +1436 0 obj << +/D [1434 0 R /XYZ 72 720 null] +>> endobj +466 0 obj << +/D [1434 0 R /XYZ 72 720 null] +>> endobj +470 0 obj << +/D [1434 0 R /XYZ 72 325.03 null] +>> endobj +1433 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F7 1089 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1439 0 obj << +/Length 1706 +/Filter /FlateDecode +>> +stream +xÚ­XKsÛ6ûWpr)Ġħh|{’̸ħI'ŻĈjUt`IHâ”UŠ£ß],@‘’œÔİ/ħX,öùíÂÌY8Ìy}ĈÌï/“³‹[‘8İ—F"r&s'N̙ÇüĜ™ÎÔ ĵÀ9™{ûĉíÍġÈîĠ(ÜÉÍhˆÈ½Û­‘Öf_ÍzğZej7šM~½¸í Lx1pµ–ŭ{S£ħ3·]JüàÚV²!Ú˘ü2‰+×´S‰|'óĥĴ×(ŭ E1G-úĝôú̙j&îEšÁ +·ñ„ıIiv+ŝ×h ëŞÌ T[ŬL¸ğ£‹ë9ŠrĈV{p…—†!Ù@W£Äü„Êû›×àƒu‹À­@wîJZ4à-à×ŜBÎl³ÑJÈL™³Yƒ*\ °ż·>ëy”Z‰—¤ĵ§ÍĈ%Ħ;-Ju9›fóġÌ.fÓzƒŜkfÓçç/ÎkE/§Eá­VŜnGëĥ\ÉÙì8€ö:A×M–%¨*Ào*ƒ‚0n‘mÁ„`t‘"żn”lŒšĉ^eè-(Òî4­T²°[}6H™ŭMBPĥôğŬ˜5ıµĥğ Ŭŭ™ñà Ş#i !×kI'Ó6pŻŞŠXLLcŒi€YŽág¸wñ 8ĝbÒâgŽĦ˙–MKÈŭĞ3?3†¨U/Tĥ˘Ċ:[ifîÎkP +˘6÷ş̕Ö5ÈÔ.—ŝ£/ĠAÎ*ZĦ dU ;­;ˆû”•MıX—ú¸:§ÜÔUYÜ.÷JÖ¨Ï=Ġ3°ĠސŠ2ĝfrö)TŽħȉpòĠÙtĈœèpŻç§‰sŻıVŽ}/ŒcNċܝŭ6<Ĥ€H€Yß8œd×(7ıĜK$Ċ^Ì2uP,œħˆğ·e%ɜĈ”h‘gÚ_zÇĝÖ;6ĠĦ6âñúÍM„Çcñĉ&Ħ‡İ1÷ÍiÂŬµ(èÇü[V=Z­ĦU1óŸÂŞr…Ù Ztú,ÛŞGk54*L<=I¨"î% á0çŭNêĊQlûèóc †Ä†fߔî‹s +0€ŝħ@Â)ş/%ÂPòÈ2ôúŠ6ŭŠ1÷:kmĞÓ eƒ¤s +2M/ ‚ÖLÊŭ‡È<ÚµG‘a‘˙Ì9 ˆ „n›Ÿ†ÏÈÂ'|‡ŭâĦÍF*šbĵvĊ +)ĤoİZCLħ͍XÏaO~„à}Q+˘ÚÏú’“„<}èÜû4rÖġ~ż²şeJžlé²Àvd˙ߌÖ´v•ÙŜ!³ٗĤUÌmG1` íLÊAÉ9)äBĥYYy”£â`>DN˘´?ĵ +3ĵ’Âa‡ë@şÓ`r=ÄuÍ÷ž¨‚äŬ{ÜË}†N Ùgî·×ϐ€R´Ó,kĠÂ6§e–çrƒƒŠŜk!¸™*hġêĊ;:L!2<](Ĉ4“Z}(`iµ·EóÄĠ×óĜFÛ +iNÖyµ-(xX9)gr=–zΰrs˜ÏÚ˘ùNeáĞPfh'ş8q˙|ġñ“a(äF­v´ì˘=Ì}3'!Ğ'²’lĦIÉgħ‹xÒg÷p@û¸p3ì|í³ı0Û5u•µd¤,ìml•súĊrÁ3}ó€LaFáİC=ˆL ô|Ğ”™=ğóv€;!&kàU" ½0ħE³kİp࣊TĞ~qù>S:pwĠşÖšG½?Äé÷Ç%}ĜgFoÄziaġĉkĥڀf?¤Ċ5]÷ŝ7o½ŸżûŒy§ÀR`Òï\˜gÊ˘\Ż;˜ğ/ÛĊ,†&!ñ4 Àû(´xfD·v˙ €cŸJô~ä hŒ.ŸĈn;=u¨ìŠ˘gĥÁˆ_íò!C @üûxŝñà÷ħ;Ĵè  ?ˆÑ÷bżU¨D˘ĠY.óZwÔġFZèB‰"ŭïX=ġĉŝQ,ş<#[ÖÑO#ħ›hĈaÀŬWĉAĥQoPÇĝ‚$ì1,.`*—:&@>Ñi€Š3ò5²‚ĴÑèÓôóiZ@Z5›Êş‘°1,tc1_F!4%UÖ[s˙=ş€ŽiTöcN8´GXÌqšÓ ƒ&̍vˁMߟ-ú+pï˙ĈŸŜż; 80)S”ûèĦ£(AŻ}9X&EûĞş;6?¨”SïâŜ{ÄvÖL·Ô!9B¤)x‹ÁS€'¤d,\0*˙ g¸éŒ +endstream +endobj +1438 0 obj << +/Type /Page +/Contents 1439 0 R +/Resources 1437 0 R +/MediaBox [0 0 612 792] +/Parent 1416 0 R +/Annots [ 1432 0 R ] +>> endobj +1432 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [417.47 707.104 432.192 717.952] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1440 0 obj << +/D [1438 0 R /XYZ 72 720 null] +>> endobj +474 0 obj << +/D [1438 0 R /XYZ 72 720 null] +>> endobj +478 0 obj << +/D [1438 0 R /XYZ 72 514.588 null] +>> endobj +482 0 obj << +/D [1438 0 R /XYZ 72 271.95 null] +>> endobj +1437 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1443 0 obj << +/Length 1963 +/Filter /FlateDecode +>> +stream +xÚ­XÛrÛF}×W ö%P$Ž0\ŭ&[ònRħ][Vž² + IÔâÂĊ%Š+µ˙ŬÓ= @RβÂr0˜KŸ3}9ÏÙ8žó÷+˙˙s%áßs¤ûN,S‘xÒÉëĞ_xNŭ?:žPiâĵ˜Qµ'‰hVÎçĞL÷bÑ·ĤH)Ò0äéoŸîŜrİH#?ržÖN‹4NÀ)|œ§ÂùĊŭ´Êĥı^IßóÜ:kÊfsŭċéÇĞǧ™*ò²óX`ˆÒPDİ< Qš +ŝ „ğëU ċ>”ŭÊŭÄŭz½R*pŸÇ²VeƒOÊŬêj÷*²óM["K”ˆUt dI,”χs–§^è~nğ [MhÚqĜµŸg˜‹làwÖç#ŬĉZşž×v…î^§l,ì‹È]wm½ĉÀ…óçd˜A(󸖊àÜ/l²Ô6Óuċo¸Í7Âû\  šB-IxŽ<ĉ VIG,îÌqkp[°Ċ˘Áì˙7üĴ[èHáEɽ˘A9²ÒÖµÉnĜQ•²Ñôuh·°™píĜċaPXáaèZÓYŒı5A—ÀtGíu[UĈ–ÜÒì²aCéN•ÚŭÎĜó{óŒDŞ1‰—{ñ˜€Ş3nĦ£ġĥÚ}ıiÌJĈ/<ô ğƒ)PSîkêÏìk2ĊÌ=i +)ѳ<ċnk€ŒĉŸÓ=k8¨ĈW£İĥ0”Iˆ‘| ¤Ğç›NÛËB÷X ċZ€²KsLÌYàĦ£g'ß°W7\ÈlMlŽjœ!u!ú÷\[&QeĴİû Ĥoİù²-s\K#jl`SWg†ôxò;ò˘ÓF^V5bB’ˆÔO ÉïY û7&&½ƒ+ÖŬ{ċ͢ĉú‘Qkfî{(|Ħşww8yHv¨-‘G—”“ûûC@÷£Á”mÈÜ˙×"˙À˘ç[„|aàZ=‡‡Ġ޳˘‚Vü–nîŝëVcċšr,ŬyJf×éA Y˜ßWŽÄù‘FËf²Ċ‹ Ëŭӕ*ˆc"B ĈHF6Ħ„µ•oֆ,–DÈÀAŒÙœäGÛĠ€ë5Ü<ôfe îlsĊPP÷$Â!~ß˙Ó>ß"O4ĝáÄcÉÁÎj·ċ|‡27›AûġB·ÉjŽĦ•5v‘ž0Ĥƒ •*¸ùµMâTj:WÜ9|(›~èFTÍĝ47:pŸ`iĦ½QŬĜ²Ĉa›af=Lŭŭ`|"+à2] ĞrÔpĵ˙D+>ĜMĤúc֞s#×' +úWys˙ +”ü 0H%§?dÒ6tÖUĈl†ƒ÷ĤDdW×vîĥĴxÎÄ$Ì(ö’ğ§žié +5÷°_‹ĉ]`a %ñâmÉŭ%o ÔĴNJÚes +kĦŬĠe3EÑAŽ^¨ÖŜ$•˙=E*¨ +Ŭ\3ŭbüí<‘ĥíĠ+šEm4ŬĊcޝ“Ñ#¨Ž‡Y€ĝf wħħÓ·ô”ñ´r çNÓÌĴêİ/P°S˘Òáa•İÛŭĥÜġÖ, +&R$è5T#KÖß‚c“@GP M1bcŒv‚PÔ]R‰ ĞJ£) Ùk„‘ƒñBiëb›u êYĴğ> endobj +1444 0 obj << +/D [1442 0 R /XYZ 72 720 null] +>> endobj +486 0 obj << +/D [1442 0 R /XYZ 72 365.718 null] +>> endobj +1441 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1448 0 obj << +/Length 2586 +/Filter /FlateDecode +>> +stream +xڝY[oë6~?żÂ蓌Ĉ +%Q·EOl.‹.ڃƒĈÁMó XrLY +$ıİħ~çF]lċ´gŸD‡äpfĝÍ / µĝ×%ß?\ŜùÉ"uÓȏëí"öħ§\ċuxt´Ğ]Ï \ıòĵP9­İ^–Ğ ŽĞÍĤh[ngU΍ëĤÈş‚Û÷]ĥm—Oë_Ŝ÷ŭÄġ•ëòû‰sĊ^ˇµ¸_żvĤZl„ıÊ#·Šß•›ÎüħÄßvEĊ­M½Gú³İŠeYĴìŝp"7 C–âÍtğċJ‡žSwğ˘ÁĤ²[ğËUœFÎhMdiëĤ#= lŻË˘ċ‘gÜëÈí4Ñ˘¸{XzN•óҞÓáİħñğèïż“ŭšĥún"ƒÈ& mQ≿&UMÏĜ‚$¨˘Á Ş9‰YLl&°N¨Ú˘`ú33—5÷CŜl <çoo–d°$pÖ·Ì^ĠÍ>+É(°ÒĦċ5c>(6~΀çŜ/5-Ÿ“(› ÏȤ1x¤bç§íÉWĵ:Şğ×üa͝Ĝ :r^9b§¨.°ŸÎ¸Dh‚ħ +nƒÜ÷Th½Cğe‡§qTeSĈc\Ész-¨LžbŞĥ+²œ;ġÖî. [ÏİkÎÂìnA8]_MʸX—$6´÷Y·Aì¸+äök&nê§ĵĉퟰ& ŝ{è°ßËğ@î6Ìġc×÷>în–НËïŻÎqà„÷Ĉ´Że&÷%GĦÀ äĜĜÏäĴ l Œ7¤Ŭ +' +Cn¸usäݘ]ĉ`;ş†XxaĈúV™üF~ÓÈ̒ ‚Ê_7ÉŬoÑLt˘™ëß™ĴD½ Z³*jŠwu£ċ܉=÷9hc'“oçƒ?ĦŠpm\Ü?‘<Ŭ0ñĤá#!' |çÈq$JĞ²äĈ{ñ‹µĤŸ,€xŭ`rµ³FĞà•ö·WEOô%£|u…ÊW Ĝ-Ücŭ@—Żt•¨è ĉ+,_K1ö`?L :kÁa€c¤²LĜBĵÄ/Í= –ü0!I‹2—1„Œëbĵ™l˘µì‘ĥÈe÷ߖş/ĠòĊfŜs¸wyÁġδÂo€Ÿ…•I¤jdí9Ŭ–™M.‡6[²ġ ZġĤŜ;ĠDézŞtèfÌôÒÇ{ĵüDù&áĵïìk–aGŭ@P[NÍ`#€ï³Mœi§jSrBCêñ<6µ:ğ$LèÔR_ŽÊBœcp'FĴĈBĠ:UEÇqö}?ó§~Íú–&g"(é:t {›s·Äs“èŬl +ŞwSŠîéÇL YJr 1ĉIP¸gL£Uq‡ ¸xˆ6Ñ4£ Tyĝ| +I›Ĵb˘$/L…Ms&sÎOŻú — #)è!éÀ™}½Œ4IµlĜYİ& 6qȤób›$i$m!ìLİÂ-Ĉr‰0†ŜK֜K8€üeşW_Mù|mĥDpZ[E#U`ç"£Q%%' +oCO‚ ÀÎï3(x(F( !x#ƒß ”ĤtİEŒ†;ŠûÛäB3§G£\Xé2FŜh˘}ݲ}Ác‡Ş´é0ñ‘ÍߑWarDĦ­,­ƒŠ”•ŸR@\ ̈́§„Ph1ĦëÏ0ö+ĥ.Nv|/Ì$#ë#üÄ#ĝ!"Όúô݇=Ÿ!üümĴħC:ˆrŜ­{Œĵŝ™·ÁȝÄvrÒȍÒé{Ÿ‡ş0 Az*o~Šc$”Ì ™2pzĤ6Òıü7ġ~߯ĊI Ġı’ÒŠ‘†%úÊëĜp‰|+Ú8œ_jvSÌRúç[R÷kSż4ÙċŜ¸x‰ĈŒ ŜêÀ@TYä„ëè@䣉Dƒoû|9ôĦˆW" ˆ :~ĈĜèá`ĈĥPê,~*5\:§d¤A~ƒñ Yn é?¨X,܁pTb +AҀÄi:(DÙڜ–£\—ĦPÁ=À"E Pİ)·f :stŠ"A¤‡(‚1ı;<ÔA‡|żd˘3è[EpRĝNMë÷ĤĠƒi}kZ}bZ={Š–ìló-ਰ@äPġí{9ż˘½@Ȏ2ò²akĦ“×UŸÊü€èEWè=ĝàġxùôĝ·?ÊġˆßóÜŬïŬ‘ûh˧§ż|[÷‰ ¸d˜(ûL¸b°@ħEÏ+t§OóÎ>Y`I:ŭ[Q.iäöd† UŠžĊ·!g.;ğLSÈ:Ûş”ŽÀ*’J\ö-ċ|u3ɰ˙òħĝ@÷MËO? ‡Ä#}Ç(7$ ™<‰Ò<œaïŞ~DqDîġ@}ŸšÁ˘½pÄFX‘ûĦ*éч,p̝”éQԆÎè!×T¸zù‘;§İ-[zöxXÛġžwûÈĦĵ1¨xZ* ¨Ìù-ġ°!ğ{ÖòŠ1–^$4/ 'G´ërT> endobj +1449 0 obj << +/D [1447 0 R /XYZ 72 720 null] +>> endobj +490 0 obj << +/D [1447 0 R /XYZ 72 720 null] +>> endobj +494 0 obj << +/D [1447 0 R /XYZ 72 518.831 null] +>> endobj +498 0 obj << +/D [1447 0 R /XYZ 72 450.385 null] +>> endobj +502 0 obj << +/D [1447 0 R /XYZ 72 393.893 null] +>> endobj +506 0 obj << +/D [1447 0 R /XYZ 72 336.848 null] +>> endobj +510 0 obj << +/D [1447 0 R /XYZ 72 256.999 null] +>> endobj +1446 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1452 0 obj << +/Length 1844 +/Filter /FlateDecode +>> +stream +xÚ­XYoÜF ~÷ŻòRmUf$­Ž - qÓ˘EÑx_ +'³ÒĜĴc£#΢äÒ%ĥ“p4‡×9+ĴKXż ŝܞ=ğp#+vâÀ ĴíµşV(…#ĵÚĤ֕í;#ñoµ–r#ì_U§Wk/ŜĜ—ùM•żÒ×Mğz·ŭÙĊ)鎸 Ċ°ıĝŭÏWżÜÈ~ħŠ<{û +Xĝž½oêĠŬĥşµ”À¨Ŭ›M)‰êòşb˘ĵ˘o‰,ûdċ†vF+]6œV%îHá>Ŭ-ŠĴġ 7Xëě iò ä&Üe­ŝc­?·Ï[şIGc…²ßµš—êkú’´ÖY­}Ï·_רıħ$Hûƒ5çH‘#]šĉ(‰f]Í_ £v+içž:L‰NµbÑĈbêŭWPyĠMorÒİ˘)şâœn@זŭÓŽ”£+Ex¤šŬÑ|PL›ş¤ó;yhëëşa†u²;= igA[g´7rb7&{_êDġ­a-q£*Œt02a*ċsŝ4<:ĝ‚†]ÖhA ×ĠoĈö]Ĥ+Í×ODœÔ=MhĤšĊċÒ=<}wùĠv8óíN­êÜÏ8T Ŝ .ßàBŜAD‡2²·Yŝ0ÁĴ™ĤÊß÷<&ñ@{Ú˘_ 0Í1Ì1ÏäXtÌħ1{ç@­S:9fÖÔKn,Œŭ7uê);ôT´à(é:Á&"?ü aċ +ñyÜey‚Ñ^İşħúÜçï^—<ÚĤ‰K6qèH`ó=‚Gˆž_CœàúSˆÄƒ,<Ì]·wĉÀ‰eĝ˜\ŭ4„€M$7 ÈÜaÌÄ?ÁRÜÏËR§9ÚŜ7:Ñé<µüö—ñ›]×K(*@Ô4×VXyŞ›ƒ‚N¨C7:iü =׉fmŸ{Òö-tyħtĵpŒƒs;uk@y^îCÊssħb֐>ğÄ ˙5 ˝(vIÌUŞWNYW]vċ´jVë €~V÷ÍĠó2ŻúNżŸê+˜“$N%<@ ñ0ñO]À­|4íòRY ĉeŬ j,ĜA0È;]ĥ<Ĵèğk”òhÇğj8Zï1 T½‚/ bUéŒeZw-o&u]O(*ĉÇöEÏ0çÂhóF3m~=Š:,ÖId×@ĠP#{ŻħĞςVnìÚàkĠ™™c€Q§ù6ŻàĠ3ħ1ÁàċBÁèF\ÍqC9˘™R礎ħÔ·FސtÍûŬĜ×´BF–HŒŬħYÈoònà2z—i˘–K…DÁĊR##mgÉŻÁ8ìf¤ÀNÚÜ=ùdĥm_˘81qĦĤ †nşŝD‹ˆoç—ĜuĞĉA™@ĜBŸ„Áx ,{#˜"k =”öMFó8>ÑÍèCsyHôM>§gĦŬġ ßá‚ÑPg ™ƒ25teB hzÜpáġĦS#&pS鏌ş ëa${6>ħ|xĤĴĝ‚‘DTċç_ žQúÇυĵf]Bû2/ôéá +Iê6˛ôœĈ2Ž"ŞîD)3zñ×½¸„ف3HGɇ–° 'w8ußѤєÂč’˘65ŜôH·|Êĵp ĝàPö lìéħ U°9ÇĤoİš[d;\Î+PO4Á5~3J #²â½#:´‹I·5/Âsĝ⋠+âÄäğy ڇĠĵ[àÛ÷¨9¤nĤ#‡*it9ÀNJ‹Z}$ÌÈÀQ tÏy{K\Tb$ŬĥSi]™wvÓ{ĝ: áZLɏùŒ;ïa§çœËIuÈSOàVxÁĉ׈8FŜ>4Čı?´4AŠŞ^Ŝċĉ'‹À÷ì7T‡÷˜ ûk™şáµ ŸmߌñÈcĜo'!€=}BKX¤hġĝD;=ş~ZZp-šŒ‡…_4 8Ŝ465Ġ `l0†Ÿüo èħ´\Ü?ĝŜ½9ù-€Á˜ówÒĠ;Ìf”y™aÊ*F8Œ7“–fk‚Ôè*Ä´Ŭ]ìħìĦ&e[X¸ËŸpŸĴN~kN8˜Ċó=żĝ5†íËÉQÈÍ`ÈMê9ù)r$‚$BÈéf?q2r‹òà"aı.ĵßd 4|}~„› ĵdŝíHg7 +endstream +endobj +1451 0 obj << +/Type /Page +/Contents 1452 0 R +/Resources 1450 0 R +/MediaBox [0 0 612 792] +/Parent 1445 0 R +>> endobj +1453 0 obj << +/D [1451 0 R /XYZ 72 720 null] +>> endobj +514 0 obj << +/D [1451 0 R /XYZ 72 720 null] +>> endobj +518 0 obj << +/D [1451 0 R /XYZ 72 564.844 null] +>> endobj +1450 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F11 833 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1456 0 obj << +/Length 2402 +/Filter /FlateDecode +>> +stream +xÚ­Z[wĥ~÷Ż[)gàJ{šž½8mïĥµszÚ$´D­y*‰.IíF˙> @ şK‡>Ĥ@œù0—o†¤“O:ùŝ‚žù˙ĉŝâÛA'†˜”§“ûĊDó‰f”PĦ'÷óÉÏÉ%á$ËĤWŠĞÄĵœŝz˙÷oo²½trĊ3’†ó›§)üNŠYù e²h삣Ç<3lÁq‹ë˙ÁçÍó­żĜÔċú^ßġ&Ż·Ż'3Yĉ/uµ +‚RŠWmF”ÁĞëÛó:xnÊu\n§™H`k!iR­ ¸&İjüżŞj?2Ï[UĥĊŞÁùĞ| + lqüñĴÊĥ-ĉ~ßr£_˙]ñˆ?gÓ+–ä_ró·ßż³wŻ­D÷ïq´Ù<4mÙnÚ˘ÁöÑϟmêşXÛíĦˆ ´· +3FŒR¨pû˜TÉӁLŻ4˒•Sx¤ŽÔJUNY²ĜşÓ°÷r\֖ĞóĈ=ú‘&Ç{2)À$D1óۆ‰;‹9żŻLŞŜ¸|} ĜIİ“Yiü|0Ò#é0’xú'´]ċmĥ6 µ½ÈÜP^e4ınĉ—²}ÄğÄĈ›c[àŬj½ÜâŬžòş-ó½ŭp¸lpäSùÙ>¸Xû}Nœ,̊OV( „3os'”\ ŠdU6“ÒÚħĠPJ™üµ@ –I^™úëĤr;şĊĤ†#Ĵq¸ĝ-_=-‹ĉµsç÷÷˙ż`D:a6`(­‰0“Ùêâç_éd Œd“/nÒjÂ3MŒ4p½œÜ]üó`yŞißz˜‰şárĥĝƒFg°¸1Á;göÜ(–Üùڂp$½PĈ 6\†#lÈ|1ÊFY>‚S¨”ÈÔ żPE–ùúpÁ +Ĥyò6Ž2™éçÖuĥÖu^áàŞÂ)Żòġ/ĥvf‘×Ŭxè„7K–œ+$)1\“”D1‰8qNÈQ× §4yW̊•U÷Ÿ÷νîz´ż ŞT„˘†ÁzÄ0@ĥ2zsœ(ea`cA˙,$°ŭ÷Ì@>Ğû`ácŬ™&”bœ’”ú`4çVó>qúbŜÇ&âŬç Ö-††BJG1 š‘TfšKï€Ìġ6ó|Ïù$êò88ôİ>XöHuia4AuiR’š`’ÊÌŜÂé}d +·y½£pÈWœÚE":›Ú:*p*’>k'µÁÊaŠV&‰ŜN È,Ġ@ŸëĤŬ!u`!²’.ë L:}P Ö5†*5„™QìJs˘³`Wž„1 %Ġ·vo)`ċ"m„š­ú2ĊB蚷:î*,îJ ç?n{pĴĜ.ÄÍ Âs‚´Á>ÂÉóÜ;Šb¨M!H]‚Ô€ŭˆP×S“bżĉÜm×vĴÍ;ŸsEDŞü×3߉s”ĤÚàGÛgŸŬħĜ܈}híÁĴZ­|˘7I³ĊŠž‹­ĊĊ_èsMx|”kö;Nĥ—&2ä˘Viû‡êÜèĴ˟ŜAëÀ›q£×'>ğ] +ä÷i÷K!3ħK0kڍÎdM{ËZ’ şÂ+Ç6êV•%–vl³^–ĞÒç‰Ŝ×çİJ!-––4u<=òĤpD]'ždzHOµĊ|6 yġı6˜€†ġ‡n2"9œ°kà Ä oÊĴŠş@o?ŜŜ^xwÂ5uÒ p,7Pl:JS†C9‘2ï‘7ïŝ[üĝŻ^_’˙fâê;Ï~,C݁m\¸Ĝ͊ÒAŜvÛi·ŝ\ĉaƒ•aĝâbŜ×`}c¸€yÓ?Öĵaĥ¨aÂ'İòĦ˙0Ë §XPħ.fQ—Êj +µéÑu°°şf@kĝË]BD³l—HaU]e€T³Zĵ›“.Í%Ô·İ´%ä<é=ò¤!ş)ûÖi[A:ÜĠÏŬ6ží•pmUŸMżáL+c"8Éh6&"…e{M)3Öm9Ö~ñvŜŭ–iŠxV9ŻËŽƒŞo<ğˆŜëKßż ĵ2*P'öĈS]|.ĞMÓ5?]Ÿ¸!=à ĠîÊً]’‚dé(/pYމ 5ÙWeé‚ÁBÄ:(¸ĊĈhċ0ˆ4ž”YCHmS< +=NÒùӑA×|°èħĉP5F‹›A}ݤMßLŻ4…Ìĥ‹#™yĜkq÷•>Ğ,yĴ8Ï0Ž1Œ¨Ìg’Ÿìç3TœV<Ô!2Š‚Q<ó=èK*ìŞÂ}Ô7 'Dî+-(ÌPjo,: +éLy4µ +endstream +endobj +1455 0 obj << +/Type /Page +/Contents 1456 0 R +/Resources 1454 0 R +/MediaBox [0 0 612 792] +/Parent 1445 0 R +>> endobj +1457 0 obj << +/D [1455 0 R /XYZ 72 720 null] +>> endobj +522 0 obj << +/D [1455 0 R /XYZ 72 454.857 null] +>> endobj +526 0 obj << +/D [1455 0 R /XYZ 72 354.042 null] +>> endobj +1454 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1460 0 obj << +/Length 2254 +/Filter /FlateDecode +>> +stream +xÚ­ÙrÛFò]_ÁòX! §ŞöAÖħħ7²½ĤRN9ÉD M”A€Á!E[ŝĝík@‚²Ŝ­Ċ fş{úšoöeĉÍŝ~âÉûġŬÉٍŸÌR7ühv·žĊŝ,Vžëéxv—Ï~u7pŭùBİsnŜüt}5×s1O#çîzIàĵïğ]ßÍż{{v3ĉäÍ~èêH3£7İ“›u֗oĥġ|á'ío^èU5Żë]WÔU˛֔fĠ™Ô)€B-ÊÀá‹y˘Yä^´ğ2C“í6Â|Ġ7İ%ÂóĴTVċB\lA™è•ğMvOêšĝ—ÉÑb4R)7 C6²,ڨ́Ż0D9k^ge‰ LTA9WŽAd+Ȏq¤*TELŜ¸5ĵ%ċ°oM# Ĉdà™ Ğf|çħè6L)ĵ}²şµl@‘\dƒċ~܀ìC¤µuç~ì˜ĈL9`jÀ=áQ™µèk?p²ĠÊ´-Ú,ÈH<ì‡#Ş-`HÄp‘(sàTTyñPä oŸ•|l8ßĠ…ħžÌĴ…K"'ËkwÙʲ1ÛĴ¨èĈH] ǍàmÜM™:܉;_„J97…ÜĞAX×5Ċ}OÖaˆ× òÁfŽf‚YC ygegšŠ¸°ĊFĵ‚˜!ĊZˆQúWE™Ŭ—³ƒQ}•c`àòóċ‡ZT|3œfâ­Aaô݆˜íkĞŜ"öƒ¸ÓXğߔp8ŻXDĴPĠMÖdàÌĉ/XéVè t âÑÖuGLÑòñvS#ôn³–Ñ™ìÉÚ²¨„ß ({r}wòlj½™šéÀ‡Ê6‹tìzĦž­ĥ'żŝîÍrÀUN“Ù#Qng›&)ĴÊÙòäŸ\&ǵMĦëİ8EnJ…{É^•(½żb›š1ri•KCoƒŻ4ÉZ¨ÄMŭ”e½Ğ›-ÜÏÖ>ôg˘& +˘A­€VÉQiD\.Z¤ ÜbĊebŒ1BtBŠé¨MÓ2zŬÔ[FÈ-•W¤áÈ,{Ӓ‚ûrƒÔ”Üe.Š€döfâDŞqRÑQa›€+Ê0‰ħóDé™ ċ7F†ëşŻ %˘ÚÈZXŬ0Îü™mwÁ:޽Tĉ“ _XlÁY>’ñĥ^ ^äHr‘Ú\ÇÜZˆ‚œoÁP + +hĥW5š +î“ŜƒĊÁġ·ò}UR‰EÚNúê `…Ċ‘Y ġĤî¤}˘öX².aëßÛúc\˜¤žs·ħĴûjUö]Gar +ËĜèZHû˘,9½Û)û͟;6ĵ)Lµ"'>5–—hk(珠JòËrîÇ}Ñn`8É#S¨×Ç.;Û5ĉĦ¨{‘!PŒä€‚Äà£ÜAk'#9i­Ñħ1:ölê7TókÄRë`ĵ•sŸÜxf’5òĠ4PdäĜ^àb²o _$MoŝÑĝĤ}7öÒÑè*™Żì‡óÀßĴĈàx6*`ŞĜ› 5Â(˘pÔ÷˘(W'`@â›&'…û„°•ÛF¸}}Ê´<!Dñë‹İL9ˆx{ü]Í=9lÑa÷4|÷&U~·9ċJlm9¸A•& ;Ç8ĵŒô<ôrqëòâÎ^ÔŞŜny(h)+İ2ı˜ĥ€"Dĉtû>ğÑŜшƒ*2ĞS¸ÀÊÂìòZ“ÚĦëk Ónޘ쒊hÇT\@C;Oႆà‰F˙m*€•ïĞÜ$q]ħ;ŠCç’ +TXíy΅Ì~´ı­óbÙéf‰#ı–•3ŝÛÑWçĊáó?B§,yíİóĊÇë‹+Ħsoħ…*PÓĠîûUç⟇‘àŭÄB•w,ô6Ĉŝ. $ñòÇëË|Z²çŬÏ׿X>‘kŸ´¸0Níói£„ÌU8ı§^J$Ċà–~›d$N[s‚è~˜˙ÓÑ÷˜QşŜ ĞǁÉÙuCcDJ‰Ç­÷#œFÈ}T£™ŠŞXú[™{Ħ+żBhÂ?#´ŭs‹ÉĝwĴyz„ ÉvE—•ô#Œİk!¨òbĊ0`7Š ÜR ̐o°ħ“Pz |"h†ÂĊñÁ†hòİ‹ŝ +ì„ HŝçB3Ż,Úl+8Ž^ž£íX‰ôĞ™?\Êxfï‰BUıà=‰ĜïŝS-.˙ħ€!˙½8Μ'iS8|Ú#ÁìäX4ŠqódÛ7V|CPÚfÇ Bûc Ûş6À†Ñr²ŭħŻM×AĜÔGìJ“=ÇÊ +ײÍÁß3ş^^^/—5şŽĵzP4ü”ÚÀ;IÇ'ïNŝ ÷1ó­ +endstream +endobj +1459 0 obj << +/Type /Page +/Contents 1460 0 R +/Resources 1458 0 R +/MediaBox [0 0 612 792] +/Parent 1445 0 R +>> endobj +1461 0 obj << +/D [1459 0 R /XYZ 72 720 null] +>> endobj +530 0 obj << +/D [1459 0 R /XYZ 72 720 null] +>> endobj +534 0 obj << +/D [1459 0 R /XYZ 72 553.833 null] +>> endobj +538 0 obj << +/D [1459 0 R /XYZ 72 262.526 null] +>> endobj +1458 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1464 0 obj << +/Length 2161 +/Filter /FlateDecode +>> +stream +xÚĊXŬoÛF ï_aìIncUwúiâĴíšv¨ tëşĊ’cĦ²dHrƒtŭÇŻ“%G6 èòŬñx$Gò~´3ı™8“Ÿ9ò}ħ|ôôÒu&ħ:˜,דPOBċĜŽN–éäkvô7)?ô­ïCŝı| v̔²cßg…/uzŝr~ŝˇĊtĉkß²?Γ=v`›?˙ԏv@v|Dzñİç?ÈĴ•XŜ燴~\\ĵ;_™çï?ˆ íÙŻ÷ +O=e´êÈ~·j‘ŞÔİ?ÈLZ£µÎŜÏÏ.ŒÉWsá·]#Äĝ~Péœ*Cò† !·=|ÎĊÙĠŻoĉĉœpf#'ĥ_'…äF-TĜm¨p̜ŝ>ıïŬ8ĥŬ0ĠĞÖÎgĵ4Ì<_çE֘ĈZ¸Öu–ĦĴ§—Q/ĝ_‡{İ+*Ŝ)Oö% +d@Ĵş`jUóğÒ*/4ÁÊ£\8äu|a;î&WyGœbŻb´ìĤŒ1ĉıġö@^âĞV•êŻYÍ" ħÚ·R¤a+y ˆ+Ÿmİ9›Œ~…UŞqEÚ0Omı|ÂÊu‘”Ÿ™ĵçÉ žÊ/ĵıĤ7TuHĈ$’Êìĥ¸ô­cÛQ1`ç°³üVFĤùòÑßvíQğ +endstream +endobj +1463 0 obj << +/Type /Page +/Contents 1464 0 R +/Resources 1462 0 R +/MediaBox [0 0 612 792] +/Parent 1445 0 R +>> endobj +1465 0 obj << +/D [1463 0 R /XYZ 72 720 null] +>> endobj +542 0 obj << +/D [1463 0 R /XYZ 72 582.756 null] +>> endobj +546 0 obj << +/D [1463 0 R /XYZ 72 199.398 null] +>> endobj +550 0 obj << +/D [1463 0 R /XYZ 72 130.835 null] +>> endobj +1462 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1468 0 obj << +/Length 1974 +/Filter /FlateDecode +>> +stream +xڝXK“Û¸ûWÈ9$T•ĊáS÷&ïŒSNyʌrÙŬ0$4B™$‚òìüûô $h²[s@£Ñĝú E‹§E´ĝûğHwïn>meX“ġb·_ɢˆ£0J‹Ċ^üT½Vƒ—ĞdżEqĥŒƒFó8üFÁoqšÙ#ҁîtŭ^}6×?Ŝ~}`jêŞÁĜŽ9â\öGy´­*íÏğAµG˜Œ?À¸ŒÛOçTu˙爎 ÏNYO§Ü[Ò²6û—ċżw˙Vq–yΗÇĠMX&%Ż~úüċîv Û·ËMìîPTÔZ5¤w:Ş“§ÖVşXqP3ótËTn•_”xuM ŬÔ²áÏ~aşĵqdş'ž0ŬŜö­ò×NÓ†›oM;´=Êż‚…Ŭ/WišÀDÔàÏ?ÀÖ?P.JCô€"°Î™ÇFö(ÇÌ{Û4yŸŬOxĜè‹8 ˘X€:a”ÉÑ ˙Äóë*˘à3*G‚OT’ît Lè :ˋ_p"áŠl½l_ÀA˜A6ĤĠĵÁÊQ­EÓÈŬáż""QJ`Ç­F„ÀO§Ô0żÁßdÏhd À¤HÏ­Á_à²òŒe˜o$^“×ħ+Kœa4a—E‚]YŠ?"ċ½é²,^ d0+ñ:T2V³½l)èà×£ƒè +£SžĦsĤÔeż +{žçd•aBp&zòäèĵ“ +´·ÖŭŸÀ<}ó¤Hsüx̑&̑@Ìñë•BzT*وÚI‘JfĈİJu˜~¤ÓÌ^ëA÷­é(Àâ·-SÚHümEEŠqš˜Ö +Wüħs½§ĈĠµ¸Ŭ6Í\.BiœżñÑ7İ CÈZrĥ¤×ÓkĈéD8ÛNÀpşÑ•ŒrΟ°Ż6îĜ(Üĝ"˘g™ +‡³Ô([ÛD~>@eáyqükYŬ)Ï.R +LLİG +/•ĉy0è +!ònÚ{&ÍĘîİì‹ñÊĥ²Żıŝt„Ú‰ġ2)/[3ö­ğ-ĵ„<€ïÒÛÁ' Á /(Ò-(‘˘ÉŻÜöÉĝƒ¸ıËFÊ[Ëġ-;{̓OÓuúyšĠI„ wâŝrSi > endobj +1469 0 obj << +/D [1467 0 R /XYZ 72 720 null] +>> endobj +1470 0 obj << +/D [1467 0 R /XYZ 72 652.987 null] +>> endobj +1471 0 obj << +/D [1467 0 R /XYZ 72 623.382 null] +>> endobj +1472 0 obj << +/D [1467 0 R /XYZ 72 589.903 null] +>> endobj +554 0 obj << +/D [1467 0 R /XYZ 72 496.426 null] +>> endobj +1466 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1478 0 obj << +/Length 2223 +/Filter /FlateDecode +>> +stream +xڝÉrĈġ>_Áı$PĠÂ8'E”Ĉ“e\#NR²C“h’(aĦğhäüĵßÖ ¨pâŠ/D÷Ûú-ŭ–f°Ĝ-‚Ċû7|˙şzsuW,JżÌ˘lħÚ.òh‘‡ÄùbU-~òŜ}ğúpû'yŜġE{Ћˤ(½ ö>ı÷dǖĦژŜXX—g÷ŭĜT ïúŭĊ%m6£aD5šşÛ1ëMІV –?>,?=ĵc˜êDìNwÚ¨ĤyaxŬUġF úâ_Ğż}—aè—iʖ( ÉcÏjS÷#j˜'Ŝ^™êíPF3ş7Œħŭv@Ä›xÓŻ/B݁mèµŝĊe‘%ŜġvÂġs&€-È$€ {lûÑlD ™° ‰rŬ‚uiPz/xf?2ŞU¸{aF£í;U‘ûŒßˆXš’v¨:·d(.F‚dN‡…ÀµSÖżjÓ³m°éGŒiš‰QpDĴ7ƒxoaŬ›Ÿƒ4°2d 9ŞÚ>ÉùCŬÔŸzc´‹ÌëO9c³ÑuWµjê_Iğ8Ž î9á|<~ĝ²Z>ĝ(ïê.Ì,0Â,ñqâçiÉâ?…€‡Qê}ŭĝé=pçİ÷ŝ|ÖVĵ\ò°zxħƒnYò<ğ@n”úq³\‘e‘·á; \‹ ı¸À¸}E—"!‚àĤßĠ˙ĥ’Żċà.gߐs1ÉjC|/ïĵ†Oî Ñ—v£şŽUˆ9ûN¤@öÄÉW÷ŬıUóâ,DİëħnÈ˘tĉÙ ²X(¸`n#îfĊ+Ċ GBÀ]c×qaݘb­„ÔŠSçT¤‚Ċ—c`*HżQ˜~q–{Ï{Ŭ1—8ĠíD~_9—ħq­j<r]§9˜×öÈÎv+Hïˉ*§Âô•İ™ÄÒñ\áĴ„ċhY`Td#ÂEoĈ {5gœÖAµœ—“aÑ­kanĠá\ĝÈĴ8žIĊĊqJWb,ü2’ÜıFE’ÒĴÚ£ ĜqÊ×ZÈ蜤½k”D UßiôRO×Y,³l0šŜjş1(£Ĥ$x­ñKùÀKşÄĴXÓ8AvÔÌŞ:Q;µµµpnÏĥ礲˙0°“H½ yyEÚĈŒBO‡ïĜUráÊUT£ÉeBÖ(|ĝ†İÚY8à³Q˜²+–ì˘ágOéÀé…Âô-ŻĝòÀbÓ·-; ëNŬQréÛ+‘ÚġüUf7ĥ˘µĊŻÉÑó‚S²OÖ1ÉyFŠ*U"ı+¤S~Ŝ(ÎbŞu3W S(~gû×éŻâ[¸=P2 -@ç$I&ÇÍİ;Ċ7kĵ›/AĉjhCµĤ1Ë}ŻîâàU;(ü¨ŒĉA:Û4fT·_ġf”č%œ #Şl•\ÂVÎ~;6ƒĜPżöÀĥÇŞ€Ïä7ÌĦQ³twGÎ;+ŜÎöŝSù˙GèÉ(óChÂ'áĵi´â)Iż§Ú‰+n¸¸úȽ$qÉ?ÓĠ/ìÓŜžIo_-_5vj"°bb[wŝ+hŒ ~ž~·Ï£äŠlżTŬYŜpóL‹)u¸Ş[B- ½Š×Ki ÏUWJPXÏpwQ$P@6|3UBIí³€Z&aĦ'ÖŬû­Ï=÷=†É$Üŝı´{Ä.À”G'ğ²Âğñ>âjŻŽ]‘!Ş/xf€ŜÄStÚŻIäÔ,ħÉ1<²<ğâ‚ЁÀ:)h8³:н[GŞYÈĈµD”ŝÄÈé0{;¸öf°ÌĤ£Ċ¸­àŬ9ï-È2hğ8ˆÙ²£hɌ5ŬˆlšˆŽ˘°WQTY’‘÷OcÎ&V9+{e2‰E0éĝŒñİӈžğYôB ċA‚‹[ħ-çRö%aè-—ŝŭ½˙ĝè3ĠŠêŻI§•Ŝ*è˜ĝ[Ħ:F;%ÄĞóéŝŬqs‡Fżç=˙K‹oŝÎp$œùĈŸTñm\7ĝh˜OŒ³v͵ġŬ•ÛoôÖ%–cyàq†şsÇ ³[âóû7‹Ÿˆ(ñ‹“ö šü%½v“d`Ħ{5v>B%Tb- ìW;íċÖ½êqäçY6ġ_?Ä ÷ĝ‹ĵs/‹ċ·ğj2KfÈÈMİË]eOçŭ)˙ ³tżı`÷½nŽ÷—QÓ¨4ôÇ >€UÇW<(_8YĠW&ŬôÇ1+\\,›}g™Òvcj)3Ġ썸n0FüN„€'„1ċU„Îĥà8cĝ3ù4ÛC6 ^›$<Öp„O3! Ï)Œ+–Žfö *nVˆ’ş\J³Bä–üÖòf’áFî†}¤E½EĦùd}Îj9 ž½ˆqŞW­€ħbŭ˙é·î ’„òşċĥI·COzŽô˙"ÂOF訏nF욋/cÄçr#*ĤxŜ×üÓÀS[2oFô @ĴOÄ[ Z‰œ‘ŭW ëôGÜÓ4P  vÊkl{ôŻ 2­g> endobj +1474 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [269.869 265.87 284.592 276.718] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.8) >> +>> endobj +1475 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [523.506 207.74 538.229 218.588] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1479 0 obj << +/D [1477 0 R /XYZ 72 720 null] +>> endobj +558 0 obj << +/D [1477 0 R /XYZ 72 658.397 null] +>> endobj +562 0 obj << +/D [1477 0 R /XYZ 72 403.534 null] +>> endobj +566 0 obj << +/D [1477 0 R /XYZ 72 253.029 null] +>> endobj +1476 0 obj << +/Font << /F8 826 0 R /F16 823 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1482 0 obj << +/Length 1926 +/Filter /FlateDecode +>> +stream +xÚµXK“Û6 çWx{‰œÄŠžĥ•['M;ŬĤ;ÓĤ™j%z͉.Iw³ŭġ’]eÒI§{X‘ € t4ğE³ŻDüŭj÷àéËġĴ‹e²œíö³U2[ĊQĞٞŭìbÈ˘8÷zˆ#ZšWM?_$렚ż÷Dk‘£DÂ=n,‹“ ’@vD0$; épŞĴŒüs>lħQÏ*¨™÷f$^Àî“ó8èn‰Á8‹ŞżUeKÔl™ĵï0„Üħ˘8¨µƒhoÛŻqšmż˜˙ĥûĥˆ°ÈsrÍħé´Ïiš~†\Ŝµîûôe B’u˜§)ûw3_äIlqïùU\p›ŻÓ ?Uñ2¸“Mƒ£ íˆ68&~oWÓÔôôÎÓL>0{]ÎË"áĝŻ=šs}À)ġħñw<–ħïU[2żd›îÒÈaBßdg˙„ĞËŞGƒ‡AO˙ċÑÛ-޳ gïż8İŝHÊbw)ôTĞÏı ġŜ‘éëòŝĦĤ GhÎġġÓÍĉéğw¨ù™%GÁ‚–ß~újá˙—a›Mx}Nf]Ŝú¤y+1͖ 1ÎDS£S³••ßöQ‡'H+@;…Ä*R@[ÙĠ´ùŜdİĝv€Òş8Bi76ÍMèˆĞïXğ½kX4>{{Z¨ċ­4lFÒDég½–Fözöêü9Ïó l$É ˘¤`yú4–ñ4Ï%‡gGQ&˙!ˆµ?$„ëŜĊĞÍ™œ‘ˆC +`ÌyçҔRĊTċI‹ A.]qÓip˘Äbœĵ#UoYIŸNܑ,ç{§Ħ?ŝ:,’‚Ž˙#APZà^üŒ<€SNv0³,r—m÷ÁԒ¨!j²%‹E;ĜĈ£`B'ĴĊ…È:)Ċ’‰`d‹(·ZĤŒr^È:œyŒjÁ@ÓĠ‹Nš.c$ààÀ…‰?r”Jġ¤yWf] KoDÙa'[ĉzŜPÙа½ÇT‚ŒíY0ŬıŬٔĥbRâêOÄ#Ż>Ŭh#Íɰ`şç„îĉçuS#‹­w&N~žxä<ĈX8áĜ#—ħ~pöêĠ³ëëgÛ-cĜ2<†‘ëp´ó[ÀuĠ{g~’†EüqEŠ8İöñOÇ:Ó8éïyGıŸQ²/ˆ”šÖ§ÖF/LlÎŠ-gGß$£ïĦ?)ùZ›á…@ttD,‰üƒ£A˙óËÎmd痍P0c3rµ&Gž­¨úĉ ÂGğ§ ²oTµ[0b¤ÙšCʅ2áP.;L¤IM_ĥ+ÍÇ@ùŭñC´È~҆êÑQ ,Z.´ù4azOßQğ‚Ó!3}8çĥ íÇ1‘@χ촙–N˘=dGçXŝ¸€?ŸiœäpċœûQpNÓ¤ĤiŽàET.ĝ‘4 ŜI*@9•†%TdyËÜJ˜“êžL谁)ˆÌ†VGċ(Ħ·5£§ïÑ×@­Yiçëç2 Ĥ–KÑ"ËàKwö,6>RŞ÷Ğ §‚lžL‚™­y•îƒĦ‘“n'óJh-ÚqސŸg˜ˆ9–ß’×ġAîY + *.àŞo¨ëA"WĜL/˘<lùŻ£% ħMÏÜâ--‹ú¤ )ísfÜišßÄVN4Ż˙H;}RP”›{Š'}ßÙ:sPküëĵ½È|x¤>Rḭ̂ ß_4#íèÖ2Ż™X¸ Ĵz2n‡çN´ĦL´vïȕ{£9¤pĊ’)‘p•ÙVkmKW“ïdÇğ‡gßÊA((ĦàXÑnxUŭĞrċ^•+~U²’›‘ÙŜ n‡"‚Ô‰ëéĜşž€›–,§ÒHŽZÔIh³!Á`"ğ³n‚ËĤ•ϰÊĝ– ‘Y%ü²rÏŞJŝeäŭE3bƒĦö"³ĉvfó7{nxĜ$Ħ”Û.';êŜĠ•!Œ‡ÁW² ˆ=hÁxi¸ñ‘'§~K@Ž–R§f>z–ĝY_ôçµWÏ8Ä­{UÖBWJ²Ó™Ğ¤iO/×d‡Ô$ Bš„ëhMGÎÂe˜/vöĵ˙/ĜOë,¸,ÌĠӍFĤK×Oñž"ZRğÏRè|Ċ’49— hÙӑÇĞmŻE jÑìâ<$şÒôî]mYĵ´IËÚĞĤTÒ`|K†ÏÁ,†FĊŭöñDŝQĵWxÏúI-ˆ°)Ċlb2Y Ûág´Û×oŜĵğ˘îçíĉġ–†=wˆ?oÛñb÷àocoj! +endstream +endobj +1481 0 obj << +/Type /Page +/Contents 1482 0 R +/Resources 1480 0 R +/MediaBox [0 0 612 792] +/Parent 1473 0 R +>> endobj +1483 0 obj << +/D [1481 0 R /XYZ 72 720 null] +>> endobj +570 0 obj << +/D [1481 0 R /XYZ 72 253.752 null] +>> endobj +1480 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1486 0 obj << +/Length 1807 +/Filter /FlateDecode +>> +stream +xÚ­WŬsÛ6 ï_áîer/V$ê{o]>şôÖ6Wğ×[Ö=c몏Œ’šċúÏ @Gr•kïĥ› H ~y‹ŬÂ[ĵzĉñĝëĉÙéeşÈÜ,ñbsğHÄ"ñ=× ’ĊĤXüéüħL§–Ğ œ^—Ş`²Q+ÉIC\ùNĞ"ŝ>˙~_Â4uö4-pGꨎĤMÛĦŝ)ğŜ]˘ tš—U5:ùœè²gİë‹Í‡ë›ġ†4ÖXŭÀœ,–Ù—Ĵ\iŬêċ_›×à’•ïğYÑċċÖÙêw|k÷ +‰9këšÔ÷ZÓrĠu­vQâÁÑv<½ ĵ‘ğAĦHŬ4óIá‹/À89gU›&²hÑIH½}·!b=ÜŬQ<ıĜ<ŝ•M‘´˘‰Ŝ“SÁLƒĈgâşü‚Sq€7Ä@f;h>ÙÖwCŻxv_h€"€¸#Lu]ö“ó41΃ħS=iÔ|G1]ÖÊÊ5hµ9w™ ¨€"¨ 9g$Á™ó˙‚JŒ ò½Ès.È&C— 粗„ÏUNû.°Ïâƒ*(>|9t,ç lÌ5À>¸!G"ċWM0jš=3§— Ĵ‰@”]7° Iœ; 1܏……PÂVÊ꧕ĵĠZċ=-ĠOé²˙!Ħß çëVѨŠH´Gw$rL˙ç?4ž#û^ѵü Ox˜ÔÒ¸öĥc KŒ­÷mA&a;ΏdİєcĈĜ=çCÇnÖgïŜ^^½bÁMxˆĝ žJŬ˘ĉ‡^PĵÌ˘ìäĥbÌKçäZ§˜ıÌJSş`şp8tSĜá{#ĤApS –ùÚ|·pœ^úñ‚, RŠ€ìŬj‚¨Ŝœ½ü¤$‘ó•†ó²ğĞä2bĵëapúÈ ĴT’%‚ÌÁ;‰x§]mžLä@°ï´Ĵ‰ŻKˆ’†Ï4´&ġˆ!ğNQİ0 UÉf7ȝâĉùNùĈİ­ô·­;Áúñŭ/ëğŠj;jÙb ášÍlßÑKsg\…Úp;T´ávh „'sï%gn{Kŭ=” ‡ZêÖ +-QË=µÇÌgż˜ZĠ-üž6ċ²RM!ġÏ|—kFĦóTbÛp²*$\›—ÈÄÀàô3oƒ„‚§à—)#"v}ˆĤiĥ_żż̳ž?KÓ9­‡†ëMËÄfàzóË£áì".uÉ-„4qäzq2é^ÄĤ0[àuËÜ48ÚžÇˆÇ˜Ç„Ç”ÇlÎvß·Ó÷-!,X"´Dd‰x"+fY‰]N-‘1!ĴaĠĞFsv ĞSX"ĥ„U#ĴaĠċ°'1>ZˆìP \4Ċ°¤RÜĤ9O—p\á;­MIxÌc,L–’‚bNmp>ùA(Ț­1e_ĉ?ħM#n‚‡Y5ȊÇ1Lż²†žĤılˆÁ=Mr*œÔsLÍ 7Â?d+s÷,>àĤCä(yîcJ’UEUĈäQjĊ‰Qü˜ÀöÖKs˜OzÛ^í kœ[š‘z-İ“šúIÛJ˘ÛaÇ'ÎUŽĊ6µmŒĤŬ"Ì2w&h< +—d-‡xaüÈᇚ¤c罂ʨU ĤàĠîÛ0ò³ĜM½dÛŝk%2^*¨lc…Žoü…+@.…ì1P†1‚7ÊpÁ3ŝ„¨Ĉ'Ŝ³v›Ĉe]ÏĠ…íšÀ}èöDsQ 0Ahi"ÉX½YŸż[o”&§pıc'á:}g %iñ¸Â%öCĊ +Jú&U>"v.8¨qMÒĝ$Vô=ƒSèÛ jĈ5sŽÍ¸MEIyĦU%G}1,tímOñk›´ùĤ“˙Ühcß ô$7eäÉ“Ç<ĉíg™"HkóÛwÎOß°@h¸Áxè+NèÀôF ìL¤s ¤şJ-Ĝ2ôöİnèƒsôĜul“¨œIÙiTRCÙĜDGġtÔòÓR7\ŻŻàicÛ΅qlúäW^%í~B$u´q_îöüŒħ&Nq‡ìhµPŸ> endobj +1487 0 obj << +/D [1485 0 R /XYZ 72 720 null] +>> endobj +574 0 obj << +/D [1485 0 R /XYZ 72 472.435 null] +>> endobj +578 0 obj << +/D [1485 0 R /XYZ 72 302.123 null] +>> endobj +582 0 obj << +/D [1485 0 R /XYZ 72 229.997 null] +>> endobj +1484 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F16 823 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1491 0 obj << +/Length 2560 +/Filter /FlateDecode +>> +stream +xÚ­ÛnÛ8ö=_aìËÈ@Ĵ’Ô}^iÒ[Ì´Ŭ&Ċì´3Š%ÇÂȒĞK[ï×ïıI˘l§³ú`ˆ<$ύçJĞĊB-^](ù>żğxöÒċÄMB.î6‹È,"­\ċE‹ğlñÉñŬÈĠY´”óñúê—ċÊ×Êı=TKÏ8]úmùçŬëg/mÚxg" @(îĥùrċ‘ÓÂÓšoê†ŒÖ B§hò7ĉÍAğ}™ğËU ç_V5Ù§MşË; ĦfİÁ6BġĦ`dĠ%ÌCo$9Y“âÊ×EXĴĥAT7 f#ĉ=ÏY÷M“3˙]ͳ-݌ÀvŬäL&Ûâa[NĠÑŜäÌEÎA°oĝ+'N¨÷U–7<üxŭî½K)%v“°(¨8Ċ€>‘Ħ›ş,kRi+cè=N³sd+Ož‘šqĠV³‰Q3n!5G¨fš’x˘ŬN'_(í3E‹-¸n߄l=¸ŭˆß]jħvç˜a[èĉPnFĊXw ‚yF;„ß!Ż‚5jŒ³iêoÑüéj^†çdÇERïĥpġó]Mö‹iıßâíŜ³ô]ħfĝÉoÁ˜×]Ŝ´|ިĝÛïEWĠ8öÉÒ™z‹ï+çċ2öF&òo):Ú¤ñĞ}S”çô1Ş mT-NèÊh„ĈkCĞ#Ñá+ZĤŬ?FïŜ‹=ËâáĴµŜ q éR:`ˆ7ñ +ˆ +yB×ѵô”!CN4*­ĥı×7ußĴ²âĦè|Ĉ0Hğ>Ǣsét+X‘¤oóìrĉÇĉĜó!ÈĴoÄġ‹öĴÍĥmżË3â#À[öàÚ"ÎúYe5˘—Ù%§e+Œ[*e†%RÉrQeĊ:íd=­,ö=xĊ€Îĝb Ž˜8m™ĥÛĵċċ?T  #ͰtĜiE"ŬòwnŒÉŬö’á’a`”ídE ThoëĤá6/÷ĵĥËÛ6}ÈŬÙ}‡,öu͗XT’=0#ŬĞ_~’¤‡ŝigXĜÒôeN\ÙÉfŠô#*1Qˆ­u|ÈĈgÓ²KZ×ğÜXû32zñâîâó…~ĠBcùĐFxħŜ]|úS-2€ƒ4—ċݴk·Ħq5ÌĠ˘\Ü^üûè|ġ†öżwv²+ñ3ULä&Q ¨|7ġ·c+óƒĜyŸ·}ٝ²o<Ÿ{:'"¨ï˙ +‚Ĝ§jàœ€Šï‹ ħY‰ŠÇ¨ QgJëäİLÍEòC7QÁ)PŸh[&”àŸX*op'*À†’ä}\ĥ's7$?D6/v/<–íu_‰¨8ŒŽ $—蠏‹öTŜĉ’&‰˙#D3ĦÄ'×ĤY.% +SĞŻ×)fŸâͰ|äÄ=ËùdNç‚Â’ò’!¨ö]‚Ì}ùâı\Ħ2 Ş6JqÚÎïĠ”v<.è“9=Tıñ“BÓİ fá'†…|SA·Mĝşò}jE˜hlX +I1ÇMÀ]>Ôî£cı`×ŝTh5ùçh°:˘Ŝt– ŻzĈ­övŜÜzp/š†Ê¸_9'·§]. 2d:ïĝĤwvġ­]ŬĠƒ#×ç+G0ĦˆÚ´Pȉ˘³5èCë—Ŝ—äìJ-˙–ŻûN€ûĤ–ʽ)”ĥ$1ÁĵĥÂ"ȎŸĜÀR9Äŭñ™ï–T'QŜCġPp“=ĜVpRIÌşX˙LÊĥ0İSŒ šıH;$ĥ`×nÈ\5+ÀÇb†Wˢ’ò뜰oDµk`͓:ĥżŝ_֏û¸Rݰs •“v]Ûw8ь—zYXÙYÎ#ĵn\NûŜLĤeyà%Ğĝ”½ÔJĉYÓAĝĴŜĤ_1_`SŬĥî…ŝÇۛ··ĵŒöIۊq]Ñë|(ç’~"ÔO„úa +¤² +ÒsíLQµp>şĴ%„™ÁgĦ’ Íà´1şĴ ÀéŜĵ\zÚyŠgĊŸëşÂ`ò7İ´ü%¸´\‡Ç}Ùgżm‹Í#ÒNĊ #òĜH‹ċD£FpŝġNò Ŭhp:@N£TòŭğÛß^ĵx'­ĴHÄâ‰(cd^ŬÔĤĥ@g†‘2V;ÓûÁ꜆Á? è”Ö->Ğ’żğħ‡™ˆä[$\X£8ûCܳî[°şâżT_e +d#{zSÔ½ `&‡hĦí‹Tâĵ­Ö9/’×=Oĥd´ÜÍ3R×"A"OìžÖ#ïŒ÷÷ùŠ×Kê³ÂÔ˘ŬòˆBj4TıÀ·y!˜³|“bGA“z7'Ä9ĥÀ Í;|ùkç8ÁgÉM„”°#XĞ<Ï,4gÍ7ê@¨Sß Ù%É+PĊb*r>n-ŸúlĦ˜FŠ4Ĥ0 +l_ŠŒRNežĥcŬ˘1_ñs*kĴ Ğ°ħMIp„ĵQ°2‹ü 6Ħçìu[ HĦV££Ċñpħ8ĦN]ı×o7Šħ‹×>wݰ ×ÌDxĞ€Ż'ÑïÉ͘BŻŽú;:•!SìÓŞ ĜÇSlí§Ì´dYë”‡6Ï!Ğ|k0héyGĠ8şÇ˜‹ƒë`ÚÏĜ s<>êà ħôšeü‡Ë°Ûšżì)0°^ +“dÂ>ħš#’ˆàÌe^ż}÷;ŜÔĵrA‰$Qòfê;U[˜ŒÀĠRĥ}hù#ö$¸ğż‹Ö-ûÑüŸ ? +‡lΏÖàƒ;;Ä´Éĵĉĵ9<<Ò>y>.ĥ=T DnjRdĝmNI’ˆU>ç͂ï_],>ÑF톴aĝ·ĝÄ.W‚ +âlr1½şÊVk^–CbùlJ`9ĵH µ Œ8vñ¸…¤”SˆĤ• §'½Zĥá;çoĜĝ‡M ĜÀ˘jĠÙ.QLì‰UGTé_ ŒSD€a1 K•‚RDËP ıûà^ž“ûnĜMâq•çfˆ$— ·,§Óß 0> endobj +1488 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [400.974 156.725 415.697 167.573] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1492 0 obj << +/D [1490 0 R /XYZ 72 720 null] +>> endobj +586 0 obj << +/D [1490 0 R /XYZ 72 720 null] +>> endobj +590 0 obj << +/D [1490 0 R /XYZ 72 479.874 null] +>> endobj +594 0 obj << +/D [1490 0 R /XYZ 72 335.907 null] +>> endobj +598 0 obj << +/D [1490 0 R /XYZ 72 203.951 null] +>> endobj +1489 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F16 823 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1495 0 obj << +/Length 1733 +/Filter /FlateDecode +>> +stream +xڍWmsÚFŝž_ÁäC+fŒĴ7@dÚflc·68…Äqœ¤s–¸‰¨t²ÍL|woOo 'á‹îövŸ}ı—}°:ЎĠyóÂzĉ{şxq%YÊT=ÒLÜkH·ïûĈ KëĜ8)úNd<‚ój–Ğ3³ +4Ĵlè´ċZŻLtîĠŽÑÂ6ċYìYGOI*K!ñY#d¤œI&s-´Œò ‡=ÌğÚpÒ´ÜÂĦƒG,êdµÜÚ9SÖëÂÄp\Ş1|-ƒEwÌ$§é2D=ÒĞħVŻŬugAJÁ8ä[¨Ì`BáÁ ĉdˆq‚W*lšçyĈ¤ë{´Ç°ÎŸío˙%jÉMmœ[TÂġŒOÇ$ ^&éŽĤ‘È$m(ċƒ‘úşĦ‚*½K[Š›?4$UÊ5Xö +}ĵè{ÏımyĉÀî=Á>ßgIĵĠ£Š˘™>VêŠzĥé{.ğĉÈĥÉĝä³ĠÇʂ{O/Ž,§IܛßÎ%ß[BÖVŸÓ:B˙*I?ĴƒŭûÈ4NGğşĦ +^‡Kˆ÷Ŝħ”³6o[Xx*EÀ˘Ê2ŝo΀·!NjˆÓ„ô'Iş™"*Ĥ½X 8á÷:ħ,"VÑhüúîÌkĝó$ĠX÷ş “2ĈiÙÂİqâhħÛò&ANk*ÒıXĵÑîĤ.óußÍĊĝ\×%bĞĥJÜü`ó^^²Bx•„b)xĝ²òwĵ›öCħhĊE›ı„‹\X•B‰[ĦĈÏġZĈĊa8ÏÓd˙žĦ5›WWĉí­iyôokè'Ñ#ÛiÄmU[ÎÒârĴqFg`Ú}§ħE5’v1/N./O³İä³éâïÙ%ŬhߣA3͏G_ïHġw]ö kĴYĵ*RŭȄBѵaßĝşÀDiÛwıê&8Œ“ °ĥb½nqŝġ.Ş{Ċĵù>•¸È”ŝuÔĥSŝ$+#½ĝ[Séš·Hr]TË9vó.ŬX)$"àŻYVŻ4Ĵ½Żgk–²î*R(şé:Q}2Ĥ)ŜpüŞŝ€jĤ‰”ɆŠO9NQ´3W„Ì)û0­ä>" +:Ñ@÷RĠPÙ%İÖ1²MÁú…éòŭÈJÊÑÖĉʝ€vDÍÒSŽç}R‡Fu +Bë&’(ϸœ)N ğb­‡êvíôJû%^£ûğ5Ĥbú?Mò lĉ’oċœĤ?âŜpŒĵAÁ½Şœ.wH'Ċᐨ²âĥ´}¸ş¤ïÁŸ–'l‘  Ùµè|3Z{ġŻvë¨É6EÔxjŽ{uü‘ñíSžĉŒ€Hċ­ĈU–Ñ7LĊƒŝ#€JŠİÔô÷ç™Î/¸¨t€çŒcıaĊħœ‘XTÁêà÷lv}K^Ù(“öÀÒĴˆ§xQÛµŭ§ù#G4iOĞífhŠ„Ĥ'i°Ċkz*d (Ó$jö÷ıŝ H@ÑüϒíN?²ÓY›ŻóÊ×ù´;E<¨ó²İ.÷{^ÁöĈhQeôr{>ossQııˆ³mè¤˘X§|İ^˜*ìŝ7lûŞÂğÊ#)ĥEdpħĠ1l×>Ì} ;ŞxğĴ䋵˜ÎŸ‚(ñU„;ŭl0*àtbİğüɲ¤[‹z“ĉ™"+œ1_2ÈĞÊJׇ˙¸–eœZß!ÊT–òŸCEßloˆĥ'g½żnúĉkäXpÈG~Içĥï5,Î/ŝv +endstream +endobj +1494 0 obj << +/Type /Page +/Contents 1495 0 R +/Resources 1493 0 R +/MediaBox [0 0 612 792] +/Parent 1473 0 R +>> endobj +1496 0 obj << +/D [1494 0 R /XYZ 72 720 null] +>> endobj +602 0 obj << +/D [1494 0 R /XYZ 72 656.206 null] +>> endobj +606 0 obj << +/D [1494 0 R /XYZ 72 266.508 null] +>> endobj +1493 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1501 0 obj << +/Length 2366 +/Filter /FlateDecode +>> +stream +xÚkoÛFòğ…Ò +°EwW8vìúÚŽà'-°WÒ˘|¨\*ĥûñ)Éfĉâĉìììĵv^+o´y£‹#OoĉGŻÏCo”ıY$£ùr”nĝ£İïı^8ÍóÑ'ÇûìĊŝxħóöqQlsóêÜÚş‰OcçĠĞğżñŻó˙€È‰ïğY3_Ç×ŭË?aù‰Ùŭú–Á7ħ`~/ƒè˙f0ƒĝ{5H—Áô›$S7ËâÑ$ŬÌg&w§WçÌäòj6?y÷îd~y}Ċ˜ÓëĞùíġ;:;IS8”ŞËñoŸ˜ô_ü™İ/šĦĊZU+myñŝè_L;ž„ È˙Ĉ“ ÔûßNċìû­iĴê&xçCWñúĝÇ%Ŝ>n +e*^üĴĞ-CכÖԕŬ)úħçü"փݜ½ÒíîàħlŝóèĤÑ_L½µ¤LàQ*î;ġżk³XwÔfĦ) ^Ÿ§{<éÏnš|”ŽĵÔi×Ĉ +4RçiŜJ¨İS/ykQWŸ=?Zm…†Q8֔›B3ĊġĠëëósaTŻV…ŞŠe]5ŠxÀX0{OB…”?ßÎDzˆĞkŝÚVµ[a[jkĠJ‹&ŞÊ‡ÂÖêB/ZS­à2âVáš.Ša2ç‰aú8˜:şħhZËRÎ6üEġ+*A]JÂÌı\2ö Ĵ·"‚m*” òêċ3)5@͎öxÈBÌ)€yċyÎĤİËMkyÑKĈĊµE@ċıA~Şàµİ`Ğì5Ž|'7‚šî…\‡T \ö‚lä j> /Rċè„,Š“Žú˘ +.-ŝB×/²Ŝ³D\£-\œÍBGµü%!pO‘Z·m]"" 'PĜE£uĊJW˘WvÖşĜ0„~ÁŻ~4-³ŸB:_qóÁ´k‘Ñì0ġVT²ä­/ä­*ŭ şĊ8´CĈJĈÁ%T ,€-Da:.gr°ŸÊp4 ÜTÚpäĤ-–—Ğ­ §àŒèéŠêÍǗċÀ}7˜FÀ‹˜Ì)äÊ˙)'g͈\/ĠĥhyùOI™cלÉÑà$ßÑ +ıò̘K +ÒĈĥBÑj7BàŠFĤx€âF‘À; u[p˘O:#M½­rŬpÍ4ëO‚†ò] Òj(à9ê ÔPĥ}‡ +jòÌF¤ìmÄĊ˘.Ëş*žxµµZĜ`S1xŻò^\[‹>Pò‘-ëÏİċ¨UĞF•Âż­Y X›ċÓP†˜Ä’ŜGÄ=ÔĞßbÁ<ÁUŸaG™DBġmċ¤¨P6†îË+ +B@`ßÇWĵâĜ`ۚ´Ŭ=ƒˆ-¸}óa~6cŻqo.†ŻDKĥˆaäpÔĵ`/‡aHŜÁïCcZÙäN¸gÁŒ:Ĉ²*á.švƒÛğˆîċEäZ)C0ħÚAW‡ ú$AWˆ2,B0„ÜŬŒ³È9C͛˙„U(v&ü™é–ğÙÙġŒÁ›q@a_ż,R ˆŬ0 ÏŬ`E<C2[/rplÁ/X á3BÏë|ÀŬéÍmˆ`ĝìîÑq{ÎuƒQ½2#i:ĊV‚‹nfAĝÖt½J¤ŸÖU…Ĉ4bĦ„ċŠR5% Ċ_Ġ@+£@Œ‚ÍÎ(ÀÍşdV @’ßDtƒ‡ÁǸŒÈÑžµ@ÚÙgœ­*5£j£îÑà3Î@Ò,J÷&Lw€ğäúİš03ÓŞ•şS}aÙ2ƒŬEħĞÁċ²Ŝpš`?·Œâd¤Ë1WµäĠŬ+ˆ9´×T`ıVÂĦ’u… êìÒ$öĴ–ìŬ ëëŽ|°Ï5Ğ·G£Otw#"èÚ`:>ŞvÏ-xóûdfŞ•nı6ۆóıĥ‚áá<|~§¸Ċ#} U5pò§J•fÁñŒgTÑrÇûd[]ŠıJ3 Ö9…v·ŞöŠ/2*kşŠ\–`(ˆ<ċĜyBüÀË J&'ŝžĵc‘X.ˆ@Dɔt! ˆċ<`JN€ +PZî!I~ĞT]\ÁÑŬ°;šêħ òĵ“gDžâÏlN.ż%Ÿ¸aUeIR†câÑŜü|9߯·gĈË\_&ĵĥŸ °ÎĈXggŝ­Ġ3˜z{Ż1ËžY°OÜĠ#Żz1gx‹a˘ĜMó23ѓ—7eì$Eàô!nÎô_¤ ùnò,]DÑĈ$ŽÇ8† Ġ²Ġ•g„u·<›ÁVNVXä.iàĝğw*Àü £1)ĜW(aSeċ‡ŭû Ŭ“JJÀ@<4¤A\ÍW‹”1w".Aħòĥ/ä÷` +QmŻ} Y +O+Żc?îۉŸHžĝğV &(MVĥ=…a°§éŸD´—ğûŒ8O¸ßš˘Ħ˙‰žaDÙÁ³ <çm3üʓFç*ç. ÙJĴyòD?•ĵiôBçlxHݵ²o" Gê’ñŞPVj?71y•ŝÍÌís6‘„ĊÎëûò+§ğ×îË[:uS$ĥ·/bzע‚)TĵB—âC uS–`/dH!iĦ–}y/3,óÀœG˜ê'îRPñËK´yöK Nġ~ÌH8E^FĦCŭjÀ’wéÁ…7 œ iGɨ8>bĤĦLH×èV™JP쁧ıß-YÓkl;-|Ï9Ĵˆ9˜0A/ĊÒ7ĝc‹ê +9>òüÙ(nıԐ6ĝÜàŽëƒŠÜĠĦQÊO +âę† ·B"³üeïz{UZìai#Ñ3‰Yğì$•öUšĊ†J_²Wú’V%ô¤ìĈEŸöĵ¤ù~–<ÄÈ2˘²– EX-ƒÀıĉşÎÓòZWêž~l†ŠQŸŭ0zż5şŭá°UAĉz~Éğ‘—²mi|@ôv~ô'‹ôcˆ +endstream +endobj +1500 0 obj << +/Type /Page +/Contents 1501 0 R +/Resources 1499 0 R +/MediaBox [0 0 612 792] +/Parent 1503 0 R +/Annots [ 1497 0 R 1498 0 R ] +>> endobj +1497 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [503.134 309.595 517.857 321.55] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.4) >> +>> endobj +1498 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [365.617 209.076 380.34 219.924] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1502 0 obj << +/D [1500 0 R /XYZ 72 720 null] +>> endobj +610 0 obj << +/D [1500 0 R /XYZ 72 462.03 null] +>> endobj +614 0 obj << +/D [1500 0 R /XYZ 72 381.34 null] +>> endobj +618 0 obj << +/D [1500 0 R /XYZ 72 256.302 null] +>> endobj +622 0 obj << +/D [1500 0 R /XYZ 72 160.266 null] +>> endobj +1499 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R /F16 823 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1506 0 obj << +/Length 1538 +/Filter /FlateDecode +>> +stream +xÚ­XYoÛF~ׯ ?@ÄìÁÓ@ ÈGÚmlGÊKŽZZÙ(’%(êŻïÌÎ.Mʊ%ygvg–óíœsîĉü1bĉy6½z8İŸF"rfK'N̙ÏdìÌÎGwUyc‘¸ ġÒKşYı@‚ğÊs÷ĞÇŬşÈçùşĜá²p[µĤŭġ½"âùġ;Id­ï}oÈĜÙíyµŞ µV¤^Ày‹G›cŞe'ĥêŜ]gMĥĤ%QóêÌ˙Sf˙Öħğ3Żżö’Àx‰tgzŸgî1ç~†„0oOqyt9ŭ;â°ËŽ×%p+\:óĠègĉ,`t}™&ÎVK­&€,œéèfO=Žŭ8LžRI²ƒÔµ/ÄÀħŸĈ XÂ}sŻ=)\‹.J0ĉŝ£²2/ĦÇÛ2„…~ÂäħP!‰RP# çŜ8ŒĜêˆ‘ÒDŒ şˆµİʚıxOü5zVGÑ7ħmìk(ŭ$H~Ö0öiĵv`!} ĜÀ‚•î‡éĊĠ”È7%"·–YARà'ÏÀ?Úŝ!ü€ûIúK\„~_ß |ĈŬĞZWĠdk?/ iFì'.ƒ›MÖ/ˆïÊ– t/*Z/+4u“Ó­}ûFކ4ĵäO„ŠĜ‰¤„g`ó˜\I0x!ÔÖb£Zâ³Înĵ¨¨kLn›#Ğ'œ´­ Ĉžß_ñµˆ~ò}”"”*ÔJ‘ğZZÉEÄB}b<(ħ‚‹ +œŬ§ÇE“A5#ü7\‰j #‰(µ"ï[ĵ0Ô}ğYa•¸.v;ħ[H•5ċà‰ĉŬċbx¤¤#sFwdeH¨5Á=Ï!}û&˘ğ D†Ò='߆ÜŬŜç]z‡Ì]eÈìhÏĜOÌĤĠ½ dtÂÀ³.²ıÙÔ=–TáÑMġ6(6p²MkE*óìnĈH´ù]‰mxı£° ħ™gëÁı̝ošĈĝ²Ĝ‹êîNO‹C-ĥ~èW2àn{_m +„ˆJ`%&z”˜ùÖjÊPëEm-+sàÚ +£Qž™M${—@b4HÜ^P[ k–>ħQp"Ö8ž˜FĠjђŠġAÀYûPÎNN^èŒŬëí !…ŸDĤ~ês_€á.†–4‚Ħ~`h˘ğ—_3”Z:jX^Ÿ)œ¨Oš´ífEž‚ }ğ!FgÚ] ˘+ş¨Š¸^^ {ŝ’ž” +Rp:ƒëz œ ím$­‹…Ù+tÀċܖ1z!YѨlñŸf’B›Ïi8Ò½¤§1 (֗·ó,œ?„j˙¤˜rîĝ‘Ĉ…Ŝ‹{ë[bt”Ğl6/ĥ/\VEQá֖üÑĦÊĊM7 +˜¨—FQ +²½ì +M‹¨hgOáÌ(lta{_Ż^K6 S‘@˜šzŝáz‚Š}uñÛ߉ô–VSXMÁ'8ŒëSĥyQ)OT<+™°rk+!È-ş‚¨"ÓÓ½wŸħŸ‡~”òƒ 8ƒLûÂ}F>Ї1 ¸ RĞ,áKÀ(IÚ8’×8ù:Çğ×ġ:Ŭ­n+ĝH"éSzL˜!Ĉ߉899=ïá˘ĝ ĊsqPñ-”\ld>ŒÊÙdzıŻŭĥ*AôyÀ4§ŝ8`îżúŒâïÖ<ùŬĠĠl_› < +Ĝñ VLĜ^ڞ +1İûĴžŬİÇ ½Ÿê fr|żnóö~…£jEÖyUögaI³píYĝô'÷ĉ¸Ì….û+ …ħáG +†)1–‰––ê̐y[4Bg Yì~ÜüçJēfh?c&´ìĥ@Ÿ3@PıëU|`ôTӳ͔Ñ4„…œ0ŸÑîĤ%°VPo'0ĊAäíh½ß§úŸwŞsUŻs0C#šÔè‰ü+qK +‚ŭ„ëzĦÚĵÑÜyŬ}֘ı@° T yżĴxÇ Â8ÌL’„^“D!ĝôù[{Á +endstream +endobj +1505 0 obj << +/Type /Page +/Contents 1506 0 R +/Resources 1504 0 R +/MediaBox [0 0 612 792] +/Parent 1503 0 R +>> endobj +1507 0 obj << +/D [1505 0 R /XYZ 72 720 null] +>> endobj +626 0 obj << +/D [1505 0 R /XYZ 72 564.296 null] +>> endobj +1504 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1510 0 obj << +/Length 1038 +/Filter /FlateDecode +>> +stream +xÚVYo6~ÏŻ>H@ĊP§-àÛîMƒĈ‹ÒímÑ1Q(ŻíßċÈGv½é‹Dçžo†äγ_/ĝ+˙ëÉĊċûˆ;9ËÓ0u&sg:£€3œIáüċ>=Œ'ży~&îċíÏŜߓ—ï³?wü0cašôì^ıc/‹]‹˘Ĝí²ĈUäĥR/=`w›şDZĞnJ<;pĞ7“îy„ğ_ĈÉÁ/°}zĵŭj5bË’ò‰íéĉáψ–˘[0Ĉ o°8ŭ `ybyÜVÓĤT3â˘ß˜Û…ï˙B‹wïzsCéÛOd:ú†àM¸/hğ•, Sç½ìġĝñîPú݁‘4ĝ½û'âĊ”Ç,‹£}­Ä½*­İ‚û½Ü°ĉTέŽÜfEÑJZÜ7ÀŞUŭL¸°e0œuA‹™èXÈŞù‡HZèNt+M²Íüఐsħ*;:5á"u áÒjŠŠ·tĴUµ,·DhÂA'[tëp˜ qĝjS¤Ż6…m…ÑbÓ +Woöáü^8Ğ˘”AxM-èpüž÷läŭP§ÙWçuu ,ÜCuïS²Q’‚˜ċ,„̐Y¨ažB ácjµĵkÛĤĊe`X|öò€oQ„ßÖâYêÓ IX”FdìS]HĞm&ÛN¨šĴÌ!ŞSM­˜G4ĊˆĤÈzı•À†ÙÒFi½’$+_<ì˙ޞ7m%PĦ(‰Ğ².2Èx?1=…ZŬġ>TUS[çÄJ[ġ…'ŞÓċ!j†ôı”CQĉ £ŭ€ÙÌwM {[șúƒx&vYàıĞW4+ˆS¨UĤ­żz £TKÙu&ĊÜĤh†oUáwJĈZk ç T-;*(HvuNv;›'²pìAĈ)´ÀĊDg‰ûá°|W +Ú=ËZĥ˘4³ +ĥzÑ`™×´£Ñ‡d˜‹viĈ"üĊ‹9šp˜.<· +Ċ´”Ö;‚wëĤöċFéÎGv*I?yKÈĴ¤!V*mg½ÒWo¸ĜŻEAz·YÂŒÔ +a‡{Ñѳùîdìù1pRÀ˘³Î5Ž3(Úż+YÏ$q`şŽ8µeĊlàá `ß´7n+i„¤µ!iÚ †ño` eı;ÁÀ²ËµÑÎŽimF4As¤á+|bĴġ-c^OeIyŸšËÄÁ%s×öÙ%ì³Ù°7\/§§ŝ7ïğÉBÙçâLï{ġífŻo— ;°Ïy¨„ğÑ´.½'‰8x@4íĞ7˙z÷üĴbz9ëŬ,$˜Z˙#A·ğ^Ú%i `˜­0Ìr’³,ËHK6ړ¸›\üì˘è +endstream +endobj +1509 0 obj << +/Type /Page +/Contents 1510 0 R +/Resources 1508 0 R +/MediaBox [0 0 612 792] +/Parent 1503 0 R +>> endobj +1511 0 obj << +/D [1509 0 R /XYZ 72 720 null] +>> endobj +630 0 obj << +/D [1509 0 R /XYZ 72 335.329 null] +>> endobj +1508 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1517 0 obj << +/Length 1562 +/Filter /FlateDecode +>> +stream +xÚ½WKÛ6ïŻ0z’X+‰’-ċ–Ç:MÑìk£A=p-Ú&"K†DíÑ?ßÎP–7Û EO ‡y~C£Í(½ıx}ıĵ¸œ§£ÌÏĤÑt´\fÑh~ f£e>úì-·j<BxŸŻoHĈŜÛržQu) ÚÜK³%j+şO˘™§àt蕴—ëFŜ*˙ıü­³À­—sôìF“(ġ§³˜Ì˜Œ'I”x׺ b‚:†–ğɉáÎĥĜÓ ÛĦa\Şü}ßµĉÄĝ²"†*ÔN‘·ĵӝ%/A|R5‹ŞÜ˜-B˙'|Ĵhŭ°UŞxÒÍÛHxÒµÛ£Qì= ĊÖĜÙÉ\e*Ún”áC´p„€zf[µĴċK(bkÄ/,Vë{]¨jüñ$ŽCëüBħò…Z]•ÖïĴ FġfDÄ훋Ñg+ù³A`,;öd™“’û=”Mêİ2׏ßWuġ­"á­Ğšj…0ô³„Uq)ގ˜£Le€Q;…ùûùô}zġŝVùûŻ)ú‰ŭDŠ.‘À6\o”È;|ë°'ĥŞä`ùĵ˘0³ĉ²bzԍùj×BĊ˙íş¨ïğ>ÛG¤Ëy8Q­Dl¤ˆŭ4b#c? ËBLíâĠÍġüí1KĵżhyU•ˆ ›ĥVĐ´ÜĥeİË }8\ö|l_L]{ĵ+'VŬ%³ÚàG%޽íBKğ‚˜‹“Ì“y§jL:œS|ÒöJSçUځ{Cl]:9÷ŬY`Ìì'{„÷n-uyÍÁŜžúçÚñ-$%žfŭ£Ö.`Ù{§ÀHR5ñĴ ´G6JÀœû1ÎFDìĈ½^Q#“ŝšöWĠn‡ö€˘ËiŻ" +OĞGgŠ9ßQğä,·†›´“z‡ĥ;ġWÖÀûħ…2­Ê•:ë~ݐpú¨bOµJxĴ*ÁIĈ§ĥ‘ġuUjh] < +7ù'ëĵ›ZÍŞÖwäëÖÜuO7…ŝôo½£GİŸEÙ7…àGkŞT + +ĉ@,#uQamá‡6*ÖHópBë ĥz9ÄŞÖ´ş6 +]¨BB>ÒtĴ9úĥŽ‚DÛ(\"ġŜİcÉVì ‰9<Œ)>ŭTMÉħç~Ħbr¨CŭÖ òÖHÓZfÂ3İPħ×ħ^ëÙÉa½ĤĠZSµ, +ğoŞûO™ÄĞ[H´‡˙ÏhŻËĊı9Ŝۂ{OĞr+ĦVóm\ ´wÙjĵ”oĵ×ıŞ:ü†"k+Mğ¨2;Ì­ulŬpÉö5¸Ĵ,ÂÙË(Vá °ĞW}BÍè6Eä§":˘µ"^'Aż(SŻWÁCX Ċwöy„]ŝ(/Ç î‘‘µqOäc;Ç]u­éP B串 +ƒÁtfg~6z·/.A |'Ş÷uµİċŽŻr§\ȟ˙È,?EœÛ<ô?Ú0´pWóZQ}!ù{U+;…3;ÀĴRsÍŻT*·5—u]Œ‡)Ŭĥ–àħÙ6{ĜàHF[ù2Üjä][Ț>†œ1’d3[p5ë<×/ÜÀĦ†³)™Ùg²O@Óäâ›ñ<7lìĵJěÛÈĠ´£%dĜNé4ġÚ2Wġñ˘$ë0 É;ĥXT/+´ŭ+ñ\ µ…:JŸµŜkQò öĵ­>MaŒÑGô½9Ô!´OxJÖ?V}\TïSj­ácuÚ·ô˘{PŝÁA"ôá9Ïp—ŸÙWċ½Ğ~Ĝ 1$Ĵ!ԍ÷œçWAЍC˜ ?‰ÄÉ4ĥµ×½Z-ġ‚ŞDÏëyLz˘İ&áP ˙Q àËvğ3×£†9i˜DAĉGĦ&&tıdN{W蟄?00'™Í:eŻçJ6:ĠqytëC­eW%€‡^ߜS( +o•Ì'7%"ċee,ROŸ4,è™ËĈ8×ì˙ƒnġ{5…Ap˘´WM}„Šà1’$)„5óÓ4 Ótpâjyñ7_.R +endstream +endobj +1516 0 obj << +/Type /Page +/Contents 1517 0 R +/Resources 1515 0 R +/MediaBox [0 0 612 792] +/Parent 1503 0 R +/Annots [ 1512 0 R 1513 0 R 1514 0 R ] +>> endobj +1512 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [411.458 591.852 426.18 603.808] +/Subtype /Link +/A << /S /GoTo /D (subsection.2.7) >> +>> endobj +1513 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [492.242 591.852 501.014 603.808] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1514 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [414.729 381.654 429.452 392.502] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1518 0 obj << +/D [1516 0 R /XYZ 72 720 null] +>> endobj +634 0 obj << +/D [1516 0 R /XYZ 72 452.846 null] +>> endobj +638 0 obj << +/D [1516 0 R /XYZ 72 325.908 null] +>> endobj +1515 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F16 823 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1522 0 obj << +/Length 1957 +/Filter /FlateDecode +>> +stream +xÚĊX_s6ßOáé“<³VôßöÎÜCÖħsıén2ħ{i·½ıa$:ĉTs”´ûPĥĵJۛÛiŸ  £ƒÑÓ(]ż ĝ÷ŭĉÍĊ*FsžEÙh³Í"?ÉÂÑ4 ü žŽ6Ċèg/OÒ(ġ&ôsê_‰ZìDġ$‰~ĤRĠÓx…Aà½#ĉÇÛñż6˙€&aèÏӔÌe=sw˘ÙġċBħ>ԍÜ}Ù4f< ÓiêŒŝ´\Yöĵ]³-)L;Ŭ*‰Ž.+ñXÊ˘÷éMĠHS‰rh“YOóa'eIäûC¸3ş‘yÈ˘ôĞ} ĵˢ0Ä˙ŭĴVĞżí·éí·Q{Ŝä^·Şxñ Ĝ\”:˙ˆ°ĞU˜Íú†32|Ù3ĵnÄŝ™ÈïEŬpäó\ÖġùÎïş"  8½xÍöÂHáÂD0=ĉbù> ‡×ì}…Ú~ŜbŜuÏŜµäó^oǃò>§ċĵ\.çƒ×}˙‹Ğ,BeĜ‹7‰b†dwY5†Ï×èŻï&ŝğżë+,ĵÙP!œ¤ë߸ÇĊjvrÑáÑ̟ÍyĞÍŒFiâ5hêÏİgYݧ·$şEî̓F4tĠz‡qH„½ĥÈUAÄg4'M­tEŒj &Ú=²iCğÔ;:_*ĉ7ìĜŽŬiô3qÈŻÔIàËÜHY½E³·Ġeİq›/hM²?¸8°ċŞ[$Ŝ§ĊŬ}<”ÜĠúĴŒöÒÒàP uĤŞ-œ[›=žB‚‹ŠD•”…,|h6óÈğ7dîUš„¸q^7MErĞÛŞx‹tì úl÷R` \]َn]¨Ĝ.Ĉñ-‘ĥì^Ş~.…-ab丅½3|‚Fż½şè~ÏĉàÙġ}ĦĞ­zj-}ĵTì’˙”ÜC?€¤OQğÖïòË]³aǀëÑË  Îc?â~ùQµô'%ۛ{vV ى2?L~Jg•hz]â8†&Q0÷£Ì•°?¸ÛÇRċü%dGĊôwÇtôލ£œ_4.˙–ˆ{ĉî(&·UypYɍ”ŭ[IÏÎŞ‚+ġâàÁ÷|ŻÏpÎ+FżnÊŝ?áfµï_Öuğwçıŭĝç ŽôÛ Ħ!@8ħĝWßS˜Dµ²$‚V­\aÇĈ†-Ĵ 80QĤaè­Ĉ3˜~†ôä œ·” “$ñZê™héÓÚö§žQj‡ZċĵÛV³²²£UTM¸›w¨Î¨9òĈ3hüÊyJñc—¨W$§ëÜSBĠDÑnHġç)-ĝu­é°™öqݚžŞŝ‘·xĠµ½p$5ÒŞ_TQ4÷ƒpċ’ù3ÎëlŜÓYnŜü˙@÷ +endstream +endobj +1521 0 obj << +/Type /Page +/Contents 1522 0 R +/Resources 1520 0 R +/MediaBox [0 0 612 792] +/Parent 1503 0 R +/Annots [ 1519 0 R ] +>> endobj +1519 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.873 175.542 133.326 187.497] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.4.10.4) >> +>> endobj +1523 0 obj << +/D [1521 0 R /XYZ 72 720 null] +>> endobj +642 0 obj << +/D [1521 0 R /XYZ 72 162.597 null] +>> endobj +1520 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1526 0 obj << +/Length 1111 +/Filter /FlateDecode +>> +stream +xÚíUMo6½çW¨=ÉÍJÑ÷Ç +d8›Ûħ Ŭ큖h‡XYREşÙüûÎp¨Ä’µMÑ( +ôbÒᛙ7'ÏÚZžuuâ™ġŬêäl‘Yı›'Ab­6VXİïı^˜ZĞÒúh+&ŞĤ›9‘ïÙ?//n–¸ġíMoÛKN–GĦÈ$ۙd6/Ä'Ϗ +:fm;óíJL‰Ĥ–d\ÏÀï‰öĞ*QoûHó›×W½›¤6‡˜&ĞKòcĊ;²İnlmۇĦ!gżĴ~€rßwó8ĤÂş}í>Û37r²/ıR‡Ä"›aÈ ‹í–IÉK2ކ֗,у™+ÛÙ·fßlèĴÀBXÇ +ÈלIŜ‚Ahü̅Vs³éèp×tĈ˘ĜZm-+¸$rŒì˘Ùí˜t§ +d”’’S–¸Ít’¸Âqz˜$ÚÖÔÊ­¨Ħosn32\—ĵF\ğMŬÈíÇñ-³…vJ{'ƒeZ–Ùß·5ï0#[B@’2 £áħŜòҝ9İçÙ×ġĞ`„6EVfĦ-ßIÜFvÇ+êÚ1Ĥ^ĊŽÓħž44•àĵ‡y‚…k'Ìċ‡œ]&'ÉŬóş0hB’MùvĉÄQdŸ“ċ“F§ß’—ÛÚä9äÖÜÖ˘› NTŠ$„Q¨s{^é‘ ?ÓŽ +*vK`_ħ҇ĠÁ™ƒ7 [(·%ĦmöuAÏK‡¨™òËĤİ ²£4šĈԀIñŞ’t“Ĥ%ĊiÁżşMQĝ(Ċ:Á³4žÚ£ŸPñ/S2ù³ÌT†¤iohOñÂȄ’żëÙvVĦÒ¸ôÜë‹7 ÉÄ-&Ĵĥ–ş~[ìfıOéÜ]>:1Œġí~ "Fè Q™ Ĝ }K‰5Ĝà˘şQœCİ ĉaâŝëĜg·˜1׌AN(N/kĥĝvàĉ^b͘ŬMáßqV:7uġDPĝmFOX×°—M݇=7 ‡È‹)dŬ9&żgá˙BÈτ~ÇĞf;ĵşi8Jû›)$´çzvxÁFÖ8ÉCş7MÒ!ŬËIş<£~6{3S˟– DtpHub½WCâÏ…†À ú~tá‹îC˘!Ĝµ£ù„cÀ%g]ŻÑ˜Ìsž2hԛïĤÊĵàĵ"äwOꐽ~Ş D×(^¨#"ê™OE81u\ŠÚÀŸ—eÇÁg°ƒ>žOá/AûZӌ˘@ jô­Sĝž¤£ñ:ż?ï8ë9yŜ] Óŝ‡W?QĜ˜7Ĝù +GúcŠĤb\qu¤IĴMaCwÇoûtò,˙,ĥċ$nFEƒ)Qż˜ġI‘˙M‘Ž_鿤ÍÉ˙Ú|()É]´âż%Z4-gÀàñԀ¸$‰˙ωËĊ +‚ĜÍS¨)ŒŬ Ï(Xî œ.W'żH˘˜ +endstream +endobj +1525 0 obj << +/Type /Page +/Contents 1526 0 R +/Resources 1524 0 R +/MediaBox [0 0 612 792] +/Parent 1503 0 R +>> endobj +1527 0 obj << +/D [1525 0 R /XYZ 72 720 null] +>> endobj +1524 0 obj << +/Font << /F8 826 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1532 0 obj << +/Length 2202 +/Filter /FlateDecode +>> +stream +xÚ­XKsÜ6ûWÌĉ²œ- Í÷9l•#YĥĥR–Ê£”+Š÷ 13(ó18+;ż~ûŠ£0ÙöD ğÑht7n0ZìÑâŬĞH?Üżz}].ް*’bqż[Ĵ“Ċ:ŽÂ(]/îëĊ/Áíq0}ç–Ğ4_O³]&epÀi(Ğ™îL{lñĝĥ{}û9ŠSúŭѲ|”םzltÍ"¨Q‘€mÖÁAYµ´•ĠMß Wuġ jF•ë‰Ê2ĜġMÓüÉtûċżï˙ç^ĊqXċ9Ÿ÷LˀöĵgŠk[S|àœ€špeJxdŒ­ŭ™ĝĥçRE‰(‚D#J^‹ĠğFÄ"5ğ‘gĴ(óM*4ıa³:Γ—Öu³…hrħÓçDDŸL›}bĥZž•‚E50ĝŸá³Ñ1Ž`ħ“‹‹Sn·@äáJ:żÚtĦì{Óùkîşîém‹!§gZ̟•ĵÜÄ6³mâĤ$ Çg›Ï<ú‘2G—ŝ!.Šïhéş 3pßÊ3΄_„Š_·"rEÊĊÊk$‹Ä¤+½S§f`Á a?֑b=nóÛ Íò7;ġ÷°]@˙Y?½KyŠò6/é„M¸Ċ,J˙—„Ş1ŝÁ7İc–ż18nĠ—Żd0óĦ(İÜ7žĦĥÄ:|˜ïàħ(œn|ÇbjÙî–‹d+İò%^Î/~‹ċ¨™ıÜê"ĠżƒèQ†êi&Ĉ­·N¸ƒ:3[×ĴŜ+[7ü”Ê)À‰Ôm²§?Qhpô†Bƒ##K Ġĥ‚ĊԄÉé†fK]R|°h²‘÷‡A!ÀhT΃ƒe$™d´*'żżâup³ó† < úß·ĝċÇ:ÎŭßğYç(r|šN²Z-~:ĜLŜÈÄá—%”% ŸtĊÀ“7•oâN^”ZÜéżĴ“c –?d|¨ĠÀ”·CÒ*ċ‚rÖJ²½µ “3@}·L~ż#lZV…˙Yä1Ï#=Úúĝ°ıÂÑ-Žxà~ú¸ŽUIR…Q\-Vy–‘ĵ´Ğóoï_ŭâ¸ÏŻ +endstream +endobj +1531 0 obj << +/Type /Page +/Contents 1532 0 R +/Resources 1530 0 R +/MediaBox [0 0 612 792] +/Parent 1534 0 R +/Annots [ 1528 0 R 1529 0 R ] +>> endobj +1528 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [117.238 176.095 126.01 188.05] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1529 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [340.706 164.14 363.178 176.095] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.2.8.3) >> +>> endobj +1533 0 obj << +/D [1531 0 R /XYZ 72 720 null] +>> endobj +646 0 obj << +/D [1531 0 R /XYZ 72 440.112 null] +>> endobj +650 0 obj << +/D [1531 0 R /XYZ 72 335.996 null] +>> endobj +654 0 obj << +/D [1531 0 R /XYZ 72 139.794 null] +>> endobj +1530 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1537 0 obj << +/Length 1310 +/Filter /FlateDecode +>> +stream +xÚ½WŬs›F÷_AŜL„}K-ĞM§İ5’&šşé’NS@vÜżûuy3yşŬ½e?ï~·¸ÖÎr­_ÜW֟W×ċZ‰“D~d-ĥÖÈ·Fžë¸jd-6Ö_öû˘ÑUşn²G=†~h/ÊŬ.Ú÷\×ŝ‰e>/C^ĤÇĠġ4möÌ-ĞĴ‘Oo‹t• ŭÉ Ŭûùĝn„7ĝ{ñ›ċyĦF#kèyN†ìŝ5yĥŝşùq×üdßWNâħù›òpH‹ ó{VÈ×7ûs֕¸_’…QìW/Ϟ²+z덳ÊC2;ġ6=ĉ ëÍuÓdĊn0TÑèd˙ğ6Ċ ›Ŭ˜,Ż'q§—ƒ9q’°éċ^·Qb7ûĴfŞ|h²R¤FVëFÔJ^˙ĵ‹vĊĞĤĴ7oK\{Kl—Ĝpܤ2I%Ùĝ${ÀĊÖĠ!C/ħk?UÙÀ³ħ‰È•f?ĊÀê~ ĤñHr½ ×ġÛ^µ+äWE Ÿ3—ĉy9€PŸjĉÁ³)oL>P(v™ÉKÊm6zji^òXEͲé"†ï@cBWêLïġÒ…ÀϖƒXÙ|jQ'WĤ•PT5Bs><4ġıô(T(~´˘‚“ˆc” +7ħm$kMT*]ÓݍĴàuĤÓÍȟYEWUYĠ3˙Ċ9S bà‡rÔoœÛ³öÇAÙzŬPLPˆùħnRò+:ҙ}=#…§w¸£@ô.ġxöÌ^\€oÂ2ĠƒšNôÈ~äÈ'tm/C’Ù%H2;×ü>’Ìŝ’½6P"wú$QÊ$AÊ ‰Rmd„$¤VòJIğâµEĥĤ™(ÊêĉlĴ{_`kZ• t™G<Ñĉ4up™i$$·ÇbŬ†ı@`ıŸí§Œöŭâi˜`ĴÓÌĴsV ÀQXS^žèU‡îg(Ö˘™ÑêfzŭAö +¸bĝ~á;LżßòÊyúrïaĊG˘¨xí˘‰IaAŜ-&°Ĥ˜gÎYż´)àB·ˆŠÓ8ĦĈ) eî,’ÁĞÀ%=ä9&iŬ0pL²ÏZ0À?,œéĵܵĜa:ŬF=€q \=¸˜P¸Dq¸Hr¸„ l;.‚ŽÉ%1ù:tLÎAǏÂ?w‡œ†`NƒH‹l$ƒHÂo3 +xAíŠĝpC>ċ¸÷Ú³Oo÷Ɋfĝî>°dk,Ì£HCÙĤÊñi×ÌbĤe!.²‚…O{xeÁÍŜä$ûˁçùö;üüf|Ğ#ĝRÜŠSĈġ_]•TFàFrçPN„Ä €İôêˆ5Ìe3Ŭ6Ĉ B– rҜ v2B.OY´ŒÂĜ^ìM < Ôĉs^˜äѤŠ’-œu­?µÉ~ûPvóŸá³Fb°/pí_Ój2ĵ.²-’Ĝ³w˜Ĝà&DDŠÁd“AÌh +ˆH+ĚĜĴP<é˘Sy.yŸ†QĊƒ.*taX†Q ΰ3İÒ)£AM°“*?]ĞcfĤ.šâÒ<—t;ĤI6ŠÒg…M…çf +[d ˜Zn·Zç€Ĉ„œ"ÙÛ§ +„ŭ§ê›Ç½P@ğĊfÀŻb§—ċUÁ0ò­ƒ8Ŝ…=ĵnĦÙDKżgéwCġ›/Ħ:zŞßôRíc'TÔ £ +î9ĥ‘ĝ½/nW˙ç&› +endstream +endobj +1536 0 obj << +/Type /Page +/Contents 1537 0 R +/Resources 1535 0 R +/MediaBox [0 0 612 792] +/Parent 1534 0 R +>> endobj +1538 0 obj << +/D [1536 0 R /XYZ 72 720 null] +>> endobj +658 0 obj << +/D [1536 0 R /XYZ 72 559.664 null] +>> endobj +662 0 obj << +/D [1536 0 R /XYZ 72 376.801 null] +>> endobj +666 0 obj << +/D [1536 0 R /XYZ 72 183.09 null] +>> endobj +1535 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1543 0 obj << +/Length 1715 +/Filter /FlateDecode +>> +stream +xÚĊXŬoÛ6Ï_á½É@­J˘dY}ĉ£ËP4A XÚ>(m •EO˘“eŭì:hW ۓÈñx÷;RÁh5 +FoOùı=yyİ‚QĉgÓh:ş]ŽÂ$$aà*Ŭ£OŜyÙĉ÷•~5ž$Qâŭ2ıŭm4IgÄ9‰”Ÿ…¨—ù²Ì7×֖ġjŜTù0NĤš>Ùè˘”Ċ˘)Y9NgÖÚ4›ĵޞ˜ás&fğEĦÚŭÍ-IXç-/ŠÛZŒY :ŻWşÇ“XeŜĠ’WžpĊìxûĥÑ­ÈëÒŻbdèĈ)`0„ÀÔÇâpfH‚mL59RÓ.¸0ÌwÖlr[.ÄY Uf…ÊUÂ1 +háA­y şàÁB•ôÙé=L"öÖÏğ-gVñqfœíêŠñ uĜß8Žĵ7uı™÷<‰ĵ”ifÉSNC ´„c€¤ÏÁ20/‚/.ɞH"cİŻ +Xsç&îVkë¸]rÁdΝô|'Ç@çXt4DzazïeY‰IŻ#ħ:Hĥg[Eş×)RéĵÏuŜ,Ĉ*ôÖ<ĥƒ^˙D/è`ë›npӘÍÖîwƒtݐZP°q=hÏù5á`ûއÖs4—+áEO#U <çEÑ Öp ­óŠĊݤj˙šAqAĈ³›Şß{×O‡Ħ‚½Qâ'p:?ÑĥN˙IÛ:8szġ­ù²óô· ċYıäo³Ğù‚„rİw䘴ŭĥxú˙´ĊıéI^ĤÜ{&Sŭ{ĈKÈ9]ñ]KR^óBWV<]äğV‹¤ğùÙġûËĞ·˘Áw+yŒŝ֎ʉтZ„!\ħqÖ Ëp^€!%š(évPĉlX€Q& +;Dt)ñÈPŽsż;5èBÓ(ò÷Mp`LVV•A³ğÍñÙÙ3şoĞœŸH-„Ĵ4ëbh 9<ċäQòòuǜ½ Sy(So4Ÿߍùšè%$ Ż~„f$‘äŸC”ŝ˘ùéğ(ñ 6 È|qĊxìòĝ/êêùĥ*_^x2Q6¤1ΰâ—"ÊÒ–Ê°„£A]àÔÉŬ”ĝÇ}]î“4ßĞRîĦ-°oD<`™sç|'ALB>X·ġHXÎ\g^EĉŞZi˔vËMù˙Y:§4e<—=>K³À{o„Ħ(\5’€½„ÍÑÒè?v`hç‚òywœ*@ÈœÉO“ìù:Ĝr†„oÖLfĈ‰ĵž‡Hƒ/G²‘È´òì^ ˜<ÌçşżKQŞ<[ÈĤb‡ht›Âù@—C5Ċ˙[`ŝĞŝ³,ô˘Üsĝ†Ô½iñšż_¨£(Êü Ìàr˘| +zgjéâöäo,˙ +endstream +endobj +1542 0 obj << +/Type /Page +/Contents 1543 0 R +/Resources 1541 0 R +/MediaBox [0 0 612 792] +/Parent 1534 0 R +/Annots [ 1539 0 R 1540 0 R ] +>> endobj +1539 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [253.347 449.521 283.567 461.476] +/Subtype /Link +/A << /S /GoTo /D (paragraph.2.8.2.1) >> +>> endobj +1540 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [428.566 425.611 458.787 437.566] +/Subtype /Link +/A << /S /GoTo /D (paragraph.2.8.2.2) >> +>> endobj +1544 0 obj << +/D [1542 0 R /XYZ 72 720 null] +>> endobj +670 0 obj << +/D [1542 0 R /XYZ 72 607.484 null] +>> endobj +674 0 obj << +/D [1542 0 R /XYZ 72 400.711 null] +>> endobj +1541 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1548 0 obj << +/Length 2638 +/Filter /FlateDecode +>> +stream +xڕËrÛ8òžŻmè݈áS$sĜ*Ǟd2µI\ħ·Rì`–¸K‘JÖżŭ*Lf÷"6îF£_€˘Ġn­Ŝ<‹ó}u÷ìĊë4ZUaµI6ĞğÇU‘ĴŠ8 +£´XŬĠĞÏÁ/Ŭ¨ÍĊ:OòàĉòîW†.ëÚèaàÁˋ?î~{ñşô˜DĞuR†YQ1·ë,*‚§‹¤ ú›A=´šž€Mpŭá–17HĞĈ=úĜôŬs€Àû[Gġxêĥ8scŝuF†”`n^ĵc( –˘şš1÷UÈGŭçI£Ĵzì ˙ŒâĴŝ  +½âöâ8Ĵòœ·§ĥ[2FÇAßµOEĵ%ĥ'ct‡Ûy.Ú~·Ó5O×Ío†H+œ> Úfj^w4hż2Àê0a;l­FĊpQÄF3ÍAuj§Ú &ž†QešñŽR°‡Ĥí ´×žûş×F RÈvŭ|.)Ċ `GχcZE'8„N—2Ĵ °ÓiŸšV’!ŭ##Ĝ9AĦƒ˜dN†£ıA”6Ûŝ@§à/k›C3* +5š  ÌÄİĠBàüh†ĉp_:=Ž,:وމ¤ĤBóhkĜßGͤV‰·ÍTĴƒ‚2Z1dOҗftĞż\ä9Ĵ´Ĝó­ĵu_€Ŭ:€ÓÖYĜ]cTf D^²€·E—:°rĤC·&§àX‹½ŽÏ=Íh™£¨==ìŽöĊ¤Ğ$í2J@ĊŽ154ğNÂnbÊd8o e€3²~GÔyt ?ħ‘\ xòÑô‡}ĵċSfÊk<ñNİ–<Ñ_Sî(ÔĠKßâIöN´”ĝ-m˜”ÁU8ˆs`ŻP vRÌ~Fó÷Ĥ“ÎT5ċáĵ ~ÇdĊ'ż6œWJ:RöVM9ëH¸*¨8Cċ‹'#ñ‰ŠŞ‘!v×Ċ°::‡Râ1vYêo?…l܁œóxœ'£4¸żşù˜ĵHeV˜gAm‹zÀ]ƒ'û÷KÊ +œ„Ö Ïĵco‰Fp’Ĉ”˜ÂGèĴÓ²’“&"¨ÁĝÉÎb”Ĵ!ʧ†hçhjstŒœNe0[½ċL…¨Ñnû-:·Ïká@ĴÏgYJ^„ ċ玎£gELŽŽ àäH¤QÂì­ Áü£”S"ĉ~ Ĥœ³Ò`rh_•ĞžKÄİ‘Äwê˘HƒËĊnZ Ñ4§QרtœL'VĊ™İ=mÑóİqKĞ WĵJZJäĜÌÏ_F/I$½}zŒ +{,§$\ŽŽû •a2-ú£÷\"'—ÀE‹ç‡‘ŸÇÁµ™R /CùÊ´jiŒè+•i›bsIXHMçžCÁ…”w €5˜íĜnùĴĉˆ’5Šh,Ĉq¸żı(³àSŬŻáĠ‡wŒĉÍSĤÖN޽ĥŬ’ n57ê0ġ,†Éhev+>yĥúLÉ! +"°×XGġ/Ÿ+$ݨmİAú*ÙÈŬ.ĤN ’ŒĤEʜ’Ê炇-˜y!ċ) NÇyßĉ*f6k^H³@EÖz “yycžÙR?ħUÒR*ÁA{‰F Bĝu8ğUŝpDÙ —Òeéİ)Á^iùîE„ÂÛُhÌş\Œy=½¨ĤDĵz²ÊÚ´·àžJ‚÷˜™‘Ğñ0-5 ĊŒ‡ïl’‘äAĜ`V뭓p Ĵ6“`LmÔ0áíħĉ%~ɉŒŞ ĉ÷üĦRŽä’ög ğ—Ÿ;?-œŸJ£.ĈüIJİ×"¤9s—šğŞf\mɽ•>˙ûËżSgÑm²Ì—‚#2”-,Œâ–c +>ŬŸÑ1hĦd1ĥNİ"AsĠĜŻÈT|ßÁœfÑ|À]ıPˆ—½qÓş]{# Ħmé,„ğpL~|â1tĥĝUü9’İÖPH8h¨ĥ͑ ?ŽAĠĴ6s‚›#ÏPĜÂW:[ĝo\ôˆ >X*52™qŻˆçhĝ`ġûÂÁŽt#I(Ìt¸£t +%'âG›8öŸ~â0Š`B‹˙öí³NYeç1d™ġÁ•§$•Gž 0o·ŝ¨­â@&rniۜĥ„İΊ“7‘$ñnK"žzşbRH2{-L\äžħ'`úÊŜÓıyĴZz۝íÚ.d ÇĴĈÂ͆^„ +Û‰ó,xÏ`8$³Á·ëG^ġĜŸ:ìŜÒz=žLÇ·Ž˜,W¸–£à[aËx‰'´1½³Ëój·LTv;ĈÉY|·ĉąğE ÌŭùÂCÌ)KdO%.ĴHœŬ)rħ¸œNÁQìtB5×/>‡ĜF=B|Yói'ÓsıµÚúĵÁ>šñ¤l[ġMWÍu‡b $YNÛ-Ġ +LŻ\a){ÚĉâħmĥöĊò´#Ü Ħm5ƒĴ4ö\2ż€Q)—ßáŬ8Ċĝ‹&Ó2ç•ĝ×ÑĥcLı7lâSWrö$&aQIĦËÂ8 +Ó°„3ó(ĝ´×OÚËWOÔOC·ùéJ½ix˜â#ÛÈAsÔµˆS”İ8 +÷׀£Ôè÷ħö{ö֎Ïä›0ßĜgòÎ67ZÜ%'q/WògÍÑAÖ[–6 e`ĥ™ù>P{5CÜÉ5jÌïñÏ'Ĵ{wA^ü‰cV„Q‘Î9žġp–Áŭ4Ä.ԚÖ&y˜ñĴ“4Ĵbĉá\Éı{BÈud˘îÏßnkc˙İà–˙“`âjŭó=QE?ÖuiüwaĴ]é ĵM]ëGEċénŬsċĤp*˙0ÙĞfĥµŝíŸ*ž·|˘„—Uħ÷·Jyï <ĉA2÷ŠĜF–.>—á„ß´ĉi êû×oßò#Ty’ê-b]c‹Î$·žXİI%\D÷ڞĝ4ş-ż~p3„ÜÉ}˘ĥŻöîħ‰[œù0ħµv{Ò*÷}ô”€ĥ2:È˗çyì›9uRêl/WV~2d Î,y +V½ü_3ƒ÷šĉŸ˙2^=Œ‹É?\X$›){°Ï/˜ü˙’7ñ.R&áŭ­<âíĠwë$İÂ(`UX–%+Pe³żÜ=û/ĝ€{ +endstream +endobj +1547 0 obj << +/Type /Page +/Contents 1548 0 R +/Resources 1546 0 R +/MediaBox [0 0 612 792] +/Parent 1534 0 R +/Annots [ 1545 0 R ] +>> endobj +1545 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.873 489.778 120.596 501.733] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.9) >> +>> endobj +1549 0 obj << +/D [1547 0 R /XYZ 72 720 null] +>> endobj +678 0 obj << +/D [1547 0 R /XYZ 72 332.003 null] +>> endobj +1546 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F11 833 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1553 0 obj << +/Length 2318 +/Filter /FlateDecode +>> +stream +xÚY[sÛĥ~÷Żày*Ġ‰ĵ÷-µ’wÒ8ÇöLgœĉ&)›ŠT@2Ž˙ŭÙ/’·i_D`,À·v!׺·\ëí™+ß_oÎ^‰­ÄIBZ7[+ÒV¤\Çġ"ë&·>Ú×EUd]Y߯֞ÛŬJÙ—˙tw?ŞlÓğJ„Í+›ˑ}·ÒħŭÄò˘ĈJWQÙ)7l¸Öĉ¤lìÔ=ˆŜ?Š˘bÙŻOK°ç°ßÏkŝĥ)ÁÔÁîRL:ovе²wiŻ>Ŭü{°VÊI‚€WûĴQ +í]³ZƒÁıT³´o‹–Ë·×›Ëk.v ÓĥíwÒµ{HğĦ$˘Áx(òžtÒPŠÊ´zDyJ"ğ|˙‚ ÷ċWŜê(zÀ#·ŭ ÜèZ÷ƒ´jĝŝé*haÁYçbÚ\ŸġUìÙĤìŠö ݊:Ŭ‘R/°qëHúÚ¤moŠ!àĴÖ˘ĊN…µ^cż˘cÁ_ÎĈ·/À8I˜²M +š˘u˘d~$P…­h°ġħċúŽnz™ıáïğĊ³yah˙·ĝVĉEVîR܅°™ç°°–[›- ŸPUÓ–g2 aß³/:•2v>&²AçÖfÖmyWVe‡6?qW2EğÊKa8ÙzGC:İ óìMÓÁÎÓĈ-";ĊŽqb×E KÍW·‹cğŻKÙ+>8Ú hJ+ĜÀ%°ÊP)8ĉNT¤ÜiĜˆƒbÛ¸sñb@î¸c^mEàŻ°ßû~I n™ĈÌ"˙“t òP€ĵJ׃J |XÈáĜóŬhÎxÛÊTçß5éuÍ×ö;Î{ž ›;t^/Ĝ&ĈmŠmJ8ŽS´FT˘+?˜T‡ŽŽ$ş!"ñóbyĵbn ,`\/˘†żS{ĜV‰—Ëxµi hĵĵ¨?Ç‚²9`Ŭ ` 36™Û ×NÑvpjİÉ17‰‰ÛÂVçSNˆ7ˆ߀OĈ@í„Ŭ@&ĈP´À ĉŒÜyì)qg Ŝ”ÄM×´oo›á(ĈYöâKS"1 5S@ĉÒŬwä°Ç(ïßNŭñ_:×§ó½ĞB¸½‘ĝXCĺŞĈ°žŝ4†ż‡! Jq1ı,‚ γ j|'ĜÁèëK_ԙÔÀğè+@hı–Öò$@3p@ċ‡p {'ÏN´,@0†ÖÄĥrÈŽâŻšĉ$â¸ÛÎÄ%AœOĥÜĈ•’0À(ٕ ‡ÌŜ”xš!튗|äĜpŬğ=,”)Għä†bò”Ê|tP )yä ײS‚H)'-g.W=÷˘·..{ 4ŒÑ:%Ñd*},é‘Jwì\ÙöàaXû  ĜDO:Sr`N–N9™ög7T(ÖüèîZ☑Épc“„˘Š@ÙçÇIJÍ]<-×rEÏnϤ€?ìĤ§t*”ŝ“äïìè+BŝGKH‚ւüÚĉžE +endstream +endobj +1552 0 obj << +/Type /Page +/Contents 1553 0 R +/Resources 1551 0 R +/MediaBox [0 0 612 792] +/Parent 1534 0 R +/Annots [ 1550 0 R ] +>> endobj +1550 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [333.987 506.708 356.458 517.557] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.4.2) >> +>> endobj +1554 0 obj << +/D [1552 0 R /XYZ 72 720 null] +>> endobj +682 0 obj << +/D [1552 0 R /XYZ 72 591.995 null] +>> endobj +686 0 obj << +/D [1552 0 R /XYZ 72 232.405 null] +>> endobj +1551 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F15 1136 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1558 0 obj << +/Length 2080 +/Filter /FlateDecode +>> +stream +xÚµXKsÛFëW`OkE`HN^Iv”ÊʎɭTùq€€Ħˆ + E˙~û5HQğöVí…èééééééŝş‡óàĝÎÛ ˙…ï?ÖŻŜ„“yYÄÎz$“(ßóÄY—Î'÷ĥéM—}ġ§Y,u Ŭ÷]ğÛ÷‹e |ßŭ‘yŻù³äÏŞÏw{&ͽˆ…9˜^W;³ĝ²ŝĊIR/ÒÚY*ċe ßíûŞm˘ù³ŻŭkĝQĠ!żŻÍċÄ]!׈öĵ,ğĊ2Œžû¸ş~Gó´K”x~ïò²Ŝä6È\,£D˜Żç +—*žRg„^ĤXUğÛċM)çq×Ġ6G÷™Nô÷×ÏO³†ÙĊ&éÙù²ì›Ï‡ U1˙܂kvĸï’E­³ƒ^›M>Ôâĝ•éûŞyßËjÑU˘ŠWoÒYtù )ġ´²Şġĥ‚RíĥtëLĵĤ~b*_İûçBUĠì$d?Vŭ–İëĵ7v i:ĉö¸ìIx˘s3-xĊ$E#Q¤áàÁ½‚7‹4t[Ñô>^ŠÖ­ˆo†ĤxnuÓöä:˙ĜżùìШ§,4s)RÀeĝ-­ÏhtO–3Mû…™ïŝÚĉċBáI”Ûñ܃i ;{ğlhJ#3Ğ›ġżŜ\­=–mŭ$]5"jĝ`ġ…ğ}§{p˜ĝöÂùDBĦy‰X쐉Ħİ)ħ‘~B³ÛáÜù·r‡rY—JqLĠ ğ1hR}ËßÎşÏÑä SvmgŠĥişY\µE5aJ÷|À­À\1 ³–6™.8„Œy\ İpÜrÛ4hÛĉ=ݳÇċsZ#à^ÏxÁ†yetĵ0Ja‹r( ó†Ĥ1hKŜ=1£ĵÖmM^bp‚ k +N^ż25\ è܊"^¤,"ÍĦŽ‹Ĝ<°]Óà=…N„ħ)ߞeG·VŽê_ċ™CîĈkÚS­@›Cß&;°ĞşfŞÈ‡ƒxşm,ħ?5<’‹çÚDG/Ì{ĝ$6¤0=pŞÎQ]ŬmAšƒĤ$ĜâĊĴ­£v< ˆ•yËB=:°7ċpşâ0çÇ£LħߓRkÁ0`-ßV6‰úŭXa>ŭ×ùĊ֔ñXL1OĝŽs„˙·sL5ù<ÊÑÍ^dÒŬl0²Ġ”É88JÂü\˨ç/e8Q{ŠÀĥâUÌ#h%)ÄiêPȆ‘ïî^HE)²­l<"ʑĤİêàˆK *ĉë`šBFXɟ™t&iÇöŭĊíKFîtëÎ% 4-Y,ÉIÌ{[pq0:“Şȑ¸t+U0ġZp˜ùˆĠĤ–݊ĤUÏ+]SïĞ´?mp ˘äe@œp!´Zü‹ÄŭPĠŭ’ dÏt söÌhğ‘'Ž%`prìu€ŜċRéIóĜİ Efii p£{3˘ âöÑĉ3ˆ$Á ŬŝLu'–@“Ì ħİÇ˗á×.ċà!ĜŠĥ)\ièKİ1ŬÉFlöÜߞŞ6ĴÙä™X•ôÉBŞ1ÚŭÓf½.™Îùs¨vûZ~VaDŭĥ ìŸ~‚ Ŭb̐*òÛ9 ġ,Şabà(%|?Ӂ èA˘dó(E`(şb÷ĜRˆê1 ôtgÓRܑrjëwbAgŠù-hXD 6 ó÷u^Ñ0U ogv-\ %ú/Mf¨ ³£ £d° AÚŞà³>!ÁG5Í:”JgŽ˜ĠîÏĉŻŞ4EµËkd„ôĉ8˒(À %1Ú µÜ 0S£ÖW@ÚFħ1Bà ‘N&<˘l§}DóŠ?Š‘E(d͂‡{y£Ì,EpŠú™³ßÇĠĠğğ7·oħJı÷ә ı@İ£Ó™‡żĦ;Ö§ÀٚżòÑ=8#îáY왈Ézl96‚Àí¸zXMħ33,rÈw²TpääR~œŠ_ĥ8>%-Équɓ’­@Íñ$US_˙uÀ­£4™´İYMJÊZŞ8`M[×Ô#sÓ^2×b%Ò9/ĝùÈÀ˜ÂKCà_·ç`ôîŬzŞb‰´0š?ŜUŠżMëÁH'hQ*ž­ÙCùĞŠ^Ê9pakxC‹t‘‹öOQ Ŭ߸Á N:œ0RÛáDžò½S +\¨ `ĜKO#÷j/—ĵ7<ĜHéÏžÀĥŭ[àY—w³ĝ*ïAċ(­=谝@iO‡Sì.>}ñ&Ák^˜Î#‰îœW^¤b kguñۉx½8*Lĵ4 ˙“ßI/ŠEĊÙż­”vTâA:'ˆµ—jċïéTZÑßʇĥâŬíŬÛçRù!­Ypç*•ż7Z~ŬX/i$"[ġ€5–SNï_ Ÿ0J8‡Cî-(LÇ/Wë‘Ĝ'ì°3ĉYEŸRqk“cdEÙŜ} S+l}lÊĉdžÂ‚‹‚„&Q$ÏRbü5‚“ˆ!¤–YɈÈÍ{Ğâd÷˘Zž³—ş·ò\ŞŬŸ„rÛêBOOBè#À>™´€_í.'`¤ĤÌiZżïڇ.‡'}÷ƒdà?sJpÌUÂÈPûŸS<ŭç„ìƒÙçĝK e3rİÓ<ΔHÇ +É?ȟ'ވ“è{’í›ŝàU +â> +żŜĞ—ŝམ™˙­;{'ÎÓ-2ÏW™³ŒÔ´{­OŝÛ-ÏŞ +endstream +endobj +1557 0 obj << +/Type /Page +/Contents 1558 0 R +/Resources 1556 0 R +/MediaBox [0 0 612 792] +/Parent 1534 0 R +/Annots [ 1555 0 R ] +>> endobj +1555 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [469.15 559.05 491.622 569.898] +/Subtype /Link +/A << /S /GoTo /D (subsubsection.3.4.4) >> +>> endobj +1559 0 obj << +/D [1557 0 R /XYZ 72 720 null] +>> endobj +690 0 obj << +/D [1557 0 R /XYZ 72 250.843 null] +>> endobj +1556 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R /F15 1136 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1562 0 obj << +/Length 1910 +/Filter /FlateDecode +>> +stream +xÚµ˒›F_Ar ŞX„A€oΛÊKİTü8Ì˘ÑŠ2‚5 Ĵ÷ïÓŻAHĈ‰]I.šžžĤ{ş§Ÿ +½[/ôžŸ…²ŝ¸:ûáYzy/˘…·Úxiä* Â8ġVkïŜìvĤ^ÏĉI”ĝ?—µeè|kZSôĥ}ÌûïÏgïV?yiè$ñĉJ9ĴÄáimn*ùì@MĞYŻ[ú.<ŝä˘ì›zNDsÇ=Šƒ\ Ŭ˜}Ġ3áÒö}YßÎĉñ"d Ż5²ĝáY6R„Fi‡‘ğç,Ê|P‰Y$Ê7ĵœó²i›CŭÖ2°³ô͞we=ĴÌ Tŝ‰°#ofsĜ­ekŞŞÁÓûŽ÷¸i„YßZÌ˘ÔߚúÖ:Ù3ċĝ-{³ğ“;ĥÖô‚n›}OEBÀÄĥ ċfÊÚıħöM+ün÷uÍĈˆc˙ġòâċ2`ĝ Ÿwĥhêµi{şë6ww¤Ğ5m÷….çÖż;y Q\MTCxUîzċ”Ä͛·a^ÀâÇ~ÄhÄ.kûwÎ˙>ëâPĞYûhû<÷×̍7ƒ…îé: ŭï 6‰Z%>˜šġn0dô„#ȏxÛ´ĵZç-|ìŜ—˜Û{["€ò3ĵÑl|žˆàDh´`êÁ˙ ñÁuĴ*†àŭn@ßŜĠ–]·2Ü+cÈCaµm[”JÖ1ÜżìßÜġeS£ĥZû7{ùŞìÇü„tg(&2ˆŝs–@n(+1ŝHÖM+T€êşŜîXĝZî\5â}mw¤˙‚ġżß"ğ ċ"ùoN4ÌDj†:vD|äĦ˙[]qpĠ!Œ`cZ+@=ĉ‘"|Ò5c‡ËüéċÉS4_LĜíÛ[;!ÎŬ´²ÇöÁ#| 'àç‘h­šzä*YGùi8 ;˘]r—˙sH.€m6‚äĊ%§|”œÍŒXIS9ĦĤ0H9 ˆIÍDKŜJîÍC'[%ÀÉgt“ˉDSàżO^]_^?˙´ÏUÓ7ó^\I˙yA}Pì_7=˧+´Ğ4€RÀ{—‘~@˙ä†*–Œ @aÛŜ”BŜo`=D JĜYKŭäD zĵĦȀâÓI‚G>Eù6TzĤ˜ĞĦëAÊbBÊZKj&TOq#yŸ1‰[v+M•ĥìzĈšŜħ8‘^”óİÀÁëpÑQ£L²ô$Y$xQŝ:Ñ]ğî„S+_@*&.`W'…,œıbğüÄŬ~i›ÛÖìvĥŭNòÊP5ĜϰI–TƒĊ¨1 ô‘ŜB×ĦD%ì8Rt²’0˙z'˙4ĜbY–|M°…_2oĊđ3Ĉeíê•ôĥżHa‹t„2ÓÈĝ4—ħç+_5œp¤Wŝt&÷}IÓ=>ôÉÛ=Ĥ5ž­†ĉҕ§Ó LS§ûß§ˆ•ıP§‚<ÊÀ)J‚Ë/GŻj½+¨T}݆ĝАŭ'˜úàd²½ššl˙ÑÖ 5ƒQÁ!L/¸VSJ”§à;œü(à ÎYG¤†é¸.˜żp=Œ$Ċ‰Û5Ì|1Ôi âù99ĈŭĝzÂħ1ħm1› úèĝ23êqÇ]ôä¨ó3Ê"óğ} d‹-^şU†Eê&  M@°O@°Ŭ·Ö€1ŽŽrp˘öŞŜ}%U +™Óhmv˜G-œcŝĠ7t'òıħ!ŝ"XN­>òĤœ ¨iÄh:áÉb˘\ı9#JÒé9#J•\I6ŻïQN”Èòh4CMÀġ°—Uù0% ùÒV\8zŜóp%m6%(dÈ £b”Ž@[3Í[ëĞo6=Ÿ ĵ/Ŭôa?R2.P+3 +hv„p° 6µ6ĵöCßیı ^7€ÚÁ h‡fÁĤ´2Èá;gT˙l°òġš%˵ĥTmy#­#;ÔĊgJk)UÌ×ù—Ĉœ˜˙ùϘgäWí訣Û{Q”ĦÊá#ĴÌ”§GD üYó +endstream +endobj +1561 0 obj << +/Type /Page +/Contents 1562 0 R +/Resources 1560 0 R +/MediaBox [0 0 612 792] +/Parent 1564 0 R +>> endobj +1563 0 obj << +/D [1561 0 R /XYZ 72 720 null] +>> endobj +694 0 obj << +/D [1561 0 R /XYZ 72 462.093 null] +>> endobj +1560 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R /F15 1136 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1567 0 obj << +/Length 2096 +/Filter /FlateDecode +>> +stream +xڝ]“Û6î}…/'ObEġÙ·^ĵÙn'ğéĠîÜ\Òşñż?€%ÚQ3í½ˆ‚ €€|ç“;w7ŝŸŒ˙ÚŬĵz#|'÷ò$LœŬÁIC' |ÏݳÛ;Üí ëÓj‡ħûî˙à]Y+‚~iÇĦlù›ûĝe/Ÿ*ġ’ÈH½EjƒÄDü~ġq÷ÓĞ7™µıïĴÌËò€ö~³Ê„ÛvеÂ}żÙĵÛâä +2/sâş?ĴÖa"Üó*LŬv$D5Ğ0sĠ!ı’¨ĈB‡cÙNˆ‹Ëe, zîŜˆ’ĊPŝ°˘‰şĠĞöŒĥ­ÛÓщ8QcË[–ù\G£söê󨚂Ù_<Ĵ‰LZ÷u[ײÙOĵ<ŽÉoµùÑFZ£ 4zIxÓâZÀmġDz.ĞŠ 'ÍЈ£ÚNíi·ÄQІ“ż"zà‚|ÇT?ˆV +܊—ĥŜċ(EĥꈛŭHk݆#+J„32âÍ!£ìĝ0c_6Ÿ<ûĈ…uáħ?/CD/C ›ċì4šÎ&ˆLÀÓXVZ[x7 2kÉz#O?žˆvKĵŠÄ¸ Lĥ'R€k‰êœY²ħ­ÖH­•vü=mô„Nv&¸GëİJo€Î —K—&î-ñ´%’J='& ôµ5IĦ# ­WEÛìew&ô,'<¨ÀxèˆÈ:ÄĴ­ñS¤ĵx¸Ì +ìħšŻġ–Î÷ê‘ +„Hoe? ı?…ê™Q_*ıAİ/ëSĊ‹Woµµż#ÂĴ*dӀÏĥ,÷Iû´"d„ :àŝZ÷[íF´ŬVÔNLÖÑöd}%†`ĝÂèψ½`[rÈĕû}§ŠlíFv×X;è+Jĵˆ_ÑԜ‰ĵĠ: +rLœœ`R+˙’ÖX!ğ5"cÏZ=+1í·U<5™G1Xá?Ş/ċ^e-1Í9j&´Ğj*ÙÎÏ'ßEw` +Y dı1\¤µ ÒÉ=E×qŽ’Ċn eo´÷ħŭèäç4UH}v}ûˆżß~÷ĝĉŝn1[ +Ï£I}&rĉ$Ó:’£ú"gĞ„ÖM_psì¤SĥJĵDèèÁEƒFĦğ3áÖ˚ÏO͜$ÒYöÒK’Ĝ/I˜Ĥvĉ@´ƒ /;íÉ)‹Bàġä€X`˜p<´UĊîŽÊĵO&W,i¸pMŸŽħi‰úĝnG€ŭÂ:6&Ĵš{ûc…áUô FS;Ӝàé+‹^m$Ác50k!ù=$“ĊĜŭƒJ—ŞvĦ—%\•DTQ ĝHÀĉĴ Vè; ÁŒ ·LL— L&é`(7ĠË'ÜöĞîvwóù&w'ˆc/ÌC'Ê/ˆ§¨o>|ô=L‚M<‘gγf­á^$WÎöĉßWB"(Â"xt£,û–ßISö!‹ċe;Aê…AĦ™Â$ö²dgä\dŝgĝċyĵĵûş*\kÖ!ÜhÑtˆ( ÜGLĞlow†y,›JÂSĴ"˘+ +Ġ ²lŒÉr‹94û`Ԓ£ġ\>%ÖGèï\àîˆÔJ êHB€/;ÊtùEÙí žíİ>eĦ…ÄSa`dy + t½˜¨Ĥġ"żRŠ×ӝ^€_£+ĥT`­9µ=€4ù¤)€?wí§NÖµêŝÙ/é µ¸QrĊ)ñ`‰e5G[ŻN²ƒ·­:c½ŻĞ„K§ŽâċŭüïûB\€ˆÛ"â/ġL"^(Ĝ5ïS‹q[ô3ż6aàû÷hÚ kĈ0= `=òˆRN`ۆÂ3­Ñ”y‘éíÔ½>JÜXuĵÉ zÄR°\ÊE§"É´b†[è­K÷ıĦÎfâ&Ç[é–zuAù jèNÒiŻÇwskÈÓŜ¤¸ċĤ0$Ñ;Ŭbµş×Q6Ÿá\ş2'5“˜k&á˘ÏA'˘ş^—ġù\UĵdI4PEqħG­sBË"²#5ò-‹ĉR ŸŞ„áF™‹×Ĝ~`„^Rż~`‘jX„%-¸ĴAbûĦ¨Â +İ­é$_ZL Fzy@ ÖÈĊ‚,ħ8ÀfŒ½…²4H­láœSE†‰˘˙~ñİğŠğ+Ϙbè:|ŝÖŠ-RĠ—RܚË'ke>- Ĝı{žkÌĊO?ÌËĤ’Póí Ċéĵ˜Öu3ì-‡ħc2W½¸5>5s9”ÀñLÑ|Ŭvrv`Yö_€)ċ uáŸ˙<àŞI5œŞ²?šß +“KŠh.Ŝèôö6–—’Œ·ôÓçW~Í!ïZŜ—‡üû¨ÚX@P_ŒC—(vOÔŝÜŞ&Î=˙ݨ&×wˆüÔ ŻÔħ+^ŬX˙6`ŞQFĴnYW{¨NÚL— DŞ÷sŭŠšND¨XYl’´ŸiŜĠ‹•ìú,;DÎĜ|âĝ 7@ÓS줉x9°Ğ˘F:ގ––ëş'0%KÙΛĝĠ"› ^ħ”@ˆ£ĥ:×$KÜ˙êì>.Áüıò­ĥÙ˙>ÙE˙lÈق"†Ëžĉۀى›]çË4xşÑşŜĵşA.Ë\ˆÚ ˆ&\ĥŝÜrĝW-ÇÂY­D˜$rÉVşPûv’^ö ÷ ÛıÑMĥy˙ĉ2%†aîùA›çž9çÙĊ +¨èŝg#ĠŞ +endstream +endobj +1566 0 obj << +/Type /Page +/Contents 1567 0 R +/Resources 1565 0 R +/MediaBox [0 0 612 792] +/Parent 1564 0 R +>> endobj +1568 0 obj << +/D [1566 0 R /XYZ 72 720 null] +>> endobj +698 0 obj << +/D [1566 0 R /XYZ 72 531.768 null] +>> endobj +702 0 obj << +/D [1566 0 R /XYZ 72 130.231 null] +>> endobj +1565 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R /F15 1136 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1571 0 obj << +/Length 2010 +/Filter /FlateDecode +>> +stream +xڝÉvÛFòŻ@NĈ҈Ü2–ì(/‘‘~“Ĝñš"žħ0X,ëïS[7AššÄsaWWWWU×úν;Ż/ü'Öż.X}'p‚8öÂ,tÒ óV~àÍĊğ÷SÂáOŽïEÙÊy ÒĈ‰üÀSApíĴ/~;a˘²ÀITè*ü_L|'M=•‹S½ŝ³ıxñ*ˆ ġ VÎfë„Iì­âÀI}EëĤtŜı˙]r¸ğıy½xżùéĊĞ•“yY&xeĝÑ.À˂ßıìKîM72°Ú00Ħn?V]ËÔÖzü"\ıŬěĵ× şóŞ5Lrá[€ /…ʠǝFUáËԊcVkĜµ.Ş?ŭ@éˆWÊÍ˲gé°i´D&ĵ]_ŜŒ\ LŬQ÷ÛĵSbšĤEŽŻĵĊr•îuğ<§Çá~”(%÷ùˆ_­Übħƒµh´ih²ħĤMüµïîûĵit˙ípN‡_rb7ċġbE‘›>-âÄÍĞ:˙PkFzŸ÷ù¨ëÇ<ßCNW›Y<Ş8ñb?ûúxü2/úİèkòâlPGŝ,@Sà ĦıŠ$4Ż[°~^ŒĠ'xaĈh¨fqï~ϸ5/KÙ鑁K0ċMĠÈÍġ˜7{cÛ0‚g/ğĤÉے‰~w1ôr—£`Ŭ‹ïÖt7]y +œräœĞ–=€djZ1Zü™HÊUŜħÔxK}ĤŜŜĉS=Ú·U{ÎNR+Kx•_Ĥğ=çs[òpóPĠ5ó´6ı)’ħ h‚•ñ‘İöżD8|Ozš'9qâEß§ĦMà]76†ßŭéÇŝ%ü"ύĜ5bġĝŜDí“ħcc\œDf"KŒR²„Áş¨y£?Wx¸†ĉ0%œHK‰È\k˘nö½qzŻÇİo£ „ß3‰ħWè˘İ-¤O›Ŭb™Ä¤êp&™:„‚½tB\jŭ ·Ĝ‘:/ +pj] ;-W>ÈóñTYîHÌ<8#ĴžĠoċeaĈú½‘veóĜËBn8ˆE{!B6á\!ےħ0ê†)K-m“ËOçŒ!twŬTËíVnô|Ôjvì„‘ÔiEÓĦıíä"Œà+yOŜıìŭħCqRW¤S PnµEu“ÙĜ›²ġ<À(˜ÉvĤÄ%n5 +ëĈsÀ%J &Èf'÷yLIŒ[“ÄÄR>QĊ’C`,&ĦûUáɨ ċŒ>°w€(†&2|$~%oɤ„ÇEı?B‚•048ŜŽHsj~ =—zü ›‚˘Ĥ'äJĤ­äşûçƒ/…ÍÜp dŸŭüÜûfö ?9#â`–x€ì°âşíêÚÄHJFAĴÍ8€s^Žì‚ÌĊ.p•Ċ4ġ"ÙÍ톁ĤöcÛĦˆ‡–%)ŠH;?\ë|t·‡dÀ-˙Š%' dĉċÄ "-‡fŜj%ƒC–]m.ŝîhú +endstream +endobj +1570 0 obj << +/Type /Page +/Contents 1571 0 R +/Resources 1569 0 R +/MediaBox [0 0 612 792] +/Parent 1564 0 R +>> endobj +1572 0 obj << +/D [1570 0 R /XYZ 72 720 null] +>> endobj +706 0 obj << +/D [1570 0 R /XYZ 72 372.584 null] +>> endobj +710 0 obj << +/D [1570 0 R /XYZ 72 183.554 null] +>> endobj +714 0 obj << +/D [1570 0 R /XYZ 72 155.811 null] +>> endobj +1569 0 obj << +/Font << /F15 1136 0 R /F8 826 0 R /F30 1094 0 R /F28 879 0 R /F16 823 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1578 0 obj << +/Length 2687 +/Filter /FlateDecode +>> +stream +xڕËrÛ8òžŻm¨-‹ĉS¤ĉĉ‰LĥÊvjì­]'“$B+Ħ%À$žŻß~"eíÎìEF£ß E³çY4{˙&’ñ—Ç7—7ċl–Érö¸ÉĴˆ£0J‹Ùc5û83_diTµ=4jž”Á âÀĠ{ÍKÖİŭÁ2t;Óñ\Ğ âïë÷(ÎÍ+uË0Ċ·yžŞĞµèGÙò¸5Ŭ^9ÎEş >ŭëšÁĠN+üĈAQp­œÎT[1 ·Bğ3ûù—Çżƒ(qòœ/ÛVó0¤ğ‹ù"-òàcr}˙€óeÁäpòħé˙öqNh[½q |xħNïç‹8°?1äÚĜëÚ~ċË´qş×ngè˜ +ï˜gyĦċOo?ŝ–Ê$E4­âvš—ŝıÓş9w‰5 Ó!ZšµĊ1 zĞ+žĦfq¨Ö èM0­ÙkĈĜöíĈĠĤµĵ „„âÁêMßĠN$C§7ŞÇü]ËĜé½ñ|¨ÍF[!dR +‡”á*Yñ HÙi"Ì'¸ÙĠ`,ËôS1h-&ƒsŬâ‡Ó]Ŭ>ËF';[E—BŽG`’C,ìY£ ^ìċœ,EπżW£“ÖlŒż5McP ßÉ Î0f(Ġ0~ĠÁ%üöŒN8£>PĝQšòĊ 75šöFy•Àé0+³vФ0şLŞôáL÷ŸèP8ŞÖJÇ+;ħS²ËÈİÇóU§˜fVÁÇ £0p½ħŠE•^,ċH,€<ˆ0X•]mz{NĠÖ@ä­y}W +ŒĈiŠ4˘K„q°ġĥşäP”ƒŽĊ4x` G˜ÑîqŒ+ÓCNĥ +žĉ%h°g”ŭ1ĉƒÔé4Ĥµ†(ĥeÈŻş9È&°xġĴ'w\òmżßƒŝ`‹MÑLì óŞ~\°·b`á Ĝ1+ù`wNÄi`â½ÏŠwâÑxÚJucxiáĵ·ŻYİħħĥh#£ó*m7]-ŽP GžÑƒĤ(‚KobXŒfŬóŒ'ż½3ûLœĊá’|b‚}hsáB? ËdÔĵ}h[SPúyB—7i4ÊwÀkR†ċ*…œ<ɃÏà=?ùĴĥí\~ù,˙‚„§iӓI˜Ìôµ8eÄ s +€jâĉßk·ĠÖ0DuÏŭ^l”}ĵ¤h K“4‡#G˜ĥ$Ğ™ ç@9ÓBİÛÖ/,Á úşq ²UıU}„CÓVµ×3qÙ4~{÷=‡ìuĦîqÇy˜€ßdıôgYüĊ\‚*@b8yĤÍ6/ e˙Wí3ÊëÑ~äÄqĦİ[9qjÁBMŠùbùûDì'†ĝrҙ ³î’Rq!âÓÛğ$ñžá›Ŝ:³Ż˙Pœİħİ}ƒ[ ÓRVUÀŽ6xA!^›Ĵv<ñâF˙YèmßiŜívJ@ğáÛûۋÑ×Ñ#V mĊóÁYp+&dkƒşÒôlÄÛL)˘²ê4yċ“xßIħ€JCn$gp‘:ĝ ›:-UğX–Ż! ċû#ċaşL™ÈŭAâr%>Eƒ_‘şĜ*kë8.Ü!²Ħ8Š€Žn(u $TvPÉİĦĝ£ÍÇàN6úú aV7`ÍÖáĞĈKqyÂ\ÒĴÑlÈnÌßYóÀÚ}Ä~½ ‰Ù“a Ma€q/Lğ\Âlá_A€ŜôêxµĠşâHI$J|uĈsÉ[""†ħaµW•T"ĊĴİĉ°S²G޳žé*oâuë#¨ïá†*\‚05nÄ˙Şċ…ħĜŜéMÜÔ\_䘷ӄäó+œ;‡ĥWê~m˜q À ‘”JT„D%bĥĠP}šşbĤéŬàÊ"V“XŸĵ&Äżğ"Ú +â Àü’Ì{ü+-`ì”äy6Ħ|é´ċó(“½t –˘aħj÷¨ïùŒ ŭ“^ĠħĞçĜc0Èa=mü1 Ÿ3ú™8ÖİRäħġáûç;Ç+é ÇÚ_Šó esZĜ†'„ +“ê/×TžÇżäż +.Z¸–BÀÍ|B 'ş×EÔ2Ë,óE;`‘ù?Ċ˜ŞLu- §üa8vÏ3OŽ“ÂëDM··—×חOOĜO&Ü[ĴÒà]ßéFñ˙1=BÚ2äú:ĵ½3 ŸžB†> endobj +1573 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.873 616.444 120.596 627.292] +/Subtype /Link +/A << /S /GoTo /D (subsection.1.6) >> +>> endobj +1574 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [442.984 486.93 457.707 497.778] +/Subtype /Link +/A << /S /GoTo /D (subsection.4.8) >> +>> endobj +1575 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [136.52 347.453 145.293 359.408] +/Subtype /Link +/A << /S /GoTo /D (appendix.E) >> +>> endobj +1579 0 obj << +/D [1577 0 R /XYZ 72 720 null] +>> endobj +718 0 obj << +/D [1577 0 R /XYZ 72 473.985 null] +>> endobj +722 0 obj << +/D [1577 0 R /XYZ 72 391.842 null] +>> endobj +726 0 obj << +/D [1577 0 R /XYZ 72 170.678 null] +>> endobj +1576 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1582 0 obj << +/Length 2052 +/Filter /FlateDecode +>> +stream +xÚíÉrĈġ>_Á[ÀŞ!„nĴÔM‘,Ï85#•E;İħ}h‘-5 @£A;ò×çmE¤ĈUÉÍĵġë×oß-ö‹hñí›è ˙ßĵı¸£Ċ:\g:[lžı^ä* +£8_lv‹Ÿ‚O˙şYT”FÁĥ]R*Œ–ĞXJċŒy°'ıZ…Ğô2‰/â—Íw kT¸NSfz[Vĥ6GnžOBŝPŝa—+“Í|*íN„|%ñŒ˜•üX7è9èù@B²ŝ̋ï?ßÜĵ˙ž_‡×wàŠ˘ ù,|˘ü2RĞh}Ħò òTš§Á§ûĞÍ;ż(†G3r)H¤Ŭè}Ñż/&Bñ=D8ɔ0ɘɵôfóÌèÇàĴ÷éì ü "bÈéĥµ0 +\Ü£ÄZy™ş‹µb™ßœÛ‚Ş‹ÀšbÇÁí²ˆƒĤ=^"‹W û"[#a§˙7ÉŞŝJÖWÉŞò0Z‡2YûGcıÙ×'ëäŭ$YÓ˙[²êÙluXdkš„ ‚A”B˙ߔÎkÔZú9RI%°ĝDĉ†n á™`G³aN$ÌwçîtF/$ip “59X³++ q#AñŜ˜³Ò…ŒàĈO‚/Ş!âZ¸ß×U…Ĉ´v:,*­§£ĉvJòÓ*ß<ĜZ’Ñ0/˜> NŸÑÉÚ/ğÄt>—*lìYrÄ>ğ“ *]NĠXE.Xw6ZzÛğ9M74÷{ŸçïšĥüC²ĈT?âµmğr냢^’^×´/AÔşd8ÛĦҘK#ŸTFú˘2À×ßDĞà“K\ôş"RÇ}AÜùȲà˙ò—u˜>_€ˆrpìP@Œ*#ÄF›@¤b "êG@Ġ`=n_ŝ†)jkĴì„?ß EËÉĵ靖£g!ğĤ}ĉ£ĝ óÏ1‡Y1>‘âıo† µ½Ü'ĵ³]C‘Í}Ÿb˜‹xL +&ƒŞ\_lu–@éxı½­{ܨë,“ nşıñL)óÛ2…iRV<ß0SÊzR'Ÿïż%Ÿž]gEXߔ!VRÑl·Ö9FŒT1ŠO+ö­ë$GqžŽ˜=RJw"ĊϜ;˜ O^ ıúú&ŸI*?@|q&*àOšà0L▋˜ ŬÂjvċçĦJô¤ċ'Ñz‰Š(—}”ħ Ç'’­H †'T]pĈI×:y-|àúÑo€½ċÍ Ôŝ­ïúĴ×$§ğƒ÷ù¨M{Än{pٌUhŬÜ9ùqzì•n~7áos͵ÎOènhùżžm½µ˙%pÓ”KÜ Ŭ Vb’ñö™i&0™5|ÓF£4‰²àɚîŒN¸?1ÖT{hŻŬáÈG|>:–U%ô8€ħu`:ŞàxêÏáÊ(\´’ÜԖ/im„Cw€g[èĜ$Ñq¤qmEΝĵ`{/6%ĉ(Ét!ĦTŠ‹ Ğú™ hTÔ­H]ˆTùı ¤WäCj +΢Ñ‘ïĠ LqÔ;öñ2ô„S7%Ĵx‡ÜÒ*ĴĉzD‘lF; Ŭ‹dık—ìĈĵ['Á{AvšÍ=AsĜĉS^ċÈ~ƒJ÷Ŝ45ĝ?šˆ`7âß8X÷?Ësïh¤h›#C.îŻW7w|„ûı[Ï~òQz˜ŞÂôÙMIœ‰J–Rî3_qg€ğ{Mˆ|êD9nFÙKr~B ĵ5gŞEb7" +ɇ€¨İD/7Ö9Ö|Tò‘ö˙“qÎîŜÎŜá˜7‡’r\µ¤™$- )蛽l0ŻĠ£fò²]%ìèW*ĜOÇEíkÑà…ŬW·žBZÏpùÁ€ZkÜLó‰P­'CAôA×µċ™QÊġLqüçof¸÷Uyƒ³Ĥġŭ ÏFàÊJDħŠt *BVêuĜÀèŝKPt„k{n[ÙgPf ŸÎĴ˘4 uĈŸ#ZT°˙>Uċĥì‰! <Íu/?ÖGÑW9~żñäҏ^ĜûI˘½ùĴÀ¸— LĝP +½aò #Ü +•çꍑXÁ¤Sß}G4˙ħĴ%?µŸ]ŠÔ„³˙šŬ\]1‚-pžŽt‚k\Çj0éώÉxŜöD +mĦïO>‘=o™dĵ_ÂqĜ̔Ĵ}€Ĵ›zĊ³É‹rAŝÄiRĝ%B]7Z2ñu-oyÄïġZ‰Ï§âüZ `Ż<À~­o‚ĝĈŻ•Y!kċXà°VÎXÉKfñzÉDÇÎ,š²LCИY4‡O5­³0…²J×Ħ˙šS‘š}³yóĉêġ› +endstream +endobj +1581 0 obj << +/Type /Page +/Contents 1582 0 R +/Resources 1580 0 R +/MediaBox [0 0 612 792] +/Parent 1564 0 R +>> endobj +1583 0 obj << +/D [1581 0 R /XYZ 72 720 null] +>> endobj +730 0 obj << +/D [1581 0 R /XYZ 72 516.548 null] +>> endobj +734 0 obj << +/D [1581 0 R /XYZ 72 472 null] +>> endobj +738 0 obj << +/D [1581 0 R /XYZ 72 377.804 null] +>> endobj +742 0 obj << +/D [1581 0 R /XYZ 72 321.024 null] +>> endobj +746 0 obj << +/D [1581 0 R /XYZ 72 276.753 null] +>> endobj +750 0 obj << +/D [1581 0 R /XYZ 72 196.062 null] +>> endobj +1580 0 obj << +/Font << /F30 1094 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1586 0 obj << +/Length 752 +/Filter /FlateDecode +>> +stream +xÚmU[oÚ0~ïŻˆöäHKb;v.ìİ…ħi‰LŬşî!%ĴBŒâĴûġ;@ÂKN>Ÿó}çĉ€ƒU€ƒ/7Ĝ?ïŞ›dL‹ ŒËŒfAµ räÇ8ÍƒŞ ~#Ó¸ #B8F÷²aÄ8C#İw›:L)ڇŞoÉĝ”…â@Âr<ü…QZr¤ÚÍŜY‰ ŞCš£½v`żĈ`葤ì{ (A½C&*Œha˜0Ñ|p£şI%·Â½Îûzğ‹(£%ŞÖÒ³nA£@^÷ÉÒx™ND&ġ òéB‰qÉıKúĊD‰N‹œ9HÏv½Û9žĥ‘íÊ`Ĝ'‡÷îĦv½T­?S;ú Ġv[·žùğlĊGcrôş– £³v'+ъjÔ^ÖħıX?ĜlܑmçKÈ3TËMŭ´ñ~ĥ1:ĥĊâó2§v$”—ĥ™ÖѕÖ9tmĈ`Œ]§Lf/RCY[*ïe0FżîˆÒ #íı]ġJ9ğ“B2 Íèh:÷*`ïkyàVÇƝ€ĝĈ+µŜ¸ĜˆkµÙ ´i-+Lkm;XĉÇÀ8Ò0½8™'³ad²G.{c֋…ví.0³¨úğZğ—‘Òpž‹ÙŻ Ŭğׅê:Ħ]GUÛhÜÓĴùċbú²‚ Ûkġ4îÊù=LS´0Iup„1\“ ŝ*ûµ³zw À:îcʐÔü žÉ8Ċ'·äáb%uòch`[oE\íĦ"‚aßĉòŸ6ċoSbc·ZÀżġŬKÍçc˘ı”×§ùŸ ³†Ġp˜Ġ8zX3gk[#ύğ$.ÑñpşġfñìH> Y„³„¤(<ˆ‹£.JŜÀ ÏSİÌI §³_oR“wR|€ LHnYKöĵRÀìĥú +<ç§´ì@‹óÇ'´G-z ^x^Ó2ŸmÛ÷k@[0,À€äŒôd·N˙ (Íb<Ç$ĉĴtŠÓ³˜ÏĠÍ?fĦž +endstream +endobj +1585 0 obj << +/Type /Page +/Contents 1586 0 R +/Resources 1584 0 R +/MediaBox [0 0 612 792] +/Parent 1564 0 R +>> endobj +1587 0 obj << +/D [1585 0 R /XYZ 72 720 null] +>> endobj +754 0 obj << +/D [1585 0 R /XYZ 72 720 null] +>> endobj +1584 0 obj << +/Font << /F28 879 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1590 0 obj << +/Length 130 +/Filter /FlateDecode +>> +stream +xÚ3PHW0Ppç2€ÒN!\ún +–z–fFf +!i +ĉF +ĉ†zĈĉ +!) +Ñ!™ĊšşĈĈĈ‰éİ –‰L$3OÓÈB£$Beĉç%ĉäTB”ä¤Ĥ•@%ċ$ĉekĈ†xÁíT022Ó35²P53ĥ@Ĝdh`Œ˘Ì5„ g)n +endstream +endobj +1589 0 obj << +/Type /Page +/Contents 1590 0 R +/Resources 1588 0 R +/MediaBox [0 0 612 792] +/Parent 1592 0 R +>> endobj +1591 0 obj << +/D [1589 0 R /XYZ 72 720 null] +>> endobj +1588 0 obj << +/Font << /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1595 0 obj << +/Length 2026 +/Filter /FlateDecode +>> +stream +xÚµšMs7Çïù{èaŬ™éÑûCB’†M(IéLĦ“,àÁħéڞ–oßG+É^[Ŝ8**Œ½ğBż˙óĤGZZ}ŞhġÓ Ÿ§·GÏ.˜Ş˜ \(¨n?V*Í(Ħ\W·÷ĠğúdtÌÈú›³ë›Ñ1ײYQŻfwËÉ|ĥ?ŭşšÜ8ĞżĝŻošMÛÌîšÑŸ·?Ż˙·ĝy~{ô×ҊU ˙3n+e,ĈĞğ‡£wÒêŻŭ\ı+ĤúğğóĦâ–÷Ü´ş9úuÏZ*ÍccàŬŒX)?˜ÊĞ@9|ĈáJ|(QBz V#ġ„ƒşiQ ÔÉ ˘ xĊˆz6~hFÇ  Ô/g_WK÷+Ż_ğgÇ-^[6-êÔhThıjgͽżċ­j<]5‹N°-$eDħ˙·GEŒ´ß§ħDS™Ğñ^‰•!`™—˜ŽŽ…áş>£@Ĥž£v†ĞŻP[V£ŞFKî5 +eO-“@´°Eè$~rċéX {3Ÿ" ç<şˆ`v0OžżĝŒs‡ŝ2L›=Ġ”VP˘­(B+0ƒ˜`KĜG{½Zúˆtġóàħ*™ÒËaĜì™Ĥ°`ˆáeLˁĤċöM3w4}Ë +ŜeûfE;ï0…ԏZ7{ĥ)0Î֘2ÖJ„Öĝ5Ĥ†êçûZġ9Bî˜X2qötSb*ˆ…2&Ĥ†HÒż ÄŻ&‹ċ6Ĵ¤T$Î|4{š İ´@Ĵ.b[i‘Á—U=›´Í]@íħ¨_>ğFÏ5ÜAӋ‹K˙ë{*éËŝíҜU ùcùsLeù4İ †ÊÌ÷ÚMgcQ4˜Ŝaž_zmLäĈxîg¸›ċxı.àùSL)•%Tñ"”ˆêAžíƒ4’îĜÒċ­Ï.ƒu&uß1kölS`İ £eÌŞpAg7Äô’záĜ‹ž_#Ûjéñ™Ħö@(çÏ/E’0ɋ„²0¸$„:„òOM0]şóô›3œ Ûµiç†è ĝ‡_v‚ АMŠÀ9aց+˘MPÁnvTàġİóŬoKżèx“ŻY;"HIù!ȞzJ¸èe\1X[:z+u;™9G_Ĉ<…ß?ıĤ1ĠwĜ'÷÷m³Xxôxpq~>{ĉ)<ĊĈÏè" ˆ‰À\GÁÂlO);]½§ŒûfNIÔĦ/ï]ìçɐ͐ȀĈÀvŠÈ@)ħ,ĝcA†u"ĜR!ÔĴcĤ ßNŽ·ğ˙ı˙¸šû'üšïPIÏÇI1’pŭ]ށ v³‡2ĝ[p Dc}4Ñ­PˆË˘ŝŠ„`d˞XÊĤ9vEĴ-܍ֆ]kżĦa›vá÷(œWïC×fŻ÷2ĥLĝ™X/ ùœİTŠĦŠäĦ$ĦX¨ĵT|QĴ³ÉâKˆ‹o‹eóàöj ÄE ˆ~$?ú_˘\'zd¤z‹  É ĊçBX„ġ<_‰§eO'%âšHlAJXX0ÂD´°iĤëvĈ›Xr‹˙ùĈŜ݇kĤ6ÖÁÚĵgí‹Étx/*Ÿ)•$ö!ĴˆĦÁf3ô0Ù3Ia'J”ħ1Óx´ħ 6ŝêM7ëçXk÷­pĉ]Ŭòß-µÒ(Œï{çí·X)ğ1ïQ&+UĈdYe¨$¸X ʨ Ì‹é|Ñlİb%ë/‰( I6O" 7–h^ÄY0Î Çä%Ñë„0nû{Wçm ƒĥÛâ ŝ?…òñR…°èkSÄi\ŽpŸ^!sHĦĞĉŸN ރ@\¨‘ëĤĥt*\ùİNXñ 9­àÊt‹ “ :aiYnG—°êÉsŜĥóöÉzd¤z`Ċ/Ókq݉Ám íµnšżVa!=Oñ7Ĥġ€,Ğè(‹Ğşn˜gżğUh;‰ê>AŸ\¸T\>XVĈ]„$¸>úÄ& ™ÄšI$"M:ÑábEêEêĥ5uÊĤL…G\D'ΉяbûòËĝ‹£möó§&ċ./ı´”—srÁRi˜Á~ĴŒ#2ÂĤ_ñÇÌe„˙WÊɆIġ Š’ƒZ˘â‰*ˆŬN÷ĠüÓdĉ™ßş¨èŠ *Äîup—ŻžŻïŒíqwç ı‰`öYENkÀj˘ÖçĴ2ÙÛYµm³ÙëĦŬİċÎAäŞídĉ2oż5R!Ÿ!•ÁaeN`ÁH˘ ,¨ġ˘%’ürúÖZ¸ÙsEòCğœùOÙ5ĊĴŒ hNt<Œ½ë'Óİëğ°µ&íÎ3ĥ#Á]Û}ìɁ‘Ï”Ê" 6¨e\B1bâ‰-˜ŭ÷u;_îl0 6ŬádΞpÊ,vie\AXbbĜ]OxÏ2úé3Ĉvœ`ß}ƒüٓOùı œ•ħ9×ÄĈ£ZNwÓ€ŻŽ~˙Êıe;ù°Z6Ŭ+X%֕lw†ŸU)óİRaŞÈ1€$ñĴ“''gŻO½ÁwÛ7ÀVyO†HÖën€A!²)R!C"§À8ħk%`!ÏÖjüĥhÚŜêY;+cPŸovÊÜf7>ÎĊµrç⛯V(ƒóħŬĈóù‰˜5Ĝ~ycPÏĊ#TĜô_µ›3ò›¨Cwrx̟ç^T"ç­Ċ­×[·˜q, Ĉ½ä ĊÖވ/ĉH|8 +endstream +endobj +1594 0 obj << +/Type /Page +/Contents 1595 0 R +/Resources 1593 0 R +/MediaBox [0 0 612 792] +/Parent 1592 0 R +>> endobj +1596 0 obj << +/D [1594 0 R /XYZ 72 720 null] +>> endobj +758 0 obj << +/D [1594 0 R /XYZ 72 720 null] +>> endobj +1593 0 obj << +/Font << /F16 823 0 R /F28 879 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1599 0 obj << +/Length 1747 +/Filter /FlateDecode +>> +stream +xÚ­YÛnÛF}÷W}(( Zïî쵀lËŞÄI-Ëƒb1P]\JJ›~}gÉĦ"‹”äµĝÉÜċfΙ˙ñäk“_ÏĝžÏżÏ~òD$Ŝ1§|b…gŽ‹ä~vöáOĈ¸ö2á ĵKŝ)vÎ%Ŝ›&³ßÎà–eğóZÓ—wgçéÏĵ‘&ıû’˜“íL$wäCúz=ë€L?wşĝo–wşBrž:Ŝ¤ëùŭj²˜ŠSé|4Ë:]éıK›?ĴWá)¤oğ£×VYėµçéğlµÎçÙ¸ÜòG8j4Ċµt-;Ÿî^ž]ßmÔ˜âIRʞD´ñšIħD7ñl‘֗<tş +À";£À @ún4/fĝXH™öŻ{qž-—aQ‹/ċĤAGşôê2ĝĊòô˘^?˙³ƒÉ'ĞĴÜ{µ@ÏĜtœíg7V ´ÂŒ3ÌKEÌ(bfUEx!vèmz,Ñcü=°9JzÜaz˘ħĠéħ‚“­c>ĞG=W‹ĉaLĤôm8ù/$&À>’Ôv $]çù"zèDĞs£=S²1À¸¨BÇ7lġ8§ŠïY(:÷‹| +“'çç7èˆĈR§Ca²í„ŠŒë*TìĤĈ,+Bn×ÓU‰ĥŸwD:ù&Œu<r;ZŝĠéjŻôQàÑVׁƒfZ´à™à$bàĝëÁžÌĤÙ,›ÏPŠö£Š6ݎJÓĤwJ˄r„ÊŞ_+g~ÄÈ˙7#ùO‚ç‚gż”ÙŭjQÈ·2H]ì¤ÖéMȁW=tŭ`BŻb(ĞAħT–Żî§(_"\6Ü´B‘LxrĵâÍڑeàE‰‘óìM§ÔáP-ĜS(ĉpHl¨I4ÚaÚ{†ıŬ +a°Ŭ£˜R˘ĞPos…Q™+ñFĠq9ìò|+ =ĥħ +½ĞY%rÎ6. İIŻ{ƒÁMé͏\sL/üx€4òXŒPçÀjfĠI£™÷ +ò $ùa]ßTĦ^À*1˘ÜcúŸc҇Z€ßK¸aíÚhSëhQ°­;ÉÒ`x’e€D`ıĜ;ĴÀöß K|Ežm] J°Ñ@­™B-Şò&€WoÏo ŸQÇm\*­³ş•”UÀ”!*ólю7ݎ +•Ö·˘ÙӜĵĤìf÷o/JÇáµO¤Ô}J%Ċ•6éÍĞŜĠ:Ï ú΋UÏşŸŽX,u6PT½iÇÇÂ3­+ğo†ċ—Ÿ·{—|Y „ú-½ÍöUĜ÷ŭĦ(äÙ/x*6Ĵ¨áO½÷C$6lÜOP4ĵ:C·S³ıeÚSĵ}„?lì^3_y‰÷Ŭ†ŭÊkfP +û_ġ.ŻúÛ­$y2<£%ĵl|.n˜Ù3Ŝ¸:>ÇY+Ŭ’rÀ +BëíĤ[Š­Rħ6ĠAĦşû˜iV ŞÒL—xÁE4Ö£wċ'6ÌeBzOr0,ĉÓïô(¸ó[s4™Ž>Wˆ uÏ£òÏûiÙnŬ‚èš1Îéâıӑ­7g9“ùr5šN³1+xŬ­>âYHɊ“(P¨á™lúÔos~ÎNšŻJWÌUħdRÍòŠEó·3WÑ£ŻË"X€ÍCc6˜†ŭP£Íl€jSĵ׃µ…JTAP‡u¨Ŝż:”şĜyÈħ•:ä×hC›ÁJî"ŠH“Ĵò(²vŻ .w„MpˆVĥùÖr[ìPÑ0PŞf“ù×rӌÊišzĤĤĉ şQzĈŬa’4zÜŞĈRK‡<¨ÓD $ö"hgUSߤIntóO†{äL3öĜšùħ O$GíNJ]˘˜;&Œ­2W6)U…VyĊ5Ò7M2·~ҐŜş’öâħÀêÜHzŽÓnN0+<š*ŠÀa ;Eéĥ éċ‰‚ĤëF,ŜŞdĜÛۂ×j¨Mċuh¨×Ş*GĊüŽ> endobj +1600 0 obj << +/D [1598 0 R /XYZ 72 720 null] +>> endobj +1597 0 obj << +/Font << /F28 879 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1603 0 obj << +/Length 1063 +/Filter /FlateDecode +>> +stream +xÚ­XËrÛ6Ŭë+Ĝ5Ó@x?:“EYU2“şµ4ÓE’…bÒN%²ċ$ŝû\)–˜\"ĦË{Î}8ıKpòûğñb=™-ˆLAFšĴoEE0ÂL%ë,ù˜AdúŠ*ÒĠn·İ§Ż˜iukNjùĠÊÎóŭC]ÚùÛ +F’fùŭôóú}÷9?^'˙MLqBàہ Ò0D°Inv“Ÿq’Áğ÷ FÌèä[ğr—0MÔ0Ŭ&ĞÉ_Ϙ¸qÎvP‰żN 2’Ê=Ħ€.5G‚KÁĵ¨ó›}ĠBgĴGuî7x (NßĵĈxùĞ}‹I7£vĈS̖öQqkÇ?*ûⲞ’´ê–#V¸‘Hó@ +Y‘f#”¤4˜Q ­(^/GJƒä,”(?BB!Ìù‹Lx˜^p°6£HŒk$•#ô².”— FXy=' –ĉ›é˙Š(Úé7ƒèd|!1‰%'…”ŸWQ´#!–f”¤¤&ĵĜ Jù(J"iGèşĜċ³ùfŸ;15úhœ ¨R­ ÈÒ²ê<ûÑN¸…QˆŽ”’0F–½LIñŽ„X´@Œ°!JbÂ{ĦbBĦ$Ħ$2Ü1zo²ÙßSÍÒşèôt˜œ(—jprŠ÷>$@Ä1CRBrdŒW”‹ÖRÑ ˜-(;ĝ|W(ĈÛġżĜGĵ2Du·à²ÌĴıÊ tÜÛü47ÑÀBn¸AœëQ¸ ÚB'Ž^!-T!…ÉOÓò¤½Z4–ĥÛÓĴDC +Ya +q3Žb8AXġ’ĦN2óâŝżËšŸíMˆ +$Ĝ8Û #ïùŜġíĥşÏ}ÛÚu+Eé"dSfĠÎÎoŞ:ë#gv$–ç)ˆö?¤T%4…˘Àbż§ü0 Xv˙ŭ ˜§ġC]”wŽŒŽsšŽh,!KTBˆ’^˘“ĝAàè<††ŸF4€ ´Ú£HâQÑKC.CìmċÎx_Š;ğ$ëè.ñ€BNdi˘†ô.CLx/¤@JÒ1z. bPlİŭÏË,wĴäĞ›£†~0ÉûŜÑcżïÛΜ67YòÛÍŬ靉ruVc5 +'pâePYZNşTí/j,,@i‘ñôƒïî>Ċ8]ö/g,}7ğzryÑŝú„Ĝ8ÂWm^€Gä4QÑ(C˘ ôjAF k8"sĉijìĞxŸñŻÊí'aEûŸ´‘£À‚Ó2×Ĵƒċkù“ŝÏşÚŽy­/Îġ¤ñŜ…Ħĵ>΁í÷ÍWêweSżN…H7ÛÂİr^_›ÇyŻĜUàç…íí³€§w›G´GÀnCòo1,XÁYĈL +endstream +endobj +1602 0 obj << +/Type /Page +/Contents 1603 0 R +/Resources 1601 0 R +/MediaBox [0 0 612 792] +/Parent 1592 0 R +>> endobj +1604 0 obj << +/D [1602 0 R /XYZ 72 720 null] +>> endobj +762 0 obj << +/D [1602 0 R /XYZ 72 720 null] +>> endobj +1601 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F23 825 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1607 0 obj << +/Length 1439 +/Filter /FlateDecode +>> +stream +xÚ­™MsG†ïüŠÍm9h2=ߓ*$@Ž 2à(UŽVe ,véß§gwVhÀ€&Ŝì×OżŬ=Ŭ MšüŜ ŝórÔĝġ +T‚pĦX2şO4K4PBıNFÓäSzÙ<`2½ìö‡Í3ezĠ´"Ŭ,&ùlıX—§>lf“&‡ôky8Èî³Uĥ˜dÍÏ£wÎ¨ño÷hnye,aÀ“ÉSÓgšLñüğ„nMò½¸ë)TK%~Ÿ'Ĉ‡çµ&Tšcϝ@Ĵ”ŝñ“™ÄИ*(5ħÚ )”(!KÒŜĉİÉYúX𭐛QêhUE‹WŒHMHÇx5}Êü=ŬĊ?›Ü]äé­[bĵ?eyĥrŜËùfµÈĤċóşÇóMĥŜwŞgÜq‘"FÚ˙ïb%ˆĈ‹‘.ŝ‘‡•!ÌBéaÚ<†ëô²ß5ϤÒ&í-èEk¤˙zĜ#Ñ&…D’-lDRÎUIžèDJÒ¤h›B$A‰ĥ˘$ùoĵHÌ#µú½ĦS ¸ztq~uuÌEÚ½wŸ{<}>‚mgˆÉ 1ü§”Üjq)Έ`^ş‹sJŻK€D fŝ6˘h“B"Àì4µÇ(Ú Ç·Âu{(§<…ġz9ÏJÄÖ#Vİ İ#˜Ñv†˜Â°ZRŽ"Á—iħĊìt9J¤­CpgL +v*£ 8eherJЈôá)=ĉM×e!ĉEțÙ:ß#Ĵ*: M  +ĤB#ˆ˘^Iċo?öZ˜‰’ -nĥMfÒÇ=PšŸĥ4U–PĊëĠŒ(Ïİ=ç sÑî €Ğ’j13]½)ߖ˜ñf†”R µÈݰ²ÓxÌëŝûŞ)ı}ûVoRH$$Y‹nÂàž\Y4ìÜ´‡àö íĠì› ÌoĜ6âĥîœño*)%h~ß%^ߜ·gëŻċ ·î×'–‹\ż +€‹éô˜öѨĦ§8'`J{š¸”"Úx_uÎğ‹™ŻMlžMòìj>~Ào¸§ÔïıÛĉĦğpžĝ֔{âÙ´<ıuña?Dƒ„~`@˜¨%b˜ w²t-./bf4¸˜ÊĤ—­óQ‡ÌkGċC ]Ž.GŞbĞÂùâx´ċ!8ĊéËè:ÀSċ +À|Ĝiıdځ1–ĞWÄaŞ`É?Q˘í p…ĠĜ­³:p1Ħ-T:³-nûŭ…Û„qîEÜâ Êâlí&@ur{Ž72d4’p]‡¤Â> endobj +1608 0 obj << +/D [1606 0 R /XYZ 72 720 null] +>> endobj +766 0 obj << +/D [1606 0 R /XYZ 72 720 null] +>> endobj +1605 0 obj << +/Font << /F16 823 0 R /F28 879 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1611 0 obj << +/Length 1549 +/Filter /FlateDecode +>> +stream +xÚ­WKsÛF ûWVލ7ûâë˜ĜI&zêŽuŠ›-ÒÇ|¨$•Ä˙>À+JŠìZ3:-ˆĊbeÈàәäġŭüìíGÊ +ccÌïƒD‰’Bš$˜Ámx1;WJGáe>–jvnTX.`I˘0o ">VuIÔ͘7+fÎ2v}“ìëüÏ·Ó YĴcĵEç:Ifé’ùÎ[Âu[}›é4,û!݉5JĞ$]ˆĵħjĝÀ=ßàö×CÉw¨ä‰è/7—ß™÷%IŜċÑu•/£ğž÷Ŝ_\’|Q=T fçq’„ŸGÚŭŽ˘ù@Eı¨ +8˘wJ‰,ŠÉğq™ “Z Ê‘J NÀMŝ—%I”ùP•‹“s$41ż¤’8ùjUW‹|Ĵşv ­Uß=ôy3°ÎޏÎÌäŻj\2‹9~^bc DPiV ùnĤÂşœîx‘wM‡ĉêL…}‰1CŠâƒÔ˘+@;a‹Z#)Ŝ¸í=dšOû]úhgĴÎäħŬ;XÙş]02îtϲ£ĊF@ÎÛíéğ׿_$÷ċb<ä4V纓û 17fJGŝ@b +;òĵ]b£6™ÎHíM׸BÒáżRٚiCĠ>×t…‹$]ċó‡.ß^!ċÜaéÑUÛ Għ‹ŽÖĥŭ…]Ïjòşĉ³KĉT-YPaá ŝUïĵS!ëhÀoŻÎŒ§dÚ.ĴE5<ş”‰ÂÏ-o9;€XäSŬ=­ì2Pì2ŠoğL,Ê*Ĵċìë™_ñ‘–/‡jÂߪ\%·tPHĥmú+ĤËğĊ˘°Qhéj|JdÄmxEYАzù‚wûn=VmÉç]fÔDŒñ†sÚµ-)ëbĜh¤‹ŭm£éŠÚQ’Ër_üS9êjĠo%5}9!ëħż!uÜ{h)µ¨*ˆıèĜ|Zĝ¸‹Ş1“ĜşĊ–I=ż'/ñ‹ ßÑ{½‰xĈTËĤ§ô`A^–œ:má˘mmDĴœ +Y˘qċÈBuÇ ,kè'›˜IO}§ŭŝöá™Ğħ@ĝÎÜ?yŽ à˜²gġ}×Lç^Q‘oÌX{PÌıEr£ıl˜(êz+î•n ]ˆIaŭD[ËŞ(\|Pµ3ı{ÏJüƒl§Û%NÄوËhğ.pcèıVwH19ݜöMżžž 'ss ĦŸl#ÁúPŽœž=1šĵ­VëŜƒ½tĊ¸Ħ†•Wċl3zùuŝR2 +j ú‰ˆ}ÎІĴM—›LäŬ ĉ²§ÑaŸ8Ëqf4y<˜e\ËG#>ÌÏŝ;Spż N|6‹„ɢ`ќŬ~•A|@XiŬI5‰#ĦÒè:¸9ûgï|j„ĥêó IaĦnòܞ“DdI +šb‘jž=矯>üIi):¸œ5E€f2bùfñä².çw‚× ĊÚW™O†aŬPl­§M˜¤ÛÁĥa–q˙*k˙~kI[Ĵà0˘Ö$ĞaÙE5QB§ñ)PMĴHA„ŞbTî½KrïV Ħô×\:ÚĤ]—˘Ls +b-2µ'š=*|#ôŝġ’?Ç´ëŽMÔÖ)ü‰$²ĥü1ìϲ[szŜJ!´yə£ÍÙġĈDÂêS8c2!ċvpĴO7oÖ[˘KQö’KÇÚ´ë‘6ÂĈ'‰NÔú–Kğ4”0żŻuçhƒ~ñGÇñ1}Zŝ˙/żŠ"‘H˜ x ˙’ü§ß}Tôüó£ñùQŻz~à‡AÄы¨hHíÈÚϏ‰cNf[!Ӕ‡żĞwîġI Ês듖ÏéAFï_§ˆh’íi–^r|up:D8bTĉ>Ŝ·]hl +jNñ†˜H eôMÄĝŸ›c I6˜Cĵ—£ÛĊĊÄPİ'I+…J’ ċ'–+ŝĞû§_1Ï cwÇ£c7è˜×Ħs´{ż c^>_;ŭe&A tĝñܝAì˙ VÜüG +endstream +endobj +1610 0 obj << +/Type /Page +/Contents 1611 0 R +/Resources 1609 0 R +/MediaBox [0 0 612 792] +/Parent 1592 0 R +>> endobj +1612 0 obj << +/D [1610 0 R /XYZ 72 720 null] +>> endobj +770 0 obj << +/D [1610 0 R /XYZ 72 720 null] +>> endobj +1609 0 obj << +/Font << /F16 823 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1615 0 obj << +/Length 1416 +/Filter /FlateDecode +>> +stream +xÚuWKsÛ6çWÔB3M‚ӓq’Î$ÑĜJ§ÓĤ˜„,LHB(Ûú÷ŬĊ.eÉUOZî.ö½ $zŒ’èğ„ŻVï.nÓ"Jó8Ë ­ÖQ)£2Mâ$+£Uŭ%nfó4• ñçŭÍ×ûÙ<+â³î­Û}Ùu¨T4j4v ĉOôóÍĞG=û{ġÛĊmĠq]È=$Ñ\VqYçä`µÑ³ı,+1X×ĞéZôìù½Úsmq8$'™iġ0“•M3Ù-İ\//>%cI"5´léî`)_Hè÷~Ô½gó\â~Tn4#)İ‘ —R¨C"jğí ­„'і\òzòğCÚQO'Ÿ1ëZú‚SĦR ‘u(ÏsÑŞQQÛdŻh 30äĦ>`äĦ{e†ŽMLóR&µ/şŽÏe4íz–‰–ükOŸƒĊ +fıa'ÉncÖ{+úÁı~ Ӈĵ +À1EàR‡€À>—ÜçcàzŒŽ¸Çğ×Xи–5Ċz?éĉġħ.úË+ħZíH8%\ÚàµCB¨ÈçS +³ +vöÄĜĉĜÙ 2’Ôé^™ÁOŞÚëyÖXێç™VĴ(’„Ä•cÓĵĦ´ĦÒÀƒÍ8Ó"Ş_Yp­pmËL\w}DÀnSŒxSĵñ“öi…€Cµ(KJ‹éëë%IqNŸ7fTdm`Û;ͧw>”(CVµ[Ğf²hIô&V˘ak˘{6ÁÓ­•ĠâÍRɊƒG‘Û ”Ç’–ġ‚œ˘èЍ7É JÎ'ÄFŬr-÷FÏ Lіö`hOBš2³–UŬ„ıĤ@Hg‰šy]Q¤H\}ÂHóşĉHÁ[ˆùĦòĝAP¸!Ò"ĤbNá–S¸Qw +éġnhB)êêĴĤğzĞ8 Œ|äŒÊrm˙SŞşÎî >¸B­A—p]œ%Îıĝħİ`ȝá;hÒÁP‘ADo=÷ĉq0¸ñ:ĥŞÚ§Ù~††,(Ž:<ÎäÙĞ–Ì T–CĈ²…%G: İF÷D3 ĉ˘7̈́ĥß;ċ>adŽ`j¸+… –KSd„ġ~χ:¸áÚ=éö(žŜJP´6ܝĜġJÌÇ,˜ulwš™_şŝȤb¸Dŭb°äHšt}ŸİçĈò\ŠoCg~ÍŸÉ @dñĈ7rúTˆüd ÄÀ<` Ĵ(˙ƒrÂ@Yġ„Ó˙쌛,Rğ€˜îŒÉ²Œ×fûì]úŝEġ[€D34ŬĠżÒpŬŬ˙ñ3 ^ĝ˜{÷Çè +ŬdÁˆa-zĊ–âĈú òUĤ½^Ŝelu‚'¤OÒF˘Ìž*…Ü[Tı^òŭœ÷_~?‹`Ÿ.p³´°™Á G‹xoĤĠÑ£5^sÄ/ĊÜ5jxnöÓú„†I~SĤuxL Ĥ‡'áž8SR|ĊŒ‰p! CêFƒ‹üĦ*‚F+ŠgKPe½-˙‹")‹x!Іĥ„-””pšÔ'jïWïŝSú‘ù +endstream +endobj +1614 0 obj << +/Type /Page +/Contents 1615 0 R +/Resources 1613 0 R +/MediaBox [0 0 612 792] +/Parent 1617 0 R +>> endobj +1616 0 obj << +/D [1614 0 R /XYZ 72 720 null] +>> endobj +774 0 obj << +/D [1614 0 R /XYZ 72 720 null] +>> endobj +1613 0 obj << +/Font << /F16 823 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1620 0 obj << +/Length 1814 +/Filter /FlateDecode +>> +stream +xÚµXKSFïŻ-r…¤ÑŜœ›…-(ìÔnHrրU‘%—$’ÚŸ~, HmĊ—yġô{nÙÜœÁ§ŽŒG‹'ÁĞ„^8XÜ "oıŽí¨h°HX×óożT‘ïLĴ¸Ô<ɋrgÙݲb8òĈÖ2uÂ;éz­“ֆä–(4PÂÈ{ÇÇWBó¸Öë˘|Ž•eGaäZ‡Y'cġjèZ ܵJĤ-65ì¤EgĵQááSUëµĴġŭZç(ni˙×â3X=r]{lßÎÔ3[p'fŬIó‡ĦĦ¸tv9çêŻ”ßèï£ŝXgı°È²}žĠ+Í´•¨Š›ryÄı³Ù°Ïâ²âŞXëz•ĉ÷˘iú7Ş$üà úˆĉ55Á‰rZáġBÛ ĵÁÈ ìÀġĜ';Ž/°öFŻŝöÈ{ʵĠĜëş߅˜H@pe,¤9ĞÄhÔÇéü~^G‚*ÇyKSı\ĝoÒ´›ùQÔDv ü—âFÎÌqŜka“"‡^OÛÀW%şáOKT.XÙ ŻÀüŬıĜUa#yĦšëEçU +Ĉ’ÊâŒ!÷<×yŭ&ıñ°Ôq'r/éŜ–ß>íġ€ßŭŻxÀ÷ÀŒ£¸Òb^|8½ŭ”çŬrğ`Ô‡koâ[‰Ŝ¤KÂF\!òáH°FÇiŒžG´s<ĞÈV½  Y’”ş"ŒÖUûÚŬeqv…0KFâ*ΓgRâ°"?aWÜ=cWĠqY·Ï|kq…ĊċP˜”Bĝ§úß[ġÄRDyç*P‚n€órB‚nÚÑñiZ x¤XĈÙr›I½ƒR"}0Ĝ;uÁ#f›/-VrV˙háˆVâÙ ŠŸƒ ìp0ääŻPx|ŸĞ ıĵUŻ ĠR*ޏJ/.P/\ T§Ô™ŞQUĤâ£hİ~Xj#SÒ4Sƒ+ŜÊ k dcÈĜžxAShħâĴ +wÖûQd­Ñ™ÛŞĉ#qĤeµ.9ñBŝ$y“Ħµáވï!RÖYÍla—:Û4Ñ"µ^ [†oœ%ôè6ü:ó$̈́dMôäıq%‹;ċiB!7ĴÛQ–·kşMB4kaßÁÒn{;”ßŭŠ@t>Ġ _j°WHġ÷x½Éäq•.‘ߊ—ÛÊàjž_‘)Ħ”•ĤÀ’{Yó;$îÉçZc19ùÁ*—ĈˆµÎ—²"û•è +kè·ŜĠß;ÏZû³‹éÍü#÷çSiĜNÏ÷1/áç +˜ÑöŻLöIKĊ9³G2g·E!§&;ÑLßµÇêÚÚH›ÎöéÉáİ42"Ċ4Í0…Ĉ ß,NSùF¨Wfv—">ûœzx1•>J{4†VNDgÚ\^Ĉ%ˆèıț”ñuŸÛîƒî‘ɳvŠ3€Ğ.€Ÿ]ŭ˜½kñı…Ħ§9ÁŒĜġ…DQWFíTuı]ÖÛRîÖ+*e0Û53°h Ü ךٚ> çüiĊçô‰Ğ\•ʃW·ġŠ` Ù˚?UÓ#16_=^ÍÒuÊVCĊHKÈ–ì1h·0µe*Íß ­³ƒK›‰Ĝs-j^u3á³0O+ÂçwŸĴ :£&Vm›%¤†4JĜô‰Êd4ŽFĝ1ˆ(²Ŝ<ĊGt|yñß>r Ġq˘KĴb._OŻwÇÙħ͍†âê7fÀ;ü%“óaܝÏ-˘Ĵ¸O—ĝ•Œ‹Ä4ĴĝoĠ’ż°eö”5‹ÛÒş×ôCŠ…ç˜STqÑ4ȤNU÷9„ĤŻRFréĤıž(k+˙/1Oá€e’B@TJӓREZ‘èŠ#2RĴ²;•hàÁc ìñx̸ÓĦš->ü }ì +endstream +endobj +1619 0 obj << +/Type /Page +/Contents 1620 0 R +/Resources 1618 0 R +/MediaBox [0 0 612 792] +/Parent 1617 0 R +>> endobj +1621 0 obj << +/D [1619 0 R /XYZ 72 720 null] +>> endobj +1618 0 obj << +/Font << /F8 826 0 R /F30 1094 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1624 0 obj << +/Length 1173 +/Filter /FlateDecode +>> +stream +xڍVKs6 çW¸§•§ħ"‰zy{ržŜt’İuh·Û#ÑħĤzD%ŭġH‘<žĥ>˜ ž”³x]8‹‡ ‡×ëäâê>^Ĵíu腋dżˆĵEä:ĥ#˘E’-ŝ´vy•ŞċJ8k+/›B•ŞZzħÎëŠĝġžÖ/O×$w,Ûá[uƒr² Ĵ2"şc§UıÊT³\6UeĴöÎ]ßJëŞë MÂú H™ıµ\ıVIûRÂÈêeÁÖôAòT–jùWòœ\ı½rç=אÂ:˘½şoq‡ËĤת³}Í™†óL}w\żÊћŽÎšĥFoyĤ2☀€Tµ`_mDsuïMcĜb{í­ Ûġfw÷³oáZ,Ĵ.uÓ·-ÄFx–&ŝM]–GĜ<†œŞë ĉĦî%Ċ²6ˊĥ£7\î;× úPÉÁ¤2Ö zuÄàŽ¸žġ~P-³nnž‰ètŬ*>§3%G0ÉÄĝÀ‰›k!TH§˘‹äcD0íċ*=ʌ[X8S0Â*  !E/6iMyĊäšA9+”Xlħ7ÔH8çJĉ…J4Ż^g5!Ĵ —Ĉ€@úÏ áÀÄ×H·û˙Y—]I€3Úı!‰ç\a&Ž|fœ£@ùĞèU0/ŞŻ}ÙC×´^ß>íŝ³Àa_„[ET`n#Gf$ĵ£M@Ke"#j¸EŒZíĝìĵ1aQ-4bÉ&hÙ÷UŠ=ħŽ×ÚÖX1ï&ü”„’ê‡.ö`=HRY}Ò¤ UĊ‘(ìVÄáì¤}:̈́1‚‹-Ŭ< Ċù3AInu>V=œeyĞRĤ’&?0fŭ‡ĠúÖŻğk$·ÀÉҐсÔ):8 +Y˘0ñ’ #ߚ#eĤŞ4d’laĈ!_Ù<á >$K(¨VV]ŝÑïÀ†YġÚʒ6›VIljӄ9“€RšƒóŒ´´Î˜U­‰àĤ˘ ?b‡Q:éK˘'Ïu·3Î`"ĥ*ЉĠßvżb²e› bgmŞŞÍôJ3şnAŽĤŝ†äoTÖQ9PY@Ŭ˘Žƒ2ËßÄ_¤.˙Ħˆe\ƒÀ01z[5y!_ +f'ÏKèŭ mşCŬÙ8¨N4Pħ ÛÔì¤-Nˆ$‹úeˆ€N&3ÎꙀzĈ¸|Ĥ2or™Wêä9–eŬOğjÁYυUÒWCŬ1fNœĈ×(ÌSŝ>Îĝ”ş'csûV–jÖĈŞ„ŬÂ+3äìNħ<äğ™Ìy Ĵò3ú9~ ëĠ½pĉƒ×‹íxíRî’Ŭ—oŸĦ_ĵÀzĵĊo¤Àħĥ—ߝÀ_¸Âeö/$ö 4cĈpƒÂĠôñ”‘> endobj +1625 0 obj << +/D [1623 0 R /XYZ 72 720 null] +>> endobj +1622 0 obj << +/Font << /F8 826 0 R /F28 879 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1628 0 obj << +/Length 2096 +/Filter /FlateDecode +>> +stream +xÚkoä4ûŭŠ_ÈJmÛI6á şĞPÄq¨]tB܍ۍ.›”${½"~<órm +Hô!Çñĵ=N´ş[EĞï^E2Ù:ğPéJĊĦ‰S½ÚŜ6zµQQ™Íj[Ĵ~ ŜO•ÒIpQVn}j6IzmT÷mysì]·ŝ}ûóPaž$Ä#Zš(ÜdžE¨„ɇ½í™‰m…ÛÇHĊž³¸~Ël³UĉİN…İNB“f*òİ ˜ŭŝ½H€Nċ^ÇùĞ]kĞòOW0âàlŬ1Is˨ûĥYë,ĝ\e}ÇKe}Û´ۗM-|oÖ§z4ǞçĴ€0êFö{9ĵıê,€“ûe‡?v½;ˆ€µHğAmԔÉš‚Pw­=à <ìËʸç鄿LÍ£ÈO“4 +~İ ×òÂùÏgïÒĦ>(S°İzd\ÌÖ¨á”ì 0µ˜ċAR× +Áħs…°dîÊÙâôŭpjğ ċġŻ×de“8éc—·²€C>ˆ„¨²c\çzF  pœ‹ëG6°bèúiw_Yò$Äĵ盅ıΙïkTFM"_Y‚Sì0ŞôË ÀIlkWx[ŜÛ_ó 䚢Lhŭ ­F€ôÀ°wíÁí… l‹aBÉ +Ëë,θ£ëm½s”fÚ§™šdç’GÍLĴX3ë1ĵİwcï] àúĞf5'f=q™ÖdGÙcPĈil÷eÇË<ĵw–B1ÎQ^@x&ëÈb×°İÚĤŞĝÂÑ>x—Ĉ’İLWâ‹+kKÑĝ›²g¤Ğ#„ÙĦ +ĤxË0d™òŜĥ}ı;Vĥe4‹üuÇĞÈ ÓŠ×–2)›—j<.&ĝÁnĵĝ1J˘F¸_½w,TÀг@]€Éçƒ)Y,‹m&Ë'éžQĈÎ}¨wM×3êşĵĞKTMÏè7eħG)`Ŝ]ż9aˆ +ìȍÛ2CH(şfmkw½kçìHNF]p)—èû!JÔ`¨ƒk×Ô²ˆĉ3Š™p}Nŭ§k›)9Yuħ^\ ³( 7yàĜ}Ċ9>ż#Éo à´`R–ÀI?òêçuŬJuÄŽs4Ž–İ‡â(Œ°‚Á‹ËßFqĥÛĞü +9žó†I/ƒ„{Û1ž;,çjžòĠŽb6ŒÀp[0y·§{öĦö…—Mġúúü’Üpyˆ½û"8läoëûñìÂD“>tcB­hF³0˵Tg8ÎP 4ħßğ/pšŠ"=ò܂¤§K?D­wœÎ‰/€] +Ísœ +óHİh‰ó'Î'Äĝ·Dü£'>Ÿ?Ÿf&L³ä‰0Ôv'@ûĠ“‚Êo=Ÿd&Ħ:c“Ž×íPÓ/ˆıš$‰ñ7úßÄWžXO‰£Ñ´Ú„ıRLìtnP$³R˙ĊZÛÇ{o­>t‰?963kÉÉé&Ìó';ŝZҖk%JCµòĥ„J)¨’CXX BvTˆž= ÄÈ7ŝKL´/wŞċÇDR]=ܛ‘~V#ı;#¨mÊÄR' +yé§n3ż“²ÈÌsŬŽ´$5ËÓ +8Ğċr sÜ<9N8P)D Ŭ­^0Ħê²`ây­fú†ž‰ĝĉQ%XFS_Fq^àµe¸o—²ë.³>j¸  ’Ò³hè\p“ŒĊÑñ&ßïKמ· şGY ŝV²<1béûÌl¸Ŭ~˘GʒúG§A‹Ñ­T|÷ :ç; K{y·§Ëž§7}HO}?nOĤ€éÁVü„Ĵ£½yÇÓ;fÜÍ\çĊ£gd´*~zaWT3Şrĥ“­ŬBoáċ^0EÜ*“јÁè&É^hĠĤĉ֊'ì áĝ/ï7-]³žUltÍ]´žżĠ´oŞ)Iĝ"%OŸ³é´ĵ"´šÈİŭ³É8? ³†GìĤİ ˜—˘Ş‘²Ħ‚²½û{Ĵâì'o”L’3•ÍÁÉRSï|ÎŜÙRşVËCĠ À¤'Lŭ,ö0O µ ŜËË9ô“Ħ8÷e‚Í1•İuü-Gŝ{‘yѳ_ X:—“şüèü[FĈQ–ħvÍ/”pÖoŻ´NDCs‘Ċá&‘K)=£zğ}ġ7ËÒŜ +endstream +endobj +1627 0 obj << +/Type /Page +/Contents 1628 0 R +/Resources 1626 0 R +/MediaBox [0 0 612 792] +/Parent 1617 0 R +>> endobj +1629 0 obj << +/D [1627 0 R /XYZ 72 720 null] +>> endobj +778 0 obj << +/D [1627 0 R /XYZ 72 720 null] +>> endobj +782 0 obj << +/D [1627 0 R /XYZ 72 700.172 null] +>> endobj +1626 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F30 1094 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1632 0 obj << +/Length 2570 +/Filter /FlateDecode +>> +stream +xÚ­ÛrĥġŬ_Ħ·Ò36—xíÛ6›mәd·ħ2i’˜‚-Îò˘€Ôz•Żïı¤liğêĝE€ƒsÁı2Z=˘Ġ߯"ù˙ÛúêÍû8[ĊqXĤİZ­VıZċqF:_­7Ğ_ƒïCu}Ç* Ŝ׍½Ġyĵ½Öq0Žßúњî‡ëß×˙|óX•a™İ FĞ[•†:ӌïíÊ8hmw­Š`ĴûÎndîŻoUô×óíÍġmAß5Ŝ2"ĝ z9É´´fċYïêÇş3Ms‚Ħnwġ—ĥ8 Û£`ßmĴ=ß}|ó#T'QAx}›ĊYCğs=žŭŒTNˆäöşCŝ‘e–(³,èâ4€³Î´ÏL·áAż#Ĉ­3#ȐaamËcÛmMWñe9_'Á€dÁqPáÈ2ô; żSĦq°53Ŭ yt֌$Z8H²ĝ²ƒ“@—ÊĈ­l5mżgV…ä‡SœÖŬCïZƒJEdÁÓĥÔ§y ^CmD +LŞ›İ;7ĵ2n]żÜòÄßoQœ4ö/cß*IëàŻÊ,ĝÏŬğw7<ŜïcÏçl h… İÜ3?ĞlNl$ħžÙÀ‰†žĉUmFäOġ¸ċÉĜx‰ „/Eş‹$ĝÀŻŜñÉŠqš°×z[£U8Ú~yÊñ‘C Zo*šŜD½Iß°6ž?âu)†ŒĊ:l7ìAì~µKUŠĦƒĠŬê,ċ +c³0½Żé1g p¤Îòx°#/“˘à˙Oëdt”du+XÈ|Š…ùd óñÓÖvKRĦĊÉ}šŬ€Ò$ +ŝ=í6‘<¨ċà¸wè³N< zö€·(˜ ]2ŒóŜ›Œ ï×À0 DĠĵ ³òNñ_䝒, ŝÁžħú<=,‘%šÀ KÇIdcHAucîŭ6ïáz2%ÙܝdŸ5rôBµNĜivuŽĝÀ^Ĝ ÙNèÄÖĥĊ__ŭqEÑ*ĈĜ”:,£bUµWżŝ­62B]Ğ'ÚĠT‡QšÀ¸YŬ]ŭëÙù<óTí|$áPŽSŒTˈ–ça™€ +ÂZ".~kœİFU +ċ}0û@Ħ}l])ˆ Ó —äħíßÁsyÁ0DMbċrŞ_0š˙[hi&—Šì”Ä2–…x÷1kmER |gZ{˖r^’sÌK’‡Iò*ܤ 2 7ê,7Ší>VQ|t5ÛĜhŭ~6Éuqß@ĵ\.œÂĊ|‹A§aR”Ż!]†Qî•ŞÏŠA/ÄĥŞì0Öa4-ĉÌĉ§^Ü´žÈúy9\ÌÈħ”Sŭ*ÏAċ!¸È!9+‡ä<î‹ :ĉ–ÒüUô§aœ‰g_œċ§Xèܙmx烈6Ú +| Â ğXò çep1G2HÊ2ÌÔĞè4ÒĦWézáŻĤ@ +BXstD\×mœe³5>²ı >)Šh²ĉĴ.çâXEfYñ +BH 4(â×ê[¤ RxW;Pvï òC ÒÁgfçù˜c!*çħ~ ó2”˘u­ż…k½àú§~Wĉ8ŬŻ?û˘&‰²8xû|^3ôBi|Qì)@“Ea˘ĵ—‘àQ…™ıς†Ħ¨ĤB^ë8ê/2âÚö ’Ìv÷uŒT/nnĤZûAöL™4}‚Ş£=–jıßħR˘Eéɸ6ì‘Ċœc1Œ)vğ(qùÈ"·È!ÊVëB°Úw²É‚]ŭŜ1h.‰<Ó+B…/Z°xoz!¤2yVúäİŜXJĈ‘*ˆĥğÑ_Ör‘ÚĠÀ<¤!wtÔ³–ŽVa1wˆB|öqÍL1§6˜Ŭ.ë‚íèAù@ĝĠ~њ;jF c<܋ş–!T%Áé(Œong¨YÁĵFàüqûVvRÑ'µ4Û³à[*ĉ\wüoĝoÑ­€>,×tNµT„nNTÄMŞ…ž4 <€ËKPy ,’o¨üg–zӅ.¤ĞSµ€\ß>oÒÉ(šö²–ƒeİċ`ıħ°ŽR_ë,щNżbZÙÑӉ|5pb#òŬ‚HÚ:Ô-$wC:g-ş;ÑÔyŞúÖ +$ŸQĊS_ġF‹`nİφċì}”[·Ĉ$˙ ‹ĉĞrO§µlh‹÷ëĤ›ÜPìá&jôq½Ü)}ċul% âu°İ‡O Û8 2'Û4?`Ż(+g×ò|j•à„ş IV°°‚ÂĈÖà j˜läÀàıC‡ĉĴ°WC0?/BßMğË ,ŽwkŒ,wĵĈŬ10Ë8b–qqbùĉTßÊ6u[wSŻur:èĴ÷i°Ğ†x ”ŻwŜċTŭĤw3y͖½s&óÎÁuĠ²%³sÛ]tŜd‡¨ wĤò΍ŭŒž(öğ'g4ì\CʧĤ‘’Ljé9'-/Mœĉ Nġ‚S-œê$0SOaèä›bKW%íĈ?o|8F™à?=%Ur—ô”¸›àz<Ŝ–#Ÿ L ›N³="4Ҟ‡òĤfR'{)>&çù9ᨛFöK=5}'D‹kÁñ [¨àŜŭTVœˆÜTĵh["Ì·-Uı°!\€˜ó@IN­ÄDÎ2.&Š™sża¸aïŸúa¨ï›cĞÌ~˜(—aäĥž˙'3ĈIƒÍĉ“ÎkóĤwÇoDܔÔöñö]…ß-·P’[Ps X4Šdjú8ĊH8Ċߞb¨RÓ ĝïÛ8Tİ–7àJ-;ž'ğŸT'ĦÏS˘‘lŠ, +×G=D{·áµ£lúxğáż9İÀٔTÄϒ +5„µ“A=Z5==şòıӌkâ>ˆĞ|êÊ'zv7Šà‚JŻw²™è-"acMöTHvŽl]S+Œ ü7½c8B_óŒÓ2Bĵ>xq,EU†íSħ˘ċ•¤bê7‚¨W'ùÑJ +I4Îŭû\²xXAݸ}Ċ=ú|î‹ç’}'ĊtĈ‹‰Ħ†Ì]YU”7‚ÊËǁgš>Aì£ Úì++äŭDÌcá—;g˙ĜCIáŻ~D(~ßóFµüè7ċLĝ=’' „RĞbŝvısGé³ °ÎġNĈòù.ƒ ™>pÎßb`"İ&ìĦ@H‹D;ÒÛ~*¸‘rBS³ ] ¨ ˆ§[#1L<ךh¸ó—f‡/ kp˙i|TĤàšnË(̤ÍÇúhì˙'ÊŜi +endstream +endobj +1631 0 obj << +/Type /Page +/Contents 1632 0 R +/Resources 1630 0 R +/MediaBox [0 0 612 792] +/Parent 1617 0 R +>> endobj +1633 0 obj << +/D [1631 0 R /XYZ 72 720 null] +>> endobj +786 0 obj << +/D [1631 0 R /XYZ 72 720 null] +>> endobj +790 0 obj << +/D [1631 0 R /XYZ 72 432.593 null] +>> endobj +794 0 obj << +/D [1631 0 R /XYZ 72 252.262 null] +>> endobj +1630 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1636 0 obj << +/Length 1850 +/Filter /FlateDecode +>> +stream +xڕXKÛ6çWĝVX;z?Ž ’-ÚK‚Ä@€6=p%îšX[2(:‹íŻïĵ(Ñk%M.9g†ß<èxġ°ŠWżżŠċûv÷êġmZݚmSĤċjwżŞÒU•ÄÛ8ĞVğnġwô~›n³ġ&IŠ8ú²×ú°Ŝduìàtëp’GÊ9kîÎNóÚ׸ˆïkĝMÖ˙ìŝ|}ŠW›´ĜfeĈÒ˙úüîçġ&E!‡°NĞèiäù×8Éš&Eä&Ŝá'ÒLuŝ‘ĠÑŻÜ­ë™Ç£vÎô²ß8Oŭ†<şçépÏën/²µyĜ#ƒÛóB‹Şí•Upˆeï)"êû›(ÜĞ£Ŝ79ˆ5{tڞ$ÛĤ(Ĝv·7Àœk•ydÖI4òÔÁQÍ:!ŸÀËâˆv8jòIĞnóĦ?<óôio<ï$àIî$9አpD&ÇŞĊVġŭàü6ñ?N´U£îd§eĉċ²kí“5Î-Ûî/(O“è8ŒG1‚êÁŞŽĞâ’G dòŠH›-À´İCêçy:oñ^Uġ LÏd´¤BK’Hœˆ ˆzksîƒ#o‘qàêÓÂ`È2À ú6C|“ĉhNáĤ·“ zÛ¤ z‹Êè<2|aÈĴŞ ú@ûè#'Ŝ)7xD '>Ê*7Ĝ‘Yĥµú7ŞmÉ@”Š—ˆK½v(ç ûȋóèôQ„&x Ġh˘èÉbPUT9Lœ&÷v8^ĝĴôp 5ÉNtɄ,òˆ|ĉq?ô›“5ßÚ~ŭcÏëĥp“ĠY­8“4|Ċz"Ô Äġ½Ż@‹3_w(Rg,dĝÁ>óBH˜!fJ,Ìì1}{8wr¨œŜxT.˜gzÎóÁa˜²fD=GjfJÀ€‘bÁ.€éî‘âWΔğq4ġaĠhTƒêÇ~÷ĤğĈIP=*4‚:ùĜ8EKqħäj€Ġ<¨ħ`ô“Ç/œJN*(#ës1œŬ8ò녣ÉͨzĴ̋™!ñ“SüĴƒˆÌ%„rÄığTĉ_m,ty2‹š²LûìÂíÌB•U\ÉŜ…hò}ë Ż ĝ2VğԙñtPìJĵĵŽ9Ĥ¨&–@4V×$ŝlÙ,%c½ħí:KÁ÷ߣżûĈpÙ/¤­2”]'’- '¤'˘L/Na€KÜċ³,Oö–Òd"oĊ*ÎbÔNP: +ÙĦġ·"îEċ ÙOƒì…2Â셷Vú”¨Îhğ€QĤ¸NH@1¤žù5‚9îÈdB"|M}ÑÊ0p`ċ‰Ñ^Ĵ}9HÜ —G*³–PBÁvŬAÀ7ÂôdĜ‘–XatttYÔóUùlÂ}i¸ ]|vÔÜá—c d|1Ĉx$–Ô|ġü÷·`pĴy]EÜó†İZÁ8ԊW'×z89lA#.(uĵ:ñ*‰ïÑ ÄĴì„΂6°pÁg·ĉÀ‘*‰+Ÿœr@…ˆÒ\ôŭ0÷ɋ>iĈ•cNhÊÙr”9ÊYĈ]ž3ċšÜçLŞY÷BËô‚šsΤ:Ḡ+ k.EgñyuËﲉî%…G,ç'ĠE5zíààŒ½ 蚅ë­.{˘Rò7|użW}+<^Y $¤"„à½ûÁFôûÎ_µ$]€ġŬ…ż† D` –ğĠќùÁ§ËŽCAoĵ§$F=ËĝH0‰nאżıFrì"¤`ázqW=ğB‹ +—ŭ9*Hé˙ó$OÙél%ġ&IYċ †B;òŒ;ġG§ÍKıä+ĝBD +müż8Y> endobj +1637 0 obj << +/D [1635 0 R /XYZ 72 720 null] +>> endobj +798 0 obj << +/D [1635 0 R /XYZ 72 720 null] +>> endobj +802 0 obj << +/D [1635 0 R /XYZ 72 602.047 null] +>> endobj +806 0 obj << +/D [1635 0 R /XYZ 72 521.84 null] +>> endobj +810 0 obj << +/D [1635 0 R /XYZ 72 413.85 null] +>> endobj +1634 0 obj << +/Font << /F28 879 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1640 0 obj << +/Length 2119 +/Filter /FlateDecode +>> +stream +xÚĠX[oş~ß_a82vˆÔ½hàKrâ6^ħĥmÒíƒÖĤc!ĥä#É{9ż3Җlmaaۇĉ!ÉápıÑvïg÷~}cĞï0~ssÇüs-Çġy/^÷Ŝ ˜mÙN‹W½w}“1î£mŜ7f,ûïÈÀ3ĈEú‡˘PcQ.‹t_yVö˙˙ċĉ.ìEVäs%Û=“‡Vı$8Ŝ¤eßäkèoµD,E!²>ŒjûÍ,û=#/*ħ˘Û´ĴòŒ|­ö ~°h‰Û^‰·BŭxúİÖyAÄób<[™dJĉóxÑq?tŒüL­]ò5ŬĦĵŽÎ_+T34*Z€j†F^–é§­x‡ÀK3fEžO—–²×6²d§¨/( )iPŠ­XÊ[â¨Êéğ/r\ô9]İ= }–Ñ\x_~++ħS‹3-…|#%Ġ:´ž”tf=)°ï3}'4=ĜĈġÁ6úĵXIäD<´ÖQ¨iÙ°W·%ÙÀqéúÀİ6IEÔ%L2ƒì+eû“ĵmŠo _<ÂU³żmfS%0S·ñ‡ùó"ĥP“£ß÷·XH‡ä#½XsÍÍŻ{/옐K}‡£ĝqòV7Żßö£íÙ²×L"ĝ%#­Fùn¨D“Œ–á+–¸ì•VÜ—ÖHïĊ‰Á²*ÒŻgW2IC“E–ïGt8ïp‡ĊĵùpµÎ7✟Ŭˆs$s ¤As &ْ^D.LÖŻŽdıe‰HË œu‘ï´ĜĴÌ·‚Gwᗴڨf§ĝöÏĥüclhµı&ıĥ§uŞÁĵBT‡"COġÁˆ9XŒ&Rû ñK@&{Ħ9\NÇc”óôô÷ûûétħĝ‰lÌXÍÈ!.RĴŜÁĜ‹Œiş,ré)8ğ¨’btšÌ•è…8Ĉ;J{É 4n-x/d×Vŝ Ĥ #%Ħ%À÷|Ĉ¨ÙÖŬLc׌ߕĝœ.…âe+Ħú; tkŠ3ÔQˆm*ÔVĈ-Ğ=M ß³ı}êŸÜx?‹o˙H“ħÌÄe[—›ê|·NP3zpìo‡´Àƒq„I‰(-_Ĥd0‹![uĝn)e!)ŽŻSrÁ˙áJjIşĜİĞ'ôĦ½íġ8J—z{ î0’Š${ŬĤJ‘gAI Ümh­TVÌòŠbĦŝP9 ş4ƒÎGu½ ÖA$›íäw  ĝŝŭĝfw‰ ÇeáWĞrìè2kÁ|£=…ñĦ¤ÎÈx#ŸI½ìè(sš42/çĴKO B‘[÷E"_ò8/Ä.ĊwÎ.òuµ$˙%ŭÛbë´ ?‘'L,ĠŽoÄñb˜<›*aĉ£çÄċ+S +’e+Œ<ÈĊÇì|ì×+ùԕ€çÙG›ı/‡BúĉĜħŸL‹ĝħSö´9eOĝʔ…c=mç{œodO+쑌ӝĜ%eESŽqoÍ,šıHÀĞWd£[\JáĈNcı•oÉ>M¤sġxÂÇHmÂmuÌ‚ héÊ0òO.Póšµ>ûG;áûj•O;Ċïüŝ‚R²òu[zà5rìC?Cż¨™`ı{–€sß48p–-Çİ.(*ÉHÉ<„ĴÍ­}‚Ž>èşC½ù"? ġ&Χ8w5ÎhŠëĦŽşC=éèPÀh×QÏTÀ³ZÀ³–8eÍß"pÍZoÄ@ê@…ħ +÷áŬ²ëŜ4T­PŞġê™zÂóûê?€˙.™[™ñ&ÄÌŝÏӖÈPÌ?ĵwÊçó4ĠŻÏFÜÒ5×h&aL·"ĈBÛ[Ĥ–]„- 0lÁDġÈe-‰‚½ĵĜ1’A„lĦÙċ…3:[m9‘] 2èñƒ@Ĉ"ĝŻ`Í:cŬ½vƒontè \qĴÂ4lÖSN…iĤA³*˜Â6¸ÒÛàĥ PqĜŽ÷„%ï€ċpòĞ9›XŸ¸q]†ĤX2§!jĴ$ÔMŠĉ,p#¸ĦzR!Ë·‰s˙;żóûRxfK™>mñĝP%úW^Ôj+V/‚Ĝò—Mŭ8˜£JċOù,:ŭ +ÜRTm€Ÿ~Äwè¨:3Îpà6³|Îz&Ĵ0 uLyU·ñ›`5µ +endstream +endobj +1639 0 obj << +/Type /Page +/Contents 1640 0 R +/Resources 1638 0 R +/MediaBox [0 0 612 792] +/Parent 1654 0 R +>> endobj +1641 0 obj << +/D [1639 0 R /XYZ 72 720 null] +>> endobj +814 0 obj << +/D [1639 0 R /XYZ 72 720 null] +>> endobj +1642 0 obj << +/D [1639 0 R /XYZ 72 642.956 null] +>> endobj +1643 0 obj << +/D [1639 0 R /XYZ 72 610.779 null] +>> endobj +1644 0 obj << +/D [1639 0 R /XYZ 72 555.244 null] +>> endobj +1645 0 obj << +/D [1639 0 R /XYZ 72 512.218 null] +>> endobj +1646 0 obj << +/D [1639 0 R /XYZ 72 468.639 null] +>> endobj +1647 0 obj << +/D [1639 0 R /XYZ 72 401.149 null] +>> endobj +1648 0 obj << +/D [1639 0 R /XYZ 72 357.57 null] +>> endobj +1649 0 obj << +/D [1639 0 R /XYZ 72 313.991 null] +>> endobj +1650 0 obj << +/D [1639 0 R /XYZ 72 270.411 null] +>> endobj +1651 0 obj << +/D [1639 0 R /XYZ 72 226.832 null] +>> endobj +1652 0 obj << +/D [1639 0 R /XYZ 72 183.252 null] +>> endobj +1653 0 obj << +/D [1639 0 R /XYZ 72 139.673 null] +>> endobj +1638 0 obj << +/Font << /F16 823 0 R /F8 826 0 R /F28 879 0 R /F11 833 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1657 0 obj << +/Length 2422 +/Filter /FlateDecode +>> +stream +xÚYIwÛÈûW½ >ħÌM˘(qD‹Ô“Ç™`ƒƒĊ3š_ŸÚ°Q„T.DWuġŝĠJcô42FŸŜߋÍğ³+wäM<Û´G›Ç‘M”79ʘSg´ G˙ÔÔt2ŝ×ĉïÍ ³+³;D9G™CÂóùZ+ÓĠÎonĉ7˙À‘ŭ%Œ‘ÔěÍxÀoĈ̘ûIü˜ċiìġİ5ÓĉÙn_•VFc]i92-mŭ\”Ñ` Ó5f0R1u™Ç?Ĉ°d”3 sñ˜‡ħ;Ġü$ajždcĂħéhßÏ6cׂ!ğ8ġËLF­ˆĞ}gŜ7żˆBž!K™uû=ĉĈrÉ3wjâQO7ïÍwÒ‡Ċ,Ó`ĉ6ŜOĈşcXÚyĝïŞ(ŭoIÄŬ{?÷wQċÓq$U(óĠ=7Š=-EáG`XJğôKŸğü4aĜ7Ȕy–ÈÔ4&ËK <*Ѝ:Í2N5לͰei;<”£á^ ²Ŭ‘ú†+=—Òġc<³áިèc–`Ĝè +aÊRÊ:iĞûĠŬxjj·úz}Ħ^šŬm­ ĥnšÚ‹·lÏf@™ĉ´(ì$@aƒıÊ3Ĥ’“6z_tĈ1_žıt#ȳlWı̛ĝìîı2àżÊzŞrq0,foˆÒ~ŭ4Öm5£ù€À –íŻĠžïê^ĵètzàĊ$t½Ë[ wÍÊjÌâcïĊ‡Z⪰·u”-pNyĝÍZWq}ûᨇ_ĈAž-cv—hGá +.`üÙĠĝX}a˙o``ĠĈ K€e9Î``ÓOdŜ(˙ƒĵg6Ê Ù-µ£?ö~ZĄEĞÖ82ËŬG…xğ˜u$d‚™é 1нt4îçw”yF_èJ8‡bĊ„ƒ v. Ŝó@WEP‹•ĤeBžmZĤbnúqŽíp¸'€gċéëûĠâNyGĦçÈ/·g_£”L£eyšò0êrÍġ˜Á 4Ż Ù ¸ÀĈ¸Z–Ëï‚}‡†ĵÇ* 1LîAyĦóG˘GÇX<[`.ŝ(ák‘ Fß\šczfŝvò\à[êCW6ċì<Şñ‹Ì˜Tbr¸'âÜáĵ·Ë Sl½`yâ4ĦÏ²Šœö”Û<ОĥÜ]Ös€İ+²D(4"ÔM•v›&ÏâËĤ)ĊkĉÎâÀÙAÓĈt +-ñCeÖ ƒ$”mâ˜ÀÉzqnì”È7)Ĉa9ˆèeŽìQÌë$™…xïDÄßߌ=[Ûܝżó¸1Â<î1O‡‘û¨1OĤ½›’µ—6|Ôà)Êìž‚ßğu„röXâ<ċm<Ä‚=ʟYì>)sôzwÙn2{ŽùĤ–=ÚZŬÇĉ\náËDčHtáëBş\t(?°^•UžÊ˘a7ĤŒw>¨sš•̘oÈxĥĦƒQ°ÂŞ8'K  ğä(Ÿ?ë°ÊLÓ~%kâç¸*DKÉ'·BC0İ´^6‰N&+ûD”‡w¸| h°;ìpêĝ}Ċ]aŽUG$ljĤq˘rHí‚4äëòü—·èˆrDGLĊ: >’Ûêz:ôc-ôBG°³£#@’Ž8 #xóIר ÈċşX÷^ŝ )úm”Ù÷E”ż—É>P÷CàĦŬ’-›]”DöË Cg,q@Gk(*¨µĤ :F‰Zkxê&0a­€J‡(ÀGgwçç~Pҝâ +C'+JLFá|içèigNdÍ\Xݨ `-×}İ?(ĜêRŝ4s8ŭÁôç$ŭÁ'’!T§ê;vä<ĥĠ–ëü_ŝú4R§¨ëé×›Ż ÌĵA{ B$Á/ċÙ­•ۗhÌÛLYœCTúıЁœX`ŸlQˌ1ŠĊ5˜ġ‰)Ž-Ĵş,cIYĈjÊ2z-Q?Ħ,C<˘äXĦ¤EV›=Ŭ +Ŝ@%Ĥİì ŭl+2â4"Ÿ +MM ĈÉ3ċ`•ĝé‚j[Ç Ĥy"@VseĊ:36§•â„ciµI&Î+(wŠÂN +A`·ö"ä~’D 3àĈÓ(àú”>³=y¸Ŝ _ê} ÙĊPYHfm= °¸­êĴT•S0L"ì5ħ½H9ürñğc҈]½J.2ê$™EdHqJŽ)µ˘úöwËËHsò3,r&Öᜀ·EKPxbHB/Ó{‘ı­Ê˙-ÔVşċeŞègyxzÙÀœžӇëËO‹Í[€êıšËÂ’žÚ 0ë?7<ÉħAyúC>Qĥá‰ûÎòïX'@šb¤Cß~ħKùËnp +ŸËÄàÒbŭ +g“H‚ù÷8&ĝq— §§B6)‚[+‚Ġ-GŬSâP"ċPU@µħ)EÖĞ5OìäŞIĵgŞ)ÈĤLK9әq98òjéêzÂ<ÎëĠÔôD§ùJşxPön†zÖżážßZ7­“ñğ^^½†¨Ù…hÎ4Dc\ÀÁ]yÍÖ˘“ĝ)Ş‹fĜÑüY‡Ä"}‚x.âê?2pQÜ]ğ ùnĈüp‡Ú½™3Ż…˙f]gp“´ĵJŞ›.Ò_uÀrû˚¤ŜŜ´-·<,‡‹o†×+ħÄ׸ΨY˙vŞĤĦ&ĥİFúԞ˜ž%Ùğ²{R‹Íğ˙f>{˜ +endstream +endobj +1656 0 obj << +/Type /Page +/Contents 1657 0 R +/Resources 1655 0 R +/MediaBox [0 0 612 792] +/Parent 1654 0 R +>> endobj +1658 0 obj << +/D [1656 0 R /XYZ 72 720 null] +>> endobj +1659 0 obj << +/D [1656 0 R /XYZ 72 720 null] +>> endobj +1660 0 obj << +/D [1656 0 R /XYZ 72 668.25 null] +>> endobj +1661 0 obj << +/D [1656 0 R /XYZ 72 624.414 null] +>> endobj +1662 0 obj << +/D [1656 0 R /XYZ 72 580.578 null] +>> endobj +1663 0 obj << +/D [1656 0 R /XYZ 72 536.189 null] +>> endobj +1664 0 obj << +/D [1656 0 R /XYZ 72 480.952 null] +>> endobj +1665 0 obj << +/D [1656 0 R /XYZ 72 424.608 null] +>> endobj +1666 0 obj << +/D [1656 0 R /XYZ 72 368.817 null] +>> endobj +1667 0 obj << +/D [1656 0 R /XYZ 72 301.071 null] +>> endobj +1668 0 obj << +/D [1656 0 R /XYZ 72 257.789 null] +>> endobj +1669 0 obj << +/D [1656 0 R /XYZ 72 201.998 null] +>> endobj +1670 0 obj << +/D [1656 0 R /XYZ 72 145.654 null] +>> endobj +1655 0 obj << +/Font << /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1673 0 obj << +/Length 2137 +/Filter /FlateDecode +>> +stream +xڝX[sâĈ~ß_ÁyIDĠ +늤ĵfƒ•!FNĠ&9c46* ɑĺüïO÷tKHçÀ>MwOϵoߌ1xƒ_?½v}şúâ‚Q0ĥĈƒèià#3pžiŒ ÛDñà/ÍrG˙Fż5ƒXí!Ĥ7òL z”ò¢ÔïNl tÓKjħ˘Úê~´9Ôm'‹äûò5Y˙”3Qm%_Ĥs"îe)EħAí-IxeE?uèÈE#ïk›ĦnjéÔrĠ<íe4ԝÀÔn*³/eÙ[- ]ß{4Ç,mûÚËĠLÔsJ$2 bQàÁûg}K*ܢmóÄĥ£½ĞSŠ‚Ä[™ĈD%ġ³˘­#“ˆRnò,.İ;ĵkX–lĦ›hF‹Í7Ä|óÉ0kÑBŸŜ,×ç›nfìkfpU›Ó{Z´MJêhy8'p•,žÄF²Ž Ĥ+Ş)ÌIsl:·N*ŻEŽÜ÷$–1I‘o& ŭxÚ -³Ë\…Ô§¨?†Û)“<#5²ÀċG§ ¸ÂÙE!vvŒ&0]°şéh˘"A’••HÁ2jFìİ’¤>QHmY2[=AçóĜ%IĞU=0‹{E²,Iš?‘{>ŸñâŽVVE’=כ˜áV¨€Â@S›ómNÒ°áN’†>JҘ´àPu‚[äéNSPè$càûwú<‰}È|Ŭ-8°…³œ3¸äRTûĥşږĥÔ}ç,moÌq]́t;Žë¨m{ wQ+Ìò╠PÙĦ$ÍÇ}’V:f|Tê_ +j¨KÁNu)H„”,b™ֆ2ĉ>$[֙ÍqÏk +ž&$–ŞÛ‰ŒCŸ5‘Ħì§\ü\qGĠ ĵ]ıİn×ÉsR‘ û…U#•3œşÂ0Ò1u·Šž}YѳKü`~.ïġ?£›BàĴäšu­Ş“Ÿ€Żċ”§€ tÄ­Ì ñ*Ĉ Z…É_)HQPG¤n“ŽžċiŝœÈògšw<×oˆ9Jií5ÛNĞ”9­–§Ĵ_§1×kì 2³NÑş:¸Ħ&ŻŻ,‹üċ˘äıš† Ö°ÎJjjJÈoDĈ¨ħ–Şż(÷ïĥ[ƒÏòó/İóÄäÛ?ĉwÑy‹íuñò”ŝ€˜Ä$'|D2û‚Ó(Éşú„~  &Z4(ŜoŞ̂ìP/P°ëyŭp(¨İBŝ„ßtŝûk"Ŭˏb˙!K*}ŭ¸Öĥ~Äx_çżNš}ûħP÷Œn€{dĝ`šĵ”Êgħy'ú(2AVǐ͂@(x- ˜÷ˆùÛgsÄu×ġêuU6‚6‘‚+'ıÂ)Ĵn–Ì+LêÖÏ$”P<+GVĦÒv˙µ¨Do,À:LqğF 0v^T<‡ +z$š G†@7u#Ŭ zŬµLí :˘ +)ŜĈ gíCÓĝLNH‹´ëïúê]²C/X€NÓ.kpÎ]#ŭ`ôtq–ğÛ¸{xmë!ùùíY~ĉ=ŞŜà'`‡wÜ;ŒK”Vò‚%‰›¤à”?—ÄôQÊnà„jĊ öÌnëeím›ÔïyT˘÷8v¨-Ċ‡CĝGËË ×ÑBV 80Ĵ²ç+s2ô´\—-¸ş9ËVÎ%ĥŠîL¸ĠUU!DzùSÉħŬŜS %m!O€ÒFı§Â ĵ€zûFï\IĜÔg0ˆùmŸ&‚UŻߑZ´˙+Bè!¨É³ż ÓyÖOŒB<Ĥ'­½ĥŸ×À.~X;ÍİXKĤr–áeÀ{šĞ+J‚ÛRĈÒ`İ‚jŜĉù ŒJTÁ‰ .Ĉ½â)p`ŭ×Ó/NŞĠ-Aĵ“¤|RÌ3žN>Vħà~òK°âóG‰dšd˘`żŒE=va+ù¸PF)'ĥr‹ÍżG׀iġÀóÎòàKŝü–wsÊ5úòî?gùî2“‚wCŝïÛ²u¸}ˆ½û~WżH+]!Ï:%cËè~r7Ñéwlĥ8ï”U!2ĴĦİlWU˘ù'PžÄ'‡ŝióìiûôĤöÍŻ"P—‰‰z*°¤"EwċĞè+ó”GżĴVĠúh%xdû@OV²ĤrP™—ñڔ_”òŸ½Ì6òb(HżòÚ?ĠβĈ%ßJĞŸ"}1ŸÜ+kL£Ëó=÷ò%JëbPOî])+*Q/İ; ĝ 0z‘ï+’ò?t¨ïLzÒ¨?Mì=v×ŜrúŬt§0ğCïDÂéD "Ġ‚…MıIDJÜn’q\½móRÖÀ]éUġżNR6ĈĴk†äô$ĜŜ†áçĦ˜K>­~ÖßÖú +ÑYFĊÛ=”^ƒèĝ=˘v­ĞĵZs),ò,ٔWäê÷‡­u\^ ĝ ÔQgû“ ùßÛ5Żñ H”ŭÍĜŽ×ôÓTÑĤ`‚J§`O_ÌNíŞ YġK%Èş´J(uʧ UœŞhOÑqİ–ׂ³0jÒTV‡ŝdOœ°AԇÛê9e˜£ħet+ùOLÓëhÍ£O˙‰¤J +endstream +endobj +1672 0 obj << +/Type /Page +/Contents 1673 0 R +/Resources 1671 0 R +/MediaBox [0 0 612 792] +/Parent 1654 0 R +>> endobj +1674 0 obj << +/D [1672 0 R /XYZ 72 720 null] +>> endobj +1675 0 obj << +/D [1672 0 R /XYZ 72 720 null] +>> endobj +1676 0 obj << +/D [1672 0 R /XYZ 72 680.571 null] +>> endobj +1677 0 obj << +/D [1672 0 R /XYZ 72 625.514 null] +>> endobj +1678 0 obj << +/D [1672 0 R /XYZ 72 584.349 null] +>> endobj +1679 0 obj << +/D [1672 0 R /XYZ 72 550.711 null] +>> endobj +1680 0 obj << +/D [1672 0 R /XYZ 72 508.163 null] +>> endobj +1681 0 obj << +/D [1672 0 R /XYZ 72 464.507 null] +>> endobj +1682 0 obj << +/D [1672 0 R /XYZ 72 423.895 null] +>> endobj +1683 0 obj << +/D [1672 0 R /XYZ 72 366.901 null] +>> endobj +1684 0 obj << +/D [1672 0 R /XYZ 72 323.799 null] +>> endobj +1685 0 obj << +/D [1672 0 R /XYZ 72 268.741 null] +>> endobj +1686 0 obj << +/D [1672 0 R /XYZ 72 237.041 null] +>> endobj +1687 0 obj << +/D [1672 0 R /XYZ 72 196.429 null] +>> endobj +1688 0 obj << +/D [1672 0 R /XYZ 72 151.39 null] +>> endobj +1671 0 obj << +/Font << /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1691 0 obj << +/Length 1104 +/Filter /FlateDecode +>> +stream +xڝVKs6 çWè(M+Y”d[:&ŽÓz§ïĞ­§Ŭh‰NĜèá’Òşù÷ÊŻu;v/$|ĝàyuBç§ğìû°ĵĥI“èfĝĴ°,˙:IÈèˆÁÓj $ ŬÇŭĦµhŬ!ŽP êĊ=Cƒ¨ZéŬŠJە ÊXĴyŭnN+üƒ’ŒĦ¸£dìî_pôN–8íƒÉ—‹mK²€ËM%A&aş\/™Í ™fäñ=63tġ43³~ĝİZċ˜“Ì G‘.˙Ğ‹!ŒRô‰44}@ÜjŽKOÈü…GîI`$pÉÄ7 d5}ñâȝÏÊO£ŞIħŝ߄cpógg> endobj +1692 0 obj << +/D [1690 0 R /XYZ 72 720 null] +>> endobj +1693 0 obj << +/D [1690 0 R /XYZ 72 720 null] +>> endobj +1694 0 obj << +/D [1690 0 R /XYZ 72 668.25 null] +>> endobj +1695 0 obj << +/D [1690 0 R /XYZ 72 623.861 null] +>> endobj +1696 0 obj << +/D [1690 0 R /XYZ 72 580.578 null] +>> endobj +1697 0 obj << +/D [1690 0 R /XYZ 72 526.725 null] +>> endobj +1698 0 obj << +/D [1690 0 R /XYZ 72 492.354 null] +>> endobj +1689 0 obj << +/Font << /F8 826 0 R /F28 879 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1801 0 obj << +/Length 1006 +/Filter /FlateDecode +>> +stream +xÚ­XËr›HŬû+X˘ŞÑ/h–`™ ²\‚Tb9Y`İÇCAPj2óój9%ËN_µ˘,èÓç>ϽĜĈ“aÓ+ûè9IŻF×È1µu°‘ŝi¸Ĝp‹{ċéTĤ{  :Żfí˙~yà •Öž+˜îġ> endobj +1699 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [180.704 672.262 192.659 683.111] +/Subtype /Link +/A << /S /GoTo /D (page.33) >> +>> endobj +1700 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [137.311 660.307 149.266 671.155] +/Subtype /Link +/A << /S /GoTo /D (page.22) >> +>> endobj +1701 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [172.623 648.352 184.578 659.2] +/Subtype /Link +/A << /S /GoTo /D (page.53) >> +>> endobj +1702 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [99.01 636.397 115.946 647.245] +/Subtype /Link +/A << /S /GoTo /D (page.105) >> +>> endobj +1703 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [110.329 624.442 122.284 635.29] +/Subtype /Link +/A << /S /GoTo /D (page.60) >> +>> endobj +1704 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [126.379 624.442 138.335 635.29] +/Subtype /Link +/A << /S /GoTo /D (page.63) >> +>> endobj +1705 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [142.43 624.442 154.386 635.29] +/Subtype /Link +/A << /S /GoTo /D (page.64) >> +>> endobj +1706 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [171.654 612.487 183.609 623.335] +/Subtype /Link +/A << /S /GoTo /D (page.20) >> +>> endobj +1707 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [187.705 612.487 204.642 623.335] +/Subtype /Link +/A << /S /GoTo /D (page.138) >> +>> endobj +1708 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [104.766 600.531 121.703 611.269] +/Subtype /Link +/A << /S /GoTo /D (page.135) >> +>> endobj +1709 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [122.007 588.576 133.962 599.424] +/Subtype /Link +/A << /S /GoTo /D (page.65) >> +>> endobj +1710 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [138.058 588.576 150.013 599.424] +/Subtype /Link +/A << /S /GoTo /D (page.69) >> +>> endobj +1711 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [154.109 588.576 171.045 599.424] +/Subtype /Link +/A << /S /GoTo /D (page.136) >> +>> endobj +1712 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [149.031 566.703 160.986 577.552] +/Subtype /Link +/A << /S /GoTo /D (page.22) >> +>> endobj +1713 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [165.082 566.703 177.037 577.552] +/Subtype /Link +/A << /S /GoTo /D (page.51) >> +>> endobj +1714 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [105.043 554.748 116.998 565.486] +/Subtype /Link +/A << /S /GoTo /D (page.13) >> +>> endobj +1715 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [121.094 554.748 133.049 565.486] +/Subtype /Link +/A << /S /GoTo /D (page.14) >> +>> endobj +1716 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [137.145 554.748 149.1 565.486] +/Subtype /Link +/A << /S /GoTo /D (page.34) >> +>> endobj +1717 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [101.03 542.793 112.985 553.531] +/Subtype /Link +/A << /S /GoTo /D (page.34) >> +>> endobj +1718 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [97.432 520.92 109.388 531.658] +/Subtype /Link +/A << /S /GoTo /D (page.13) >> +>> endobj +1719 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [113.483 520.92 125.439 531.658] +/Subtype /Link +/A << /S /GoTo /D (page.34) >> +>> endobj +1720 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [129.534 520.92 141.49 531.658] +/Subtype /Link +/A << /S /GoTo /D (page.38) >> +>> endobj +1721 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [145.585 520.92 157.54 531.658] +/Subtype /Link +/A << /S /GoTo /D (page.47) >> +>> endobj +1722 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [161.636 520.92 173.591 531.658] +/Subtype /Link +/A << /S /GoTo /D (page.53) >> +>> endobj +1723 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [142.68 508.965 154.635 519.703] +/Subtype /Link +/A << /S /GoTo /D (page.42) >> +>> endobj +1724 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [158.73 508.965 170.686 519.703] +/Subtype /Link +/A << /S /GoTo /D (page.43) >> +>> endobj +1725 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [174.781 508.965 186.737 519.703] +/Subtype /Link +/A << /S /GoTo /D (page.46) >> +>> endobj +1726 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [153.03 497.01 164.985 507.858] +/Subtype /Link +/A << /S /GoTo /D (page.25) >> +>> endobj +1727 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [136.896 485.055 148.851 495.903] +/Subtype /Link +/A << /S /GoTo /D (page.29) >> +>> endobj +1728 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [152.947 485.055 169.883 495.903] +/Subtype /Link +/A << /S /GoTo /D (page.102) >> +>> endobj +1729 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [130.282 473.1 142.237 483.837] +/Subtype /Link +/A << /S /GoTo /D (page.17) >> +>> endobj +1730 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [98.955 461.144 110.91 471.882] +/Subtype /Link +/A << /S /GoTo /D (page.65) >> +>> endobj +1731 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [127.514 448.636 139.469 460.591] +/Subtype /Link +/A << /S /GoTo /D (page.42) >> +>> endobj +1732 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [143.565 448.636 155.52 460.591] +/Subtype /Link +/A << /S /GoTo /D (page.44) >> +>> endobj +1733 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [133.547 427.317 145.502 438.054] +/Subtype /Link +/A << /S /GoTo /D (page.65) >> +>> endobj +1734 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [98.761 405.444 110.716 415.794] +/Subtype /Link +/A << /S /GoTo /D (page.65) >> +>> endobj +1735 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [143.454 393.489 155.41 404.337] +/Subtype /Link +/A << /S /GoTo /D (page.19) >> +>> endobj +1736 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [128.566 371.616 140.521 382.353] +/Subtype /Link +/A << /S /GoTo /D (page.24) >> +>> endobj +1737 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [155.41 359.661 167.365 370.398] +/Subtype /Link +/A << /S /GoTo /D (page.83) >> +>> endobj +1738 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [128.151 347.705 140.106 358.443] +/Subtype /Link +/A << /S /GoTo /D (page.87) >> +>> endobj +1739 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [145.101 325.279 162.038 337.234] +/Subtype /Link +/A << /S /GoTo /D (page.120) >> +>> endobj +1740 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [121.869 303.96 138.805 314.808] +/Subtype /Link +/A << /S /GoTo /D (page.113) >> +>> endobj +1741 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [97.294 292.005 109.249 302.853] +/Subtype /Link +/A << /S /GoTo /D (page.18) >> +>> endobj +1742 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [117.496 270.132 129.451 280.869] +/Subtype /Link +/A << /S /GoTo /D (page.50) >> +>> endobj +1743 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [153.666 258.177 165.621 269.025] +/Subtype /Link +/A << /S /GoTo /D (page.32) >> +>> endobj +1744 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [127.044 246.222 138.999 256.959] +/Subtype /Link +/A << /S /GoTo /D (page.33) >> +>> endobj +1745 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [116.943 234.266 133.879 245.004] +/Subtype /Link +/A << /S /GoTo /D (page.134) >> +>> endobj +1746 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [94.388 222.311 106.343 233.049] +/Subtype /Link +/A << /S /GoTo /D (page.56) >> +>> endobj +1747 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [110.439 222.311 122.394 233.049] +/Subtype /Link +/A << /S /GoTo /D (page.57) >> +>> endobj +1748 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [111.685 200.438 123.64 211.176] +/Subtype /Link +/A << /S /GoTo /D (page.41) >> +>> endobj +1749 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [128.04 178.566 139.995 189.303] +/Subtype /Link +/A << /S /GoTo /D (page.58) >> +>> endobj +1750 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [110.854 166.61 122.81 177.348] +/Subtype /Link +/A << /S /GoTo /D (page.40) >> +>> endobj +1751 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [125.798 166.61 137.754 177.348] +/Subtype /Link +/A << /S /GoTo /D (page.42) >> +>> endobj +1752 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [141.849 166.61 153.805 177.348] +/Subtype /Link +/A << /S /GoTo /D (page.47) >> +>> endobj +1753 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [157.9 166.61 169.855 177.348] +/Subtype /Link +/A << /S /GoTo /D (page.55) >> +>> endobj +1754 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [173.951 166.61 185.906 177.348] +/Subtype /Link +/A << /S /GoTo /D (page.56) >> +>> endobj +1755 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [115.974 144.738 127.929 155.475] +/Subtype /Link +/A << /S /GoTo /D (page.29) >> +>> endobj +1756 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [132.025 144.738 143.98 155.475] +/Subtype /Link +/A << /S /GoTo /D (page.60) >> +>> endobj +1757 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [148.076 144.738 160.031 155.475] +/Subtype /Link +/A << /S /GoTo /D (page.65) >> +>> endobj +1758 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [120.596 122.865 137.532 133.713] +/Subtype /Link +/A << /S /GoTo /D (page.113) >> +>> endobj +1759 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [129.008 110.91 140.964 121.647] +/Subtype /Link +/A << /S /GoTo /D (page.28) >> +>> endobj +1760 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [150.567 98.954 162.522 109.803] +/Subtype /Link +/A << /S /GoTo /D (page.92) >> +>> endobj +1761 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [336.414 672.262 348.369 683] +/Subtype /Link +/A << /S /GoTo /D (page.35) >> +>> endobj +1762 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [352.465 672.262 364.42 683] +/Subtype /Link +/A << /S /GoTo /D (page.53) >> +>> endobj +1763 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [340.565 660.307 352.52 671.155] +/Subtype /Link +/A << /S /GoTo /D (page.19) >> +>> endobj +1764 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [356.616 660.307 368.571 671.155] +/Subtype /Link +/A << /S /GoTo /D (page.21) >> +>> endobj +1765 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [372.667 660.307 384.622 671.155] +/Subtype /Link +/A << /S /GoTo /D (page.98) >> +>> endobj +1766 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [351.081 648.352 363.036 659.09] +/Subtype /Link +/A << /S /GoTo /D (page.65) >> +>> endobj +1767 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [361.514 626.434 373.469 637.172] +/Subtype /Link +/A << /S /GoTo /D (page.65) >> +>> endobj +1768 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [343.056 604.516 359.992 615.254] +/Subtype /Link +/A << /S /GoTo /D (page.101) >> +>> endobj +1769 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [343.471 592.561 355.426 603.299] +/Subtype /Link +/A << /S /GoTo /D (page.13) >> +>> endobj +1770 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [359.522 592.561 371.477 603.299] +/Subtype /Link +/A << /S /GoTo /D (page.28) >> +>> endobj +1771 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [375.573 592.561 392.509 603.299] +/Subtype /Link +/A << /S /GoTo /D (page.108) >> +>> endobj +1772 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [348.452 580.606 365.389 591.344] +/Subtype /Link +/A << /S /GoTo /D (page.132) >> +>> endobj +1773 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [350.666 568.651 362.621 579.388] +/Subtype /Link +/A << /S /GoTo /D (page.14) >> +>> endobj +1774 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [366.717 568.651 378.672 579.388] +/Subtype /Link +/A << /S /GoTo /D (page.15) >> +>> endobj +1775 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [382.768 568.651 394.723 579.388] +/Subtype /Link +/A << /S /GoTo /D (page.28) >> +>> endobj +1776 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [398.819 568.651 415.755 579.388] +/Subtype /Link +/A << /S /GoTo /D (page.109) >> +>> endobj +1777 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [419.851 568.651 436.788 579.388] +/Subtype /Link +/A << /S /GoTo /D (page.118) >> +>> endobj +1778 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [440.883 568.651 457.82 579.388] +/Subtype /Link +/A << /S /GoTo /D (page.120) >> +>> endobj +1779 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [336.414 556.696 348.369 567.433] +/Subtype /Link +/A << /S /GoTo /D (page.77) >> +>> endobj +1780 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [349.421 544.741 361.376 555.478] +/Subtype /Link +/A << /S /GoTo /D (page.23) >> +>> endobj +1781 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [365.472 544.741 382.408 555.478] +/Subtype /Link +/A << /S /GoTo /D (page.105) >> +>> endobj +1782 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [386.504 544.741 403.44 555.478] +/Subtype /Link +/A << /S /GoTo /D (page.115) >> +>> endobj +1783 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [335.722 532.785 347.677 543.523] +/Subtype /Link +/A << /S /GoTo /D (page.35) >> +>> endobj +1784 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [368.031 520.83 379.987 531.568] +/Subtype /Link +/A << /S /GoTo /D (page.23) >> +>> endobj +1785 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [384.082 520.83 396.038 531.568] +/Subtype /Link +/A << /S /GoTo /D (page.25) >> +>> endobj +1786 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [400.133 520.83 412.088 531.568] +/Subtype /Link +/A << /S /GoTo /D (page.29) >> +>> endobj +1787 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [416.184 520.83 428.139 531.568] +/Subtype /Link +/A << /S /GoTo /D (page.36) >> +>> endobj +1788 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [432.235 520.83 444.19 531.568] +/Subtype /Link +/A << /S /GoTo /D (page.40) >> +>> endobj +1789 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [448.286 520.83 460.241 531.568] +/Subtype /Link +/A << /S /GoTo /D (page.41) >> +>> endobj +1790 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [464.337 520.83 476.292 531.568] +/Subtype /Link +/A << /S /GoTo /D (page.58) >> +>> endobj +1791 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [480.388 520.83 497.325 531.568] +/Subtype /Link +/A << /S /GoTo /D (page.108) >> +>> endobj +1792 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [348.59 508.875 360.546 519.613] +/Subtype /Link +/A << /S /GoTo /D (page.35) >> +>> endobj +1793 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [364.641 508.875 381.578 519.613] +/Subtype /Link +/A << /S /GoTo /D (page.108) >> +>> endobj +1794 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [399.87 496.92 411.826 507.768] +/Subtype /Link +/A << /S /GoTo /D (page.20) >> +>> endobj +1795 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [415.921 496.92 427.877 507.768] +/Subtype /Link +/A << /S /GoTo /D (page.28) >> +>> endobj +1796 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [438.752 484.411 450.708 496.366] +/Subtype /Link +/A << /S /GoTo /D (page.15) >> +>> endobj +1797 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [389.548 473.01 401.503 483.747] +/Subtype /Link +/A << /S /GoTo /D (page.33) >> +>> endobj +1798 0 obj << +/Type /Annot +/Border[0 0 0]/H/I/C[1 0 0] +/Rect [337.244 461.054 354.181 471.792] +/Subtype /Link +/A << /S /GoTo /D (page.123) >> +>> endobj +1802 0 obj << +/D [1800 0 R /XYZ 72 720 null] +>> endobj +1803 0 obj << +/D [1800 0 R /XYZ 72 685.159 null] +>> endobj +1799 0 obj << +/Font << /F16 823 0 R /F8 826 0 R >> +/ProcSet [ /PDF /Text ] +>> endobj +1810 0 obj +[818 0 R /Fit] +endobj +1809 0 obj +[818 0 R /Fit] +endobj +1808 0 obj +[818 0 R /Fit] +endobj +1807 0 obj +[818 0 R /Fit] +endobj +1806 0 obj +[818 0 R /Fit] +endobj +1805 0 obj +[818 0 R /Fit] +endobj +1804 0 obj +[818 0 R /Fit] +endobj +1811 0 obj +[693.3 654.3 667.6 706.6 628.2 602.1 726.3 693.3 327.6 471.5 719.4 576 850 693.3 719.8 628.2 719.8 680.5 510.9 667.6 693.3 693.3 954.5] +endobj +1812 0 obj +[525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525 525] +endobj +1813 0 obj +[1027.8 843.3 877 767.9 877 829.4 631 815.5] +endobj +1814 0 obj +[670.8 638.9 638.9 958.3 958.3 319.4 351.4 575 575 575 575 575 869.4 511.1 597.2 830.6 894.4 575 1041.7 1169.4 894.4 319.4 350 602.8 958.3 575 958.3 894.4 319.4 447.2 447.2 575 894.4 319.4 383.3 319.4 575 575 575 575 575 575 575 575 575 575 575 319.4 319.4 350 894.4 543.1 543.1 894.4 869.4 818.1 830.6 881.9 755.6 723.6 904.2 900 436.1 594.4 901.4 691.7 1091.7 900 863.9 786.1 863.9 862.5 638.9 800 884.7 869.4 1188.9 869.4 869.4 702.8 319.4 602.8 319.4 575 319.4 319.4 559 638.9 511.1 638.9 527.1 351.4 575 638.9 319.4 351.4 606.9 319.4 958.3 638.9 575 638.9 606.9 473.6 453.6 447.2 638.9 606.9 830.6 606.9 606.9 511.1] +endobj +1815 0 obj +[777.8 500 777.8] +endobj +1816 0 obj +[583.3 555.6 555.6 833.3 833.3 277.8 305.6 500 500 500 500 500 750 444.4 500 722.2 777.8 500 902.8 1013.9 777.8 277.8 277.8 500 833.3 500 833.3 777.8 277.8 388.9 388.9 500 777.8 277.8 333.3 277.8 500 500 500 500 500 500 500 500 500 500 500 277.8 277.8 277.8 777.8 472.2 472.2 777.8 750 708.3 722.2 763.9 680.6 652.8 784.7 750 361.1 513.9 777.8 625 916.7 750 777.8 680.6 777.8 736.1 555.6 722.2 750 750 1027.8 750 750 611.1 277.8 500 277.8 500 277.8 277.8 500 555.6 444.4 555.6 444.4 305.6 500 555.6 277.8 305.6 527.8 277.8 833.3 555.6 500 555.6 527.8 391.7 394.4 388.9 555.6 527.8 722.2 527.8 527.8 444.4 500] +endobj +1817 0 obj +[777.8 277.8 777.8 500 777.8 500 777.8 777.8 777.8 777.8 777.8 777.8 777.8 1000 500 500 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 777.8 1000 1000 777.8 777.8 1000 1000] +endobj +1818 0 obj +[816 816 272 299.2 489.6 489.6 489.6 489.6 489.6 734 435.2 489.6 707.2 761.6 489.6 883.8 992.6 761.6 272 272 489.6 816 489.6 816 761.6 272 380.8 380.8 489.6 761.6 272 326.4 272 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 489.6 272 272 272 761.6 462.4 462.4 761.6 734 693.4 707.2 747.8 666.2 639 768.3 734 353.2 503 761.2 611.8 897.2 734 761.6 666.2 761.6 720.6 544 707.2 734 734 1006 734 734 598.4 272 489.6 272 489.6 272 272 489.6 544 435.2 544 435.2 299.2 489.6 544 272 299.2 516.8 272 816 544 489.6 544 516.8 380.8 386.2 380.8 544 516.8 707.2 516.8 516.8] +endobj +1819 0 obj +[656.3 625 625 937.5 937.5 312.5 343.7 562.5 562.5 562.5 562.5 562.5 849.5 500 574.1 812.5 875 562.5 1018.5 1143.5 875 312.5 342.6 581 937.5 562.5 937.5 875 312.5 437.5 437.5 562.5 875 312.5 375 312.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 562.5 312.5 312.5 342.6 875 531.3 531.3 875 849.5 799.8 812.5 862.3 738.4 707.2 884.3 879.6 419 581 880.8 675.9 1067.1 879.6 844.9 768.5 844.9 839.1 625 782.4 864.6 849.5 1162 849.5 849.5 687.5 312.5 581 312.5 562.5 312.5 312.5 546.9 625 500 625 513.3 343.7 562.5 625 312.5 343.7 593.8 312.5 937.5 625 562.5 625 593.8 459.5 443.8 437.5 625 593.8 812.5 593.8 593.8 500 562.5] +endobj +1820 0 obj << +/Length1 1846 +/Length2 13448 +/Length3 0 +/Length 14468 +/Filter /FlateDecode +>> +stream +xÚ­–eX›ŬšĥÑ˘Ċ]ƒw-Š)îĊ  Xpww§X‘˘ĊŬŬŬ½hâRœ˘_Ŝ½gv;3ż#ù‘ó^·\ëZ+OBGĴĈ*f +1IAlX9Ù8ß$Ä?qr8Ù88ÄQéè$@@'0ÄVèz àäHŒĦ ï·ĵĜš@LÁĥĉ.^>ÁèŽ +½=PâxrÀĥĤ 7È Ş˜Íâ-@-ñ˜AP˙9P>^ğĜ?Ħ€]üñĜ%ŝ€]ò Ĝ?ü‡ĝ9ìRˆÀ.ŭ‡¸ì2ˆêÊâ°üCP-rŞEŝAµ(ü!¨Ċ?Ġ˘ô€jQŝCP-*ŞEġAµ¨ŭ!¨ġ?Ġ˘ñ‡ Z4˙T‹Ö‚jùô‡ Z´˙C‚P-:ZüqCë€6vozƒŝ“˙!h7“?Uhv0qĥ1³†žê‡99 SL˙Bè–A˙Aè­`˙÷=˙Ï`èĥĦ7ÂhóW Ô³?í`öŝ³ŝӑûtùkÄ?ëg‡żÚASÌ˙B¨p‹˙ ÔZ w; í_ĝ/„:eġBMħŝ ĦüúÍb˙ӊZj ĥŭµŬ äÏth1ä,CĠÛŭY†6³:€l­Af,áüݍ˙p’ê-ôÁ?îó@wngíìĝWhÄŝ/„zñ—Sœ˙Iĉŭ‡@.9 Mw˙9lèö­Žµ€Şĝ£‰*ĠÉÂô×ñ@·ää +ùĞÚù/„şëòB rŭëìĦĠŬ5.h{÷żjžÇqN ‡úżÏDqqˆ›'+7ô~²rAEA…ó@ï4Ÿ÷˙È4qv€úìôŻ_è£ġżÙ }ƒ@n Ôċˆ‰PeJCHħχĵİD&XqóĈ8ĊÚÙv´ÀxXëÂ9{ĤġšO÷é¸ğˆğ”¤Žm^*RgŝöqİóÏğ.FğéͤŸ.ÒÜÚQßaĥ6Ì]óÂ*ÍĴ'iç÷gŝ8úŞÌ ݇´JÓ­ëRםÄÇ˙I*ŬZ#4¸†ž›J+Ġ8Œ'tÍ+)am2Ç2ı‰yċÒĉŒsŸ‡œ“ĝlóÛäUd¤#IĜ˘Úëï'¤˘ŜÍuüĴ‚ĵ=!ÛY{eÙ Ċġ +ì¤]?u6™$Ü\›oôhĥ[ê(î·%׆KI…Gğ€qKï5Ïw<ħVm§\˜Î!·#A@>ICÑAé5ÄÉ<‚²ñĝĠċĈĠ*ŭ-Sħu3Ûà›}!m‚W?~Š‹ĉÌ8 xYwJ4@všÌ½+Oż&„‰G#=W_Á–Xx”ÛĴìpÙ+şı—]úú•á’-’‘ĥÍOì|Wqâ½Z_6ê18Ŭıé [vr€Míwl°6L wDxà3•ˤY!ÛÛ3›ĝĦ¨ġ*áŬħ •4LŒi'”s*×w0Á5àĵ.B3âvLŒËŝwıœ‘_CPkZöYWÈ$~Ŝo$¸˘Ä²‰wŬĥ,£g¸rêĈĄ7S+§"}ÑÈóQÔ`ÊâkàÉÎíʨ’Q<4Mċ8B6t›•éFħ^0ĵbšÌÑÔDĊôú˜vÌ˙~ÉqòŒ6RrW*ħ(@[a +ÌĴII7~\˜‡!ùÔq‹€…MÔĤĤ{ñ†sïÖŜ§Ü^§WHŸÏ½1hĝ½Ôî¸0êĈô&}µ"÷äwۚŭ>É{c n—ż bûˆöġkĞıÀ§ÁßûS´şRï@9ç,ôCßNħœ]>÷žsJ.jÊú[–‹e{‹hJëƒÓ/PyÇ­|0sʃU&v( +½–RħVËsß? „°q X“ök‚l–…˘^kÛbemU—ÔıßŜçİş—×YÒvÏżéĵ>Ù4׎!t#ŠÍo{@S³"Uu´&˘CPRêĝ·úIC­€&ıĉ‚\=Ÿ¸ïóôk˜Öq°hxçW?n—œš}ZL82Ĉ Èğy‰£Zžë‹ż°Úż–è•ğFíƒġN+íĥkMçzj?"ËiÙµÔ;í§Ŝ0?ǝsċù°Ž(IüxW-œ´ñíxĞ‘_ĉMAÏ=Œo¸yŽÔÄjĴÛ÷ s!cé:ÂÂg3âĈ-Lc–‡…§ĴÏ ’ĠYË#Ÿö£üsĝ°ÈċOqèA½U’ƒÁ%ŝ}Wb°ä³)%˜~Ëë€wj[Ú{FÚ ħJsGĊÏë _~„×ÌàhG’ġ Ğl4÷WH‰cÉn€ELü%4Žà‘0Ͳ¨Ğà‚sNP<\óÙògKh:òlW\Š“kU§ÔEç qzMñÎoµ–%şä‚FAv2·š'şĠ7îé=öe²À8êjjn,ÚÉ´4 MMħï˘B(ߣP_S°#Í"ĉı~³’D%jÀĉµĊ°ÙÚëc”İ™Z\§ċŽóë;cñ̜WâŞ#Uc{˘Yımê­Ä@&isġGŸôP•s“Œù!ı°ÑŽħƒ^,"Ôŭ\‰ ˘˘S•"äC‘méĉı:Y~³D£›WÎ%żŬ—“ŭâŒÊĠˆKX€Áj†ÑQĉ?W‡MpfÙ$öFġ3ï £‰ ċ ‹¨$fÓ;!1ìâ/‹‚zùz“Ûލ4ĤTŽ3|H„î r6x@°ß†ò½ĝhfÑżcl“ÂSˆ +Z[0­=äÍG€ÌFw"ó Nrè"QG.où_ĵŬ.zG9]‰N§9Óż_+V%ÍŬ*½L“w +‚/÷–>QœSĥûú0Œ˘ß½OġĞŸ ö`üWúzS|#wŬ¸Żh³Ül;4té·Ÿı§ż{“ôîŬŬ‡ŽkéĤċ·BΰĴ”ÉÚ`'>IÙTlˆx·şŭ§ÁµÏ-ƒ!nŜŒ†ú°k-ÎaŻ„V}F0D+#‘gTXÍ 24O~dÁp_Ŭî.ĵ'"u™ñÖ9½ócċürİcji>:GKÚyË/Ĥ´,E¤Ç€ŭıŝl2w‰Íİ0RĠ$‰oMK+p;KŬˆzÒvjıäSĤ:\ZEViùÓ&ÖpY4,$ÊÙd_ż!6Ş7 ˜éWô;Âm<¤÷Ͻgħ}‹–Ĝô;Š>ôŠäÜAFċh¨x÷wО_sY¨Ŝ׆w#_ĵ}Ĵ°z,ËŠ[¸¸Z É'Óa=¨”ċPz'|ÒӜDzLĞë4´rŸV\ûXƒĜ9yĦ˜ËÑĤ-êáĜßví$vGePq—7E€ïM‹ĝµ½ŝ—7{|ÖĈ6S=ħĤy€ÉjĴ8‡VÄ6Âï'ó!ÎÉÒğßIlà@cÒñĊs‚  rWü€@qßí¤JRÚú§¤ĉ“)ÉóŽŜA³iŒĈü™ȘÔDǔ…âÒAñĠž&bĉ$ Aa>K8ŭòSWo'ÇÀpeÈĴ×m˜ÜŻ Ĵ™Ĵı”qĜŜŠ#l˘FK:ôuôZ +~T,×µŒà3q‚ߣŒ]–jßvŭ3?l l< + ü=F[n5•ê@ê€À‚OĈ-JqBñÔp'ĈSOż ƒÈŭ:eİQöĠRÈ-+kŒIÒV莧 \ŻÊġ• îîr8ŒŜ™oıÛáeiç›=ħ%ˆ?°‰ëĉ–ĉÖÛ8f2W™·8„]Ú3iĈ‰Ö9° oôZ?ĝaÛQ-Ù‹ĉ½S×ğ'°Ĵroè&aÔ­Ól6`ÇżP÷/ƒ” Ù¨U0ßöúâàÛïHáD4üäÈj‘X(ĝÇ´ô‹Ĥĝ0[ĵĴžñw‹ĦíĈżŬÉï׉*3¸„ÊÖëSY{d'Û>ópvDğ2Á7Ğ#ĦĊY“.:M× 2beÛ•Ö…­+û6íĤVkşyr ÁA;ŸHœpŞrÒw_N9ĉOĊ£yèŒÔÙ݁”ĈŞċôÙ@ Bùq]?ŝ%ó´#ıóċxˆñ­ñZ +1ˆĴ;Eüûi>YġŠÎÍd#—pċëċkBÉ"ïß-I˜Bìû%'CBkoxàGİıĥp3í\żDċ0íoÔş2‰?ġ4݊€}‡içÚ/]Ò"77UÇn_“ÏmÛŜËùǚYp +žڊ§ÑÛiÛTr4cÇĜ…oŠJDrQ†Re9wQf?;1RŸ)Ér +èúH˘ȤÚEYUàkß%âPóü ¤ÓŜYĤá1í%Y#”Ppƒ-ÀYĴ ³ µÖ²gwU4'^SKùÍû•§ˆÂ–ç<~7OÜ6ğKwm#<„ lNLŬT~ê:ĦEĊ}áÂ7Ċ]‘÷€µ˘ÔÙàµ{ĤœS§Ĉĵİ&aĥ +69:ĵB4ii+9k™nO ‘PġÜRž!ġÖ|R‰ZAdY÷²ÖH› öyi‚£Ĥä—.oTwTĵÒÀžŜ„YÑ‰…İÜCÒĠZĥ}QŬŝÛĵiÁTÍçívÂW=n7ƒ•É6ˆ¤g­_{*Ġq&ıÊĞ…eĵe-_>ù­=֚Àıİq|İ˙2˙DŒÔSïò3ĝŽNĈd’v’OġÖá ùéo|÷Éçc´˜1Rħܸçmp{$q’on­T…C¸kŝ ’ş/E‰œ^}ŜÑԗ)ÚöŸäqUCpòĜ0T’ŭ”JO~µ¨ŻQ½vbâÈĝûOÓúNïÂËpÑ86L< •k’á"…8Ròó]pÈ$·§ì× ´‘të,’(üÙĈBÑKsĤ‰Íٜ÷îV×Y䉿ıż~‹™÷‚O¸ˆúµ+‹%Zċħ+’zò5/ù<·–!sÁâŒ8ˆë‚~2“˘7ŝôNZ)<ĝ—òZe‚§Ż‡›Žï³f=kháê¸ŭP(:ŠvĦ]ñ£|ż$í‰L“WçWBcßĠO[-Úv?;^ġÂ*5ŒŻwqSaÌ7òŝ`Pâ„pNé-ĵ’ß=övX$ˆf;ĤŒY8ĈÂßĠèıŸ÷­sğ bt.V/Àċ‰ÜĴ’…½c-`7%l÷lOĵ;E¤@ñ;ŝ-¸…dxĵÚÁNty<êeTó 3-ĥĊ+mú€ŒL'^›dœLŜkêÛêwDeò˜ŞV™²l…ˆél.î²óW÷ċ܌›>œ:Ú{÷xɂÜh4ŭĝ`ҏá\dJ}5ħœó$&›cD½ĵğ2ƒ8Ŝj²ìžŝ×(ÁCĥ´Ù?£×ĵ]­½Œšw”F$ş&KWëO3İáÊĉħĝesäĜIñ:ħÈ~­jŬ"RÁ· êP#ú•ŸöQ +³„DƒXĉĊĉwû ôÎèšż7v™şĉâñµċÒ¸×ÊÄwĊbÛ;/Ö I6÷59µmfÉâèĈâ(1öíH>XY/O AìKDò°ĝ4âìÏ_áR_µĉ­gxšŒÖn Ċb“ĊĈgLEêĦĵŻĈƒ£‡×ÊUku@ŸèŻß‡M!(1?‹ސ<íúí´#OSLê=>wè-$ˆY wċİ•S¨gĈ,°X³L³ÏViuÑ8§. ’ĉ'~ċûéX¨Ĝ„ÓĜôÒÚ]ßôӋè›_ÈÊU„¸Ÿ"J~Ğ×jËq£ġ÷L³•DŠàH0Á—Ï;ŻÈš sÒÚ¸oÔ£Ġ&‡"—-a -ŜùrDn/•Y°˜:t%GĦZeI"݁…âË£^Ġܟ0Ž{œÜÑŬíIIKRÄùÖr]ÙfÔş*‘ÌÁ,f˘4™äÊ ÎµÖ³b\ĵùŠqż<[ĵáNġ– UâBûl^Ô­tV2ŻJ£_uĈ !èŞ m™ +Ü;ŞéÈuרkJÛŻƒ‰Ŝóv܈˧ .@ZŜ6iLJTİnŞétW—çֽꍘĞüö†'7oàÍFİ29)öÍWcŽo*hCr0”ĵóW[ÓÍíµÂŽ/mNNó_Ò*Èĥ¨á[V .’ÄgŒú;„hİîu/œ% ¸G ^ċŽYí‹-ŭCݐnğ‰3͏ëï(wcĞ”Vċu)ħêTq DÛ4Wüx·Ócàħyô] ï>ê•Ô*—“¸ì AGĈżżäÖÈ|Í—=wċp%öâí?ÙN‡ûòĠeG–QÁĞ,^I¨wa„“/„wŞĊgö(kRÙğ[3·ìymŒzî{U–8pùä3ŭ܈Ïıì^SŻ0#)_rW_y·¨Kóó8Y†ĦQ<‚5]¤jNN[;Œ:hÁŻ%b\[kjaĊ=ssá~ĥHjƒvhêxBÇHIÖŜtñ*ÔÖġırÄ Ĉ½u>ÇöÉJ²™‹+Ŝ²ħƒ˘'ܕdDb‘a­VÚS¨DŞXh†Id$–ĜjRĤßÉ÷nĦÍĞ2.S0û +˙RİfÜÒ"½i뜖*/ù]Ĵĝ’DÀȒC”ü›¸¸“l†Ħr½—àD}<8 +;Ùßi*Gi§;qŭñĦ`ŭŬuOì€ +KÔÑQ~ähÀ[ôJq3Ĝch u÷Kƒ÷7|+…ÒÖ EÎÖĵaĤ„ ŭz#ŻĦ ŭbDLê2iÑôµï^˘ŜDehZv?{Ê ^Wìœ[_íë뀂j_˜óoa(”ĵ鄓(>ÜÈÉ­÷ŝê­ĦïÛĝêûFpʇ3&ŽĜċ£’}8ĊÛwJ°&èžIoA;À}E”X룙‡Ĉt¨aÈSêcÄíˆ'ÛŜ4,SĞ6ŭC0ŻVT­°'+eŭJÎÊRàĞÑÛDíÓiZ'>…šìVHc|—Ëç.L*ġvĝqdJşğwħC0yjP“,ĉ#!ˆòóqÔ7Ĉß猖xµÛZä{x?.SġM êù8Ğ[™RLe2“ĞÊRًĵħĚ(ëWhr=WĴ}êíOş‰Eµ_Jí ~¨>GzĉOÌŜ×qúÉFûj˘âocßĝ7g)}`Á.İlôĵ›ĦáŜÍêĦċ"%ĞBŽÉ%Im|’=ó&Vİŭ‰y É6‘’té£ZOí Piµĥù¤CßäĞŻB3ĝEÍĞú|—eKS g‘ 1+;:'%%ä“Üáá8cf6' Ŝş9Ġ7œuR{ÚÜîÄ +7ĉŒ3ÇY„Ù÷k‡uŬÒlާÜRúwm~·˜¨Aû WÍlsPì/Ġ€.³ĉ³†OŜ&•ha8m{ŝc8ıĦ€˙ ,˙'}퀋‰Ô2˜ÌŸS4d‘-µúUYÀDù`îĊm߉ßùÚÎĈâŻ/rìĤWˆLY„$lĠÌÑgâhgAŜĠykÉu•…$ž£syG{Uê½ŭaíq,gÓjrĉ(R‘ê†ùe2ĥĜÔ£ÛcóŽa ġË =B„ÌÚ>Ŭ ²Hµkğf÷=w‡ċN~ô{\’Cá¸òˆd2ê|ʀ½QJaĴÀÀ•uëdÊċ~ŭ´2Ħ…bùÒKÖ°5ÇħÂ[–núÖܢŝ6Œ2Óç°2ĥigèĉİ_ĞÚáôo‚ŬÏġz|íÂGĞ›6ŞŻ\pî†.Úíê³$:ĈYÉ)QmnÑ4ĝÁhÑG ²ĠşOèžR*eÙ1„ËJdĵ%”—]—‹•Ï{61ԍÙmñğRĴ3äGáë°PBFURJ°Ŭzi/³bġĵ²ŭġ=§9%|°×Ż`Ê0&êò\ ìġ:e~şq3íd%c;té)µ@…ˆ—ŞÓTĝî”kùĝż:ħĴ“]"PxR²VihàȁmݵŻÂ$“Íĝ G@V‰k7'–7.Z1“ġArߗ³ġŠêbÊĥèáûqdoòk=Rt3<šÒµV-”†$wWœ2}ı{çÙg?ŒÏ½Zyç÷×È?çKވ' ÀB˘sMûîG (÷‚Ż*,wd:=ž¸—Oà~³C†Ûñè$ÍŞ“"8ŞmڞeÌ +Só9ċW¸cŝ|ġ+2ß·Ó‰ûŽáKĤċô˘sЧz8е_|·.}â0ÖâÀĉT6ÙK:Ŝ|4'~Ĥl⊴öܜ5öÛ+×eIëö¸ÁSJää +Û\.o.ò€9WUÂ+ +„Û¨xN0[¸á°TĦÙà;‘#ċÁ|öò‹=v½ƒshu÷ağĝĈW ġ·/˘ +–ùınĤü…ož)ê„Tá+ßwßnj]ĨŽ…M=ÚW"W\îĴ­MÎdÖ€0ÑKĈ2z›ä‡}èÉÙóçr|ܗOô'GXŸ>Üífs÷1À™ +h²ğ/°4|W Ï·°oj)ż~…‘ì$ŜNyf§uÄxÉ/dôÁŻëŠ‚(çıœ7TżBÜM›î]ÍÇnKw ípŭzR{§DŒóöñ‰y0zVÚLÎI½Ü•fkĊ€z£á {=7@“9,ـO߃‹ŠÈĤom¤…ĉUOCĞÙ´F˜?!}ıï·'Z|Küöĝ=}g'ÉİU—O^ëZ†§şL°‘+ÏäV–t—ݰܗöĵcäsp9„™+4żl}ÁóIÄSlYq–—è´ŜÑî—ŝÀĝĤ9É@ó¨•gŸÉË9o5ĵŝP{‹Ÿš‡ï8ċĉ<‹\ĥk‘—ÂhĈ£XËÑġoÂ…DÊÒ1—͘J]Žöî7îŞï0 Ċ…òçŽ +?liP½ò•;‰ÇüÔvß“!ô44 _)v(üühòĈ='Fòö‘ı;pDUŠPnSJ—7i+AvʞŽ/kZW¨˙6hÌ̉g£1 µĦİjSÖGŸ=NAù"…âú]mÚ.ÒÍUäò˜&\T3Ħg„;"sœĊ(|hžÙ;œí‘j4Ú(­£éeìÁ·:%ħ–EŽĵá9Ä/ۉ k2OÄĜ#²vì.žÍН<—Û?œĞ`B­W<wtŸt FrÑt°HT£ïd¤GÜÛjbŒÑޘt:ċ2ÈżÇ2écáy×ĉDĤ>XM_uêĦ4ÁĦ“˜‹EHĽÍÌgîN˜Û‚_ |\ċ2ˆ=ƒœô™>Bê* °8 +ħÇĥÇ ½D֝ĞÎEhħ‹/a›œÈÙIoÈÌe–„$~ż›Ċ}"ŸÌû)X:‚ ǜ5Sˆü}Ár5ŜŬw6P2Ŝ°hqġTd`[ŜófŒúÁiĜĈ˜q„OÒëqċÓú’ …Żħç5O_~}N`ߕ‚ċVù½ĵ~u†£ğ’›ħx `ƒż`è›^Ó%²ĈŝlQ4!–Xá‡ßg*A2ĥŭ“ê|™‘ċËk“p²ïö“nœ‘ûšħ„5Yˆ •Ô´”?[íÒ]C–€_IËV×ÇV=ĜĤżEŝrħĠ­?B£ž_cAdós˜€ïÀÚï@Ċˆ¸òkIOaÓşDŭ´;Üĥ˘5žİ<ìä˘3ópú/ğ”U>ŭtkÌ[xëéŜÙ­;_VuS9c7ü4LÓ^ä5Û­O8;wí÷ĝQFĦħ 8ë5§ÍGĊ4esSŬȲQĠ?§‡ÔúbçWÜâB èœzêd–o‰ku+Ò@Éê pHų́+˙ê•îÓF‘nA!‹Ò톳KPù•5¨×Âkİ?yY*£µşCGg‚GnfċŻ,ùòĜÀ*"úU] +Kµ|— „ ЉKm°L_Qż;ĝ.önZ ƒL7Ĥ^oƒDž,,½?4~ħµx"ı¸vœlIŞ”vò”êŸ 2”zfŸs™h)6é)áK³Ì‰Ş Ìܔċ ^°PœpëöĠ<´Äó§bï3Ü䛒Ù Ç›.3;˜üƒ:…aRĠ²mɂ\`ßG V~Y`Ä~$ŠìĈF2Ĉ6Ŝï˜u˘Š uħ É ì˘B2I:*}žÖşX¸=Ìŭ!ó,~””‡ÓH_ìġ`ŭĥlıbúGÇ +' +EkÄ;™×X[o|ÜĜž.ßÂb~´„IèÌ­pÙ}ÉBf?›Q‹Rıq&·èĴ%˜LE8"›2şägžÄ’^­^ν€ùۉ.fuˆÉüW4ôì`Ûß³ô™C+ü¸-ÂqÎ뗙Ön§5ÉfċÜëĠek D] +Ğ>†˜ÍɁî˖Ì_,ÏŽ\ŭg[8›äC];bȐž—Ûì[ѕĴŽġL6ì~"ëó†ĉ 42tŒIà;`ï\™šħÓώñ){VóĈwB­¨ÊwĴX"/Šġu“!uvÍ ÷oí7³.ĵi¸áüyŽñírßÖĜË^.GÌĊħ +£ â’S6Œ|#ŭžphW66ڞ÷=ñ‚xĞStê·ğ…!ĝ…ĜüÄnhÔx‰kU3żsk_/U¸DzQjd[ċOìßvc|}ŒÂìŒï9mÎI“|wïĥ"ċK܎ÎIĊAKë§X —ş)IG(̃wŒ÷ñ”÷$xc¨´ ĥoAöŜég=&œˆ˙#–ZîYv½€YÊÑÛĦĠošÓĵ²=aÍúߑ[[,1bİÓ×ñ¤ZĈNĠYċËaAĥĜ#GáòäÀTɎĈ>Ġħ’ĵ·àħ€íú[ÜĠŸ F:݃îu‚gŠ­+úȚK+‰)2=MJˆñ NçfJÁEŽròmıb˜wi†öŭĴp8 ϋY²Â€——’—ñċgíĊ‘ĥ•T}ÀjŞHü °EL™)qáĊ)q7яË.[Ôx œ~üM³É;'µëEÂċcSöÙYŒĴĦ ż;ûó÷ġäwê{gÀU)^·— %,˙è“!uB ÈŭIQĊ6ëÈ6“-½"‹ĉxgÊÜE—;ZK³ĵHQ +5„Ĥ~ïäĉ§Gĥ<4&ŝ!eÔĝl$Ċá£kûĞA.´°È ?kŒ<é°çîDĵŠġ5Ìv yh}°öaRօ“:Zĵ÷aígyx܉{G[X •ĝPì ³WèD] +‚ÈlŜ•œ:%˙ÇWĉWHĈkBċĦ\4Ioèù(eé•üĖßÄH§÷&Íâß ÷7?óӏÚ|L*˘G&ÜħS‚Ò%‘—¤7´7Óâşù˘€ömM”8Ĉj¨ûVƒY|w2Û˘“ ¸Qšä^JĈşÒôK|¨4Ñc)ûúäRgçÛLgeĉĜ•Şoŭ`t‰ÖŽ8i@Na%q&ĉ +ßóŞòTßhôŬɔnʛzYrQÔš0 ‡î§aœYeoïKmŽÇRhĵĥ .ü˜âUZ1[ߔĈ<+Îc´ŞŜ›ïñZO²^Ë àH—i"eÔ5¨n"Eˆ VÜ*E…'s+4Dî"àŝüaÄmĠtÑç“sCG—mĞeĠċH:oéxĜë` +“/é:ê„ÎöµçËÌòŻ˘œċ´ëË íèŒĈö$à]êˆyIfİâÉ0ӐŬNûĈyWÉÀ ŝ…ˆ·x.Ğ]áKBH Ĉ› /Ò0K"6Í}ĉ€ó#ĜÈ ŭ۔ڲÜbùœkÚ,ŭŭïÄ=Y(cışüÉXu[Vl›İ•ižœ‘çĊ¸ħgIÄg‚ĠˆòÙĝ½6.ÍĵL€ç4„JguĤğ‰40ûĝ3mŸkÈ˘½hô)°ì¸1Eyî€Ñê¤gä ­àŒ‡£° + eòÒ¤a‰G̀:c@_@hûüäH~GßtqĵjÄ֜'Íİ-HlÈÀz_¨IûĥGâ ¨µŜ8·I‰V¸Œ!¨+Š'0NEê(òÖDÙÌ1i½ +Xlµ +FßÒ )Ò)Iöŭ8ÉĜë60褏VsíÓñ 1è.Ò^Wäfŝ8önhŞó:lôĠ:È: Œöì¤Yc‰ŬNŸÎ3l(AۓFÌ;™+Ġ›úzê§FĥĤg²Ÿ§GĠgµï¤‡l܁Á˘ı„rփùmo7Ï2íĦxĈli8ߟ$;ù—I“iğosÜş5lϨÒŭYè $GJĈÓ° ùÍmêÓ·˘’$6CŒŸŸYÔ6>;‚{~êèÑ]Î]ĊŠŽŬQÏ) V’òڙ^7>×´‘~'Ù|d÷™h^dÙâ‹gÔûĥI—À2żz6`zÀżĤċ*ŭÖ§¤ÎöI~6Äcx€ĉs,,û½™>,˘CŜâ}ÌgŬêaa<ĤϏ21ôZ‰Nç´Oş¤br³HO„è=v„Œ£Ŝ?1|ĈÜ|än+d•OË ò%~ĜßigZ h~ĞYéšÌöžúìFPÊmĊ.}%üŠÍ-ó6+Óր +•Ş9_—( +‚şg—­Ħç‘ŭ˘Ü+g7\ğ-şÚĵA]›żGĤ 26|S‡>Ù=Î1j[ßb.P˘ht<~òsĜdfî0ahġ{„[Í)ÊMq­péœÍŞzñkf$ċK6ü_€ħöZïĠí˨.úzĜá~ı&û”ÄÊh›c~=¨8qxƒƒ/{³=k;ZŬê2]YÁŽdB ó5Š ˘û´tLÄ}İÖÙçàĴ„ġ—Lö£C DÁÑ /0÷K9ÖĉñU'ĉĤöġBÔâ :ր“ĆV…_i_µ‰+Ċ'ĉġ%~]Îu„ĉnûÍlGÖò8šĉk.´ĴkC†ş†/ü•SŻ'b’³È½'U+ŠÊıȽĴ§Ż\x*mż>›’²)“¸ ĝ9Èé\FâŸġ0²TµŞ/ômÁó€ßÙ²bçĞÇ Ĥ˜#ŝqm×Ò§ĉIFĜż‚É$AÇ1ĜUDy +ĉ²ĜÀ2XG²+ĥTkY€sïÁ'äŭ=2Ġ˘HVXO;UĠ51wטa_`ŜÏ\‹Ü#iAü:áydc›E‰9,3¤†ĝôŞ29JÍÍÊŜlÖLúfWrŜrž7ssa÷G ċïĞ[ğBڏƒ/cz6ĝ„3³)´ü|/_üC굊ÀÎ f­œi†iGŝŸß¸ŻOwŬŜ´#Ûò„aa !Ġ›~\k{,‚“Ş íŝ<Žy1˘G òµ’ 뙀ƒ”6OĞhѨÒTĥ£#FlñĜóKÌ ‚zżÊ—¨é`dX EœĝPq„R—“ò̜uŻN$§^ 9"ÌéĈlĈK¸k M{Šŝ°}íÛpBÔßïhDĜÇÑ×D€Ĉœ{aӚtH°A÷ЉÈÏ!5Wµ^\cÜ´ıÁ+e_BÊ\ TÉĦ˜ċG_­`ßh†˜Ĝ"³9;áGäñËĞ9G16Ğċŝž#ǵıĝ ˘)ÌÏVx³ê˜HöDŸ\‘Áë&OHUQûáRô@4‚ìüÑĥ ¤o˜vğSyħ„ÑΑkV·ŭí\Ïñ%BalVħŻ/Ú/œx™Ûíi!e úœĉŻ6‡jÒcĦ;àÌ×Ŭ +íĴ›ŬJĊ›äí~ RNĤ‹AC몊ĝ£=Zd~ÔO§W³ZŸÉvïܨH˘û%¸;?zµġ8èóÍï$JAJc\­rÖÉnqžk³-O%RAŞ2½Vm‘%ÖĊZR1½H~ŜdCbÜ#Żá\fĦU¤"Ҟ.ÓNşóHċŸ­½–L2²ß\uw§Hċ”ˤÜX}óTlE§kşÜ£|ûX‚Ì3ġӝ ì ‹ĜewğŒ26oò³3ó “–£Húż ħÚŜğ~ -1ċĦ=ì„y87&YâäSJ+ Žİħ˜ñİĤ>ÙU}Êمë)™ċıU­ħ–ížµ ÀîÌûu†ŠġK3Œĝ¸ŝˆ$–×7Cû¨Ö^‚9 +%@qqԛµĤĴO€—vÒNYĥ#Ŭ9q4z„\ Ó´ĵĉ‡†hߣ? €Şd)rwäAüŝ½ä6§ÌÇkCxÇP~äIÇŝnddùĵœóĈ:Ħ2 X4ħ`×dĞxj>6˙JO>½¨@_òÙ,#[ud%5Á{ŬĵhÀu6ĊYHzdò·Ñ’š°öç÷ +VQœ9ğ˜ŝöç3°OdYwz0môr.|In#™?İ Fáqˆ?O·éè~B–|f<žÉ“Ä\ğÏG´Ĵŝ•LDpâ+t+Ŝ(ÖÌİühûˆbÍ {% àż’ó]t¤V—w\Ĵ´VÖì¸a¤{êRÚp1z;7½rŝû£ƒ˙`Äúì^ÊŞ5• +î;O·{‘/ËÒCq'ÜTĈÀ!mö{'’“ݵĉîĵ ïŠXIúwÓİß:­nx½ 9ĵĉB†“dŝ×SQĤ°j^˜ş]]`™½ĈP6™‡ŽïŜ\Jrržku£Żz\+{pâî1XŠ}ulìżÌs`D‹Ô|c%ŠÓ\²|Qˆ{?4š$;àâG˙5/Ü3–ÀĥH Ġ#ŽèÏΈӏI2’‰x‘Ç6j>ï'Ŝ>Tàú~Ó*Êó¤ÓšadF%GÜŝ• çôú)û AÁOa)xŝˆhŬEÉGN<< d]àl64f´´/EŽ£xóz‡-n• L°'G„s]Š@ĥ;ĥǙ€Ê8›O}-˘Ŭ=g É MÉĤGĠ*99÷ġ²¸ĠĊ°?Ì|6r9ŬÛ#êv·c]Áy ıgÛ6M:ÎÎH|ƒİRŜgˆ+Ĥİĥ>>Ċ—8ıUoĈ:͆bšë¸c³A/ñä+ĵc3z ÍàGAÎ:ÖÙZiOZÇnˆeâX˙‘tĊ!ç*éQcŞvğ…žT3/Çë“í‚ÍO½Ww@ċw’,ŝßĴt´ġä}û½Ès™ŭĤ'`—´Cİŭ#Ğ^MşO°ßbx¤żÚ3}£›[µ<üğ—ĉDH=–ñUSîĥ_‘ĥÑ!²ÒÊıQ£³D˜Ğ)~ONçAŭíSÚš´E|Ĉê=ċoüÄû QO\y%ĈÄñë&iÎ2Ïhŭn‚'[1n\0l2#ÇÇàĝ¤]ċqŞ-²,DW$Ċ5IJ§²›ôžaÖ÷_YájWĠlŻmŬJ w”UaC +u¤0ßş’6ÀÒeÖ1bjŜFAħğREšÄ#/iğÄdF¨>H/Ħ§ĝ{ɘ'™ÑZ<îzĥÇ Ü¸AĞ˘Œè4yîġy£˘·v'£Í{³iÛèĊNl2s]%γ)ċ]zòŠCdj Ú´ċ ÊxpFÏQWVf#Hžà§v)-—a‡çĜŻ— úĉüû^‘Ċ7}v#ĝDÔİ]ŬofQI‘DólÏW?ÛjñËHr@Êguc“Š™ċ%]ïžZ’3œßğuE_cŠo÷ ëŸü "“‹/q‘!Û˘÷Ç +i×Ħ²… ²L{ó½DXW(i37ïC7y%Zŝœ‡Á\~`8Rß#ˤž˘‡¤ÉûäÂnż _ìvı àƒµĴ2+.•ËŞì4Rbö`¤ íuE”ßH›£m°4ŒÔ´Ö5ŭKïéÁhŠĵíÑĉÄ'\íPÓï2Ö䜑ı2kçMín?ŭâm /ş_ĉĜGq* +ÂM1J‹ğ×Ĥ™,#ĈĤ!W}íF2dGĉ7ˆ™FLˆ4ݽ*²,Ù¸?(§‹Pİ× à\0\ídĜ—ĴEJÖÂ{É@·Á"mwS£HâUŽŽ•ĠßW)S¨ù‹Q×È[%QÏWxšĤ ÛéPgP9ĞÛ×?M|ÈèÇĦܵÛHb˘óQ÷ÂR8²G2½˘ë—ĞĈ˘QŸ›%W÷%Áác61‘pЍ@:½[ÔşZĥ=äöVܔ’–Óßd‚ ÏJ/ÁŠĵOjç•/°IFWĽÈ,Ÿü‘:"“­Ŝí¨ĵvk +K´áŽÀžŻïcuˆW$~ô³ŬQFÓdÇœ·] x £–:iL-EE}ûQ5°ŸÔamŻ”²ušŠ9pÑdôjù÷ŒRÜ|äAx@Y3ÄgYĤék5—‘ehu§=zñ)ħıږ˘şÂí)’ÙÌj¤%#O³ÙĝÏñö™w ˜\„—üT{MEO ‰šT3˜Qᚖç‚eI÷ûĴ™÷>MWòûv;"èŸĉè ™'LsġR3ž$rBvD瀙RûL14 ³wŭL·MŽ ƒ%îuĊdYP*‘PϖûĊZ÷‘܎“,&kr߄Ê-˙Í·l”Ĵ6‹@Çν3Œ‘MÁ3JàĜÁ§ôŒžuñ˘žEê£pçu]Cħ‚Ìŝo(έhË'Ó`hR-+q´Š†ŭ +Ŝ0 [MÎĜÙŞèĤAD]Í5TĊ%!>#”ßËBdÄ`G$\&}j#ü­ĠßÓáîF ÖŞŝš/;òñċQŠqdCÎtd\‹Ye˘1‹W +GrKsĜŸŸt1°pÂĠ0ğóŻo”×ĵ’Gìŝ…'’x‚ŻX=ıĉYœÍĤCñĊ•U.~½AŜàË¤·óTV„êR =›~ZoÖwuß,âï”Uµ‰ž8&ÏŜ³‘ÀÜÑt)JjĦ,)eG, ´ĥJQüb²Ħ{ñŝl°vUméW A§Ğ–XLžÈ˜5_Ŝ÷Ğ"cŭÖ̉)5>ıx´ +5ßm÷Nğ…‚ġϸ÷}˙ß k- +endstream +endobj +1821 0 obj << +/Type /FontDescriptor +/FontName /IDSUQC+CMBX10 +/Flags 4 +/FontBBox [-301 -250 1164 946] +/Ascent 694 +/CapHeight 686 +/Descent -194 +/ItalicAngle 0 +/StemV 114 +/XHeight 444 +/CharSet (/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/a/ampersand/b/c/circumflex/d/e/eight/exclam/f/ff/fi/five/four/g/h/hyphen/i/k/l/m/n/nine/o/one/p/parenleft/parenright/period/plus/q/r/s/seven/six/slash/t/three/two/u/v/w/x/y/z/zero) +/FontFile 1820 0 R +>> endobj +1822 0 obj << +/Length1 1799 +/Length2 11435 +/Length3 0 +/Length 12422 +/Filter /FlateDecode +>> +stream +xÚ­•eX̖­qwwwww× ÁĈŬ5w÷`Áww Á‚ğğċöwÎÌIfĉï}ĝ[µkݵWUwS‘İŞ3‰™;šܘĜ˜ÙĝJâÚlì6fV**  ‰›µ£ƒ¤‰ÀĈÇÇs·°³Ĝ¸ù98ùı8¨ŽNŜ.֖VnZ şŠxbö@k3€’‰›ÔÌÄ îhf tófˆÙÙÔŝ9á +Pş]<€ĉÌllsk37€)ÒځċGrŽž/›ğ;ŭ÷–Ċd +@ 2IY4wt°ó˜-X”AZ@“˙Ĥŝwsiw;;eûÚ˙+˙³obomçŭ_ŽöNîn@€’£9Ċá—j˙mNÜÑî˙ÈÈı™ĜY›‰9XÚĴ˙^²v•ĥöšĞZğ™Y,Lì\˙Z:˜˙o  Ĝŝe€EêƒĴ˘˘Ŭçż6UMĴÜ4ĵŝÓöŸê1Ûbícefee‚ŝŝû?ƒ˙%&ċ`ĉhníz\ÜoËÀ— `í`ô½@ŽY˜Ŭ@G HüŽ.˙\'7€EìŸ7€EüñX$ŝ/€EòñĤûñ°X¤˙€EĉħXd˙€Eîô˙HOéô”˙HOċ?Ä ÒSŭC ½¤§ö‡@zêˆÀ˘ñ‡@³kŝ!şÖİk˙!şÎˆ¤û‡@çLŝC s&öN O‡ è]ü§´jú‡@ŬÌŝCœ OfŽööz°ħ‚Ì˙B|À˙ èšYŝŭp˙SÀô M\­ŝ:ŠÁâ‚ZXü…˙lZ˙iÉñzüñÏ£ğË_í@%–!Èô1NPVŜNV@‡ż*@kÖ!(%ÛżˆŬ_JÄŝ/³ ù˙´âu°vŝµšĈñ:è°˙Ĝıwú³ jĉdât°ZüɌ“íżV]ŝG”œ pA—gíĝWül Ñ˙<üÈèúÏWò_5 <ŝJ‹ 4ĵëŸŝ! Ç_épÊ]A˙ȂFtµû÷ÇròÇț• Ż+ċĉéĝ×P÷ż”°Ç_ +ÉóŻûöú Aí½˙BP€>́:ù]ŝ-ġżéÄĊ½|™@Oˆ‰ä”€‡‹Ġ˙šığ€˘vû׏èĦŝ7[Xƒ]@/ ÂÊ˘£™@ˆMzSXù'İ™ +hzpqËĉċ†žıNÄàċDpğ’1gúzíçÊ/˜(ûû¤žŻ„Q~&/2Ŝ÷=Œ÷żĝ´j_QòŜs">Amošż=ċW™Ŭ/OÑ)Ìı:ÉW•Ô8€]#ëĠóĝŜ›ÂÍ£-ŭĊN3<´žšƒL -ı<‚3|Ŭ-% j}:ĝ“M8\ Ï+ÇwŒçB¸ŻÉïFĉ“ÎÓĵ‘wtŸ&0ê>”Eí¸UÊԉĞ~5Ġ[#ÍfÓ³ğŽÉš§ıatÓÏĴérZ­™Ï-Ò}RçĴ‰”çAĥŽjë,"ÓĞK¨˜n^/è°2ÖU'™(\$²RùŬá#pĥġ}%­DÁFw‚RK›EGù[žC!t%~1Tê­ú{@&‰kBÊĦtqm„Eı*ċÂ^“ÜFòéxêŠx ·UQ‚³äG´KÁcx)ô(۞† +İd4eïĊPŒĵÌ#üÒ'Ċk_îÀûĤ›*ı8)n§-ÒZMšğ odÖKaj:GaHvB}MJm­¨È&6‹ÂÁ%цÊ:šiq$6û'­pĦ݊—?İJı܊6˜U˜ ”%`4Ĥ8  +S{öĤx(Wk†Ŝĉ^ÁIĵC ĉm€ĊZ ï!f-”ıdv°ċZ,˘ĥ~܁‘ÈÏJIûD°ëœÇŠĝmqı¸j8hˆK@9× {QH5 c~”5R‡¨]Uŭl'mvÈj`)xĠo”P@]İué+ìŻì·ƒ2×|‚ÌÊ5ˆ[ĥòÌ)ˉġVĥ³–k'“+|ŝŭĞFÀ(œQ‘Áì#î-8ĥt@@iğƒĉô…KM/ӗ4wJ"g6[fĴĜí|Wn´Ü"éqv”ö탠ÀÉËHf—&gL +?÷:'’ä…3¤µċTŽSĝ'ܽ1'ÁOÉ!Ĝ(!"C&9[¸#2üö„ {XL'Ħ­ñù†ĉ³Ġ­û2tÎ!! +¤Öï+‚¨ŽŞâ¤Yżŭf_ô>İŞâS.y@£h2>Šĥ´â9:)Úe(ğJ' ÷—_FQ³uÓĵÈڀᇇG[Êr÷µ›°bÁÒér¸M×Y[SËĤh5ÔV#JhBžWS$RßN£Ü,C?F1ĝg€§ığ:c™ >ġ,.éL\[GB20Ĝ͐qv`-Â2ŸöŽQġ|éUsan½Oğf‚4Ûk“¤DL$ßûP””u§<żÏӛ{wÜgfÉIû£ù€oŬ”qÌĤżn=Ñ0cĊHuMĜ\ü~9íÖJşzŻD¨?Ş}lnİV~j‚ÛxÌÙJÍ*¨t6—_NFĠQj'%3GwCL‰¸·ä{Şôô.0˜›fv _Ĥ1 Tğb1œ80)‚‘ܤĜœ‘£OÙ'|Ŭ2TÉ:Ò;ò% ÷Û>Ölçr 5&”&zù]­ÎÜSw²K"½n²Hĵ Ú#T´"'Yt&m0˜SĜfxĦ׸b!us§Ž~Fñ@ĉĊú¸n¨•›J „¸Íp\?Â|F"+êŞvGg|ôÊ÷ïSĞ& ‡oË$a:9À<,û)ÚĦxŜ”À@äkÂtàòUi,HÑnÔYŒ£ñEĈ›v£„şJQì{à„0@%JëË@acĉ':Ŝ=ĉÏá‹;*鴌m<8hÎ+ëTşäĴ%Kѽž,ĉ âĈĈ‘8‘Ëi´îŒħˆt5:mVÜpc·m+Î ™‚ID&ìûĵw(BĦò€í]ĜVŜ~,½’žs TXtŜµqîşš à^רÍ&TÈÒ~½’WÚx°=óŒ9ÔÁâ} oV‚8&ÁÊS›÷‹üñFŬġÎXcĠ§Œ~„FŻ)³!éhġͰû³*¤˘ĥŒf˙:Ú.áĉ݊yı´mŝ&›CÍ×ĥ,ŝ÷7V}g2 +ï"ê3ÈŻëĈšŭ‘>ċVÁèÖFc‡oµ™ ~eŻmܭLjA­6šmÉŜ&PŝkC.÷ƒQ͕`Qœu ÖĞJâH]è°Yü¸âF˜/ôXßáËÒ +È +YVÊ>Yı´"û%¤’$ç˘ööWRœD&"TáÜİHTSĦşEöŽç°ÏEğ$‡uŻ™Ĵó3tï +ŠÓÑ8D¸äZE™ñù`ĵR'uÈĦ`À­¤`Ċìğ[û#ƒ²×qEÉ +5`Áyš`zh_›Ùeġ¸“áUJ?DŽq äövû·şÎ•ĞöЧ9½asvç“Ŝ˜Ä XY½›#ĥ +Ñ Ҏ Ÿ²t_¨ċôW<.ÒÁwV½ÛÌÏ<*¤8îïݝDĊá•ÛÂVK[‰’z×g Ŭcšë]Ÿk[ı" £)™ú…9\ġ–SŸ=Ŭ"O™´ž…Ëò{)Ο‘"eٔ,>ĝk„âĠiîi,.À„ñ9şpÑŬ€["_ıàgv’§à€›qÙ3ä0Ò)rµrĠŒÚıŝ£`Ĝ[™l@Np2Œ¤_×Ê×Ói?™(+w(×QY:cu$›Ŝca•<ı˜Q×ĝ/$ÜŞR¸¤Ġ—Ĉiş™/yQŻ)coÊİ•GĊêġƒÍ(ìnXnĥİzjZP9?Ì]‘S m[t}Y§xıĤöTˆßɍ_‘NĦ1Zwö°¸Ħi‚â7c„%—†bB)_G…wá!L ôQOï6RÂ?²ċŸSIíô€ìR3!ĊÁhŒ§7OîÉ5@LÜÎÖLŽ$Żò*05Úߘ_މÀ˘·"(}OsÉ +ŬŜRYŞ’qÀ+o Ëì3Î<§Ï²ÔnĴŸ1+€‰Flĥ'/“šQ{THp3–Ê[LònMĈòY3|b~Öìúġôbıż‹ŬÇPÁËÑÂŞO×Ŝ•ı’óö"sjÓ‰íuíŽSôc;ċ1m “}´àgÂx ÇÚ!:ğ#G#ŝ +ŸbJÍ΢eâ ĥRUo;aŽ•Ċ`Ŝ’\¤Á% ç9ĉ$Vàóüŝ¸„ĝ­Y¨€ösKżŸ½8Qëj +ôڏˆw*kĊíŬÙLBe'§‚:,<£ZO_ö‹Ĥ9çImŠêYèĈûĝĦ÷§Û2@Êĉµ}~ëĉm‹ĜÊCnŒ{–ó`üëıZÄ&*Ċµ›ş˘ƒ‹ŬUĜz@d-Îlş9Ŝû]ċ`l5JE'”v–³£ĝEœÑ ŸÌ¸ċ6 +It ĵ™ÖÇ{Ò÷:üW›PŸÁñĤדg†9)&0ŠĤċŭ`pÍ^`bŽjÍb芠 …eÇñΧbÉ4J²ĜĴy͐Ûĵ½7ı8ÈrÑXí›y²ÜYʏĈŝYDĜ;;_Ù{"k‹YH+_ĵÂNİ`(‹/teĝW°Ÿ“ëbÀ&ĠI‚6­óܕ1VÖJuùîĤ+˘“lżj÷…ˆÁ.nŞA +Ĵò7ĝ6:ŬfŭT”›ĉ™"WSŬóĈ›ĤÖxĵ ^x1ŭ½A1 û­ïa=t+?ġ›oNDÍ*ĵ_-§òTŻÔYĊÁŬ”WRm'n& }ĝ95ïœc‰È²Ġß@}cĈÇ3şìMŭ™`Çŭ ‡ + £ÙáG#b( $í×E#*D™ŠĤ/{Ġ0ߗÓK׋Šİ½Ĵğù†lsS`˘È-Qgï£VNÍâ~Ûlméù=·H£Š“)/ëŽŜıçf6”HŜ(ĉÏ<żr%Tސ‹D¸T8í¤yíAc‚ı[•ĵLJÒQ­ÚHé{¨‘]5çÂ։épĞKÌŜ΢{HaĞÙı?ŭ¨ğĴ[——ĥ™¨BÍmħ +„.aoî²£+ËĜëü‚‚CS]îö *ħŻ?üNŒ£üĵÊŜş$”ŝsËŭĤ§XAZ u÷vŜ +çïġgËQŝFô]1È1Y]L˘蒳^yE—ş˜`ü“ô÷¤S:´ÚI00NKfzVÛxƒ‡,QÛpĴ3“D Žö›yföp† żŽğ­n.fä0ş/)8̛ùmÁ+4Iħéüˆ>Èż„™• ıÁM²ÂĤ’?k/x6„àhĜNñ“@Ġêŭ’8ÊO"½Ä-fşäq´)÷YĞ£Ÿ²Y~ê$9ˆŻ-êkJ.uf˘hyGĦäGŬî5iĥ)çEv`‹ˆş×3ë“ÙË|!İ?u½CÈçw.ŭŒĦ>. ċŒ= ùš£k‚xaJ0QÊÓt.Ŭ釷·×^xzÒŞÓğŬÔgaB}5ŞïÎĈ™ÚmP—Ŭ+gß#úU,>è +I`=½{˘=ÑföµŸRs9Ç'ülnR?ÇD§êAı_yÉÇ•‘ĵ zÛÒ"ô$‚ż'€UŬ ĞܟĤ\òg\ĥˆ$ċ[˙Ġ‚œâÏ+p$‹ġÚâ­;îÄċÍ/ĈĈçtċ%;Cß6üE³n sïFoŜVġf÷j:‰^Ä,jx_yĥEÉ Ġ†ŭĤ-˘WŜ ¨ÜßĤ9˘ +Yî; {>j.ğÉPĦUpóî>>˘iü@Ô ³oáH)ĴH¨ŝM<ómkŝĊT˘´ˆfƒ´ä(\ŜûŜ<ñŭ„c3v#cqW—QïP“ÖÑERôûï÷ÄŞ>„{߸,ï€ÑÜ ^¨Aä…Y|0$É5äItÓùP&Ù{9tÒaxİÙóI!Ay’ÂÎE²à҄ ¨AïÊ/brÏH‡V+›nÍ<ġî +ñU\ÛüĊ%|ĵ<+èİwßPĝ1 +#²ğ ™;ÔŻd7ä²}ĝç&œDŻOÈu¨Ylğ}–ïà8fŽ-Ì_×ŭ?ù-N[ÇHĞìó\÷ġZÍ=ü´¨Ÿxx½É|.‹Ġ +ż£(ô~£ne=Y\YÁY,µ”›Â΁ĠŒ”ט…En;œ ~‹™ġ'iP‚î ö{]ÙBv"´ŽĠŸšµjÇBĦKÁ˙zġKÙŬŸ§’-*XÓFĜaî0jìñ|ĥrMŭĈž{ĊżVµ5ùàı°QcX§ĤXÓhʨß3tsoQĴĝĊÁL;ÀĜ˙ Ë§-w7 ;aíúş#Àk²#zŒqzĤ1eDg´ëtğOWxŒ"Œĉ@öÎ6ïwe•ö+;‹½jòħñí—kñeÀSğ;1o<ĴÀŻzGI ÓÎpĦ|~¤·Wĥ‘Ĉrސ]Ĉë2œvläNëcbµq<¤Y˘ŬwĞŻi?ŒbWŭa›Òmj>o^ ÷?S0ŝŻ„Šĝˆ‡ÙNÈʋpÒĤ!ŞPŬÁ-ĝ}ĤĴ}t-ŭò˜ġû ĝTıj]|kYÍ ÔKeEoâÌÈ^‘ÇŻçŸı“x%ÚĴK›ċ-IšàġċŒÎĞ×e¸ñK7­4½ë$‡íX·TÇ[‚ŝEÖgÔ +*ä5Ĵ" màŠ[”Á$îF³‚˜Ĝ-:â⽓B+û”ı°Ù(`ùt \X˜ŭ~Tp§<ÒwĠyY7›“ÄÁWN/Ċj(c|ÏqYAĞĊŽ‘ż0ižÍ ²j+–°K"êQĈ4äee{k•NÌ9éŬSGËÌ˘‡*à‘ÂD6q_ÁÚÊ À> N!—ĵƒì ÓµĜXÛ¸yµ‚ë•ÀÌ † JĜiİıÓ'`ËüĥG?e.wòá¤@-Ċ+nœĝ½³Ç“¨tıoAé +g×gŽ/ÖÔiYnlÖSŬĊĞ8ĝû4í—|ŞXzu^2]°hŬ”!Áq3e=ÜV Á˘Aè­ĞÖä|ŜE!+ÁùħóÔ +Π¸‹éa÷$„ż¤*[6Ríè) I´"ÜÛş ż|nèqD“ÇaUb°Â[wŞâñŝ FŸ6ÁĠĤ@!ïeBs#‹ 1qÒ]ĥZÍTŒŻîĞ=ŠġB,ÚF'ŜÓîúô™fKn"‹>)rd@Áġ—°ëö"Ġq›êš;²SûZ‹÷ĥċ!ö`²ò'h,Íä0ocjüM†Bòg ÉĈ.%ïŻdşÜOx{[1·Ç(Ùħ‹ÖdW}\/çLA [dfè]S£ĉw5,²iıµÁ}ŠO +÷uĝy„>^ ,H IZ6]e˙úΊ‚:Ê?”öŭ*ë  'Qž5gIqdûĤ‡mf·£ ˜‡ƒDñH8.àBeN`ž‹³·6%jA>AŞ&1ŞaU‘ŬNUĉ~Zûh•ÇWkiREÊJôÀĠw“ĉAeÑٙÍÛBĊгñî‹h–ż}ŸfxŽÍ%ëMŜP)˙:5sğԒ²Û½.‰ÍĊŝhÖÒàÇ$h½ĝá÷³Ċ=G,Ž™2íÊdOm˘şŬ…5ߋ}ñ†bôÚE¸w…£8Ïb +,Dß`ÁĊÙ~şèŝî;zŝ{k)Tïo’äĈ´ní)ô!Yû8Ġ´1Xc °ÎĜy;#ï³ä!ğ]žĠaK£rËÒÀzHŒ–¸í1.j­ÎŽ„)T_é¤ßĤá.dËE; 1ÂÎÚÊ8LjŜ}UGJFĥÜ~ZÈá`°ËeÍÄz|PïB=ÓM´ĥŞèò&C#Ż· ĤFìo2˜^ÉUŻK_ßQјĞċA$ı5ʑÙH§"jÊĈ—ëÄĦ™Ġh@%eŸVKĊŝZ-Kċ€ŻTLŻ|„”ĵ÷òŭD"z]¤ïb3‚ŠFEıEóğ 2*½\+ôQĈÑħʤŽ}Ŭc½a£6!1ĊîÀpù#fàÓ=#éèÌyżÎÁŜ˘]˜JjiúĵV3޳'6·ŻĉÇkŝ1­>ÛġY™5F8bîrÜ)vF~B#žwñ.™v¸Òr[6.x˘ßiIíŸx5aƒ+şCÉM!<$ED4„œêċ‘ú;†úħ8òĥIמiz\Y÷|Ҁ˜Ĝ`Ü3ƒ²†;@A2ŜsÁĈĜl<ñĦƒ¸w[C7|Ê0u2·ŽÍ ùzVY;VoşAİà×ċÊQclô¤>¸jż]%:=b%œjŠ€ë‹/¤- Çı!™‡žTR[²àˆ‰ş‰Éèj49úzĤœvRħf ÓOAËABĦĠeŬ&™0`ZĜ™Îŝä↪°Mɨ”ˆO^ĴÎÔĴÖÈĵĥdċCXz-Ż ­“Ùĥ\{&²ß%‰S\hêŒĝ‡7áÉùşp‡ĥ éè7{$¨§Û% ö0uwl|ùW]S9Ġ*…["s”[%Á^î*³ß½ ;]ÀL+DĉÁEB]˘[8öCSQ'üˆmù1ĥ)à`‹Oêe†ù?9‡ĥ'}ĊY…א5ŭPrí“%T—JYġ†ú‹â6*.'²Í†ü4~ĝmĊ9UġFÀÈü<Š;z“½iV~Biŝ<Çàħü;ŝs”ÏYŝe.moĈȋʣAîkÄ(ö˘4[˜ÚyÑÍ:rl‚2!ƒ!Żàĥù·wÇd-²Hsö ‡`2İ$oĞdß%Q+ ½÷µ"­Àŭ) ÙmÜIÍMDïeĞ£ĉ·OÒĉu™—3 ŸO…ùĠkÀĵĉ´ÄS:ĥh%jë*GE/5áeŬĞDÄ 9ĊhȓÚêÍi—Îşâ’êɉàùSŭê¸úÙÚg‰OꍂÂ6qĞ]µzNxWóŸ%S-rÄ2|:üú ÉĝÊP> UUÔ>–3—ò?´'p?4} óÉÜäçUğq­àĵCù-Ö ‹‘F,Nú—>'9qížf‹žġ,j}ıìg[ Ŭ0kĤW j˜ +šaawÙX™-Ôw–xĝŸĝÌjîIfoŒ0'‰Ç#iĵ—Á¨ÔËÚVŸċR˜^e%µù‚¤³ï”²vmÇĥ}zîêEğ?ü‚x&›z&0ïçDËEK[|ííĉŝMÖ?Ġ.=?ÌìÄ`LM¤Ğħŝ˜Ëx”Ñ~i^AlxnÂÀu›!3`ġ]Ċ)Lİ´CMïŽËc-×3ż4òS{â €vIĜÎç,iœFœĊê~ƒŸƒ³êG8“˘ù\Xğ¨Üál­Ŭ°R½ÌŞ×öDg¸*c?·=Ĉΰ6ϋSà—Żf1!~ +µÍxr† …{ÉX.Lf‚›óN쏚à܄…_’›ëQ”žO5†­é™e‡‰‰{á*Hè’3ħ ş•Â^Â׏_a¨ +£Í™?¤?ìïaħšeÀĊŽçÙ0Ğ IwÔêŻÜ +ÏypUŒ5 Œ‚9%ÑRé*+!cÎɇÄr’9ó)| +I„+[È1}=ÖȈG*#zI-ĊŜxÄc¤’KsġäêLHcLÓmy#a˘JĥrC>ñôMŬĝj°rAU™Úԝ\?˘Ì·µq–ϵüXĊ=ŭu0şt6żœ5+\üÄV n‚I:ŝ*—‘“Ë [”–˙Ğ|[i[­résekÜ[Ûĥc.‹+2Sàċ–ï ôúk>iîm\a픞żš{×;ù¸/aí><ÈpżÛ–‘3îûDü£2Ğı7ƒf,ÙÈĜà·Tb|Ëır*Òéwöz5 ĉîßQ—^ġ}¤x^À0 r­ßbĞj²[ Ŭ‰bt)UF“6™ T†…H L,Şd­5#böŭ\’óÁĴñ³sŬ4€ïx¸ŠÔc‚­ÏŸê Ĝ{çğħ¸ñ›ĵĠĝB +ŝ£žÂmt bÎ˙ŞJö²Ğĵ²a›=CòÔ´óp<қïbpIü¤c۞‚Ĝ×ġqĘËn4‘ĠYŭ˜,$ĦŻO­F%>Š 5Q^ŠÀÖíC'­ü…9P7lœ\Ĵ|ÊħR˘Fz’|~ÀbùôôQ Ó÷W¸/|Ĥ_ûvš•€7IÊilFuÒĈœU“*Xiŭ Ìğ,6w³>ù›Ż4ù ³+)Ë%Ô(rÏċOSwùVrêŻ¤hÉ Œ¨²Ë=Ü]S‡‘iŽHÖÎŬʙ“Ŭŭ(dÖÁkÎgüJ•<"I)_Ç·Àéí]Ĵŭ<Äí\š£vÖı [„“0ôO´`â_Îİ3 !5™ +Ġ‘ı +ħô.-^IMÛVTëQĠEö$ž5Ġօ#Ç{“SŒ3`e(ŭm¤v\9ĦFg1R +\í·JĉpÛIä†êé<ĵĊŒ(xrYOZIBÖyœĦ³î‡ĦX¸T˜ĝV˘I¤y­à£SBu'ıKi絔MÔ,Ĉ µÈ& ˜Òċäa§x7üĴüáhwżĵé#N"Ĥ2$&A’€ò·Jñ;ġT¨’.36vŠÑü\ŻÉÀ³ Ò~ĥ·P.7Êݑרu° ż^Ѝŝ3µşo3y…EĵÂĦżf(­:ŸY‰"†½°{i7ž:lą§Ë kĴM·Ú İ£²ŝä W{×71È´d<¨häú> ¨`lDÓÔĦÑ;²4îk–°{ĵ?§]•ï”R0 $Ĵâß~UöŜ~Ĉäü†Ä›™}@ŝÑҘêS. n̉àéòÁp:}‰( Í´QNmžc˘³ za)Ì?ú …"w2uî˙lRYú8îú £b*B²•ıeĈ7nĈ.^_c|Ŭèû î“,™íÁĉ6§x—&ĈAĥ^àĊ@ĉğa‘ġê;ż§4côF½mLKyžJŝŜ›ĉŝÉİċ쌰Ĵ³Û·fZÁÌi\]ċe‚ ÇÊ ­˜ħiAw˜ŸJ,ƒyħ””¸77çiâlkñq êß`ŸY鄎!-2ı÷6Ħˆ7Ü0>İ.ë)™\Ĵq,oŞkBÜdšE„M˙S½És´TQñğĝí,Á.ä5gçuhúJgÛB)—-Uğ%Á5G–›˘Â‡U!ceĈ1ôS8++îLuĜ2cK<‚qT‹ótêUN.Ô Ĉ&YÎúd=Utê8~¤Ċ÷مB?n„PBPŜe…\fĵtwr(£ŬDYkI䨔óĜYK8|ŒÍ] +qÜ1@¸Š(…ŭV­àú2[K ŝiÛü‡sŸ,ó͞àéĝ xÍjċ@ì끗 %$§}âKƒÓ÷!ᝳİÔk,)£÷‰oßÜÒÄb¨Ÿ÷vVdĤŝ ġ¸ )–ÍmĴċL)Œċ íĵẨ çgkî4vhĈ  †K`Ŝh™¸AŭT¤–|sBĊäĝèŻ·ŽI‘?$şĜ4ŝŽláŭGAhÜïfŸûçÓÌ<ĴİôÓÜ`£e{i? ĉ·5”iÀbuâ¨ÌdOW +m{ +ğP´J£7Ú •nĥD”ñĠÈûu|ĉĠò“ŸdIÖ+=Ċ[…Z)I€0…|4ù÷ŞÎ’d>=;’ÖwZzœŻĉħù…Álíà<ĉí·,¸Gċ<=G²2–ú0ŸYkî|ĉNĜ֟ÏKû¨XéyŒ9òż^vÛ0ö˜^Nô—Ċ~‡E_ЧJÈŞÉmqëßĞ– q^AîôQꝭJDñvB÷ıûià™…êûFŒ§7ĵ uDÁ‡íìÊjµÂ1éö†Ö{žj­°4,ı †Ħɐ‰Í5éÀÑrôá?/•:œġ½C|ġlgĤü²ĦğᷝÊ'ljç•䢙œ³\ĉlĥo3BÄĴc›lúüğUöš—1l2¸9Z—³*)NWÓ~Ÿ‰ ˆCĠÔJĉ,ĈE“‹· ·Î+\Z´ôeŭDòħò!‰İ1)Aĉ•x·5p­ŝ§wYÒ.úCwÇĄ<^[³ĜMëçquÚPÌ“\FgvYÎRïsÂ#ƒ}cĵ‡öÇ9ĥ=XŒoŬÀ İލϙw·ß-°:[KÀ[!`çÁ]ìÈàÛ|Ö8û?xÏŭÂÑçƒĝÁ`£êĞÌÊĦàkUÁñ½(whêˆhy‘â?V+ñĠR˳ĊA)‰Ê,qy(ïóŻàk•OÄé³uiAMûh´ïŻ:EÖBÚ\vÀ61¸Ħ{×E” +Î +&mĠK@™À2îrV¸T­¨Ĝ7’é.úrŬ₰?Ç-ßtì Â.&M{˙- ŻZÁ@ĝë(7ħÒ£ÜÜä˙öÄct +endstream +endobj +1823 0 obj << +/Type /FontDescriptor +/FontName /EQHLLW+CMBX12 +/Flags 4 +/FontBBox [-53 -251 1139 750] +/Ascent 694 +/CapHeight 686 +/Descent -194 +/ItalicAngle 0 +/StemV 109 +/XHeight 444 +/CharSet (/A/B/C/D/E/F/G/H/I/L/M/N/O/P/Q/R/S/T/U/W/X/Y/Z/a/ampersand/b/c/comma/d/e/eight/endash/f/ff/fi/five/four/g/h/hyphen/i/k/l/m/n/nine/o/one/p/parenleft/parenright/period/q/question/r/s/seven/six/slash/t/three/two/u/v/w/x/y/z/zero) +/FontFile 1822 0 R +>> endobj +1824 0 obj << +/Length1 771 +/Length2 1151 +/Length3 0 +/Length 1689 +/Filter /FlateDecode +>> +stream +xÚ­RkTבŞĦĴòRIĠzX%róÔ + ˆħh €<$f&dJ2C‡ $ âƒJ޲,b£Kž˘˘TXUê–X…[ÀiáËëEŞVEÀ×°K˙Ŝ5η÷>ß·gŸĉ%gˆ l,ÁP‚Áar„ T&“rĜ€<³Ù-‡•‚ĦaJŽ@àV뵀ğ°ùBŜ +!OĦP,Ŭˆ#İĝ„Ò'E| ÒÁ8˘R˘@Ĥ$4°ŽìĦRjS!0ad‘V ÖOŜÈëá τ!&…˘"À&8A)ĴIORTŝ;Ò§ż§2a<ƒ4|ĤlÒiÂP­@°šÂZ‹‘Ó`ÒË˙Öôĉ½VğVİ›l?•ÔßxÑ˙T`şt=@†A0ŽN—ĈÂïÌÉ`ÑëĤ³RBİET"4U g%“½òŽdH E!„JÔJm<…(4Ŭ ™ß”–<^˘ŭói§È(%‚ÑĈt°˙ROĠœżj2$1€6“ÍĉBò{Jš6LŒŞ0AS—ç”84RÈ%"+0q‚B°ÀÒ1‹‰byÉä5†S&ßĠ Xİ“ĞF†Eï06`iጌ)àïż‚LŒ\ÀàòÈQì•ŝ€ÏcçüPÇq%Ĥև è}­FÈLaĜĞ(ĥ[˜*`ÛçûÏì¨ÉWuw¤g,´ŬÖ~aûiKs¸7ÀíŜĝK4üÉÛ]?GN¸”ŒD~ǂÔĵ>êQĥĠ$gmïqµ:{+Èg=R '&ϸRÖÖú‘îÎûĥĊƒé~ġ~~/ó‚cŬš~%u¤pfÍí[ݟĉĤmîè³9} y•P’ÊÎÙ+ŝ}ŻèÚÄpĴ +³U_™ŸxàıûµġnwÚg‹À\&s¸i |5‡M7¨û;(œƒi‹mq‚Ġráì…~7ċ`÷q —%.¨ı)Röûì.ş`ÀËòa·4?§$"V3şàx…›Şf60ĵšj×·nhÑĦ— +ë×ċğĠwr‹9éûhëSĈ_ÓŝX²kĉ³¤—/{_ĵ5S[İL^vž'gÄúú ÎôñĤ·³İŽ×ż²zĊ+5ßÜ'DÁ½NĞÌmş÷g7É@œàfžÇ­c_yÛ¸”ÂqŬŝòÈ6ĝ~ßdŬ›(6Ĝ â/£ŸöW>ŝÏċóAn²$4Ħ7ċ\ômß+µ ĞÂÜk f&Y›$’Ş%M³ħžù^Aî ĉşˆ£f·íR·ĦèĦĉ|ĥob|Ñ ĦßĦîWCż”ÄXGŽú-ÊuÚş m7óaôr“˙ï"kSŒŝµ§Ĵ?Ï[ĥŠÎfĴ۟v˘&²f‡ÎĝD0gßqAŭcŽCyöùg˘ĤŸÔex¨ó‰Üü|9½ĥñjíÂ(êee +>×ҊâèàÉqS&÷Ügy‰İoşƒŽ?\mÚ³ùѓÛ+íÜH:ġ÷ ¨éâ/Krßní ×;ıŠ›Úlèŭ–ğ?÷!‚­çğê½[ÔB­ğĝŻħUë\Wu´‰­÷-´ïŸ A͕şZä1x%D™êcó´ÊÜ”>óD­Íéĉ‚väġİŞ+w°gĠi?/bÍX•/•žÑ.·›qwĉĜÓÏÁçĝ–C×#ĝ ċğĦà;QF+&ïuMèóÜŻŽvüvv…L-{› ߗ2_e4tÎËjê*]àRneĝl;û™ékî7g̍[ìĉákQöšö7ÜŻE(œuœ­ħ÷Ċħ¸Ž|‡s +WSİ_ ĉuc†uƒ}Çv]Ίù¸ÀzÏGáY*.ycݍj·/K<Âş5ŞëÍ{/U;ކâÑùŞĥ;É[WËêNîqÚÉ9ĴÉ.îš[”z_Ü‘ŭ"ĝ§ F—<=g),x9¨é=ë_^,Ú)şŬş—VÛmŞ.-Ĝ+›[ĥñƒp—#íW…×]÷´·óh§.#^½I8½Ü{cJ'ĴÛü8ĵeM„mÁœ×ö6şµ3óòD!]7wh’:n”ċŭ†ĈȨmUĉpbòXAm³Ċ‡Y>ı˙ċ)Ġüħ‹â–¤ë=_ÛĊeKbѓŠJbU7ožmÓ³Ĵ¨#ùUÔÚŝ˙Íé'ğ +endstream +endobj +1825 0 obj << +/Type /FontDescriptor +/FontName /SYFPBV+CMMI10 +/Flags 4 +/FontBBox [-32 -250 1048 750] +/Ascent 694 +/CapHeight 683 +/Descent -194 +/ItalicAngle -14 +/StemV 72 +/XHeight 431 +/CharSet (/greater/less) +/FontFile 1824 0 R +>> endobj +1826 0 obj << +/Length1 2231 +/Length2 16865 +/Length3 0 +/Length 18065 +/Filter /FlateDecode +>> +stream +xÚĴĥeT\Ŭ²ĥğ;ÁwwKpw—à4îîîÜ‚ğğ „àîÁ‚ğë×ÏŜçìdŸ÷ï7šÑ£Żš%÷ĴYs-(I•T…M퍁öv.ŒĴLĴ|QyV+ ‹%¨ÈĊÒŜNÌÈÈ`ċċeHA?@|œ|œl”Q{O'Ks (í?NÜa[ “‰‘@ŜÈĊh ÊabdPµ7ħşx2„ml*˙D8T€Î@'7 )++ÀÔÒÄ` 4·´C`ŝG’´™=€ûßfSW‡˙]r:9ƒDhŝ%“ijog 0š!0+ĜƒŞAZŝ˙ġ“K¸ÚĜ(Ùŝ“ŝŸFŭ?ËFĥ–6ž˙`oëàêtÈۛìŝŻĞ&ßÚäĤ–ĥ˙wUÚĊÈĈÒDĜÎÜ`ù·ÉÒYÂÒhŞdébb03²qŝË´3ŭż"@û—f--IYM%úŸéżÖ”Œ,í\Ô<ŝ“ġç1ëuÇÉÒ Ëj/+Èôùß_z˙§–¸‰½İ9€“ `ääd䉚qĵY–vĤ@$˜™ÉÎŜġÄ`fï„ρrq˜…˙1ŭ›¸Ì"ˆÀ,ú‡xÌbˆÀ,ŝâf0Kü!V³äb0Kŭ!v³ôâ0Ëü!Ù?Ò"÷‡@Zä˙H‹ÂiQüñ€´(ŭ!ċ?Ò˘ò‡@ZT˙H‹ÚiQ˙C -¤Eó´hŭ!í˙/H‹ÎĊŭ‡ĜAqFĥ ›d ˙µr€9ƒ†ÖÒÙúO³AҌ\ŝäE˙!ŒLĴ.6@³żĵĜ˙c˙÷%üÏH˘Éċ6ħt2qµ5³Ê˙š9A5Lìm@wü?Êŝq´·µŭ³VöŝHg5ÉÔŜĈĈÈé/8àŸ¤ àiaeİ] #g‹?ğŭ'ĈÑô\ĝOĉœ.P˘Sû ğF +ÖŻëÖԟÂĊ­%‘i£Ú@ĊNŞ‚–îXÁœµ>ìg×FżzißċŠñT—Ÿôöù;Ŭ¤‹„]e›Kċ÷§“²Żáh¨ġïC£µBYsU'À>ô +œÊ˜tp.fXmŽ×qƒé Ü ñy·s†ö.-ÒWJ.½’]vz‹Ż2KĊ,‰EöUħԏp^oG€ÔŜÂ.Ù$Š­€sÔ$—‚XÏ´:¤ÈíVä¸:ß2³Ĥ°ĵXQn²Ġ?û!9|J~÷vÊÔö-qF°ÜA{²Ħ}ñS4FDP:ÌĊÍm&–“RÁub&ŝ"tùKä‹'SíÖgÙtù—y5Ÿ^JŒut{(“ !•ÒjĠáBżÀŬÀd N3iìOıtaHŜFêaŽ,‚û50e( +â(¸0nnûMt™U]ëĈĵ½ĝßÊOyǟmĠtş†rġqÒLa+s’Ġmĉ.à(Î5³,ÀZÖĝjC? Ñ8q}áqY‡ލ3‘è'q§`ĉ'e]u,(•ËL>K*~jŜlı˘IÖ.ÒOŠÀÛj,QÓıS÷/a°¤•7u]ĦĜ +Y^‹š]uxš§ÑUö“äÈxyÀËql[½IQê8Êl÷éO•ŝ2žŭ­Ċè{H^˘½‰ċ… Ló{çq/˘!$^\iĞ ûìl7ĉ§IÄġ ˙ùÒò¸.•YĠRƒŞŝÁr‘m¤ ĜÖä3KŸġİ(µ³í^‡KûA”Ċ ›Ġ̵˘d³$oSeµYĈŭ4̉˜PŻmXĈĈ+›1gêgSOÒ è+˓Q/z˜j–=£:Ĝ´ú‘1ĥ&U!×;i‚Cíé;N‰Žĉı*ŝŠâöî²to×KüÌÑo¨Îb“Ĝ%˜’ÄE#?=?6‘ÈLì\³ĴäÄÌĥ—PîGÂĴĞaö6Ħ8f†a_‚Ï-Ċ3í"¸áÖTŭ™ćqݰmŬ˘DTŽKµt…}í™ÒSġMˆ=Ê遏g2Ǘġ.ú‰x£öR‚˜ ĝhŬL53ßÌFü+v&ż^_µĞmg ÍĵefĦ½Î–•Ĵ”[TzŽñp¸+ÑúUlmZ âĝôK–0k†ÑÙSĊĝíèu´”t`Î* ͂ < ŝòHħԅBOHğƒ6˘ŠII˘£â9ÒĊ…G ZJzÔ=“R.vܽ— ŝy'Ôë&ôŞQv4iY¤_| ÷²P<œw> k¸‹ñƒŝè÷ŭÓߍ‰Ĝ]é\pgŭAj/NŬÍ ‰gΕÀö†gêF}NTF·g–URhPzԃ£rg,ßQèPşĉz½>Úòµ Ĥ§§++8­Ñˆ”µ°îĈ h–çœİçÇ–^›gŸNşXŝ*ÌêñáÇŭQ[hQ|o2ē§pŝ£?T„‘GôÑ8`#(ÍTX 8.Jǚ§ka7ÈIòô—Ät§N¸$‹Bn öÎLôeqŝ•ûÚnè‡AŠŻÌÊ#žRQ})pk/àtÄUC[€‰ÌBĊB"1Ŭ"J|Èċû”$#xö݃O”xŒp2K:Òß <¨W°A¨O3HĈĊ­pP…>hm|R½œÈ_Dĵ•‘ċŒP\ԋĉړMJêŝ˜ĥFŠN*ġñÀ ­ıÑ´" ì9œ 9âÔYôiLBhét§ĥdşÑ?7cP–"3ƒîä—żĦ .à!Sžê_ıXbí‡ĉn`½™ş„:Bo퍵%ô-ÔT É0UÜ*Sì€ê,ĊD‰}=xËċ.hyW÷GĞG›XœYm:8½RTĵn>Â-_Âĝ×bÜÊîW˘–UE˘­™çġ>]™ı˧XĵI‘³we9<ÓÛŽĴäµVrWÏç\czÔxĦCœê\YŸ,; Í1CW”qž7ŭ¤;§ÍytÏÜòŭóàUż'*ϋŝŭ3ŸŝiÇŻ°ë”*^Ċ#>W;½ÒÚ,5ħÒĥŜ‡ğônF?ÎÁ2é[àÇşo5;`°Ĝ~Îٔ2sÜIòŜÁUkŒz~ĉžÇĜ=cˆftÑQ„} c†oßk8ÊP~q6woŸ}z_ĒßE zä2½rÒà bóĦ­áôóqcwÔü†ż…7#‚z g6A´zMn´o×ĝ,{žğĉX7yÂŭsRTŻ3h‰ŠÌ¤mŜgÁÏ ïƒzċ³P;3Ĉ3[F‡Ċ^r’;oíRÁÚÓ×˙…™à•š-İ’3i^5_ŜRNÁk9vnR'9×)û=ĊäÇG4Ċ{ fÏ7ĵıÏĊÌĦ+ñĵŸ…E/%ˆT²Ë·›šË~·pMù.#Ñ÷âىñÑċ=­D¨9–ġšÚdÊ˘£"6ħßa™*|ï†RaF–Kí*I71‚ İ1>ŭ7ßöë2HUvŒ?Q˘ŸĞ-c+ĝ˙Ž uÙèvr†,VÂÎàv<(+^½?\΢YîŻÛêÏĠä?7¸â`ŞÎt&HÁxg"×<Ĝ‹Ân÷hFK)×Ç£ġùàüĜÊ×Ú)öóĤĈ QKYƒF‘R1HÖÎê-]uo:ö|-ț*éÛäÏĥŒ„Sô³˙ V7ÜšíǢ ş˘Bb61ÏÙ¤3ôş$"§µŠıRíK'è4µQ&sÀD§~À/­Á³•qƒ§4ëK/<áïá=¨h'û€ŜúZħÄqYĵ?Àèù=ğıN9)ĥşÏċ—Oùò’QÑ”n daİrëôGoŭ„Éh¸‹’zšŠİJPˆĥ0ÛÙÊ rŝ g„„ŭ²ĠÈ[é‹Ħôwŝ&£ğ}ċĝAÏĈOĉ şÓÁû0:vòí +áÀ…Şĝbí%Žİ§#š5ÊĵÇ ĵĠßĜëŽĉhJìÈ&Ó9Ö4ÙKmW[ĉMÍfîÛµòa<żVĦ瓤DêÜë.Ìë{²o.ÑöMh$=ŽZ~œ7uQ‘·ó•‡P@ŠGŜÏ+q|:Ч¨Ĥ7}ÑŞ8K#`FĜHšq)<£÷–‹œîĊ]/ŭ ew)†WôĝğĦ½ġŜ‡:Ĝof`2[ŭ&op£š-֝ïÈ Î’ îˆL³ ’’;ímƒ<…$"x&ÑëW×ÍBB¨“Š,Ê*!żD…E}ˆXi:$~ùşÖˆ~tġ¸# ç|òĴğ†Ĵ~\e$4Ó\˙ĵ·Ğ^ƒ*ÄJĥĊÑFK‰‚hߎú\ùyıˆWÊÜg%&ċ§³[ċOĥçú[0€göNŜ1fĜœÛzŠRƒĥì!ímŜlNœçë7G¤€›Ô²öŝ~H…BɊ;~kòµ|+\ù™—§£3!Kiî¨&VbfNYĝĦ‡`Qr¤öm‚%wg`¨İimzÉA3£üÏl…Ÿ~Tëĉì½Ĉ§dğáË*kc\û‰Š·Hż7˘@_:âsËuÚ£rÉò!ë¨êžRal-nĈ}ô;ĵìNJ!fçÄߤvŻĠeġ$_Ê-Ò‹.S÷,ä +‰PŜÏĜımdâ9û6½‹ñ‹DäE|"Ħ°} ˆë€mH   ħ|ûê²ŜÏêáĝh„9ό¤‘+‰ŻIÖOÑÈ4ˆßUWÇqf¸šŭÉZïX'S(•óĉ@3â…ñÁ€W’p-Ħĥ{\wßVÖ +7Żĉfħ?uVkq,Žĝ³™YêÙÀí>T$Ï!‡âĤMFìQw-ѓŜì9 ħi֝ĉP¤äNŒt<”ÖWn˙h*ên“üy·rg)51”Mo.ŜJŠéhı /İ>­@ ôġN†%V$ŭ ñàùğî~]ŜŒÓ½SûN~Z>³T…·F6P˙¸ı3´œıFŸ?k(‘lĊ +rÁy´€¤¨f÷Êßsċżˆ•"ê”KEìAM:@£ŞÒ•ä”CĤe·f§ŻŭÀ**‡C§okK #D7Ì÷têZĠöEf/n˘{>ŒĥäMħŻX5Œî L2h8µ³àê3LÎt ċ:Ï]Z§dI…›îròh>éqQTÄ'ĉ³šjhï…x`snŝPœ;2U€4ID_“¨ùà_Dq:XÀܟpĊ.‰^ Nô6ó:{|C ‘ìŻóZ+ËßZÔH}ğ/#M +%üIĴ@ıŠñOŽżÍ9jV̽ŜQHGßħj.˂ŞÔ!7Ĝ.Ĵı •üÂhcç^ħJ×È~¸Y^§_@ž”Ï’½Ş£ñÛ J–Î;!f=η„ħ2šŸ¸íĝŝĈ/£ù„ÇAxk,ËN‘ĞX·•ó0ş@Íáct™ežU§îjŜiĦİ +’ŬĤGÚ-+ılÖB6šƒoĥİ™l˙hê­eƒĊV+™Ħ#ġïkċR0əÌp^İÄêɒTÎ[^5GD†~ú½#FäžgŠ>ŒZP ŝw Ú —fTooµàıŽÉˆxâġӘĜħŻd¨”gÍĞ9GÜ+…ìd=°ĝáX†6oµ`ˆ0Á ÓHĝ°€[·™’˘m” +°žtÂü‰,>oц*šÍÑq…¤dƒ…½ ¤ĠÁXç’ıî=šc0·ħÍcÓÑNğj(ÔŝÇ#Ĉ0ħ‹Cêö`B)‹êŬ8§íÎĴ2U•PәĥtÁŬççĠm9ÁüED8Ëñ‹^ÚRoÈÁ.Âĵ‹ğ²¤ÌîWÔŭCm +zEqVѐ“ƒµ&-^ï7=%”×<=y  &nz#¤òĵÑX€TXbèVO!Ş”TóDó#Ŭ6*BĴŝÏf݇ıDÈ­òÇ}Żíd‚Ĉ;ZM£\óŭ÷ +óm’ŠRXÓ5vÙĥ}ÚeTe­‡i;ò˘eûŸqisİÜYe\à>ċŒ1Tè²ÂĞ1 ÒÏA›ıCİkkmmİyk¸y1Ž~‰4rñlùĤ"ÙPk|·:­¤Ÿ°ş´$·XçĦĴâü$=~Ú` Ĝ$"c_é–6éÄ3dO1Òf­œT1ĉ9û™ûÉaƒ‡ŝ´†ĠBVQÂħ@ġ~<޵³LĤ§Ùcb€˘ËL,›}“wQI‚ ½C,‚għú}eß!,ıY*3żƒÁöm‹:~üCƒ_Ó  AÛRßm™Ĵ‰9R–žà#ĴĊñĈ(ĥœpĤÊ{].|6ŠÏ\ĝÍ̇7’ĠUĞu+QK_ˆ*wŞadÁì)­Çf6şĉ¸Ĵòû/'8Àdß +Hġĝiíݝe*)=jġ—ëöyTU ÁÙî”#p…sŻwbsBFv÷ĥG‰Ñ&¨’‹KŝĥOp\ıIĦ~š`—/ïÉ %Ĵù=&ì…Î!V{OxĥT)gàëéúħe8üTĉñKB‰öWÑŭĉi‹)#l¤'ÓJu§pıŭ}ŭ³,˜6%úVTxYëERòl +ëÍŭŭÌĝÍCšĜÓ‰Ûŝ85½?™£ò vŜs·(ŠÊYxˆžMĊTeW”"ÎÀjh\"„Ż7óO‡ĥPa?iĈğvì_•ĝġûJïĦ\A l"1ë`Ùġz>}>|.ÛöƒèŻhIÙÑtÎ+ע § ú*˜ŠÑĊ>Xĥ Ż&^HÓ>êzöjÖP4’%û­o'H¤[lŞ~ċœ}Oì(£_çe^ +´îÓçà/Ĉ`<§V/uKÈ順ê]ċ×ûD|îŭsĠû1IäŠfĴşŝptA‹İÚŞû0ëı‰PÓÂôŭî"ô!Ŭ™ß,ÏĈJ8`@ĴÑĴÈêÍìĉ=À½ ³£‚zžŭ‚'‰Q’ö:ÜùğCĉ@M†”ÈËöYô–Ç— wWĠĉ ÚĞi‘g‡!Ŝ3h¤§6C\{˘CJ"ÏO@XW? ×ÇLXFWäг“{˜Á²×îQbZw£°?Öç9d(Q–êĤOàfĴŻ“ 8›žô~'ŠĊ:Ž9pV^p(èèX dPàÊóÀÎ/6~Ħy:*™×ŭzƒ!ĝvâk”Œ˘ÍÄ|eü5PŝS@~‚t)öıÖĴpMv¨¤îû**Zn-ŽŒV/Sm”¸žÍŝ.ü€ÔIRMGoĦğ^¤‹bÈ(hÌĈ tg?ÍP…´ĝoöD.%Ž–ĠuTlĥ_/ŭĴ%Ġ“*)ş²Ër!z¤mÎ`Ĝx݈‹ ‰3‹V‘NèB’tŸ?£UŒ+\}6ŝ²7ŭS;//Ó*°rċŝÇŬ{uĥÍĞôWët-½;Ĝi*ĤË@ċ³TöĵĦ/ìóBŞ:žġ‡*É‘Ŭ6ıžâ ú‹6ıEÌÁ\`fhÛċ4j$à'Œµ8£[Spz^ivİ ÀRĉÒĠ5İù ÚçôdG¸Ŝ;Ÿˆ²8K/ô$jQx×aѝї?£Ŭe¨ôğ@ –yˆ>R]Żu^t[˙F uí¸‰šĴÑÔO\!KCŞóùıċċ-‡shİ´%ÍKÖ˙۟˙ÌÀ7Bîžı ıV;˜²Ħ&suj'{Ê1Ù}dQġalŠ İ+ä(FÂî ùïĞĉ³1ÊĜĞ×vczr´,‰S}‚l—ïÄRò&òù-9ùíèßĞËÊ_ou)otZÏKݽ\ó|Ċġ]‹1ë;›5ĝÂ%¨'Š>‹§÷}B‹<ÄòÜgÁ Şa E¤Â/ğÇXÁüz?¤4—5m …9šĉÌÈlžŽëŬĈGe˜ ÚĞ/Ê!‘r“Ïoc '‘„+S†HĥyS…´£vwµˆ˜•Dé"ƒ÷oÒluЉ !Z‚ƒS’ĉëĦQß̘U¸Ŭ šky›‚ħZ‰—4ä’-¨*žQMqa ô^U²Ym^/Ì)-ĦMNŜWC~ ;³ÄÇ)‚‚ÇÒôù>*ĉ„/I’•ôôĠV;ڒÛħßLż)µ8ŝ€ô÷gĈÙä´˜†şvŞ~’EbŜ"W LuûI&ʜBî\ĴzvĉژëĴ°8÷}ÁRB{#êéÓüÌ!~öFéjŻż…òYú·İ>CLŸmĜnĠÏí‡ml}[³ż-ĵ°ˆ|<Á…"b~ĜZ`'hhŒô3)̘èj&Ÿı „çlÀ‘Ì£"ĝDĤXäÖ`wÓÉĞÙĊpƒ^VĝPr_q2ӓóaÁ|úħò<Ğb$1\ĤÛq€Ş1bC!Ë>4šß$$ÑԞèrZŞOKkœö›ütË˙|Î9bHÛ{t‹€uf’,d{iÄù1|z3NMĵ§"—ê¨2×ĦÓ7/ƒÜ…,Cî°Êá銓àdĊ0÷#!ôn°zÀN6FÓQxżßşKO†ÏóÓ.^ûxòUoBЏfŠPóQyßŜó s™fj‚¤ï=²>+ġì*7¸‰É¤çŭ]L–iċ|ġXZç²Óîß4í56⇂ĥ‰%*J'ċD:µ09Nä‘Ħ´Ûoğm'ñħ Ĥ0^“!ip2h(ÍŜÙ Ö_Û|ĊE£Í/Yž%˘ÁĝЏÎ5ş#!ıílôœy£èŜ +÷“Ĥށ­âìÉÁHĊ3)ü/aD2ŭ6ÚM`‰uÏ1mm×N#č’lHFËcÄó[ç>>“Ğ;‡‡Jà§Ö’111;ÓìçÑNĠuÛĤ|s`q³žĜġÄ5Ĝ™73L,ŝUqĊè^"Ĝ_\ż²–Cç”}Şy8ħı7´S—Ñíúa ½ö@m-™âĜöĠo-9%í'uVÈÚ Œd½<ĈĦèSQä3KMŞZz/mNêSŝ@ĉa lŠ™Û›JÊ@FĈÏTyƒY[MVĞĥפʍ#ö@Üz‰NıXO˘8}Çá1‘F¤h‘ʜ19Öd·oŸ,(ğßĉµxĠĦ0LÏ6 s?D„ÑçH]›˜lKüÚŜc³4·5ÒNhÇhn?Ğ–qêÍ×Ĵ=xlN¤û&ko:Cñ>Á–Ynŝ6á1ı˸\ê[”Xĥû4ĝRŒpsxêLpèžGċˆ¸×뚉ǃ/ĝq?í£ âŞ`Sġŭê9@ şÚĵ4s—”³`Û”~ù= Ôwmò9;ÙU°ġ§šl[49›êëâtĠ£3AÏáS²p$‹üTSwi9kt9ÙÎxıƒ5l ŜĤ‚³ár9Ó˘nWĦ ÎËf  òv²ciéQ…Ŝ××óô)'Ġ·ĴÏ(íáâ6²Ĥ:Èmç%ĉèûy3ċ?÷o‘’kyĊÙGĊ=úVsÈIÔîIĈmU"6F3’èd.G7ó2„‰fĴŸ&ìïŞ|”ħô šêá×]uŜ²"ëŒ È„ß‰ò‰‹™ˆËó<+°ÎÈdşµ)žkÏ]œŬôJىHħCѝ*:ÁƒoêŠĵüÎLGÏĥŸŸÊ¨†G/ÈcĊ¨{\~’ı +Ĥz×ğşgĤĝ€ÁLÓ q^–ĞlÀùŠL ÁƒKÚ+êŽÏ`=uXü%J™`ÒŻ~‘/lŜö­ĥ¸…mlHçġĈ Vg}0I´ÊUÛşácäÒĈËHû ¤5¨è|ñ™lœ{ÜËÌܧj7½$AŸ&Š) +›G€Ô/lŽĤÊÉ]ŝÖK9Γlqq+I^‚‰žĴtr2€‡Ĵ5£EKö2ĤFaÌFEo5: ız1SÁ:òL8žl'FÖF)qˆËrG‘`S8;ÑfôÒ¨\ı³á“6İ[hĦ;÷wq*š…=y<GĥĦ"ÒOŒ09Qg‡}Ϛ“żéòżŠŬŞŞN—ÊFVĥ?_›²¸ÓKš?áÒÂr˜Db²Î¨f”Ş8áİĈÂŬmà³9uSCü‘GÉäpÂĉÙmÖè”ozµ%އ)p_@˘{^Ċf~ħıy$eŞ·˜àıĦóí—İ ĜÂ@Öʏ,ÓNç ˳3š£Ż°ğÒx›Üè5š÷ċ>Ÿ80fM†)ħ`Éû=݊#rĤYko€£Hg@àٗèsš‰ĥ×íüŽâĝ1 à“‡%·§ŽçğBÁ•8|ĉÍVÍÎ ŸÚV4ߖ•ŝğp;jì@ċ 8Kñzò~°ñ öcА‘Ë Z1ÊàĞvü·Àž,£µ–qµ*Rĉ‚žŭ‚¤ +O.~Ÿˆ†w£Ó}<6$r Oéğ L˘kĴH_s¸èĵĈ°;ğ*Û4Áù„ž|£uqb/ÒÇĈXĉš4›Ë +0›ÓM‰ĉÛ^\é;QHhĊϔ(’Ŭ•ĝ2T¤WċĤ8ĉKŠ[H8äwTŠë̚÷‘úh[ÒÇkı8eQúÊ:‘ÒG‘,Ş‚Ġ%²Ö1ÇQ„™dµ/n< İîl/a âġ2-ä„.’êCîqä° ŭ-·ZGófëÛ¨ğ".A/Wî›ívhŝ!Ÿ+çı’\]Vá˟ċ‡NÚm5³ò´”Ä)Š:òĦ­ĥl”4flΟĊnċà´ ›ÒíĉŒ³Ä^Ô²5’H˘%}ŻÄ„8 ’ŬK8k¤Šğ=ŝZ8B`_>öpÎ +kŞú?|Ŝ§|*m3_ĥ'ĦdßOÍEÍêÔQ’ŬzˆHÚÊMĴhÁ„žŽ×K"˙=0ŻVÙ_+Ħی–é1éׄ3[Żħ(Ž/%…rĊĵ¨Żĝû׀•l&˙rIÁöü ^úœéG·áΘh1²ĜG4]·…2˙¨|§ğ´$Çß/Ż>ž#ŝ݇1U›Ìĥâ%Ày\}[ĴŠš•ĥ4Ç;yî ˆÄÇ=dXĞ•ċ:ğ5€ĦĤb ŭ™y'1MŸJuI|=o# v›9\ï¸Ŭ"DÈ'BÜ_œ-ú9ĴÙµ 0Ġ!Šóŭ†aV˜-@·.2'°Ui6ɰ='QDu=7žn`¤ßϐná%7˙‰…ÏÙ °ıuĦÛcWĞdŸ–ŸL‰I(ÜÄÓ­ ÈŜÙ@ö\v,Jġçeù›)ëĦ9Ïâ̲h~g0şŻncÁú™÷ĝŻĝó·ŭŝĵ—0 ïâ’KE‹BZ[Ùn[òŽSwçtdy ”ß +mğțÙßÁ—ìà*§-]ŽÒ_\“~Éi¤Ù9ĥúOŸžÎ£Ñ´dFÑĠĥÏ9°ȅ"\‹éžd˘c_ĉÜVġànÏ ÌÓÉÇ[kÖ׍O/ŜpzSĤċÈóÄûÑüBż@,`jÌċEÚsağ·1nşYèS‰Ó0à·ÁBĞ´Ÿż`os˜F䆠–ŒäÏdÓ§šˆoN>46:gĤTĥ“AċdvHUAuÛjéÁ˜Œ(àġ°è´ )CòÚ$[AiÒ .™]3[UZ¨ n1‰ĥŜ½pŸŞµöıĵŸš´Ċ7ê^•³•½qHúĊ_î“’eñèB£ı÷Ž~ Ëv$O„yZÂèĠ ç͸î˙ +AF­·°FŜçİ­ĵs—ì9-7vOœFßû¨!Š6ŻSŜµKÒ¸˜ñÇÄÛ%;ŠÚÛם ş×OĴ(è™ÒB4(iX™=ħWµˆQö.‡ƒ‹ĦY‰áWsi›bôM(bËl–Ħ µ•ŭ!ö´ûŭ²`ìÑJ6ˆìß§ŜŞÏ,tŬ’Ù X ’ñ2´—qQjżMLìŻÚqGqŒmċ} £Żcj†k?D)´zçê!Lċµ °ž*6ıjêF aÙ§Û’úıÁÙ):>ĞÒք*ÑŜŒĉAf]?UgÙ:U7$€ä×0bl;C}ĈgßAî~ XâJfu}ĦŜ32DÀ·Ŝ70ıײšÚs˜‚›ĴÏÙVİ/Žġn@ƒFS¨°˙ÊĥHGEa½ħ[÷ĦÈ´ĉވ‰Áp”•d3 vÄ6Ò$–è#­DLΚhcÄ ŝIÜà ™.9 e <Ú3ÜyWÉmş'I5–cjuQó[7"Ġ—ëü~Ö/´ÜÔĝ$’Ÿyzše9f9û7Û˜ìèÔ0½ßߞ™İÛYßyeVÜh´Âû½ĦéaÁ÷Í|ӗ[ÒábblœÈä5Kß7òuƒjlëàĈ)ú¨?EJWï£yÛ(Ġ~'|ەEÎıÁÎèt”ôÙû$š,[lĠ¤V§ôKĦitÄܙŸ-ĥZŭw²ġŽù:™\^PFô›Ì ıDyÍVĈŬ§~²Ïı!<S·…sbÎù  LÔ ­\Ĥ}›Ñ´†·0ÒĠ’U ı9·§~“ü`qK_Ŭöv‚aĉ“òV>3Î&JSiŒX.+ÒIġġrm{sJè~eÒxœ Dq ßY‹ĥ`ќȆ9=ŻĠH ŝĝ!,j.ĊE-JCŸÛF ˙np/•Ôîó;×3™¸úDI·n"qî‘ğÏ|ƒïŸGĠÖĊSÈĠÓw‚ôd³€÷L¸b@6^Xì\ÜĴ ˘‡Œż†=<†É9Ë<˜K8úzıŠï-_Öŝ¨ĉĠzŝٔıÀáÇè ‰œžœÙĥÀ’£Á uş‹Q”ÜG˘´I˙ġzÎež ğáê~wÍßà’¸˜‚V9ta ÀPóħ7—¸U|Kq<ĥ9x§“Bv 8J%m77†È@Ç˙µÖ*q` @‡°×É*t+Ħ‡ôĠë#ġŞŞÊòŝA_u0^Ż86\Άc^&ż¸Œ—µX]\ùJó´zNùiž(ߕƒ6Ë;[’d5Bfa¤+Çك×íú[nŻ‘žxİ î矷°Kӈk—2@ÑgÚzXGZô†yÇdĥâK'/ açYLG„R>ìĵ’hß{öçóÁĜ铎X¸NÄ}Éá{Gí@İIâg¤Ŭ uÂ)X ô¸ /‹+txûŜmÓïVݎ‹ß§è­zm&‰Âw;™öñ[ۊż8JÇĵ Y%VÏĉ)ĜÄe-fÌ§Ú %~ +=Ż‘1>4kÉĉÀâñ†Ş]Ho·`q9’­–Wµ{*êZPíġ7uK;á >ğgjş“„èÎÁ˜ûħòÇe’•*úĜĤĵ"ğ>óˆ”e"1ġÈZ[b³KLÈğZ1ŸzÒŞ_6*rĦ+/Xazo,y2aSOĦ> K&ôÛ!’?;y>Ğ#ĉz? +£a‡ùòŽğ§8Zâ]%AD·á2<_ÙĊ8XI•T,Â2èWŜmgÙ~îKÏB¸ZÀ½öĜcóCí˸½aİn“>š‹LÎ3<}ÛŻ-„¤ß†{3b\‰à²ñû‚²ŠÜy‰°6£°Ü#üġ[v˜O`âq,&Ġ\Ö@²×Ü#s<êċûĉĈښÒûy"=UùÙSÎUw fú•‘BşŸ‹[YĈ ‰Ĝtö‹ZšáŠċP;Œĝ,UŬžŠ ^‘ŭÛ3µoD´Än‹ŬŬ_ÔĜĊaĊ>¨Á‡żĝ”È ˙ ŝ-ÚĞĥš/1&Äñé­8–é“t³"ú›Zzé$Ö5}ĝ"Èh Iħĉöë­fo„Éz$ióü-}ŝĦ™skzÑ'˜ğëÔq Lè[Ġk1ύ ċβxkeŝ(IÓĜĦïv06j…ߏ½ #ÁCn¨ĜžJ{˙<Á"ú8²]VÄiwC›µġ +É·"ħ‰ .–ˆġ0ôCşä£§5Sboá7Òè"}_ú%%{…ıa+­MóÖKyĴF=ó€`yĴŝÈbó.ñş½I€og!§•¨Yla <ĥ~d0àÊ7ĞPwZ@h4f#-‘EÌt08‰°kWy÷ĞŜ`]àî.Lqğ2Ÿ?Ĝ!fŝ}–'ÓÙi žVo’ÇוGÎèÚ|%~ R}Żħ":&֣ψ˜l3à›3½İœô_Ù÷Χ–:JÇl”ċġġFh´÷Lé™3Yäp;b)K(̍*żÈS+ŭG„Ó_Z,Ĉĉ Ÿüü¤[†|A91÷#˘ĞŒ[ +gÏuŬLácA'w¨JÜ|û–£Ìß$—ÙÊÛŬ¸zAX™V´ŜI51Ÿ²àpJ <Á‡QÉŭEòqħ$N. j–Zhî“ëòjph* 9÷dûxñ—ËÙôÛİâùŻb0÷ +‡\KžzpÖÏǗžîˆñYGuèµLûċğÙN3…Ğ4?v<‘™ş7ĵFŝ=˙÷ĉ÷Á•ÄI8Ö]Hîcï +?ŽŻÄdŸğ6Ĥ÷Ċyd³í3Ġ JÏL–]Ċ1\/ÏÄSҀÚÁU—l?y|(U—މeŒE²—£Ğœ‹€ó"Ċ nSnġ/ÙÔĤÂUÔĈچ~´t•:à}—ë +èyêàTk9eċ.ˆÁMqóXÍK݃ôèµ- i1ğÚm–\ïÀŻLŽÌċµ`ɍ83ÜJ­Ú]ÊĈ?h]‚ÏÀubIä¸x£Ç§J‡³ï‡Ĵ31Ŝı÷äl ÄĉÄ*ìy|v |´ +š¨ôžJħÛÏêjôAy•2ċ&Lè´9?9î" +éÇêOhÂĊËRĠ–ĠPÊˆŻ¤2Ħ3уy“4œZÚŝÎwısİb7Tŭ뛉i7Ġk $EħigáeäwH#›éz††¨s° MRû2Ï6ì£vñÁÓĥ2bÙì NÇzr¨;+ħsŞ)N˜ˆĦŜ<%Rĥwđg"żd‡o˘=?4§Yä˜|9- O”'Ö·~úûÀ°NíۖĊ™Û²Üäóܖ´›c~~™lòóàÁMUÜĦ^EÛ֚A[ûzÑĉy‰^ ~ŒĦŒ‡x‰1ÌAÙÍÚ87¤sıżĈÈĠ òè'B$;aŠĤkÀ2“ŜQ>ˆc!S¨AF@Ż^b‹£÷cˆUˆx½wPËÄ/Öy ‰”Ş%òÏĤ†—vv]¸a?\¤Sy˘™™:*è²ó{^)ĉ}#B[ŝùîJƒC||š¤\b3Şi!1YgWÓHŜƒê2żÙÑĝ ËÉ]í¨BlQNÁ›žˆİ‹Š‘Ü8dğ“.úÊrjŸàüYç›SÍ +ɔpÄ.íÊ?Á˜aĝk›Í/ #ϊqÔxäÜŝ¨UÒ˜§Ò—w˙İQĴ‚mJêènÔAèbÛ`,h˘Ú"+ÏoÊcúÏŝ5§Ÿ ǤLK`sÇ 4ˆ/†?ĝݤ„H§^YĞ6?Ž F'Ĝ‰MïôRĴ‰YgwÇùQaÄğ'éÙ2MaTġMobÑ#ÊÔĜñÛV3€Kìï¤=İ…ŒDóĉ$ìç`à&Tır¤$‚Èó·ÒQšŠ'sš‘É PÓšĴaFà”²‚]<äڊżDD,Ž ]ŭŻŭ‘ĉŸñğÚDO~í>"m½ŝb‡ ö²+dnƒ›GP ĉ¸Ê$˜½ĦUvDe¸Ĵŝ° áЇ{~şĝ]£Ġœ+{o°èKhöİFmùĜ* +*£°WH˘Á¸Ġ6ĝôĈ˘icE[ÛËÛsȑôéÀ›UçıÎUé W¤ÂÖÑ<î0ŭÒoĵdì´_+ÀĈôtô^!‰ƒŠşÎ+ĝ=v0ß\mƒu~,•\ċט’ïƒĊÇĈâtßO,B†¨e3 ¸çh/* ŭĝž…T|QP †= +[ŝéô$ RġBŝŠĦN0ˆŒŝ”KÙĈ2ŸDYÛÔq÷YkÒİ<ĵŠòdçìÓ³‡Ĵß^òQPٍÇ*\ħüü½„tkèÜW'.mŞ^ĥM˜ŬğSÎEßÙ`-E.ßݸ˙ +KT×{ê/³£ ™…Ŭá80IŒLŒ^ö>_apqá™Ĉ˜¨~$:êÏFÂ}BY²Ó-7Ĵ˜1~ÄÛ,ûwE×1!6öÙZ:ÑħI¤(ççMŝâG8t9Bi‚&A.¤ZVü:ħĞŞU0{*˜ „§Ŭ}ßfIŸ•Òvu BĊñ-ƒCŠ>.°s’‰96€ÑáĠŻû7T  1kĊóL£˘żáO;M5šKQSvĊ0ïĈmkèEë(:AúÖs­su sÄxşĈö {úŭĈ(àݐpİş‚ġt…­:˙ف 4—.ĊöRrĠ*ĉnšğ ö•PŞ˙8›zÖڙC‰ĊŜ7ƒËîÔX\gs·ğ§‚&QkföA™ì“Ż#°Ö +†[˘îŜĝ;UĜ +Rl£1&ËvĈ:]ˆ|,‘ùusèı0Ŝ‘S;°¤ĸÈŭ…ĜZVŭÁ…ÜUĜŻ>Ĵ0żX~ _8'ğVY°S×ô·KitWĴ4`—ÖHŻa‘j>Â?鉢ÚìGw\ ߈„Á\k_µßib^7¸Kĉ‚ìXğžİëAÛçĜBVpċş…Úöúm~´ş2ô`É NÎEÏÇU[ĈXžgFn‚ïÙ5#ÒĵĥcFy(˜•Bhm¸ñGĴUÜĊĉİc޵|ÀԅŞxñïàIn–˘8ËÁĞ˙ħiÈI%”hĠüCÌäHqŭƒĊÄ'–÷’bjT°Ĥ­ïgh0qÌ&â’ßŜ´…‹[ĥS'ÈeÙħ0ŻĊñ=B9òƒzˆĜ™ġŞ-n~›_ì^™IĜ )-1?Ú*†'İżĠĵŻîm˘ĵ„‰`ò`˵£UP-Ż­QzÈÙPˆùB„+î‘ŬĥšbüXäiïŻúżç2!nĤˆ·VYBšÔN&f¸[żR¤Ï†Ô´ŻL*k!ŝÜËì/oL\,b°9ç™v?—ŸLâÁj³ĞD„PÈ˘çßî5 +^Ŭócsĵzäeè·ö‡ùÑÜz-½KŜ9 U^˘bÓŭXQ÷éĝx“‰ÑÔ\ƒB ™ıñ+´8Ç që ORċÛ"×NÌÇMŠ^ŭ|ô +–H…äKeìġİEédXk§İ%(ÓU_‚Ŝûž:Ôĝ£³$X{QF +˜ê†…ëS†¤²Y\)AlKdĠ‡è>ŽëżVŽ[‹ŝÌ!_ÛÜ cĦ,ç•S˜?ô?Üğŭ˘Íȟöêħ9)ö‚Ĵ wiÊzb‚„5´eynĊnµ_`ŝ‹ğ+ êڝX™JϽċ͕W?AnÄ +òYZïĈ³ÔûwsC-o³Uy)³¸%#§S/LÂä{jħgàe™KöcĞ0vuĴ4 +‰^ÁŠ8îŝ ñt–Ü7‘áBµŭĉMÚÈ版ŝrˆog´Ž†çD …~.ĠQ_$4QKĞv³ö hVÍ&ş•ёżlüòîĜ'ċUÉinZ@?{ĴÈŻÊĤ݉|kÓbn}“š˜n”.? tĤŸ(ô†˜B”NeoRâÛ àĥëCM„ôaĝ™!òħôڃ/›)ê=ħŻJ`ùˆ˙CCOñî>vw-A2ʁaˆ{ÂVĦyĦ³²÷.œêĞe'Ž•6´ â­áÙÔ´0w—R•3Šlž v7˜&ì…Ù²?ċ×}­í—̇‰Œ‰›Ağl:ħ0‘’°Ä…/éKƒ°M +Í ŸX,_Ż8i`ü^£Ü5‘ĜYĤ’…ÒE½4Fᚙ˜Ŭŭl˙N§GxèMôèI)OLßÒ Ìì"–“ÀM’t˜›Ÿ†(gT?`–8Ŝ3ú*W‰niÖè?zï´í{ÉŞ‚óûèzˆĊäc³mcd‡zTtl7:àµ%3qÖ˘sÎ~ĥ[;)2­GĴ”ÂĜ Óa}éñ†èXöù“1ˆeüRûŬÚGħ”Çf­żvL³ÔÓ>”drfN蔟 $y*öËÔödóš0ä y9÷”íAë>aŜɗĠ×|\p7L˜½ê˙%q?°#p >ċê< 2j£§H\a0£c#ĵĝğ>JKóTÒ!ÚiÂ(Oi–f +Ä.ì’ï͍r7)…ʙȒŻHOúāŝ5{êĝsöĴ;˜âÏg%`RĴ_şÁJKDñÇAµX7eŽ…D–D·ÀT8}Y‘Áŝĥİm_zÁġóŜz5fóùLĝîa6= ÍxьŞOÓœċĝ^os˜€½ğŻê|ÊkLp´IjcüAJßsöàìRœ´óìCfFŭxN|‰ë c ~\н ûFÁ´^ì*öàR…&ĴWG+œ#([/Ħ2I%UNçŭzjËVŝ˙úûİUd) MrĉL}ÉI˘š7™µo2ÁV˘é ȗÔÙâqb~g[ıM|zÈ˙^Ĵ+È4†ÀQŒdNÛŭU²?›WĈ<ûŬäÔwİÒGO—Ô1ğ›l‡*Pĥ˘.kÀ–.ôÛb PċİHí6¤bĦ?cċWÄo³qĴ=eenjß@A _BJxх6$ +EKb×ÊL0`›zBfÖD2'·ú}'ìb2†oh<ìVµc;^™qC>íI˘cóĝ<`ë·ïï•=òżvˆŜÍ^fí“uÎB 8GıéŽĉ˘rTĊq…wO +!ÀÂ1Ĥ$rĝÛ˘@ïa'ħ-WŜ£• Ñm)%–ş•‹ĉż DߋRCÓ\Ż{ĝXjòÑF2F‡ĜeÓĴR÷~Ğڟ³p³ÊÜŬÌYE+‰ËfÇNÁ&ϖ({—ğYօÍ7,”‡(V2Ôɸ˘¸wV;Z¸·³Ó +Ú&|íqMXt–Ċ²ó4 ġLjTBPçá( r6CA-qg\ÁŒı–Şq…)L"¨DÜ'+ĉ[š/sPÛ–z8èŜĊnÊÏG2pġ\pgjġAäċèż:WŞ´ü)İŠ7íÓ +ĵbà°dìDÚl]m)Ú‘)ÓŞSCĵûĜZKó*NâєË΍Î~Š:ö‹4ijú¤àaĥ-‰òSJ¤7(ĥp]¨s'Ğ›ü‡ż İlï[FÄwIfÜpC9ƒڔšVu_ğ”ĥËF˙ÚŜ ùàÔçÑ?£+mwßêĦşìÊR;ьÖ{ A8£Hġ5ÔUğ¸—Ptۇ’g0F‰˜¨Özeî2'Ë£²–°Ğ†"ìjYßÏ8ĊËÒĉùŸE·y!ë3™Á9“8NkD³Žuĥ—kĠ)ÎH˓BÉV•´K+Ğu1&PKX/ĉ(Z/6·ñ›ŒŝĊà1,ßğÛÊUXĠ9˚Ŝ[ +ü†4ĥmDwuÀù;$òúíj¸(äŽÚzyXÊ8òÙ=żkWÀˆƒ(?2f’Ó>âŬÜ:<=›-:™6ĊĠ“-BȓĴ<ٚġVQNĠşŭ‡ +0Í%…‹6Uv]ôĤvÜ5>û€Öñi6ôRC2ޞIïÌÁQĴüĞĝ4+šÜ†Ĥ,/Ĵ] +endstream +endobj +1827 0 obj << +/Type /FontDescriptor +/FontName /XXGKWP+CMR10 +/Flags 4 +/FontBBox [-251 -250 1009 969] +/Ascent 694 +/CapHeight 683 +/Descent -194 +/ItalicAngle 0 +/StemV 69 +/XHeight 431 +/CharSet (/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/a/ampersand/asterisk/at/b/bracketleft/bracketright/c/circumflex/colon/comma/d/dollar/e/eight/endash/equal/exclam/f/ff/ffi/fi/five/fl/four/g/h/hyphen/i/j/k/l/m/n/nine/numbersign/o/one/p/parenleft/parenright/period/plus/q/question/quotedblleft/quotedblright/quoteleft/quoteright/r/s/semicolon/seven/six/slash/t/three/two/u/v/w/x/y/z/zero) +/FontFile 1826 0 R +>> endobj +1828 0 obj << +/Length1 1367 +/Length2 7534 +/Length3 0 +/Length 8340 +/Filter /FlateDecode +>> +stream +xÚ­”e\ÔëĥÇIé’îĦ‡fhP¤ğğc€†bˆĦ鐖’¤¤[ş IE:%Ċ;ûì{ĥžsßŜÏĵ™ïÊßZÏóü٘tôyeíaĥ%˜;œÄ’Èkê >\66y/…ı+€áIHBġq +@˘’Bâ’"¸ly˜ êèċ9˙ +ÈşAĵ v`w€&îqCÖ°ğôavPÁuuèŭ•á ƒxCĵ|!ö|¸ ÀjĜBĦî¸ü Ruw€Äŝ6ÛûxüÛċ ñòFŠ‘"9H‰ö0wWÀâ€ËŻCö‚ •üˆúïâJ>Z`·żÊ˙µ¤˙ğA]˙sóCĵš0{ˆ—û‡CŝÖĤ ħ‡ú¸ŭ·Wv…ÚÉş;şB› ŜJPˆ½nçpğzCŝe‡¸Û˙·äŜŝ%_IŬÔĜT‡ûïóü—O u‡ <ŝİúWżô›‘Ûñ‚úÌĝ@È@äïß˙,˙Ğ—˘ğÌêŽĵ"˘°—‹ĵH‚Pw{ˆ?âÌÏçƒ#Sȝ`^¸§¨(€_î/Óß$à—˙Mâ~…HL9Îoĝ•“ €_ċGFêü&dMyĝÁż ÙÁö7Iĝíŝ!¤ÏĉŠĵc˙ĥ ˙eqsû@ĥ²˙‘Ş ż+ gûûŒ˙ @Vpp€ŝ‘ àwü‘~§?PÀ˙g0R‘눔ëöAH)żµŠ çt‡şCŝ#µÁ~ςL†ŭ‡ıBßnd1°ÄŬâ[0è­^˙1•0rNäğ‚ŭħ‰ż&ġú‘“x˙÷A|!ÈE†{#oÜïdÍßDáN^?v‹÷ƒŭ‘€\ŽïˆœÏï7 +" ~ FĈ@ĵŝÎŝżOGNĉÈ+$ àD6–ˆ‰˙Gœr }•ïïßìEVÄb‡ğ0³{áœÙU˘X˙ĠµtDŬ“ëKÉMe6)á6ĉ6£ß­w\{î¸ÒQ˜grÖìŭĥŻÍvv@ ­Éiĥ&b˃ù2|¨­qĉ|_UûӗÑò4Ó×ŭyÇ{…:@ƒoXËL(=ĉ =9˘b&JنёuìBLzÄYžċ1ÂÑ+~Äi)+Cœ£ħ›ı—N`í>oŠħ Rï-Îż’1§ÈµtŸ˜ŭì4çĉêŽOPáfL(NÌii½ğİÊċ—žjdOÎrŸ‘ÊM‹*6³¤ÌŽĴÑ5ä…=[ž‰-äĞÛ.Ëó^ĤÖ2í-ĥċ\òñœ­¸ż×Úo5 C­\z´S\0ċÔŭĴŞívñhÙĦí*}ô× yP°5;)Kġ!ŒeeUà²Îoċ%ĤEŜŬ›Ŝsc +èb „ +Iiö?ț À$&ğ(6ŜynüÈ-[Ó(XċêIöqJ[MA +DfŜ>z†ê šÙ§rażìhŬOL;@ÎrżzÂùşĠŝµzGŬ#³HÖâŻħ ĵĉİÍ!§Šû˘Ş?(kï1Ô_?À‰ŬıxÒ!´è‘=şY@İòXÄ´”ŽıĤëž{üéÔj€YàjŽĠY’•NŜ˜ïL–iu;ÉÔîtż˘}TĦ=ušµĴîê#H$ŝñ²gי/‘ġàQÏÊèöŭ 1œÌÈaAÖf7<h‰óĉ<ÎıJ5•˘çİu²r§ı맔 İPöĊÓ—żƒñÈĵşdĵġŭ‡ŭŠxR(SÉ9éÇI<”Ĝóv¸îˁá]<âÎÚĜ&2Ú!v%ŽÊĜÏ>ìJab~ :œ$²ç~ƒĈ„]Ğ7'³X;f™™ ŸŸNáŬÄ]‚xàĞ@:aŝÚ$ċÍV2 O‡·^†œâ˘²ü9´½ğǃD$GYZßstüħß§ĥóW£·I}ü›­Ĉ<`ŞĝıΐX—:œŜñ>²ĥĥı˜éĵÖÜi3ù6G6 >/PZ>8”ĝĉŸŭ¸avCĥ‚ħ1ê%żicQĈáçׄAò$!¸|ÚC’ĝ:ı“>ÜuI€Ü|wZ6Q˙™‹<ŭ’G­§fw_€…ÒŜı÷á`úí£„†Ğ g3G~“ˆ§_Ó@%ŝÊÙFÎİR|ϕDz[„Ŝ½†X쒔EͧÒ}$}<ö@ŭÒ/5püúĊÛ{Ô8ç&`£‘’ŻÙʂDĵ}Y&İ\ŭ‚"ĥÚo˙0äıÄ~aé—CéHRÍ5´ÉZÔŻAв64be(ŽhĠ/ámëĠ‘~./ÜŬpRAŝn"ue@cĜè Ċ.şÊJÁVǸuzŻX2a?ŒE$eJ–2ŜnÒ£ ìÎ{£Êë˜#xË3Z (u"²áʰ÷5ІCżihVeJ]~DòtS"D[LÄFÈöċa|yá`òeî<\N³EßÜĠ(Û§.öz\-‹Ë |7ôšeM9 úÔ̽Çİô€;È9I4CkúŽ÷)ŬÁˆHİĝ3ĤëÀá-‚e™d™ûży›ıòQè“tüŸ5]Ê[\.ËX×Ó§ċÍ÷Gp`xÜ[5kŬGΧÛ'[êıƒħĉ+zıŠÉolO-É7ğÎñD;ÉíWX +q„"ç£ÖĉPf·Ûş4{›`âËm~,MŒ¨L…CìšùšJĜOÁÛş]ì Q'ŭı½,Ó(8ƒ½ŭIF4S9êX5ĝżè²N˘ŬžEˆ9Öµì{j⍚*ŒáQííeÇx²Î/Smx³Ş<³"uêÁaĉŭĊŭp1 Šˆĉ£‹{"ïB½e?ċÏ?âtĉ:Ò;I)ƒAÑÀö”İ"vœQ)gâż°"ŞĞsT[lçve´§<ò˜-Ò-è¤Ğ-ëÀÛüv/ƒ·cĥ˙dìÔ,Etżá]L¸*Wħi)l–œY;DAĈğï\Ö´[Êġ"°“o²Ëğ#‰jMĵÚÜòÛʖ/›ÛBIÖ!ÁĦN(Ŝ0/k-iÌ ×Lġ‹îK0‘ÖÉ9çŠĴ×OJß öϜÊ­$ñqË1U=İSOYĞ üHc´Ŝ6Öżİż%ħ$/<Ìhù˙†èA\„ Ù+[ò#§ŽÇíŽBNù]lÇÏĥÇ.‡LĥmıA_üœ&ólĠ‚dş7gC M’ĈŬŠg݁h sûž-ĠkÛô´_\ëŭ‚Ĉ,Û?èOĥ|Âr€ÚĴpVóG1šÜ°Îi³S‹Ñ—Èġ+¸[³ K.”ŭ}Fġ‹v͟™ŞÔ]œÌÖo5†ˆ +YÔ,şÀvt˘}ÇVvF™á°c˙¸|7ĵ2uU[+’<Ëç³Â˜úÔ_ġĤ1>0ŝP]i(ŬEċażİĞÄŬ-E@÷^Ĝ >6^ĉ ġóW|‰dgRj*•7żzŠZ}:K¤ÛydN‡í1`&ò˜Ëşûôg@Ĉ7 ĝÜAM­·$ŒĈğ(§2‹ûǵǢŞĝÔ|9"5îiXêğ~áLZ•ñó5$ÂÎŞm.UĊl 1ğCĜoÉw¤LûȀu?dÂÎúútEXΛvX__nÇíÚÛ{Çq$wÚû’ĦĞċ&PH’iHż§³É† @ŻXžT&ĊDÍì8O†z­²j]*^ݰc‘ێú€´oĝü™áŬSÔ  qïC^óG%~à oQÊG£Á´ĉ`ÁoĠĉZ™Ċ@ğ~0-Ĵ +£rÉMÓ&èû nÁp-îµĤ%x~âÑPvĦèĤŒ÷ĈUÚLş1ÛĴÁ…Î’”µJN"Ùĥ"ŭ#|K°ĥ>ĝÛÏAÑ[ƒg…µT³˘Ç[ƒE$TOĉĉ‹Ĥ•³F4ŸĜÍüÒ˜ o Ċ°İc–³Ç=˘˘İĜÄúˆŠïNĈĴiʋĉ+ÓRy<ê˜6 meÓY`Ġ§‘ìŬĞ>qĊ‰4ğ°Ĵ.6;5•û×{J Nż”tBѰÀĝArN2ç<=ĦŻ:ŭ2•Ûğ+FE™İ)˙ÀȝbĞ'O”}Óí´?‡v“dgí@²Ÿ­ĝl¤-?°ġ´­üDK½QĤî!Á6b²S°ċżòjw*ÑĞñ£2ĥ°@•j¨ñ£‹P{Ww&·' ĝÖ{1”VtvÜ)ßÖ:ÎçäF—Äëĥ=˘•r#ŭ·rûcNmş•üÀF{Ŝ;%ŬÙĦȏ@è˘F ÑBÈ&0=Ê3ÈßäÔĜbM&êá—}’öâ. ×üúޞD½Ñ`MB£„xÇv-7% í‹?qċŜ ÖPêε˘°Í’-iĦ*Ĝı-6K‹›‡.Y(“lĥĠóĝ–òĊöîV„)&ÏÊĞù‰Ö^ÙK+ĥ*›S‰U7Ğ˘Ê¨ä!ËÖĠ ÎTFċ³Ñ°ÇĜS )5U˜Ù,,ukÖŻDĥ…En5W1&ċäÛUhŒÇMw™>„uŒìı7dżĞëšĞÛÛI#ÎITo}àé^Û]­ĠÎû˜ċG#ÌX¤äŝŠ›Ġ WU#LI¸ÀÑKñUˆóp÷[?ô^C×) vğ +ˆ[)î1plt¤§d,†=A-$áy|CìH½Ĉ22ĥHt˘ïĴ¨3µŠMB€Ñü˘˜23zÄ˙eוĊôj5ü§ğ0#§WMĊԀëÓ~êŭĤÖ´GĦÏêŻ,Tt-;Ê ›ë­—X(ŸáPÑN~ĥI$äġ·%¸EĊòFIÜ‚ìÁŬ˜[Yaş…ş_AïӉWN‡xMˆ-xµ’Ö %c477Â|îöİ :û'§,TFĦñEUV"-hĊyi:(…oqmuN™()YÀĜôÓ1”ED’6™vœ,Ój¤?ä= È·Í[è"Ħ#òĈŭuĞdzJ˘ˆù£Ÿêĥ¤pU7TA ݉âûà˜WzI½uF²¤#FgzBÎĊj9ŬêçJ%E¤ĞÔé˘ tO÷´Ğ ³Vkèçx@_\}âċ³ì³žÍ VfÍmĠaŭŜ<żĜE=êQí ä3ôl‹e/Ħ­Á³H´òİö7ˆ‚­ìÑÀ¨ıwAR†ċĉ+Ŝ{N˙áá‡áäĤôi­ŻŸ˘GĦ6JwÀ={ċĊ‰úR™–;l•wşçŠG‰+Ž$ŽĈSȇ²‰ïÑŻ˜a?‹ŽÏ>˜SĝìœlêÙşĜ·@W xNÛم×üS™J}´¨3^ïöżğIŜÏ/iĵÁ^ Ò.Ôşì9ÇŜĝ‹I· ÂiEğÔ_6Ebq‹ŜdÓŞ Şñvîöߞ’ …za…?}]ŝ”ÍV“ġ;’"Għ?§éM„ÊšL +QHÊŬJ$)½oÔĠ8/°ësDĈN†u8YNˆäŞ?a ĵÛí#@·ËŒ=ÈċLùP­.|3ä]°š"dPĵÇ÷ô Š{ƒ¸vO +“niş)6£–eD~brħˆXëÜ雛ŜB ÒâKFUşDŒ&ŭë>š‰)Ε%½Ë²wií˘>IÌV1+†°A6j, Żğe …WJÀşĞ\ôˆDmÇW§_ĴûûÑEŸ+û&Œ‹cû S?n³f8ŸÁ% 7ÖCm,êS™Ż£/ڜgcê*3t“aòyğgPĴŭp>“qQïN%ŠÈ5ĉeËôĜÎJżëĝdA-ċbN§2ZH™ĉcCfNĠşƒ¸_eŬŒ%ĜJÛpóÁk +iŜÀ‚İĵŜçŠĠ”'JDTpË\&ŞŜù8ÖĴÓ :üü.)£ĈÚ­éÊŞû’Ì!9ĝ7FОö>³÷v¤8MXÌĜOÙ^ĉjêĠ$ïĤäh!3EwÔWÈ\Q=Ï*@<Ġy0í?t+ĉGéiäBWà]ĝPjšnχÂZô9ž-áǍâTI…6ĉ€éÈ>T3fÓ‰/X>_ÛÒÇ| ĴWX¸ZGÈŜD—mè:£Ê睨 Ĉ;êC*ïüÀĘV$è{ôƒêğ/|ûU>òg{Ÿ~Ĝß}ߨö•6ŞŠŠGĝÙĥš ZŬç^ÑÉĊä¸Ġì'—Ëğ{˟-l.]é`k•×]î΋Ġ„'šPq”€4•XtÁÁ­@|"yÛÓ5҅'Wàú Bô€“Ġ½´ÍG)ŸÔÂ<Ùù×?¸?Ġ#³Uİ%µ&:j­éÑ,~i;;^yİ÷9"Ê뤑 ³ö³‚Çj³ P41-°{L²P2\û§Äm…)Ş #`ŒcŸ=75/Òû}5Âì-{'`/{²jĵ•Ì'ĝ³›Ĝ$ĊİsÁi½W ÑÇh zŸˆ¨oÙßĉ9Zcsi„‚ħû…Ğ£ĝġıJ.r€„M/×Sı¨•5âÇŝÔ:Ç´Ĥ E°ˆyX>O2ĥ,êœzáit$!d—rŜ=çísxŞHmëDrnûdż„…×ß²ĝ´'ÎĈ_=­`ĤtŜş›@ŸiÑıKSBĤ ŻŻĊ|+Ĵ8“Y(ŞçġŞŭ,÷] HûaİÙĵlP_ßWĈ˜Ïád9Aû#|´çœ5Â.ê­Ŭ4†D=Á‡KcïDïÉĝ§A/…ŽŜ.Н\c“.Ĵ8´3NÂ~ÊDŸùÄ×´Ğ҇"Y6+ +P—#…ĉÄK[FoyGÑO—ïܕ~n’ƒ%óT ƒŬß´Upĥ\ÙÔM¤ç5œì-Ò žGaŬkȏk !{"bFSZhİ›†ÄœšCïç“ÎĝŽ11Ž%YÈ@×ŬµÓôŬ„è(ħrE•XÛD¨m@òü2߉÷ımġÇŞƒZäŻÌ^=„MUzȊğòĝëTa.˙Ñ.é‡qˆN<ïGOߨ_xÓÒ½ˆbĠ’ny"D+ ÷Ÿ›oהûÛŭ…âù™žħ/еl´í £6-qÖêö¨…vŠ>‘ [ĦĵzÑ@ìĝ|Ì/b½ĝeUäĤŜ"– Ò0“%\²sġx +E ÁFu'P3/„Es”: 66‹Ŝ¨˜PÍ!½;Ÿf•b´Ϟ·7CZŬ +~ĝ›ċġœ(}Zá+M…RĜàmäwş+Ş6·RtêxŽùt‡ì˅]uZ²oİcŭ•ÁMUĥQÀC!qĉh÷7–ĥáŭ›ĵІŸg8ÏTkŞ÷Š޳6 ŽÑó„÷²Ğĵ’´CX/”Ĥnĉĉ}_ìÂΓÑH¤Àt`“#ŞY X`ÜñßÉëL˘3~k•=Wb&³ġùVΟjceoe•0èˆĞ)=ĉ^„:ħŬtŭ~+ÂÔvRĉĥZšĦÉeqür×;Ÿ33ìŭìòŭ .ó¸çĠşŽÍ3€| ÈGÇ(ù5“.+ 0ìĤUK–ŠĈ› ÷%zYü‚³{R}^Xbj/ۖÔJ'V¸tŬÑìħ˙ë鞉DÎPZ–ÌŒ:‰ÏWŭßşk9)„ÛTíöÚl Ûbâċu²‡Ĉ­–˜1˘9|9nàu^êÌïwëoXšĝ”ÂОŽyÁ$…ÈOûTħFĤeŻġqí†Ê~àĝ˙ċÀˆÔŸş Q˜ô”Ĝ ġOÍ+4B™£|òZ2s˙ mbWĤ’”¨œžîp{ĵZĤ#ΎÎdİ\Òíċ'xĵĞż06 lMGĉĤîܧ"zeT)Hŭ—^×A§ín·ÜMŒ#˙UÜTà +endstream +endobj +1829 0 obj << +/Type /FontDescriptor +/FontName /FKYWYP+CMR12 +/Flags 4 +/FontBBox [-34 -251 988 750] +/Ascent 694 +/CapHeight 683 +/Descent -194 +/ItalicAngle 0 +/StemV 65 +/XHeight 431 +/CharSet (/B/C/D/F/G/H/P/W/a/b/c/colon/comma/d/e/eight/ffi/g/h/i/l/m/n/nine/o/one/p/parenleft/parenright/period/r/s/seven/six/t/three/two/v/w/y/zero) +/FontFile 1828 0 R +>> endobj +1830 0 obj << +/Length1 805 +/Length2 2064 +/Length3 0 +/Length 2626 +/Filter /FlateDecode +>> +stream +xÚ­’y<”kdz˖8e;éaLÉ2c ĈĜ—,c™* 2Í<Ĉ cl‘ìBdçèPYҐħ•„BÔݤ"ʒ5¤p„N$Ë;ê=§ÏÛù÷ŭ<˙<żëúŬ×ŭŭüî *gç jL˘ÍiT†*†Lmq€€İ @ĦĤtÀ Ó¨G P@ ÑÀ8È PWZ:Hmu (`J󣓽ĵ€˘é‘ +0öéd" +ĜŜ {‘@hD2ȃĈ +€Û9àÀ@ ’`@"Ài‹L€ïa¨ž4ġ½L +ò˙ğ ÒÙP€"òÀF$Ѩ”0€z +Àħ4ö] ›ä˙ġópó +KÛżÒżÚ?2%ìżšŸ¤ĥ4H§ŝl= ~g³Iä żŸğB&S½(  ö½D4'‡‚$;2ƒè x(à·:H%ŭ ÁÎíÜg‹q:Ĥüŭ=żġìd*1Ì˙Ÿİ;ĉoñC³ÓĦ“CĵLM Á6²żż˙Ü~şËŒJ¤‘ÈTöBhj:&ÀŜ ĥÒ™JC0” ‡Qi ö€ÉYÀ“FĜyN-MnĵSúĤPnñC!8ĉ‡ÒàĜ”ĥ:ÇŭP(~ò›úw&&´pU$PU×TšJ}ö|Ä :¤2í;Íżµ'™=†‚DÁW4˘nœO^C3ÒĴäE‡‰×ítl}ÛËğ‚ħ”kOĴ”FëœÖ+ ÄEfxf†lÈ&·DĜw›/F¤ç÷oÍ{Ìœı#´\`6í/ż;·§ıĦïÓĵ&ÇħŜÑ.fĥséƒÂçÚ)u|Ç÷FnW;>ĝfû8-”“yċxb|Ŭ!¤N4?€y^#q$D4;“{äyl¤O"£ò­%Hl½„˙JÖÖ)>÷+WöĠ,ôs–ʨ×RsJžċAKÔĞÂÈbêi:Š_hO†€²üI‹ ÷ÈskwkD.]â÷žYx'mPŭ/Ċc zD£ĝ&ìĝ†'57·˙xÌ/z¸?  +êGG”.ĉ>ˆaá§ßdÉÏĜv‡ +ÏiSĊJ/?ŝúċĉ}WġĜ•gċÖ1ĦWk +Ëß³Ž5UCŝ*?‹Öví³è¨¨Lğ̓ ˘6}2ĞĥÂD0n<Ġï7£İDjeûà—°°œüœĠÇÇ0âô÷Ì­ qŭ‡3!–äת>MhßÎĤ÷2(Ì"HöS [Û8PÍ\<ğ‡‚n7I[1€ĊŬ.­İrÂğ%İĝ²q%>Žàt˙÷‚ ċYµ‡SŠëëƒväœèô7{@£~tӖ ›vü’x†|ġ>Lwž ›.Ŝ)âÍçžĜÂĉ×ÉF„=*ÂñËëùòÛÇı\úĦĉy{b˙ì})RYğµ[ĥeoê’X³Ħ‘;jŸT™óħ-žv$Î0§ÚĴÑ3Ñb9‰GPĠ†ŻżT’Ĵ­ğO¤(ĝ5"ó•µğßJie4Ô´GeLԝUE³}éYV +ÑbzĴ*µ ÔÙËİ­Ŝíŭġôù²ĵÓÏ+ËBûO>w›EYjŜ½Ğş •ŝÈJĥ9 [6UD¤ÚsʽSos˙ĥÂÖâèÓ[!çFħ׈übùĉäĦbÉó“x?_ܐŜTçr= ż­A_BF½Öcĝ +1]Ëڐùĉb$‰ Y”ÏFàߟ"Í Dë1|ħygtĉQz VÌÔĜ³ès<ž,;ëĦШs½rV²ŜʂĜߘ*aĜ¸Ĥ°§Ĉ|_$˜™Š!~‚çܙĦ•ÚÎ2Xi‰ żéfUf`t:‚ûIċ€GÌ4°%ĞÁħoò-üüuċ“÷bí˘"XòREe•ĉ›–]ŸÓE§b˘Ïë |@m}-²·ş¸ÎduÄÄ|ô·éŻïœmú-°ú Ŝ¤oû•œoÜäu’XŸ.³ä³QÊzĜ5‹S·dïc„ìU–ĵMwsµ+CyŞi'ֆ^×ĤY;+²Öâ‘áUQ:ËJï”G>2ĥ5sL_&Š5-`ìzYÔu~éÖV=ŽúĴ‹_œ-.””ĊYe™ÄùÖ·yŭñLiV(˘Ĝ-‰çq›ħ4JîùhÓUW{YxKËÏ=ĉs'.P 5.„euM+÷WwÙ[ÑÉ͵aĊÉà½fiôÀ·ĤJœ˙ÂĊ~!#Ĵô,”Ò{xPv3ÑȊ܅µyÑk?ée$M^OèIm³Mtœ… + ĠÉ'Ŭe•Ş( ^W]Ïġô$)X÷‹Ëa+Ż'öu œîÔéğ)óôş ı;żp"~gb5<” çmqH^ÉÉÏÑ£ŭ +MAÓKóŜu'˘<ŸwZ>VxlŬvkLRîzù3”’‚–CÓWħ İĜ†GZöş]b$ßbğĊ‘ó­Á§Cw‰†[ Y³k—)“żß.‡Ô•—ÇĠ6oÑ-pJxé^FuJâŠZĊ£î5s¤tğ ÔaHb˜.yĦÌĵëaÎîJpÓhÒŝ Ŝ2ş:ñNĤKxġ>˙JAûŒk ĈámwŸÜWŻÎ͈/—ßžÚ}-Adj¨ŭéÄcŬJĴ ‡Jêó_Ÿa+úÍä[ND´ŠàXŽd Ù_­KUë,[ÏҘħ*v—§ 7 W.4Ë}F+ÇËUúnüĤ+ÙÊȀ˜1y`QŒê@oƒËWÁ>˟ي÷(Ul5E{×µ~W²ĥ]ĴsĊ3jŝ҈şt[Á?.\,Ôz_ıŸwé…İEkëÑtóĠĖvÍ­fhéŭ RôÖФ6¤fÏuŜM‘”ŞÁ­¤ğnööŬûCòjJÇŻì˜0·ġı½ĠҟŠşbÊ bċüġO6ô=ŞŸ y‚żPâÏñö^/ñÒ ş`\ĴаS¤_z9•B"áu6Xµo×2‘s³ždÜïáhò  °Ù!7‹ÑXVjê÷Ótùxi³îë2nYlN²­­QUa‘až›ħ5neCO^ĥÑ5ÁsÒ"İ_ŞĞ×÷"*x¸’ôdwg3žz­ï>Ík…-½aïpğw*UdXjÀĠŽ( yÖŝëï›ÉB€Ù.Œ+‰÷gÚĤÄŞC°•—CÂğĞd.Hù> endobj +1832 0 obj << +/Length1 747 +/Length2 1286 +/Length3 0 +/Length 1814 +/Filter /FlateDecode +>> +stream +xÚ­RiXSg•çÑ£†M[•í,bHB lŠ“ˆ6)ğÊ%ıÀ… É $@0,:T¤*--2 kË2E„Êbq‰-Bħ Y)€Ì3ôï<÷Ï=ï9ßûžï|/ÎÀôa'6Ñ.z˜ˆ'ÚÎL/ +@Ä08œ3QáQÈ ÚÚ'A@"Dk;K[;ƒœ‘h GgÓupŠ‚x0 äL ‡˘”=X 8°`á'Z?Áĵ >ċ…Ĝx ‘°a +„@a0cħîDžŠ”÷eĥ ú ñĝJS€‰Ò¤) ´ÈF¸À†B1nˆr¤tò˙0µı9]ÀḁQëí•ŭ‰£`Žèß<-@!ÀDĜğYê ½·Ĉ„Ĝ° j3낂˜ċÄ @á} ĉÓa!Äö€QV8 +rĝFâ²7›PĈĥaÁâ”k€“qh57(ĉ˘Ŝ˘è˙4]×n`âħ2, x¨*żg6˘qYĉ*×ÁÊy÷0z•6/vş  1Ležµ‹şU‰™)6ԔĠÇêfżNݽ`3|#–÷éËS>*íú‘à³Ö¤Ï™ÌU½ŜwdLÚ1™KY˲·Œ1yT‡ĤĞwnÙí8rĤċ°Äış§ħ‹ŝİ2•Vf¸şċ,š–¤B ÏÉ= ~´€9GúläwżYŭŽìKd:‘u5û)ëAšŽoçzëğdrˆK1{jEUÖğŬş·ÄŞ K/§y1ŭŝéeډ·MÛOcC"ÜSÛ &ìN˘e'´ĥ d_ĝA˘Ĝċ2BéyPĦÚ0z)ċeD<ó‹½ùısĈM2Yò·O'çġ=œ%5Şš2‚I |ĞÔħĥéh²¤ Ŭ”œQB;[{KÔ_×Dżr¨ú›Ż2 ğŭ÷pĦ&˙ÛhġĦİ–÷·ğ vq÷ŻùıjïiĈ˘ÁŸwW'…§I8Zèımz …Ï÷Ŭ˘w|jÄȎ ' tŸpïÛ4UúÙ{-Ġ* +~ĤE<"ޤPÉ5!ğÊċö!“OmEUœµŻ}ì<ÊFfs33lç‚ÓK“ġ‚¤'“vÎğĊù|N¨\RÛݨ°glˆçaċè%ë>5Qı<†CVËó<üċIyÒ¤%=ëÜkáO1eqĉ³o†ĉ‘³×³gúêKöG˜£–X-—íċ”s@_OhüwW^vtˆÚL,MŒY½’ëm5{ĜPè_ğbJj™Ž½– \\CìÔPYŒ×ŬJxCŸĜmzS|>cqdËb½î考{Ñî"ì›ŝĉ1]K§˘Ĝ­ñ‰ĈKŬOíimš£ó™°-ş×çĜƒÏ:Ž­L)–ÁİtpÑ-|,ÇĴpšH SqD47ĥžżĜĊ€ĉê:İCe™ùZÔì}g>Ëp²kĈ.Ŭ 0>)Ş_YvŞ/oÁfQ[Wûöw÷ĵkÖ¸½ŝ÷İœHFuOrôšCPñ• %ÄùʙÇmŽ˜ M„1Wá "‰ŸıDÜ·Rĉ˙ lŸ +“ éÄçŻ[ÜOt5ŝŻ>×\¤y˙¸¸_PzM˙Ċеn‡ñ5JIcñÏu”c=eYZòß$ÚW{߄ż•ê²:n÷štç^²Q\”ıñbµ5%3y%5÷ġ˘z~ö אĜÌ{ìïÌşòk‚­Ĉ‚iîòXBĵôd%x*ħ­Ñ5²òî‘!O™=(€†N݆xO¤-?˙Ĉd?×ôÄùw^]2•XW˘–ÂĤ³m…vż˜ĝ4œ‰46\gžñiÉŻl‹­Íñêí­U6ĵğP–ŽXTİÎWw´ӟ™ċ§3Ñ)‘{à è\˜‹Táx&ô‹9Żq¸c7ġç‚Ó÷÷e0˙·àw +endstream +endobj +1833 0 obj << +/Type /FontDescriptor +/FontName /LKZNMG+CMR7 +/Flags 4 +/FontBBox [-27 -250 1122 750] +/Ascent 694 +/CapHeight 683 +/Descent -194 +/ItalicAngle 0 +/StemV 79 +/XHeight 431 +/CharSet (/M/T) +/FontFile 1832 0 R +>> endobj +1834 0 obj << +/Length1 815 +/Length2 904 +/Length3 0 +/Length 1456 +/Filter /FlateDecode +>> +stream +xÚ­R{8Tyî&jğĴ†Pżj=’ÌÌĦ1Ş]&˘—IIЧcΙq4sŽŽƒ÷J%Â>ħÉeyÚDı+Ô°vcġ(]´ı´ÔĜMıdsكzÚĠżûœÎ÷ï÷ŭŜçŭ>µBS„Aí œ2…Xà; ÷Aħ8 CC>‰ÂFàÛa +µ%l%âÏʌcĊċ1 ŸW˜Ä—ĝĈS"°‘Ħ$&‚qà S¨Œž!‚@Hˆ0”R°€T +ܧ:€;€’A(Âb@@0|P †3ĜSŽq1x30è˙ +BÉÚĜ@›4´E„À +€ b[@oĦ´“˙ÔìáöRİ–MŸNé–aRĊ{!ó¤P8Jâ³{ÑsÎ(‚Êf³Ž,ĊD6¸DŠSh3‹cΝ!°{LŽ"%òbX€N(ŽÌĥBÇ7m„íi·ÇKèiò~ŻÓ¤+ŒáÔn…? +8ĠÓ5ôħĤS"19ĜÏaq8-¤żŜ³³E‚á`Ĉµ0I +}AtĊĦÀp•TN;f³p‚˘[M8$cj­ĉĉ€MwÁ3 £ıi˜2ĥ8ú/ˆVŠ0R$EESûŭHp[†áÓÀ§IĜÚòPS3K`jiA;ƒ Àq˙#’$ŠSÓÇFçùĦcôPTŽŠím„È:Úï̵ùvÙÍjlQeQ_ğúOžeé.äfş­•P9/²:Kj™‡ZtvŠĴSV%şñ‚Ó/(,½çùM·šġ@ÈT‹M]œµëÚÙ}ċTÖjĥUjC+ĵ×ÎOŭNC´0ÖÌ9°t8µÌ7á%›ÙÓżıİ­yGNW”lŽ–nF˜›÷uFĵ l?ħ0Ĥ§#ŜŸSĜ€Òû‹Ŭ.¨Šä†VWYi÷×D,EV¸d…ç—jާLï׏Y_(ç;4é $·{·Îçd–û琝²^ğAİÈt(Ëd"E{G%Ú_ÜÖÚy=Rżw84óĴH+êÒ-hĠ‘xiúĦ΅OşDûTĜiUd|ğXeĥĴâ–J-M™ ŜŸˆ–“1wı)ıüñìĉ,íÏ:nŽe^òSï;•ŬÏzöĠÄdr³Ş†ßûpuoXžUCͤX“[Ž£ñĊoLŜBÉG‚5ĉkvJ[>huş> endobj +1836 0 obj << +/Length1 2243 +/Length2 14662 +/Length3 0 +/Length 15873 +/Filter /FlateDecode +>> +stream +xÚ­µeXœKÚ5ŠCà ğÓ¸ğğğ5ğ'@p'¸ğğ'x hp·à§÷Ìĵ;{ĉû{.úkŬRĞÖ]U™Š:“¨Ĝ $vtcbcfˆ+jh°ħĜ˜YYĊİ¨Ä]@Ĥn6`G S7€—— êä`ç°ħòq²C~ÈTq°“·‹•µ€VœîŻ$n€¨ÈĊĈÜÔ hêf r€ô07µ¨ƒÍm@nŜÌQ{{€Ú_5+ÈĊdÁŒÌĈ°°1w˜Ĵl‘YŝÒ$ëh p˙›ĥpwúżÈĊ" +@û/™tˆH °£½7Àd‰Ì˘†Ĵ‚hù˙CÖ˙6—r··W2uĝĞŭżœúâĤ6öŜ˙É;8ığ\Š` ‹˙Ĥjƒŝ-NdaîżQY7S{sQG+{€ġߔĞ”ÈBĊĈÍÜàĉâú r´ĝ_ çŝ€EFAYIUá?CŭWPĊÔĈÑMÛéïe˙ ³ŭÁ{\lĵúĴÙ ‰ż˙ûÏ“t4[Ĝ8ZĜ\SSodÈñ À— `hò€ĵ ‚Y˜ÁnÄ€%Ĝù݉r,˘Q˙F\ħ?ˆÀ"ŝñX$ŝ ^‹ä߈›À"ġħX¤˙ vˆ€Eöâ°ÈŭA-òD‹ÂÑ˘ĝA´(ŭA-Ê#ˆ•?˘Eġ‚hQûƒ ZÔ˙ ˆ?˘Eó‚hÑúƒ Z´˙ ˆ?˘E÷oÄ Ñ˘÷AêL˙F:S'ÈU2…œ żs *L]ÍmlÌm\ÌŬŝĉ9Ù˙â!‡ÙĈĠîÏŝJvûS éhöA*ÌLÍí\íM]­˙fÙĜ9˙˘]ŝA@\0s15ك,ŬŝA˙C˙û +˙Ŭ•íß´Èíżòy9ŝĉ˙§bˆùß‘hĥ‡ĵoŒó/ĈÁá1lĴ×ŝ8ÂñŜlo˙O͐ĞÀúÓ’úŻEıŝŠ;ğCŜ–żğ@ôA½İ?ş@²üÓ’aiñĥ…Áî˙\’bġgHÜêŻ÷ôÏÈvŝ¸Í 1ÑÚÛÉäĝ góoû9#v˙€żŝl‚ bŒ=ÈĠġqˆğ˙Ĝä‘aù³ÒËÑĈô8Äub…!;rú†4s2u9ŝ× 9Ùŝŝ÷˜9!ۀœeŸÁqBÜr²w˙‡Z6üg7!wë_ß·?sâü‹ğ,Ìŝ웗ë?ä)áàŭûßJĜĜ -ŝ16ˆß4!E ›˙>„Àżr@˙ÒÄò˙½ˆ—˙s“Ĝ Şŝ, „ĝâfíúÇùĝçĉ ŝG¤‡ûŸMAÖt‡<Ï.ĉ`—2r@ˆ`Ï\KHSŻ@ÈŞŜ˙€úüÑ éärù·‚˙÷%&öòeâ0ħs!ï2äċdġ˙Ż4swÈ Ŭŝġù‡|ĉŝ[Ú@‰ ÈyylÎj›Ö^ Y0]O-fĠŻTß3׉²”m_4&ïLż^§óPžŝ ŝİçÓ{×è?Ġ ݳ`çĝÏó/żt”§B+Ħħ‡ĝƒ ŞWߣĦ73”‹[G*^3"ĴŽšƒLíígçÒHΈ5ϷɉpkS!ĥH- ĞàwĴ‡¤Ü¤c¨{s„ĜĊ²—š§l#2˜xÖ $Ĵî×b PġEŬ,Tf™U½éUż·9.·ß­tOoŞ·ĠözC}ÚzcF?A°7Ĵ@‹8ÍëŞ}‚X.…ĤwÄ'Ù\ĦĝÖÎĥ2D&Œ•½Xò?Y8SùĢW˜FSҀéóJ,?BÒĝĥ) ?uşËĉC³%à›ÀFcĊšdÒDŻÒ1şžŸÜEâo"è1íĴjŽëî¤WÌİ4Ċ…c§üŜ+Úĵ#Ş Ġ# ^Oí80ë–TÌÎ_ô5t͜F=ċ+lÙÒĉOÎ =ÙMşwv ei²4sz•çĞ7]h˜e³rĴˎ¸_‰]ùßÎnTÄöĉä÷]Œ ·KÁé^ÜNœË‚H¨â ğŜŭÊ÷OŜß0sHôğJ ·08,]$ ÓĉvpO(§h}ó–çu”<’´äßυKx?Ñ8ö,ÓĥzġzÁݲÈù?~/T‡;q)CŻ{Ĵù[÷ç²a%hsM–—}üÚSAEbc(ÛEZ~ĥo“ĵ}Öŭœ<׌#}Tpoè*·²âƒc֋ù]n^¨@_{wşñ Eĉ`‡|5îi~÷Uıě—y££g³ˆÄ­>ï‰OĉŬ"dpڐ!é×pL· ò8¤|7Rژ|ü—Ż–.)j'òFŜ›á&ʸFáçÙ9a—70#zžjġè›u%EmĴ½iBġ|'†b Fg2WĜxÖ)ÚÖ!~ÍÔÒ޽eòd9gސ9‹hı “‚š‘+îÌBn†­½CÙ²6÷ŞÓÁµÍnkA2Ĵ òVbñàÔ vĉr—M*d”‘ ĝ³€ı~ ŠŒ;#’Pbç†ô=£ZL´ Íd×ù¨ZçÊroN}zgĠ@]—Ä£çóŜĊŸ„œ‰)úŞHZ` gĦcU!ĉ(&sfpBĈVe%eĜß,‡Bsû’xVcËj@Ì%jtîÂç`’KUíà͈Çí²¤4ŒlVxŞEŜfeĥ²+h7UişüÌŜµieQĊtÛ-p—kóëLü4í%6ò-ÒÍÚŭÚOÏĦÜÇġÇIġ@ĝŸÒ‘ŠĞ3?ìşD>˙„Ëϸ}àۖ0AC.WŻ˙€ĥxÜUE¤ZÍX\ħ)£‡8ÎtûI³‘AħXƒx×İ~Ŝ^İ’Ë7Óġħ§hĤNÁŠ€˙17>¸·ñsôĝ׳O/"&BÁÍÂŞ½L2ħߙô‰‘†ië6(›Şôîĵ[ħIŻŜżèŽïĊK~´tŝ>ÌöA÷[@écI­ßN›~}•‘†ĥÌŬuy~Ù‘ŝvtA&$EÔu™s4ÄcŜ²›ä –İeR0ž™zùž><öNHûXkêq›ŽXüŽŜ}¨ŸÂ|ñĦrş g`É2ż'ǜĦ:/ċUñŻgö1²çn<nâÂ)Ż9ıBß;è¨ħhŞı×?Û„†™ïâskVċZ‰.4·‡d݇ +”)ÁJq˙Œ‚0Œ[½Ĥ9ò3<óÙ+Dö-kmñ>£Q’ž +³³Òċ™™û)’ÎTıĉÓVûñâŝò(Ĉ0;1ËYԖ˘S7ä]kDMʑùŬıZ}q 6xÁħnáğŭâ*kBas´‰3V-£"ŝ{z¨ĉèD5˨€eJħà,ÁŜ[ᄃíĜ½#fK2mӅO§£Żċq +nĵCôrĜgï#ÓÊğÉîĦ-F àŸ¸ž\(“X<]úŽuĠnU÷m?sä?ż"9ĉ,ĤîQRV…µx’Ù-=¨ĥgqàŸĉ8|“~"Ĝ7½`§"ù5ĵ9 2@ޘí1‡=ù²­Q(^ìcHuè9„³…(ôdÉÜŝÍ]³ YǓùËBòÇñœc#o٘?ĝ:<0·‘âwÌ} ó1CEî|>·Óż‡mg1Œlž™1x›fyÜlvîK„£pÇÒiғwŬCcˆˆ')I…>ySĞ—żT!ħĥ˙n`·dyUëéJ`™5îö ĝûY½²"Wx)mB€•oÛ]œÀAŬĉ˘×ÎvÚ^IvrÁè“Ú˘âReNrĜŝ€6Ld„ë›s„}’fAĤ&Ġ ш:)ÑİQ'Ġ$Ŭw f‚Ÿ-{Ô<áè“vÇ9%O9àYàğwMèŞyĠ˜ĝñê"Q¨íÒNG³ì褞˜‹8‘ñ(ĴLÊaL`OVŽwSPèrš8sûżœf.2ËÜ,0żg<ĊŠÒ~ÁÄa½™|jSRôğzAĊ›îB´6—+&ÔtٍöŻġ½’fԟżñn™1RÖòĝŒ¨¤ÊG;kîÜ9>2‹.DM‰Moöê7­ŒÜ{Ž90•8Ó´;óö5’L²Û8J?Š–&—‹}ŽŠ‹σÓI)ÜÜ>fmÚ×ĉ­ŠdLżı ŭHĥî¸4OZ„Vэé·Ħ?ëƒ ŠšËÌŬÔgŭJµ‚ĉè睛CŽžíLTQnšùÌÇÜlşÇgk"Ó)í™ìmÙÄg„–ìMWÎü%XÉAAbFŬ\”…AŠ°CĈ¸is +÷a 2*T°b¸9HĠKĝ‘şKĝ&ÈîèĥJüiħ-‹óŜȰĵFçgö¤Ÿˆ˜Ï™MŜàY²Èj˜‹ċÛáñ(uUù žĞΒùŬÀ“½â0˜0Ó^˜ƒà_G°XpĉcX~4“>ûĞĉ*ܲ)5Q:ò>ë›ÎQw² +eŜúŭéLq +špxAŒ,Ŭ[]l+lži“ÂÛŻè7Vv÷Ÿ÷‰HA‹:ŝlx3)lŒ§L3U3F\ô½ûÑÂ]p·• Ħi´“²žïÚÍĴ~h4{rġq­qòTÊwĠt w†ßâSóÔ2ħ!#n•‚i6Eìî}™÷ĴSçĊĴ~ÄŬĴk“iñM´ ‹¤Fu`νşĈT€ | ğ%óÇ[ߔ<ğf0R!éĝŬsH‘ŬeŻàLÙcd5,ß4˜+ĴĊŭë”I ñošħğğlé}…Ĵ’n.X İ÷Ùòémĥ)ïaJ%/݃ç6ğaıd÷'YIĈĠNç6œ1§7M^LÈ µërÜ_0C@ċ.îÒÑ,Z÷?y½²ßı]ôá~Tµâĝ‰&Ŭ™ğ1ƒ²¨@Êà“|·¤iÇË}s–A0ŝ\R>ċ‰^ú­½#”Kî§ïŭÈDß7Yyœt3ĞIK3\`ÍóÌp+‚WÁµHŜàúñuŽ__Ġ¨yk°-ŝË6œi³µZ3;ìÇ·ߎo|IVĵ³}?ûsc'JEÚÑĊÇ ûeĝÖPvKD_ìaöRġ/l­wż[p~YşÄĊ) +ϜO-aĦ},‡™gىXËŬÚışDĠĝ4'@à£ŝ/ùԟOîîœRìZ´oßóÑŬcm°„#M´vÎuò›Ó²İ‰ÌNm2”ß~œˆOtĴ“Û4*û˜áÔÑÍö…y7‰¤²#óîSĜĈİ?vĉğPE b³œġȗË[3‡"'³*•Uo×-Ç[‡€Ë2K¤8 ĥt˙"ŬĠGn&—´ƒ)ӋĊ÷ĉĈߜé†ÌÏ3Œ¤ "ĜşjƒŠPĊ4`Lİ5YP´şgÁ%xW”ôÓïRÇË(…›×V•Ò×oĞĝGÏıêHÖF÷³ï“!…ıE&MvĦ˜rmEĊîqQáÈ?ôœs1р_ )J4]>hM!%Yëe”LaQïÖqp”×`{2ĉİkĴéËM o’¤<)ùÀ@ĴÑ–Ù{Çn'fŠ:÷ÏÓoˆıäMÌ·½_8ÊiŬ07ší—­Rː6áÎâÑ1ÙÑGû£ Ġ„êö`vNIáÍëĠ“ì‘=‰îX¨ŭÔ˘?~a£çg‰äv-s{öën<Ĥ!<|ì²Ì (ö*VĦäñ–wîAÏö °q,Ûcò\ĤHŝI×ÔÚKuíE!.¸kê4mƒ:pÇĜĠ”Ž•È:ażŞL{Eš;¤ò˘bG9½ëĈ 4ÌÙz:7:s“iĝT =ĵéòN;½d +ĉOù¨}ŸŞ“Fşcƒĝ ‰áYYċfÚOÏzO+ħ}GVä̀™ıî +3ڛ– Mí‚{ßmÑñéùĵ÷4mħ{òd ÉfĜKhI?—Ĉ]:Ċ²3QÉZš/í#}ìĞóñ"ÁMÛU@“Ê6">÷WM̝šô?ñ>|ßkÔd{m˘ÉËʀ-1~¤@ÎDRˆÜò[ŭF/5_((~ÄîÄ~…4vÁÎòì+ùôûÌäòĝzG$—“R£Ċ“Ì?tĤ~š& u%ßÈôCV$ +X§5Bè­ßX$ŸÄͨMoyÎğĝâDÁL³­!‚Üo ™Qğgğ: +=5ìg7à€H$ÎsĉEû9qä,9=lĊûÊáNU6{4µêí”ñŻ™ı>éOĵşË75ŭE‘´Ú_ġ­½´Gä"]­Ygùç|>’żÌ˘[˘ĉòĞ3İ­ĈÀ@êìŬ³â}GB³*‹şäîy9ú¨?%!gÑ +šÍó’éA†.Œ`§¨%€Ċ?·žV•€{ƒ Ùñİ÷÷[X÷ÙV +rY&3äµ&‚S&5Xİı[ż7 vĈsĥìÏ&}EÜËßܓ½Ä&“;vë…:gĴ‰Ú™ ÷ŠƒDÖ½‰NtN‚5éLŸçI'+Î(ÁRcz× +Šì™ô_Ä)°lU£ĉI8n $ád,UŬiΎéŜİj´Ùï0E³ĥıŝŠÖPĦ,Û/Ç ‰Rûf¸7dÏu$ç`œ˘Ñ¸žvážÏ$Aäb6J>g;¸×›ğ´½´(ü„NĉkWÎ xî›}ŜİCۀYQ2NÍlĝQŻQŝ#ĥdŠvŸŠBÚ S&°użĞïĵrR:2)³]ù9tÑià*i$}·á×ÌŭĊN—Ŭ#~>#.Â%tqŠvTı›ƒ¸·ç‰ñI°Ğäŭ˘Ò +ġŬ•Ú’Ë`“ ™ÈĦŜFĥŭP4úƒxh‡èL?ċ&”OÍŻwbeêSq‡VÄʙžÍçĉ—zWf Q´K‹âaœƒ{½Ñhf)w"ZÎı-Ëßğżğƒú4]Ŝ#ç&‡€ċMŭĉö™•SAÌφÁ9˘ı.éAPĵsğ +À`Í^`Àmµ9İŻi@Š %}Ħî¨ík&úžYrÈ"ĝ&‡Ŭhz+Èĥc1żƒ@*‰ĵĉŒO.?µÜᨈʀ4ɑ^ï­U}0êïœë˙zKÓ#Ş˙V%À?kó0‚Ûè÷¤DŬnì&Ksž”—ƒz‚Rê9&ħ…ŭ¤ôĥòg_SÖK÷ñ‚RZĥe +tƒ¨ËÑ:BužXŭÏçSħ½}֘GnŽçİR{JúĴĈeW[á˘×*ÀÊ*9QEägĉúÊ-lòO½,GFŻ{RoUnkißċÛç‘`˜SËÚ˘˘Ë3Â_nß}fĦr ̄h z5ĉp­ÀZàtòöZd2R}ô0Òá^qc AL5cFtıQE×Oše+ŬaĦ\We§ÙR÷H;œtÊżb `"=ĥoL +aL+¨vÄ˙QAàİNÒéĝĞw„|ñĉüıI½µŝs'‡S"9A1ğ”Y+Éù› ˜$žš>;ïóS…9)+îL$L¨Rlħ@ öŭÒ óğëŽQèp-b|Ğ;B˙eTĜ*!ŝşĈğÁ¤d<ž³*sğ—mC÷K;Íc:?ÌğïâmŞRzKĦLöZ(ʋ|V)|gÀù½DnÁ˘ĴeòsÖßóßÇR#Fä Ôŝĥ‚Œöö×ïÁsİëeħç\ĦTÓp%œŽŜ|˜)–¤&v|ŒYİ1ĠDö{^ÍwĜĠîŝ9çh+Gċ( l0EYPĝäûSCb­Ú8—òmŸMóuL{JÀŸbñ× fhNâd'Cĵöµċ¨eȘ%m›äe´‡?ħܕ>Rĵñ°˙u4ŝÚŬ‚ +—\>Äë´×eS*'>1^pĵ‚ñîúK˘Ĉ£b+Ŭc˜¤ Żyµż`|$¸ü &ôişeb7ùe=TĦ•&bß³$  l­2ŻäéôREsúċ {{è÷: Ô2‡ë +FcË'Á˜v N··“ÎKĤçyċ8˘Ŭ?ŒLì îĊ\/*lvžb§ :Äú#uÒ.‚ñ÷lŒcşċ˘ĥ†ĊBCN† {ÔK£%V # RıŬĊ„ö­ĝ=ċFv9EÎÇ÷nY'¸z>ßnŽnÁ£+a– ôpGż›ÓÂ'^çMĤ%ׇ}Ä2C›2b-Äó‡]¸€/_ôÍĉ˜f*ÉO·\1ݲ˙¨•˙Š}‡ÍĠÜ ŝİÙ3.´›*×îĝކ°arI(ÚŞıÂWÔ…u“ž„Ï‚ŜˆÔM_kcĤVd™)}/òn$AX"l ‚{+°‹ĵÙÇŻ³&ĵœi}“ŻúFöĦPF9mIq*ŞQ/ jU×ün%}Ísé¤6Žá[‡ÛWƒ·ïç‹ †%–³’è/ËVñ)L³“z’¸ïKbfâM>]&EcÏ˘ôĥ°œ?7T”Ġ„çpµÔ*4kB³[=ĉ \'ĦèœG'eS°Ê£L(eıĴòÁ”hZ›¨D…Eš€~7Ù[´5>ŝĤÍŻ„(&ŝPu•íÊŭ¤³4ı‘`–FX´ÓaÍH+B!\-Ĥ•Îz[5 ˜ËĤ›F\y…Âvĉ1ft׺Àá9  üc3'ß²¨ÌY‘JPJc҂2ÖRĝ=!‹ÚÂŬçA1…ŬЇ†Á°U…:zİü&0Â(d”Ì⠔@$§îËv›|’Veç‡$‰ûÀœ4ĵï– )4ZŻl]ZıݞÈÚӈCßäcD³‡—ŒŭÇŬùŜ[Ĥġ‰*=•ŭéïü_îï‚^kÛÚsws†ġż+b1àäßòêàŽÑ8eòĥ#ċĠ™D"é ġé¨İsŜ3xv‹£òK:Jĥ ×ç˙žvÍÓÉâÂ.BpóIú~3?›ĝ‘jëĴFhr§@ì¸Ĵ‘²QeÊá+Ϛ5@á¸T%:^ŝ›§ú,Z†>ë–&°{äz9QÇ~µŸ\Ŭu#Ħsr6?ŒÔc/ÁR´_ž~yˆ£ŜĦĵ+ ׸ıêéÀ '`,´'‡K ßôÇ;GG!ıÉE’n,Çà¤EÀyÎÙÑ7˙6ĉ$D?{1“„iáêBzÎĝ<ĝğnŒÍŝšdóPœ½Êĉ$¤ŽŸ§iŠœ ¤EŸĉ¸lYvġLIŸ-O™ġó‚^Ú"<ɓND[2‘ŭ_“ħÓJŠż€I‡€C UpjĎĦËĝe‘-of¤Ê+Ġ ‚Ċ&Ğ S^+X³î1u÷1^çeC mbO‹˘“ĦŒ/bHüÂAJÜÁâ·ĦWD•÷Ĉ‘޽"Yuä'0ßĤ9Ċ²í0 £ŻZĜĉğ›HĊ³ŝ‘*îr!Ŝh“ípsÜ˙ ß’}ú,H:H|VÈ´û|(ƒ Ÿu#zÏ겘ġó“ÊÂ\ëm3Á| +—Z 1qÉ}üŻjsœ(,*“Uèم?ğ›Fbe?hĉû:b½ûJ²Ğw:+òĵQVvñ—äĈ•Ŝ+$£L   Œ+ïzġÙïmX*üœĈJ­gĤMùKo¸;Hĉ\„Ì“ġĊÄêer3Ġl?›Ŭdp}hôOŒ÷ŽAÉ/!ħŝıfçı|K¨ġˆEz >4Ż×ôÙBƒË:žĊIÔ4´ÚÜDßü Àġ şCżê'\ëBpk⪎‰n\Û*aÙ§ïŝTMŻh9rü•4UݤžeÖ\­?ġŸtÄäēì1c´Œ8Ö817U6HüżĤ!/Šo€‘â3ŠŞıÏQNd\Ò?MÊéy:Wf ÓıkĞÓ£’s]ċhv›ĝ“Jġñ‚Gk˜9ž"Qdcgâ +UfhŽLóL֑Ĉİ×ĵTé˘+¤Q%eW×h’ĝïkôöaJ[ÂÀ{x= ƒ27ÎĊŒi\èVÖÉ×(÷l,ŬÓzÑiÇW¸¸îxĠ´ôm™œĦ:]mĤ–o²—˘HA„`Ê âÁ #ä÷SöÇFÁ>ĈÍş‹?ÇxICÑHm˘:^Ž&xn[ĥ³ŽĴBÍwe£•sÚ@™ ŝœ&’Ŭŝ&á¸Ïo`MĠĊ6;eìóOĠżöÁÒvoj÷ûú˘á ŠáñÄ[”H‚sx=Âg*΂;î +³%ÊJŝĝo²ħ3FÖŬOa,²g£@m½ÇŸ( Qê\Ż2 +SáÊÔ z§Á¨Ŝ,”şŠÍH}™e‘<Ȓ³ä'ŝLĥô~mè}/qhY8i?pĝ]zĊä{Á Kŝŝ½-.³‘;OövD­@ì×%Á\Şr™ íNmèù‘Ĥ§QĥQïħ6÷R%É24<š‹<[ĤĴŞz.ĈŒžÂ˜•ö{ı9ßÊŜ6Öı>Üü‚·79YJ¤;>֕ +˙=ۛ-ŝʵ{ŒÓ—tŜ½Bc"w>x–E–î’wc˘ĵèÖÓĴzr8w)6™éI´˘R!ZS£i4x>#™z͐xxäĠÖò‹|Wß7žÙĤjŻáEŒĝGŽRQàjìyĦhÊÚhß~;Ó0 ÈIo÷E89ġLÓԏ†ùĊ%'³ħIS*Ö^¨<¨Ĵ²ÒÒmĴîz~9xvM­Ħ+‰›UEûí¨DÉ:Êħ€ÚäŝáL”½üܲ=•äçn×nsaS‚°ÍH) ’ï¸ żn$/3ĥĉ¨ĵ+]weIÎŬüó|ż€Ġf%ĉĵX¤<Á܋ѓ+À–J4>]ı& …:Vù@ ӆäl-ÜŜí6OˆújÛîÏä—ßßİ.-mjkXÜ?hğÛĦJ!Ğr8œpo†áéÂ46œ!mU.Uȋ-LzQ(W‡è·˘XÚeÌ ‡ĴH"ġÊË56D +YqĦöQRuÈz™XW•Ğy]>´kZÜßçj½âĦM>ñù„lá‰qÂ(ŝ€š>äbݐf*ŬA2ÒÚ‘Ì DBŽ&İï™òò5rĥúHJüèĵ÷Ë žüV_ì™ħ)u½Opóµ)ġ÷(ÈRß@ÇHĜ'*uÔû ¤6é °Ó2̎qİMĦ°0˜c‰sŸ`Eĵ)4po“;áUÓ|S¨ÁĞ@ĝÇĥRhڝ­}(Ɉ=tĊ´Ŝé{ËħşĥhÚëŬ´ÊĊÖ`‰8Nŭ›Ë³ħL²ÜfĊÌäxo+Ĝ2ۏ‘ġÈÎ?bW”) 3ÀšÈ/ĵ„!S²—Tµħ„”~ÊR žĈê{äÛë,è](‡Ĥñ Ŭ`ħ½çŝXYÑĤ)ßüĥWJ§ÑÊF²QaŻ5 ‰˙tglŞÏŻÍOeԟC$Ey;C¸ŠPÖ·ZÑrž<ŠCESñלġëZZV_Ü=ú Áވ‰²6ƒüFòÖóT'1àp Ŝ֋ğ†û7 ïfÁ·gHĴĠĵ7è-ŭĥYp0&™à*Ó0ŝ e:6½eœlñ-² ”V$Âëûß0íĉ(Ħ¸Ï#lXwÈüÒJq½†ĜÈPbÑí˘?#IëL“·ÂÇ@Û¨#ní˙"ƒĤD¤yF?{ĠPù”ĝ™ò0>úJvĴ›'ŝ•dròŞnŭe˙;g7v„KYï+—ü1p/ğÌĦaŻPzëˆ!’ ċ^„Í7ŞG—ëċ1xíŜŸ&²jĈwuK†$ŒÏè{Ù_Òap:éË~Yle•z)÷Íïl0}HElŻĉ[.—‹Ò-óo‡Jó‰èˆƒŭÖs·ûrQáG·“2ZS_=#íĝu•úÁĵÍ6ê<`÷ÎgÚäs:9ÖšLĞÉôôÑÁêî.k +v­—ï´¤½%—ŜAœa+4ıš ˆR–ÌqYy€FŬPË÷àtÒNPûëtĜàÒNfva1š"ŬÔÌ=Tf^{İĵSrœuĊ‚˜ŭIıöŠcKèûù˜ĥÔ=Î~\ÛèXyDìıÎŞ²9lE÷TDS1çħF´F”ÏËUFäÄÏ[1rÖwïŠ.ħ<³1k†|ǸB#ò™şótÇ~ĈçGŽì”²èÏĠŻ ÷L zŒuş²|G}iqÄJ0ĊzwĴTGÏöhĊZ›ÀT +{Ñŝë]8‡€Ğûž÷úı‘ğ‡N+ JñtŸ„Ûĝv]2ŝ2ĦŜĥEĴĝgżI:şVñµıé´{ü2ۇ˘˜ğ.MQâ6:´gŜX’AuŻkʁr”4ÎȊWìg£p?—ÚéU‘Öj5ReëE _ˆÈ7vû}s€ŞÁ÷r€­3żós°½š$ µŽ—Ä5ĈĈêW˘.gy>ğM´8”kj3‘¤ìÊóŻŬJñ:&ŠŬuÍîe§­ĉĦ4³oVPl·f¨ġ—ÉŒ‘µWzK…ZÜİNbEIŭ,Ĵ^ê +uĦK)* 'ŭWJüèJž]Yù?Ù‹R~âQHŠgF`ĥà +“b°?B÷_ÍèËĵ™ÜŞï›ï6*n8·%9ş(§ +M÷Áe„p`|_;dAÉ~ˑĠ~!cÀ`ò1â˘ıp2ĥ“É`x‘Nxs˜ÒYq)1_Ħp¤¸uÏ6Ĥħâl9“!69ûĴ‰3öĵœZğğşN½Ê/†^·X›+H(ĵ?Ŝ=Ê Bh =ƒé¤j=YĴbä\ş˘ĝy ŽEgçz[´Ï"ŜŻóÛX˙ó6\”aħhOáGê*M%Ԁ'.éC×4wŒr›1yôż7­ÙpŻzÏÂßnҀ)__÷Ĝd#pâ('úœ“ÂÎJôĤ˘)Ŝ(aß –şJ‘ ş8*mˆžDPçôöÇrá÷X‡Àv‚rġPïíâòÍÔ9>}Áßy˙ËÂ)gF"&iŻnġAî§_7?ĵ+J^uœKéÇĠ5Ŝ“!ÂDˆ +PxZ^ĉÖmğ½1ìŽ?' {tÔ˘ğh<ô4$’?ıŜ5‡KúŝȐÈÍrÄċžËßgBMjaáŠŝiZŭlQ? § +ÈèÏÑ3œ)w' ÂImSíAp +ŝUÑ%i~ßáhĵ}Ò ôâ[OWc2snq[äİŒhA_Új—3Eĵֆݗ<—gêr:ÖK–JĜU+™_ħòì(èKò§˜Bà=}HĦ}y‰/½§.wËxoéÂÈ˘NOŠÛYĦÚrF‹4OBH(•'‹ŝ/ސĉ½mñùè4êçy˙îWé Ž ÖäÏĤW“ğżâÉJ?mP,MI3ĥI€~“Eıġ¸_!_ÑÖ[jP–²ÊĞŬC <”ê4  #ċŬônİÓ̇ċPZĵğ1Êï‰Ğjóž–ĝŬ‘x7O-b•5Ġ³0§–7ŭ1\Ğšxße‚Ĥ"É+Ŭs Dĥ@ÜÙĦş |³5r·3ĠëÑ£0<îߏr…‰Q{qÍZ£ĵÍĉÜCµ™ġäsY$,,!˙sıT.–Ìé§i×Û&›24jCÑ£ïi”ö;ëoµ ~ëŜÑdĊt>Á4á(ä2Àoq`Ŭ +YdİÊgrlV|LEÜËâ|YÏO_fĥ1× Z|ġúŝUêÀ̊ڝ²ġâÈñöVŻ'Ŝv͒ Ż‹ĴTäÌ´7ċ×DgŞÛ'żħOvd~”awĊÎêŻ>òĦßvŻßi9ż€³fXˆ‹~MÌwS8·ÉHŞlĊ\}|§?ż6‰›&ˆìgSïOüvŭ$•}GıOr)‡ö#RSĥĤi•›IFu|Çw#èÏ dŞ”ŜB¤çï|8„KT ­K¸XHTœü>÷V—°½ƒ=4– :`è]i…Nŝĝ> ’­â¸Tˍ§™ä·ċ‚:ŜËŝšoç3µżh_/7f´W4.Úéi’Œú{£ĤŠ3ò2û$üúáVü{Ş6·ÛǤfj"k9,vIĜ CÓ* ÄvşĜ…é(¤rıú^½˘"j|½ÛíĴA Ê6?ĉÌâƒMzĥ3ï°` 4÷ıÄEÊí &÷ìg£Ó#Tş÷İaıùĵS£ä}†0êL¤è$D^ġËc@‘>?Ëí)ŜÏÄà‹HöÏ|)´#éfÑĞ\lğĵÓH9•1+Ŭ&³ĈyÖ6G×{ğDÓeyTœ¨{‹#W(Ĥċ1öa h ıÀƒ`[ĠZlWa{V†É߸½MÈÖĦ‹EÈĴÔ§M +¨Fc<óìħ%çÜàT(ĞÈzMŠĊD£„F]YdÏÄÍàY˜’œo˜ıştˉo*Âq_ O7,žBĜ}ްCrL?ŻÍQ /ϗĦò…G‘ ߄Òé~7—<è”{‡Żì½r·3)Ĵ†*mż, rÌ&f¸*f*99İËú˜—hÈċ”; şĥÁú†³ápçyrs`ÖûJfN÷ëh‡ĠĤtVéJ&ˆ£!Ü˙‡²hbD#UIΠNÎe‚´€´sHO”u%Ix`WÑSá­ıÒ×ÔİKŭ§—xFÉòb•<ìH÷”Ípü7éġÖV¸Íŝ2ì+÷ġjŝ(kÄÔòÓŻŬ³G‹Ŭ"ù–éžâfjŬ +6ËjgÎĦ0·#â[Ž9¨z ̝S‰!ìŬ~ÍN—B— CC´=bı?`³Èݽ;°Hçs§˘e˙ŽŭĠ'{'Žák|•9Ú}ËT!…jû­GÄâäá:…–{REé(œ0:ÈTĊ$ŝƒcĵĉ}9)ÉŜÉAě³Úpêo#‘xQ“^#’·’ĜiÒ·gMX„OĜ8Ô Ñfì4ċUytŸ‘<=ùŬK nÈ|7֗5^5™ûš˜Mg4$†ÍÈ +â‘%WÒŞÄ§œuИ&ıŜŬë(Ñc.zŞ7† z„ŝÍĤˆnMa&?Sc€*ÚŜ Ĵ·Hú€żĠ]•iu‚)6ˆ§}£)şÖ3%D2½Ĉ7—Ÿ`ĥéÍŬ·/¤qÏ{4ɖâk sé}Ä2­%’µ’!ñêqœn•ĤZ íİgÇüst‚áŠÏa+™“°î Ĝ¸h†Œ!Ì6…Şç. –;ŬÏ1xƒÏSD@ŜM<‹u"b>”Œ·rä]•6ÓˆW8Ä6„Ž{ìŭ>èËbgE ÒZ< ÷U^úx݆k¸İ>(Úynñ‘…Ôôħ?J z]üœkQû~\Ë PÏÚŬÔ×О5u+Îƒm@ĞȘĜĵ8݉‚ĝĵ’FŬĴ~|÷Ô­Ĥí´c ŭBÒŝxZ¤ŠÛ 8Î,ġFZÚlΐ„ÒH"*XÂáĤÉú§<˙Bò·‚•nnˆA™8™!… 0T“Éh·neZìr*vl_u)„–DÈĝŽŝKœB ~́ìĞq "ïg^˙s˘e^ÉíÑH7̛—£U€Kı`â:Ö 8è‰hLö14-ċg֐ĈŞġ2L!FğÎ›ÙJžânĈĉÎïXŞ_ž(ħÜ\ŽĊí“H…L& ñLÒzİ]Óû3Ġ´V +Ŭ‹ĴÚCB•ĈâzKldèż²(Z8äTêi…ĉE^àhĤ¨ñ’'à÷Ĵ*Äî°ĥby(ħE@4ĴzÚġWŽ‹t\c´§X]¸ĵh,)(“yÒôóë­ĦVb¤Ÿ‚ZoğÜò³ġ“#ÓëŒĝ5Ó,{`q2Ċ&O͎ı}ĥµòœUİ$=‹ŻĴ~—Ëçeħ2aáÔ¨i1êX„y‚3yš÷ț?8–ċbUìĈ—CµĊıTĉ-òr7ò ÷‡¤zOÊ~ÒÑwŜ¸ kĈ­ŭ>; ­†=•6\a'Ġ TTÁĠìôRD;ÛiÇFzñâ¨UĦÌŝĜcŽğ!wôV× ×:7:¤t-„ г•ħJÀ‚Ö7½:aÛKµ;³÷×:ıĉêkWÎCnO“'ç,ŻÓÔ¤ÎmĦIa ;ÈĠÜR•m”˘–-œ?T†)DÙĤŞyċkYǑZO Ë=Q`Ħ>+šÖ&8G£=ÉÔÄÎĞñ Œsᵂ!ò\ċ™Ÿœ§>Ñn—D}aĵy‰²ÄR׃ ­JCf¨ÍVĞ*Żqĝ*PÎ9ÜùÑNġÌ.TğR‚ùŽÛD’#?ö +[>óµCPûĊ+Ġ1Ä1j~Öú‰7+Jh&ڑ’û­ġU‚d>eµlšħ“Á˘äۓÙS=Ò* `pz90xXlĝ¤&” ¨îˆeÒ ŜsÜ$,pġl‹·V7Ŭ~b8d¤_ŭ°üĝĤ‡@”ù-‘$ROÀ>4ÙCÎÔÎH + +ynÉRZ…MJİAZŽ4žĜzœĴ•-9ò—BI›&ÖÛZƒÙoYB­šó2R':ôWŜh\[r×ü|vr·šMœT}6^šCŞĵ‚Ñü~œ–JżÔúġSÚÜĈ!ĤÔǤ­Ü`Â׃ú "{êıOWŽı |Ç2ï’\žj„{31…oùğSÓvL)ĵħÔvü.³rÌ~Ï£XĵݤP.ħ˘ëŬ36ք˘)ŝĴQÎhëxñ‚CĤĥ°N§˙ZŜF1žÁżH"âÎôúdmœš›@>ù†öĥ5\47Ŝà]ݳ˙ OQ9ÊNċ"Sw,‹ádqÈ…AŽĦĈ(›_oAéŜš³BKàĵzDîµI`Á¤…^§kĜÉhXœ´gĈK C·˜Cd5÷^ŻÜIÙ$éĴ· żüŝöĴ"s¨ äj•éĝ¸ Û5y‚·-h†[Ğ | A]_¸vLÁNá1ĊĥzġŝBLvúÈĜ"²jlmí;/7Û/żîÄ-ĵ“ç31§ ô­Ĝû žÚ‡~ĵ5)ÉÏrĴ/lKŠÀ³œ’-ßQ4!ċÛë2Zßfµ'?÷ŝ<ƒ)ŠÏtòžôµÂÂÇŞIòÛ³NLx£i(wáŬÉOĞßʔğ÷Ù$–Ù‘"ΔU.~ŸɁK Ĥ÷ *kċ+•S˜Ôŭ Y]%ôhÊ n‰H6ï@ʽĥŽèns²ó=İW_…+Ħ‡Ş„‚Š—_Nn}ħ½ +9ĝ+^‰ĥĞB;Ûpí‰lÊlX‘EgŜ•Ïàħ&Ŝö/xGÓm˜}[9ż„û˙3ĠV +endstream +endobj +1837 0 obj << +/Type /FontDescriptor +/FontName /HLONQR+CMTT10 +/Flags 4 +/FontBBox [-4 -235 731 800] +/Ascent 611 +/CapHeight 611 +/Descent -222 +/ItalicAngle 0 +/StemV 69 +/XHeight 431 +/CharSet (/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/a/ampersand/asciicircum/asterisk/at/b/backslash/bar/braceleft/braceright/bracketleft/bracketright/c/colon/comma/d/dollar/e/eight/equal/exclam/f/five/four/g/greater/h/hyphen/i/j/k/l/less/m/n/nine/o/one/p/parenleft/parenright/period/plus/q/question/quotedbl/quoteleft/quoteright/r/s/semicolon/seven/six/slash/t/three/two/u/underscore/v/w/x/y/z/zero) +/FontFile 1836 0 R +>> endobj +879 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /IDSUQC+CMBX10 +/FontDescriptor 1821 0 R +/FirstChar 11 +/LastChar 122 +/Widths 1814 0 R +>> endobj +823 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /EQHLLW+CMBX12 +/FontDescriptor 1823 0 R +/FirstChar 11 +/LastChar 123 +/Widths 1819 0 R +>> endobj +833 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /SYFPBV+CMMI10 +/FontDescriptor 1825 0 R +/FirstChar 60 +/LastChar 62 +/Widths 1815 0 R +>> endobj +826 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /XXGKWP+CMR10 +/FontDescriptor 1827 0 R +/FirstChar 11 +/LastChar 123 +/Widths 1816 0 R +>> endobj +824 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /FKYWYP+CMR12 +/FontDescriptor 1829 0 R +/FirstChar 14 +/LastChar 121 +/Widths 1818 0 R +>> endobj +1136 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /PRMIXO+CMR17 +/FontDescriptor 1831 0 R +/FirstChar 65 +/LastChar 87 +/Widths 1811 0 R +>> endobj +1089 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /LKZNMG+CMR7 +/FontDescriptor 1833 0 R +/FirstChar 77 +/LastChar 84 +/Widths 1813 0 R +>> endobj +825 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /XEVZSX+CMSY10 +/FontDescriptor 1835 0 R +/FirstChar 0 +/LastChar 33 +/Widths 1817 0 R +>> endobj +1094 0 obj << +/Type /Font +/Subtype /Type1 +/BaseFont /HLONQR+CMTT10 +/FontDescriptor 1837 0 R +/FirstChar 33 +/LastChar 125 +/Widths 1812 0 R +>> endobj +827 0 obj << +/Type /Pages +/Count 6 +/Parent 1838 0 R +/Kids [818 0 R 830 0 R 835 0 R 839 0 R 875 0 R 914 0 R] +>> endobj +953 0 obj << +/Type /Pages +/Count 6 +/Parent 1838 0 R +/Kids [950 0 R 988 0 R 1025 0 R 1060 0 R 1073 0 R 1077 0 R] +>> endobj +1084 0 obj << +/Type /Pages +/Count 6 +/Parent 1838 0 R +/Kids [1081 0 R 1086 0 R 1091 0 R 1096 0 R 1101 0 R 1105 0 R] +>> endobj +1115 0 obj << +/Type /Pages +/Count 6 +/Parent 1838 0 R +/Kids [1112 0 R 1118 0 R 1133 0 R 1140 0 R 1144 0 R 1149 0 R] +>> endobj +1161 0 obj << +/Type /Pages +/Count 6 +/Parent 1838 0 R +/Kids [1158 0 R 1165 0 R 1169 0 R 1186 0 R 1190 0 R 1195 0 R] +>> endobj +1203 0 obj << +/Type /Pages +/Count 6 +/Parent 1838 0 R +/Kids [1200 0 R 1206 0 R 1212 0 R 1218 0 R 1223 0 R 1232 0 R] +>> endobj +1241 0 obj << +/Type /Pages +/Count 6 +/Parent 1839 0 R +/Kids [1238 0 R 1247 0 R 1253 0 R 1257 0 R 1262 0 R 1266 0 R] +>> endobj +1273 0 obj << +/Type /Pages +/Count 6 +/Parent 1839 0 R +/Kids [1270 0 R 1277 0 R 1284 0 R 1292 0 R 1300 0 R 1308 0 R] +>> endobj +1318 0 obj << +/Type /Pages +/Count 6 +/Parent 1839 0 R +/Kids [1315 0 R 1321 0 R 1326 0 R 1333 0 R 1337 0 R 1343 0 R] +>> endobj +1353 0 obj << +/Type /Pages +/Count 6 +/Parent 1839 0 R +/Kids [1347 0 R 1355 0 R 1367 0 R 1371 0 R 1375 0 R 1380 0 R] +>> endobj +1387 0 obj << +/Type /Pages +/Count 6 +/Parent 1839 0 R +/Kids [1384 0 R 1389 0 R 1393 0 R 1399 0 R 1403 0 R 1407 0 R] +>> endobj +1416 0 obj << +/Type /Pages +/Count 6 +/Parent 1839 0 R +/Kids [1413 0 R 1420 0 R 1424 0 R 1428 0 R 1434 0 R 1438 0 R] +>> endobj +1445 0 obj << +/Type /Pages +/Count 6 +/Parent 1840 0 R +/Kids [1442 0 R 1447 0 R 1451 0 R 1455 0 R 1459 0 R 1463 0 R] +>> endobj +1473 0 obj << +/Type /Pages +/Count 6 +/Parent 1840 0 R +/Kids [1467 0 R 1477 0 R 1481 0 R 1485 0 R 1490 0 R 1494 0 R] +>> endobj +1503 0 obj << +/Type /Pages +/Count 6 +/Parent 1840 0 R +/Kids [1500 0 R 1505 0 R 1509 0 R 1516 0 R 1521 0 R 1525 0 R] +>> endobj +1534 0 obj << +/Type /Pages +/Count 6 +/Parent 1840 0 R +/Kids [1531 0 R 1536 0 R 1542 0 R 1547 0 R 1552 0 R 1557 0 R] +>> endobj +1564 0 obj << +/Type /Pages +/Count 6 +/Parent 1840 0 R +/Kids [1561 0 R 1566 0 R 1570 0 R 1577 0 R 1581 0 R 1585 0 R] +>> endobj +1592 0 obj << +/Type /Pages +/Count 6 +/Parent 1840 0 R +/Kids [1589 0 R 1594 0 R 1598 0 R 1602 0 R 1606 0 R 1610 0 R] +>> endobj +1617 0 obj << +/Type /Pages +/Count 6 +/Parent 1841 0 R +/Kids [1614 0 R 1619 0 R 1623 0 R 1627 0 R 1631 0 R 1635 0 R] +>> endobj +1654 0 obj << +/Type /Pages +/Count 5 +/Parent 1841 0 R +/Kids [1639 0 R 1656 0 R 1672 0 R 1690 0 R 1800 0 R] +>> endobj +1838 0 obj << +/Type /Pages +/Count 36 +/Parent 1842 0 R +/Kids [827 0 R 953 0 R 1084 0 R 1115 0 R 1161 0 R 1203 0 R] +>> endobj +1839 0 obj << +/Type /Pages +/Count 36 +/Parent 1842 0 R +/Kids [1241 0 R 1273 0 R 1318 0 R 1353 0 R 1387 0 R 1416 0 R] +>> endobj +1840 0 obj << +/Type /Pages +/Count 36 +/Parent 1842 0 R +/Kids [1445 0 R 1473 0 R 1503 0 R 1534 0 R 1564 0 R 1592 0 R] +>> endobj +1841 0 obj << +/Type /Pages +/Count 11 +/Parent 1842 0 R +/Kids [1617 0 R 1654 0 R] +>> endobj +1842 0 obj << +/Type /Pages +/Count 119 +/Kids [1838 0 R 1839 0 R 1840 0 R 1841 0 R] +>> endobj +1843 0 obj << +/Type /Outlines +/First 7 0 R +/Last 815 0 R +/Count 10 +>> endobj +815 0 obj << +/Title 816 0 R +/A 813 0 R +/Parent 1843 0 R +/Prev 779 0 R +>> endobj +811 0 obj << +/Title 812 0 R +/A 809 0 R +/Parent 787 0 R +/Prev 807 0 R +>> endobj +807 0 obj << +/Title 808 0 R +/A 805 0 R +/Parent 787 0 R +/Prev 803 0 R +/Next 811 0 R +>> endobj +803 0 obj << +/Title 804 0 R +/A 801 0 R +/Parent 787 0 R +/Prev 799 0 R +/Next 807 0 R +>> endobj +799 0 obj << +/Title 800 0 R +/A 797 0 R +/Parent 787 0 R +/Prev 795 0 R +/Next 803 0 R +>> endobj +795 0 obj << +/Title 796 0 R +/A 793 0 R +/Parent 787 0 R +/Prev 791 0 R +/Next 799 0 R +>> endobj +791 0 obj << +/Title 792 0 R +/A 789 0 R +/Parent 787 0 R +/Next 795 0 R +>> endobj +787 0 obj << +/Title 788 0 R +/A 785 0 R +/Parent 779 0 R +/Prev 783 0 R +/First 791 0 R +/Last 811 0 R +/Count -6 +>> endobj +783 0 obj << +/Title 784 0 R +/A 781 0 R +/Parent 779 0 R +/Next 787 0 R +>> endobj +779 0 obj << +/Title 780 0 R +/A 777 0 R +/Parent 1843 0 R +/Prev 775 0 R +/Next 815 0 R +/First 783 0 R +/Last 787 0 R +/Count -2 +>> endobj +775 0 obj << +/Title 776 0 R +/A 773 0 R +/Parent 1843 0 R +/Prev 771 0 R +/Next 779 0 R +>> endobj +771 0 obj << +/Title 772 0 R +/A 769 0 R +/Parent 1843 0 R +/Prev 767 0 R +/Next 775 0 R +>> endobj +767 0 obj << +/Title 768 0 R +/A 765 0 R +/Parent 1843 0 R +/Prev 759 0 R +/Next 771 0 R +>> endobj +763 0 obj << +/Title 764 0 R +/A 761 0 R +/Parent 759 0 R +>> endobj +759 0 obj << +/Title 760 0 R +/A 757 0 R +/Parent 1843 0 R +/Prev 275 0 R +/Next 767 0 R +/First 763 0 R +/Last 763 0 R +/Count -1 +>> endobj +755 0 obj << +/Title 756 0 R +/A 753 0 R +/Parent 719 0 R +/Prev 751 0 R +>> endobj +751 0 obj << +/Title 752 0 R +/A 749 0 R +/Parent 719 0 R +/Prev 747 0 R +/Next 755 0 R +>> endobj +747 0 obj << +/Title 748 0 R +/A 745 0 R +/Parent 719 0 R +/Prev 743 0 R +/Next 751 0 R +>> endobj +743 0 obj << +/Title 744 0 R +/A 741 0 R +/Parent 719 0 R +/Prev 739 0 R +/Next 747 0 R +>> endobj +739 0 obj << +/Title 740 0 R +/A 737 0 R +/Parent 719 0 R +/Prev 735 0 R +/Next 743 0 R +>> endobj +735 0 obj << +/Title 736 0 R +/A 733 0 R +/Parent 719 0 R +/Prev 731 0 R +/Next 739 0 R +>> endobj +731 0 obj << +/Title 732 0 R +/A 729 0 R +/Parent 719 0 R +/Prev 727 0 R +/Next 735 0 R +>> endobj +727 0 obj << +/Title 728 0 R +/A 725 0 R +/Parent 719 0 R +/Prev 723 0 R +/Next 731 0 R +>> endobj +723 0 obj << +/Title 724 0 R +/A 721 0 R +/Parent 719 0 R +/Next 727 0 R +>> endobj +719 0 obj << +/Title 720 0 R +/A 717 0 R +/Parent 711 0 R +/Prev 715 0 R +/First 723 0 R +/Last 755 0 R +/Count -9 +>> endobj +715 0 obj << +/Title 716 0 R +/A 713 0 R +/Parent 711 0 R +/Next 719 0 R +>> endobj +711 0 obj << +/Title 712 0 R +/A 709 0 R +/Parent 275 0 R +/Prev 635 0 R +/First 715 0 R +/Last 719 0 R +/Count -2 +>> endobj +707 0 obj << +/Title 708 0 R +/A 705 0 R +/Parent 635 0 R +/Prev 647 0 R +>> endobj +703 0 obj << +/Title 704 0 R +/A 701 0 R +/Parent 647 0 R +/Prev 699 0 R +>> endobj +699 0 obj << +/Title 700 0 R +/A 697 0 R +/Parent 647 0 R +/Prev 695 0 R +/Next 703 0 R +>> endobj +695 0 obj << +/Title 696 0 R +/A 693 0 R +/Parent 647 0 R +/Prev 691 0 R +/Next 699 0 R +>> endobj +691 0 obj << +/Title 692 0 R +/A 689 0 R +/Parent 647 0 R +/Prev 687 0 R +/Next 695 0 R +>> endobj +687 0 obj << +/Title 688 0 R +/A 685 0 R +/Parent 647 0 R +/Prev 683 0 R +/Next 691 0 R +>> endobj +683 0 obj << +/Title 684 0 R +/A 681 0 R +/Parent 647 0 R +/Prev 679 0 R +/Next 687 0 R +>> endobj +679 0 obj << +/Title 680 0 R +/A 677 0 R +/Parent 647 0 R +/Prev 675 0 R +/Next 683 0 R +>> endobj +675 0 obj << +/Title 676 0 R +/A 673 0 R +/Parent 647 0 R +/Prev 671 0 R +/Next 679 0 R +>> endobj +671 0 obj << +/Title 672 0 R +/A 669 0 R +/Parent 647 0 R +/Prev 667 0 R +/Next 675 0 R +>> endobj +667 0 obj << +/Title 668 0 R +/A 665 0 R +/Parent 647 0 R +/Prev 663 0 R +/Next 671 0 R +>> endobj +663 0 obj << +/Title 664 0 R +/A 661 0 R +/Parent 647 0 R +/Prev 659 0 R +/Next 667 0 R +>> endobj +659 0 obj << +/Title 660 0 R +/A 657 0 R +/Parent 647 0 R +/Prev 655 0 R +/Next 663 0 R +>> endobj +655 0 obj << +/Title 656 0 R +/A 653 0 R +/Parent 647 0 R +/Prev 651 0 R +/Next 659 0 R +>> endobj +651 0 obj << +/Title 652 0 R +/A 649 0 R +/Parent 647 0 R +/Next 655 0 R +>> endobj +647 0 obj << +/Title 648 0 R +/A 645 0 R +/Parent 635 0 R +/Prev 643 0 R +/Next 707 0 R +/First 651 0 R +/Last 703 0 R +/Count -14 +>> endobj +643 0 obj << +/Title 644 0 R +/A 641 0 R +/Parent 635 0 R +/Prev 639 0 R +/Next 647 0 R +>> endobj +639 0 obj << +/Title 640 0 R +/A 637 0 R +/Parent 635 0 R +/Next 643 0 R +>> endobj +635 0 obj << +/Title 636 0 R +/A 633 0 R +/Parent 275 0 R +/Prev 615 0 R +/Next 711 0 R +/First 639 0 R +/Last 707 0 R +/Count -4 +>> endobj +631 0 obj << +/Title 632 0 R +/A 629 0 R +/Parent 615 0 R +/Prev 619 0 R +>> endobj +627 0 obj << +/Title 628 0 R +/A 625 0 R +/Parent 619 0 R +/Prev 623 0 R +>> endobj +623 0 obj << +/Title 624 0 R +/A 621 0 R +/Parent 619 0 R +/Next 627 0 R +>> endobj +619 0 obj << +/Title 620 0 R +/A 617 0 R +/Parent 615 0 R +/Next 631 0 R +/First 623 0 R +/Last 627 0 R +/Count -2 +>> endobj +615 0 obj << +/Title 616 0 R +/A 613 0 R +/Parent 275 0 R +/Prev 595 0 R +/Next 635 0 R +/First 619 0 R +/Last 631 0 R +/Count -2 +>> endobj +611 0 obj << +/Title 612 0 R +/A 609 0 R +/Parent 599 0 R +/Prev 607 0 R +>> endobj +607 0 obj << +/Title 608 0 R +/A 605 0 R +/Parent 599 0 R +/Prev 603 0 R +/Next 611 0 R +>> endobj +603 0 obj << +/Title 604 0 R +/A 601 0 R +/Parent 599 0 R +/Next 607 0 R +>> endobj +599 0 obj << +/Title 600 0 R +/A 597 0 R +/Parent 595 0 R +/First 603 0 R +/Last 611 0 R +/Count -3 +>> endobj +595 0 obj << +/Title 596 0 R +/A 593 0 R +/Parent 275 0 R +/Prev 575 0 R +/Next 615 0 R +/First 599 0 R +/Last 599 0 R +/Count -1 +>> endobj +591 0 obj << +/Title 592 0 R +/A 589 0 R +/Parent 575 0 R +/Prev 579 0 R +>> endobj +587 0 obj << +/Title 588 0 R +/A 585 0 R +/Parent 579 0 R +/Prev 583 0 R +>> endobj +583 0 obj << +/Title 584 0 R +/A 581 0 R +/Parent 579 0 R +/Next 587 0 R +>> endobj +579 0 obj << +/Title 580 0 R +/A 577 0 R +/Parent 575 0 R +/Next 591 0 R +/First 583 0 R +/Last 587 0 R +/Count -2 +>> endobj +575 0 obj << +/Title 576 0 R +/A 573 0 R +/Parent 275 0 R +/Prev 563 0 R +/Next 595 0 R +/First 579 0 R +/Last 591 0 R +/Count -2 +>> endobj +571 0 obj << +/Title 572 0 R +/A 569 0 R +/Parent 563 0 R +/Prev 567 0 R +>> endobj +567 0 obj << +/Title 568 0 R +/A 565 0 R +/Parent 563 0 R +/Next 571 0 R +>> endobj +563 0 obj << +/Title 564 0 R +/A 561 0 R +/Parent 275 0 R +/Prev 559 0 R +/Next 575 0 R +/First 567 0 R +/Last 571 0 R +/Count -2 +>> endobj +559 0 obj << +/Title 560 0 R +/A 557 0 R +/Parent 275 0 R +/Prev 467 0 R +/Next 563 0 R +>> endobj +555 0 obj << +/Title 556 0 R +/A 553 0 R +/Parent 467 0 R +/Prev 531 0 R +>> endobj +551 0 obj << +/Title 552 0 R +/A 549 0 R +/Parent 531 0 R +/Prev 547 0 R +>> endobj +547 0 obj << +/Title 548 0 R +/A 545 0 R +/Parent 531 0 R +/Prev 543 0 R +/Next 551 0 R +>> endobj +543 0 obj << +/Title 544 0 R +/A 541 0 R +/Parent 531 0 R +/Prev 539 0 R +/Next 547 0 R +>> endobj +539 0 obj << +/Title 540 0 R +/A 537 0 R +/Parent 531 0 R +/Prev 535 0 R +/Next 543 0 R +>> endobj +535 0 obj << +/Title 536 0 R +/A 533 0 R +/Parent 531 0 R +/Next 539 0 R +>> endobj +531 0 obj << +/Title 532 0 R +/A 529 0 R +/Parent 467 0 R +/Prev 471 0 R +/Next 555 0 R +/First 535 0 R +/Last 551 0 R +/Count -5 +>> endobj +527 0 obj << +/Title 528 0 R +/A 525 0 R +/Parent 471 0 R +/Prev 511 0 R +>> endobj +523 0 obj << +/Title 524 0 R +/A 521 0 R +/Parent 511 0 R +/Prev 519 0 R +>> endobj +519 0 obj << +/Title 520 0 R +/A 517 0 R +/Parent 511 0 R +/Prev 515 0 R +/Next 523 0 R +>> endobj +515 0 obj << +/Title 516 0 R +/A 513 0 R +/Parent 511 0 R +/Next 519 0 R +>> endobj +511 0 obj << +/Title 512 0 R +/A 509 0 R +/Parent 471 0 R +/Prev 483 0 R +/Next 527 0 R +/First 515 0 R +/Last 523 0 R +/Count -3 +>> endobj +507 0 obj << +/Title 508 0 R +/A 505 0 R +/Parent 483 0 R +/Prev 503 0 R +>> endobj +503 0 obj << +/Title 504 0 R +/A 501 0 R +/Parent 483 0 R +/Prev 499 0 R +/Next 507 0 R +>> endobj +499 0 obj << +/Title 500 0 R +/A 497 0 R +/Parent 483 0 R +/Prev 495 0 R +/Next 503 0 R +>> endobj +495 0 obj << +/Title 496 0 R +/A 493 0 R +/Parent 483 0 R +/Prev 491 0 R +/Next 499 0 R +>> endobj +491 0 obj << +/Title 492 0 R +/A 489 0 R +/Parent 483 0 R +/Prev 487 0 R +/Next 495 0 R +>> endobj +487 0 obj << +/Title 488 0 R +/A 485 0 R +/Parent 483 0 R +/Next 491 0 R +>> endobj +483 0 obj << +/Title 484 0 R +/A 481 0 R +/Parent 471 0 R +/Prev 479 0 R +/Next 511 0 R +/First 487 0 R +/Last 507 0 R +/Count -6 +>> endobj +479 0 obj << +/Title 480 0 R +/A 477 0 R +/Parent 471 0 R +/Prev 475 0 R +/Next 483 0 R +>> endobj +475 0 obj << +/Title 476 0 R +/A 473 0 R +/Parent 471 0 R +/Next 479 0 R +>> endobj +471 0 obj << +/Title 472 0 R +/A 469 0 R +/Parent 467 0 R +/Next 531 0 R +/First 475 0 R +/Last 527 0 R +/Count -5 +>> endobj +467 0 obj << +/Title 468 0 R +/A 465 0 R +/Parent 275 0 R +/Prev 439 0 R +/Next 559 0 R +/First 471 0 R +/Last 555 0 R +/Count -3 +>> endobj +463 0 obj << +/Title 464 0 R +/A 461 0 R +/Parent 439 0 R +/Prev 443 0 R +>> endobj +459 0 obj << +/Title 460 0 R +/A 457 0 R +/Parent 443 0 R +/Prev 455 0 R +>> endobj +455 0 obj << +/Title 456 0 R +/A 453 0 R +/Parent 443 0 R +/Prev 451 0 R +/Next 459 0 R +>> endobj +451 0 obj << +/Title 452 0 R +/A 449 0 R +/Parent 443 0 R +/Prev 447 0 R +/Next 455 0 R +>> endobj +447 0 obj << +/Title 448 0 R +/A 445 0 R +/Parent 443 0 R +/Next 451 0 R +>> endobj +443 0 obj << +/Title 444 0 R +/A 441 0 R +/Parent 439 0 R +/Next 463 0 R +/First 447 0 R +/Last 459 0 R +/Count -4 +>> endobj +439 0 obj << +/Title 440 0 R +/A 437 0 R +/Parent 275 0 R +/Prev 327 0 R +/Next 467 0 R +/First 443 0 R +/Last 463 0 R +/Count -2 +>> endobj +435 0 obj << +/Title 436 0 R +/A 433 0 R +/Parent 423 0 R +/Prev 431 0 R +>> endobj +431 0 obj << +/Title 432 0 R +/A 429 0 R +/Parent 423 0 R +/Prev 427 0 R +/Next 435 0 R +>> endobj +427 0 obj << +/Title 428 0 R +/A 425 0 R +/Parent 423 0 R +/Next 431 0 R +>> endobj +423 0 obj << +/Title 424 0 R +/A 421 0 R +/Parent 327 0 R +/Prev 411 0 R +/First 427 0 R +/Last 435 0 R +/Count -3 +>> endobj +419 0 obj << +/Title 420 0 R +/A 417 0 R +/Parent 411 0 R +/Prev 415 0 R +>> endobj +415 0 obj << +/Title 416 0 R +/A 413 0 R +/Parent 411 0 R +/Next 419 0 R +>> endobj +411 0 obj << +/Title 412 0 R +/A 409 0 R +/Parent 327 0 R +/Prev 383 0 R +/Next 423 0 R +/First 415 0 R +/Last 419 0 R +/Count -2 +>> endobj +407 0 obj << +/Title 408 0 R +/A 405 0 R +/Parent 383 0 R +/Prev 403 0 R +>> endobj +403 0 obj << +/Title 404 0 R +/A 401 0 R +/Parent 383 0 R +/Prev 399 0 R +/Next 407 0 R +>> endobj +399 0 obj << +/Title 400 0 R +/A 397 0 R +/Parent 383 0 R +/Prev 395 0 R +/Next 403 0 R +>> endobj +395 0 obj << +/Title 396 0 R +/A 393 0 R +/Parent 383 0 R +/Prev 391 0 R +/Next 399 0 R +>> endobj +391 0 obj << +/Title 392 0 R +/A 389 0 R +/Parent 383 0 R +/Prev 387 0 R +/Next 395 0 R +>> endobj +387 0 obj << +/Title 388 0 R +/A 385 0 R +/Parent 383 0 R +/Next 391 0 R +>> endobj +383 0 obj << +/Title 384 0 R +/A 381 0 R +/Parent 327 0 R +/Prev 359 0 R +/Next 411 0 R +/First 387 0 R +/Last 407 0 R +/Count -6 +>> endobj +379 0 obj << +/Title 380 0 R +/A 377 0 R +/Parent 359 0 R +/Prev 375 0 R +>> endobj +375 0 obj << +/Title 376 0 R +/A 373 0 R +/Parent 359 0 R +/Prev 371 0 R +/Next 379 0 R +>> endobj +371 0 obj << +/Title 372 0 R +/A 369 0 R +/Parent 359 0 R +/Prev 367 0 R +/Next 375 0 R +>> endobj +367 0 obj << +/Title 368 0 R +/A 365 0 R +/Parent 359 0 R +/Prev 363 0 R +/Next 371 0 R +>> endobj +363 0 obj << +/Title 364 0 R +/A 361 0 R +/Parent 359 0 R +/Next 367 0 R +>> endobj +359 0 obj << +/Title 360 0 R +/A 357 0 R +/Parent 327 0 R +/Prev 351 0 R +/Next 383 0 R +/First 363 0 R +/Last 379 0 R +/Count -5 +>> endobj +355 0 obj << +/Title 356 0 R +/A 353 0 R +/Parent 351 0 R +>> endobj +351 0 obj << +/Title 352 0 R +/A 349 0 R +/Parent 327 0 R +/Prev 331 0 R +/Next 359 0 R +/First 355 0 R +/Last 355 0 R +/Count -1 +>> endobj +347 0 obj << +/Title 348 0 R +/A 345 0 R +/Parent 331 0 R +/Prev 343 0 R +>> endobj +343 0 obj << +/Title 344 0 R +/A 341 0 R +/Parent 331 0 R +/Prev 339 0 R +/Next 347 0 R +>> endobj +339 0 obj << +/Title 340 0 R +/A 337 0 R +/Parent 331 0 R +/Prev 335 0 R +/Next 343 0 R +>> endobj +335 0 obj << +/Title 336 0 R +/A 333 0 R +/Parent 331 0 R +/Next 339 0 R +>> endobj +331 0 obj << +/Title 332 0 R +/A 329 0 R +/Parent 327 0 R +/Next 351 0 R +/First 335 0 R +/Last 347 0 R +/Count -4 +>> endobj +327 0 obj << +/Title 328 0 R +/A 325 0 R +/Parent 275 0 R +/Prev 279 0 R +/Next 439 0 R +/First 331 0 R +/Last 423 0 R +/Count -6 +>> endobj +323 0 obj << +/Title 324 0 R +/A 321 0 R +/Parent 287 0 R +/Prev 319 0 R +>> endobj +319 0 obj << +/Title 320 0 R +/A 317 0 R +/Parent 287 0 R +/Prev 315 0 R +/Next 323 0 R +>> endobj +315 0 obj << +/Title 316 0 R +/A 313 0 R +/Parent 287 0 R +/Prev 311 0 R +/Next 319 0 R +>> endobj +311 0 obj << +/Title 312 0 R +/A 309 0 R +/Parent 287 0 R +/Prev 307 0 R +/Next 315 0 R +>> endobj +307 0 obj << +/Title 308 0 R +/A 305 0 R +/Parent 287 0 R +/Prev 303 0 R +/Next 311 0 R +>> endobj +303 0 obj << +/Title 304 0 R +/A 301 0 R +/Parent 287 0 R +/Prev 299 0 R +/Next 307 0 R +>> endobj +299 0 obj << +/Title 300 0 R +/A 297 0 R +/Parent 287 0 R +/Prev 295 0 R +/Next 303 0 R +>> endobj +295 0 obj << +/Title 296 0 R +/A 293 0 R +/Parent 287 0 R +/Prev 291 0 R +/Next 299 0 R +>> endobj +291 0 obj << +/Title 292 0 R +/A 289 0 R +/Parent 287 0 R +/Next 295 0 R +>> endobj +287 0 obj << +/Title 288 0 R +/A 285 0 R +/Parent 279 0 R +/Prev 283 0 R +/First 291 0 R +/Last 323 0 R +/Count -9 +>> endobj +283 0 obj << +/Title 284 0 R +/A 281 0 R +/Parent 279 0 R +/Next 287 0 R +>> endobj +279 0 obj << +/Title 280 0 R +/A 277 0 R +/Parent 275 0 R +/Next 327 0 R +/First 283 0 R +/Last 287 0 R +/Count -2 +>> endobj +275 0 obj << +/Title 276 0 R +/A 273 0 R +/Parent 1843 0 R +/Prev 131 0 R +/Next 759 0 R +/First 279 0 R +/Last 711 0 R +/Count -11 +>> endobj +271 0 obj << +/Title 272 0 R +/A 269 0 R +/Parent 263 0 R +/Prev 267 0 R +>> endobj +267 0 obj << +/Title 268 0 R +/A 265 0 R +/Parent 263 0 R +/Next 271 0 R +>> endobj +263 0 obj << +/Title 264 0 R +/A 261 0 R +/Parent 223 0 R +/Prev 243 0 R +/First 267 0 R +/Last 271 0 R +/Count -2 +>> endobj +259 0 obj << +/Title 260 0 R +/A 257 0 R +/Parent 243 0 R +/Prev 255 0 R +>> endobj +255 0 obj << +/Title 256 0 R +/A 253 0 R +/Parent 243 0 R +/Prev 251 0 R +/Next 259 0 R +>> endobj +251 0 obj << +/Title 252 0 R +/A 249 0 R +/Parent 243 0 R +/Prev 247 0 R +/Next 255 0 R +>> endobj +247 0 obj << +/Title 248 0 R +/A 245 0 R +/Parent 243 0 R +/Next 251 0 R +>> endobj +243 0 obj << +/Title 244 0 R +/A 241 0 R +/Parent 223 0 R +/Prev 239 0 R +/Next 263 0 R +/First 247 0 R +/Last 259 0 R +/Count -4 +>> endobj +239 0 obj << +/Title 240 0 R +/A 237 0 R +/Parent 223 0 R +/Prev 227 0 R +/Next 243 0 R +>> endobj +235 0 obj << +/Title 236 0 R +/A 233 0 R +/Parent 227 0 R +/Prev 231 0 R +>> endobj +231 0 obj << +/Title 232 0 R +/A 229 0 R +/Parent 227 0 R +/Next 235 0 R +>> endobj +227 0 obj << +/Title 228 0 R +/A 225 0 R +/Parent 223 0 R +/Next 239 0 R +/First 231 0 R +/Last 235 0 R +/Count -2 +>> endobj +223 0 obj << +/Title 224 0 R +/A 221 0 R +/Parent 131 0 R +/Prev 211 0 R +/First 227 0 R +/Last 263 0 R +/Count -4 +>> endobj +219 0 obj << +/Title 220 0 R +/A 217 0 R +/Parent 211 0 R +/Prev 215 0 R +>> endobj +215 0 obj << +/Title 216 0 R +/A 213 0 R +/Parent 211 0 R +/Next 219 0 R +>> endobj +211 0 obj << +/Title 212 0 R +/A 209 0 R +/Parent 131 0 R +/Prev 167 0 R +/Next 223 0 R +/First 215 0 R +/Last 219 0 R +/Count -2 +>> endobj +207 0 obj << +/Title 208 0 R +/A 205 0 R +/Parent 195 0 R +/Prev 203 0 R +>> endobj +203 0 obj << +/Title 204 0 R +/A 201 0 R +/Parent 195 0 R +/Prev 199 0 R +/Next 207 0 R +>> endobj +199 0 obj << +/Title 200 0 R +/A 197 0 R +/Parent 195 0 R +/Next 203 0 R +>> endobj +195 0 obj << +/Title 196 0 R +/A 193 0 R +/Parent 167 0 R +/Prev 183 0 R +/First 199 0 R +/Last 207 0 R +/Count -3 +>> endobj +191 0 obj << +/Title 192 0 R +/A 189 0 R +/Parent 183 0 R +/Prev 187 0 R +>> endobj +187 0 obj << +/Title 188 0 R +/A 185 0 R +/Parent 183 0 R +/Next 191 0 R +>> endobj +183 0 obj << +/Title 184 0 R +/A 181 0 R +/Parent 167 0 R +/Prev 179 0 R +/Next 195 0 R +/First 187 0 R +/Last 191 0 R +/Count -2 +>> endobj +179 0 obj << +/Title 180 0 R +/A 177 0 R +/Parent 167 0 R +/Prev 175 0 R +/Next 183 0 R +>> endobj +175 0 obj << +/Title 176 0 R +/A 173 0 R +/Parent 167 0 R +/Prev 171 0 R +/Next 179 0 R +>> endobj +171 0 obj << +/Title 172 0 R +/A 169 0 R +/Parent 167 0 R +/Next 175 0 R +>> endobj +167 0 obj << +/Title 168 0 R +/A 165 0 R +/Parent 131 0 R +/Prev 135 0 R +/Next 211 0 R +/First 171 0 R +/Last 195 0 R +/Count -5 +>> endobj +163 0 obj << +/Title 164 0 R +/A 161 0 R +/Parent 135 0 R +/Prev 159 0 R +>> endobj +159 0 obj << +/Title 160 0 R +/A 157 0 R +/Parent 135 0 R +/Prev 155 0 R +/Next 163 0 R +>> endobj +155 0 obj << +/Title 156 0 R +/A 153 0 R +/Parent 135 0 R +/Prev 139 0 R +/Next 159 0 R +>> endobj +151 0 obj << +/Title 152 0 R +/A 149 0 R +/Parent 139 0 R +/Prev 147 0 R +>> endobj +147 0 obj << +/Title 148 0 R +/A 145 0 R +/Parent 139 0 R +/Prev 143 0 R +/Next 151 0 R +>> endobj +143 0 obj << +/Title 144 0 R +/A 141 0 R +/Parent 139 0 R +/Next 147 0 R +>> endobj +139 0 obj << +/Title 140 0 R +/A 137 0 R +/Parent 135 0 R +/Next 155 0 R +/First 143 0 R +/Last 151 0 R +/Count -3 +>> endobj +135 0 obj << +/Title 136 0 R +/A 133 0 R +/Parent 131 0 R +/Next 167 0 R +/First 139 0 R +/Last 163 0 R +/Count -4 +>> endobj +131 0 obj << +/Title 132 0 R +/A 129 0 R +/Parent 1843 0 R +/Prev 47 0 R +/Next 275 0 R +/First 135 0 R +/Last 223 0 R +/Count -4 +>> endobj +127 0 obj << +/Title 128 0 R +/A 125 0 R +/Parent 47 0 R +/Prev 123 0 R +>> endobj +123 0 obj << +/Title 124 0 R +/A 121 0 R +/Parent 47 0 R +/Prev 119 0 R +/Next 127 0 R +>> endobj +119 0 obj << +/Title 120 0 R +/A 117 0 R +/Parent 47 0 R +/Prev 115 0 R +/Next 123 0 R +>> endobj +115 0 obj << +/Title 116 0 R +/A 113 0 R +/Parent 47 0 R +/Prev 111 0 R +/Next 119 0 R +>> endobj +111 0 obj << +/Title 112 0 R +/A 109 0 R +/Parent 47 0 R +/Prev 107 0 R +/Next 115 0 R +>> endobj +107 0 obj << +/Title 108 0 R +/A 105 0 R +/Parent 47 0 R +/Prev 79 0 R +/Next 111 0 R +>> endobj +103 0 obj << +/Title 104 0 R +/A 101 0 R +/Parent 79 0 R +/Prev 99 0 R +>> endobj +99 0 obj << +/Title 100 0 R +/A 97 0 R +/Parent 79 0 R +/Prev 87 0 R +/Next 103 0 R +>> endobj +95 0 obj << +/Title 96 0 R +/A 93 0 R +/Parent 87 0 R +/Prev 91 0 R +>> endobj +91 0 obj << +/Title 92 0 R +/A 89 0 R +/Parent 87 0 R +/Next 95 0 R +>> endobj +87 0 obj << +/Title 88 0 R +/A 85 0 R +/Parent 79 0 R +/Prev 83 0 R +/Next 99 0 R +/First 91 0 R +/Last 95 0 R +/Count -2 +>> endobj +83 0 obj << +/Title 84 0 R +/A 81 0 R +/Parent 79 0 R +/Next 87 0 R +>> endobj +79 0 obj << +/Title 80 0 R +/A 77 0 R +/Parent 47 0 R +/Prev 75 0 R +/Next 107 0 R +/First 83 0 R +/Last 103 0 R +/Count -4 +>> endobj +75 0 obj << +/Title 76 0 R +/A 73 0 R +/Parent 47 0 R +/Prev 71 0 R +/Next 79 0 R +>> endobj +71 0 obj << +/Title 72 0 R +/A 69 0 R +/Parent 47 0 R +/Prev 67 0 R +/Next 75 0 R +>> endobj +67 0 obj << +/Title 68 0 R +/A 65 0 R +/Parent 47 0 R +/Prev 63 0 R +/Next 71 0 R +>> endobj +63 0 obj << +/Title 64 0 R +/A 61 0 R +/Parent 47 0 R +/Prev 59 0 R +/Next 67 0 R +>> endobj +59 0 obj << +/Title 60 0 R +/A 57 0 R +/Parent 47 0 R +/Prev 55 0 R +/Next 63 0 R +>> endobj +55 0 obj << +/Title 56 0 R +/A 53 0 R +/Parent 47 0 R +/Prev 51 0 R +/Next 59 0 R +>> endobj +51 0 obj << +/Title 52 0 R +/A 49 0 R +/Parent 47 0 R +/Next 55 0 R +>> endobj +47 0 obj << +/Title 48 0 R +/A 45 0 R +/Parent 1843 0 R +/Prev 7 0 R +/Next 131 0 R +/First 51 0 R +/Last 127 0 R +/Count -14 +>> endobj +43 0 obj << +/Title 44 0 R +/A 41 0 R +/Parent 31 0 R +/Prev 39 0 R +>> endobj +39 0 obj << +/Title 40 0 R +/A 37 0 R +/Parent 31 0 R +/Prev 35 0 R +/Next 43 0 R +>> endobj +35 0 obj << +/Title 36 0 R +/A 33 0 R +/Parent 31 0 R +/Next 39 0 R +>> endobj +31 0 obj << +/Title 32 0 R +/A 29 0 R +/Parent 7 0 R +/Prev 27 0 R +/First 35 0 R +/Last 43 0 R +/Count -3 +>> endobj +27 0 obj << +/Title 28 0 R +/A 25 0 R +/Parent 7 0 R +/Prev 23 0 R +/Next 31 0 R +>> endobj +23 0 obj << +/Title 24 0 R +/A 21 0 R +/Parent 7 0 R +/Prev 19 0 R +/Next 27 0 R +>> endobj +19 0 obj << +/Title 20 0 R +/A 17 0 R +/Parent 7 0 R +/Prev 15 0 R +/Next 23 0 R +>> endobj +15 0 obj << +/Title 16 0 R +/A 13 0 R +/Parent 7 0 R +/Prev 11 0 R +/Next 19 0 R +>> endobj +11 0 obj << +/Title 12 0 R +/A 9 0 R +/Parent 7 0 R +/Next 15 0 R +>> endobj +7 0 obj << +/Title 8 0 R +/A 5 0 R +/Parent 1843 0 R +/Next 47 0 R +/First 11 0 R +/Last 31 0 R +/Count -6 +>> endobj +1844 0 obj << +/Names [(Doc-Start) 822 0 R (Item.1) 1121 0 R (Item.10) 1227 0 R (Item.11) 1350 0 R (Item.12) 1351 0 R (Item.13) 1352 0 R] +/Limits [(Doc-Start) (Item.13)] +>> endobj +1845 0 obj << +/Names [(Item.14) 1358 0 R (Item.15) 1359 0 R (Item.16) 1360 0 R (Item.17) 1361 0 R (Item.18) 1362 0 R (Item.19) 1363 0 R] +/Limits [(Item.14) (Item.19)] +>> endobj +1846 0 obj << +/Names [(Item.2) 1122 0 R (Item.20) 1364 0 R (Item.21) 1365 0 R (Item.22) 1396 0 R (Item.23) 1397 0 R (Item.24) 1470 0 R] +/Limits [(Item.2) (Item.24)] +>> endobj +1847 0 obj << +/Names [(Item.25) 1471 0 R (Item.26) 1472 0 R (Item.27) 1642 0 R (Item.28) 1643 0 R (Item.29) 1644 0 R (Item.3) 1123 0 R] +/Limits [(Item.25) (Item.3)] +>> endobj +1848 0 obj << +/Names [(Item.30) 1645 0 R (Item.31) 1646 0 R (Item.32) 1647 0 R (Item.33) 1648 0 R (Item.34) 1649 0 R (Item.35) 1650 0 R] +/Limits [(Item.30) (Item.35)] +>> endobj +1849 0 obj << +/Names [(Item.36) 1651 0 R (Item.37) 1652 0 R (Item.38) 1653 0 R (Item.39) 1659 0 R (Item.4) 1124 0 R (Item.40) 1660 0 R] +/Limits [(Item.36) (Item.40)] +>> endobj +1850 0 obj << +/Names [(Item.41) 1661 0 R (Item.42) 1662 0 R (Item.43) 1663 0 R (Item.44) 1664 0 R (Item.45) 1665 0 R (Item.46) 1666 0 R] +/Limits [(Item.41) (Item.46)] +>> endobj +1851 0 obj << +/Names [(Item.47) 1667 0 R (Item.48) 1668 0 R (Item.49) 1669 0 R (Item.5) 1125 0 R (Item.50) 1670 0 R (Item.51) 1675 0 R] +/Limits [(Item.47) (Item.51)] +>> endobj +1852 0 obj << +/Names [(Item.52) 1676 0 R (Item.53) 1677 0 R (Item.54) 1678 0 R (Item.55) 1679 0 R (Item.56) 1680 0 R (Item.57) 1681 0 R] +/Limits [(Item.52) (Item.57)] +>> endobj +1853 0 obj << +/Names [(Item.58) 1682 0 R (Item.59) 1683 0 R (Item.6) 1152 0 R (Item.60) 1684 0 R (Item.61) 1685 0 R (Item.62) 1686 0 R] +/Limits [(Item.58) (Item.62)] +>> endobj +1854 0 obj << +/Names [(Item.63) 1687 0 R (Item.64) 1688 0 R (Item.65) 1693 0 R (Item.66) 1694 0 R (Item.67) 1695 0 R (Item.68) 1696 0 R] +/Limits [(Item.63) (Item.68)] +>> endobj +1855 0 obj << +/Names [(Item.69) 1697 0 R (Item.7) 1153 0 R (Item.70) 1698 0 R (Item.8) 1154 0 R (Item.9) 1226 0 R (appendix.A) 758 0 R] +/Limits [(Item.69) (appendix.A)] +>> endobj +1856 0 obj << +/Names [(appendix.B) 766 0 R (appendix.C) 770 0 R (appendix.D) 774 0 R (appendix.E) 778 0 R (appendix.F) 814 0 R (page.1) 821 0 R] +/Limits [(appendix.B) (page.1)] +>> endobj +1857 0 obj << +/Names [(page.10) 1062 0 R (page.100) 1579 0 R (page.101) 1583 0 R (page.102) 1587 0 R (page.103) 1591 0 R (page.104) 1596 0 R] +/Limits [(page.10) (page.104)] +>> endobj +1858 0 obj << +/Names [(page.105) 1600 0 R (page.106) 1604 0 R (page.107) 1608 0 R (page.108) 1612 0 R (page.109) 1616 0 R (page.11) 1075 0 R] +/Limits [(page.105) (page.11)] +>> endobj +1859 0 obj << +/Names [(page.110) 1621 0 R (page.111) 1625 0 R (page.112) 1629 0 R (page.113) 1633 0 R (page.114) 1637 0 R (page.115) 1641 0 R] +/Limits [(page.110) (page.115)] +>> endobj +1860 0 obj << +/Names [(page.116) 1658 0 R (page.117) 1674 0 R (page.118) 1692 0 R (page.119) 1802 0 R (page.12) 1079 0 R (page.120) 1807 0 R] +/Limits [(page.116) (page.120)] +>> endobj +1861 0 obj << +/Names [(page.123) 1810 0 R (page.13) 1083 0 R (page.132) 1809 0 R (page.134) 1808 0 R (page.135) 1805 0 R (page.136) 1806 0 R] +/Limits [(page.123) (page.136)] +>> endobj +1862 0 obj << +/Names [(page.138) 1804 0 R (page.14) 1088 0 R (page.15) 1093 0 R (page.16) 1098 0 R (page.17) 1103 0 R (page.18) 1107 0 R] +/Limits [(page.138) (page.18)] +>> endobj +1863 0 obj << +/Names [(page.19) 1114 0 R (page.2) 832 0 R (page.20) 1120 0 R (page.21) 1135 0 R (page.22) 1142 0 R (page.23) 1146 0 R] +/Limits [(page.19) (page.23)] +>> endobj +1864 0 obj << +/Names [(page.24) 1151 0 R (page.25) 1160 0 R (page.26) 1167 0 R (page.27) 1171 0 R (page.28) 1188 0 R (page.29) 1192 0 R] +/Limits [(page.24) (page.29)] +>> endobj +1865 0 obj << +/Names [(page.3) 837 0 R (page.30) 1197 0 R (page.31) 1202 0 R (page.32) 1208 0 R (page.33) 1214 0 R (page.34) 1220 0 R] +/Limits [(page.3) (page.34)] +>> endobj +1866 0 obj << +/Names [(page.35) 1225 0 R (page.36) 1234 0 R (page.37) 1240 0 R (page.38) 1249 0 R (page.39) 1255 0 R (page.4) 841 0 R] +/Limits [(page.35) (page.4)] +>> endobj +1867 0 obj << +/Names [(page.40) 1259 0 R (page.41) 1264 0 R (page.42) 1268 0 R (page.43) 1272 0 R (page.44) 1279 0 R (page.45) 1286 0 R] +/Limits [(page.40) (page.45)] +>> endobj +1868 0 obj << +/Names [(page.46) 1294 0 R (page.47) 1302 0 R (page.48) 1310 0 R (page.49) 1317 0 R (page.5) 877 0 R (page.50) 1323 0 R] +/Limits [(page.46) (page.50)] +>> endobj +1869 0 obj << +/Names [(page.51) 1328 0 R (page.52) 1335 0 R (page.53) 1339 0 R (page.54) 1345 0 R (page.55) 1349 0 R (page.56) 1357 0 R] +/Limits [(page.51) (page.56)] +>> endobj +1870 0 obj << +/Names [(page.57) 1369 0 R (page.58) 1373 0 R (page.59) 1377 0 R (page.6) 916 0 R (page.60) 1382 0 R (page.61) 1386 0 R] +/Limits [(page.57) (page.61)] +>> endobj +1871 0 obj << +/Names [(page.62) 1391 0 R (page.63) 1395 0 R (page.64) 1401 0 R (page.65) 1405 0 R (page.66) 1409 0 R (page.67) 1415 0 R] +/Limits [(page.62) (page.67)] +>> endobj +1872 0 obj << +/Names [(page.68) 1422 0 R (page.69) 1426 0 R (page.7) 952 0 R (page.70) 1430 0 R (page.71) 1436 0 R (page.72) 1440 0 R] +/Limits [(page.68) (page.72)] +>> endobj +1873 0 obj << +/Names [(page.73) 1444 0 R (page.74) 1449 0 R (page.75) 1453 0 R (page.76) 1457 0 R (page.77) 1461 0 R (page.78) 1465 0 R] +/Limits [(page.73) (page.78)] +>> endobj +1874 0 obj << +/Names [(page.79) 1469 0 R (page.8) 990 0 R (page.80) 1479 0 R (page.81) 1483 0 R (page.82) 1487 0 R (page.83) 1492 0 R] +/Limits [(page.79) (page.83)] +>> endobj +1875 0 obj << +/Names [(page.84) 1496 0 R (page.85) 1502 0 R (page.86) 1507 0 R (page.87) 1511 0 R (page.88) 1518 0 R (page.89) 1523 0 R] +/Limits [(page.84) (page.89)] +>> endobj +1876 0 obj << +/Names [(page.9) 1027 0 R (page.90) 1527 0 R (page.91) 1533 0 R (page.92) 1538 0 R (page.93) 1544 0 R (page.94) 1549 0 R] +/Limits [(page.9) (page.94)] +>> endobj +1877 0 obj << +/Names [(page.95) 1554 0 R (page.96) 1559 0 R (page.97) 1563 0 R (page.98) 1568 0 R (page.99) 1572 0 R (paragraph.2.8.2.1) 90 0 R] +/Limits [(page.95) (paragraph.2.8.2.1)] +>> endobj +1878 0 obj << +/Names [(paragraph.2.8.2.2) 94 0 R (paragraph.3.1.1.1) 142 0 R (paragraph.3.1.1.2) 146 0 R (paragraph.3.1.1.3) 150 0 R (paragraph.3.2.4.1) 186 0 R (paragraph.3.2.4.2) 190 0 R] +/Limits [(paragraph.2.8.2.2) (paragraph.3.2.4.2)] +>> endobj +1879 0 obj << +/Names [(paragraph.3.2.5.1) 198 0 R (paragraph.3.2.5.2) 202 0 R (paragraph.3.2.5.3) 206 0 R (paragraph.3.4.1.1) 230 0 R (paragraph.3.4.1.2) 234 0 R (paragraph.3.4.3.1) 246 0 R] +/Limits [(paragraph.3.2.5.1) (paragraph.3.4.3.1)] +>> endobj +1880 0 obj << +/Names [(paragraph.3.4.3.2) 250 0 R (paragraph.3.4.3.3) 254 0 R (paragraph.3.4.3.4) 258 0 R (paragraph.3.4.4.1) 266 0 R (paragraph.3.4.4.2) 270 0 R (paragraph.4.1.2.1) 290 0 R] +/Limits [(paragraph.3.4.3.2) (paragraph.4.1.2.1)] +>> endobj +1881 0 obj << +/Names [(paragraph.4.1.2.2) 294 0 R (paragraph.4.1.2.3) 298 0 R (paragraph.4.1.2.4) 302 0 R (paragraph.4.1.2.5) 306 0 R (paragraph.4.1.2.6) 310 0 R (paragraph.4.1.2.7) 314 0 R] +/Limits [(paragraph.4.1.2.2) (paragraph.4.1.2.7)] +>> endobj +1882 0 obj << +/Names [(paragraph.4.1.2.8) 318 0 R (paragraph.4.1.2.9) 322 0 R (paragraph.4.10.3.1) 650 0 R (paragraph.4.10.3.10) 686 0 R (paragraph.4.10.3.11) 690 0 R (paragraph.4.10.3.12) 694 0 R] +/Limits [(paragraph.4.1.2.8) (paragraph.4.10.3.12)] +>> endobj +1883 0 obj << +/Names [(paragraph.4.10.3.13) 698 0 R (paragraph.4.10.3.14) 702 0 R (paragraph.4.10.3.2) 654 0 R (paragraph.4.10.3.3) 658 0 R (paragraph.4.10.3.4) 662 0 R (paragraph.4.10.3.5) 666 0 R] +/Limits [(paragraph.4.10.3.13) (paragraph.4.10.3.5)] +>> endobj +1884 0 obj << +/Names [(paragraph.4.10.3.6) 670 0 R (paragraph.4.10.3.7) 674 0 R (paragraph.4.10.3.8) 678 0 R (paragraph.4.10.3.9) 682 0 R (paragraph.4.11.2.1) 722 0 R (paragraph.4.11.2.2) 726 0 R] +/Limits [(paragraph.4.10.3.6) (paragraph.4.11.2.2)] +>> endobj +1885 0 obj << +/Names [(paragraph.4.11.2.3) 730 0 R (paragraph.4.11.2.4) 734 0 R (paragraph.4.11.2.5) 738 0 R (paragraph.4.11.2.6) 742 0 R (paragraph.4.11.2.7) 746 0 R (paragraph.4.11.2.8) 750 0 R] +/Limits [(paragraph.4.11.2.3) (paragraph.4.11.2.8)] +>> endobj +1886 0 obj << +/Names [(paragraph.4.11.2.9) 754 0 R (paragraph.4.2.1.1) 334 0 R (paragraph.4.2.1.2) 338 0 R (paragraph.4.2.1.3) 342 0 R (paragraph.4.2.1.4) 346 0 R (paragraph.4.2.2.1) 354 0 R] +/Limits [(paragraph.4.11.2.9) (paragraph.4.2.2.1)] +>> endobj +1887 0 obj << +/Names [(paragraph.4.2.3.1) 362 0 R (paragraph.4.2.3.2) 366 0 R (paragraph.4.2.3.3) 370 0 R (paragraph.4.2.3.4) 374 0 R (paragraph.4.2.3.5) 378 0 R (paragraph.4.2.4.1) 386 0 R] +/Limits [(paragraph.4.2.3.1) (paragraph.4.2.4.1)] +>> endobj +1888 0 obj << +/Names [(paragraph.4.2.4.2) 390 0 R (paragraph.4.2.4.3) 394 0 R (paragraph.4.2.4.4) 398 0 R (paragraph.4.2.4.5) 402 0 R (paragraph.4.2.4.6) 406 0 R (paragraph.4.2.5.1) 414 0 R] +/Limits [(paragraph.4.2.4.2) (paragraph.4.2.5.1)] +>> endobj +1889 0 obj << +/Names [(paragraph.4.2.5.2) 418 0 R (paragraph.4.2.6.1) 426 0 R (paragraph.4.2.6.2) 430 0 R (paragraph.4.2.6.3) 434 0 R (paragraph.4.3.1.1) 446 0 R (paragraph.4.3.1.2) 450 0 R] +/Limits [(paragraph.4.2.5.2) (paragraph.4.3.1.2)] +>> endobj +1890 0 obj << +/Names [(paragraph.4.3.1.3) 454 0 R (paragraph.4.3.1.4) 458 0 R (paragraph.4.4.1.1) 474 0 R (paragraph.4.4.1.2) 478 0 R (paragraph.4.4.1.3) 482 0 R (paragraph.4.4.1.4) 510 0 R] +/Limits [(paragraph.4.3.1.3) (paragraph.4.4.1.4)] +>> endobj +1891 0 obj << +/Names [(paragraph.4.4.1.5) 526 0 R (paragraph.4.4.2.1) 534 0 R (paragraph.4.4.2.2) 538 0 R (paragraph.4.4.2.3) 542 0 R (paragraph.4.4.2.4) 546 0 R (paragraph.4.4.2.5) 550 0 R] +/Limits [(paragraph.4.4.1.5) (paragraph.4.4.2.5)] +>> endobj +1892 0 obj << +/Names [(paragraph.4.7.1.1) 582 0 R (paragraph.4.7.1.2) 586 0 R (paragraph.4.8.1.1) 602 0 R (paragraph.4.8.1.2) 606 0 R (paragraph.4.8.1.3) 610 0 R (paragraph.4.9.1.1) 622 0 R] +/Limits [(paragraph.4.7.1.1) (paragraph.4.9.1.1)] +>> endobj +1893 0 obj << +/Names [(paragraph.4.9.1.2) 626 0 R (section*.1) 878 0 R (section*.2) 1803 0 R (section.1) 6 0 R (section.2) 46 0 R (section.3) 130 0 R] +/Limits [(paragraph.4.9.1.2) (section.3)] +>> endobj +1894 0 obj << +/Names [(section.4) 274 0 R (subparagraph.4.4.1.3.1) 486 0 R (subparagraph.4.4.1.3.2) 490 0 R (subparagraph.4.4.1.3.3) 494 0 R (subparagraph.4.4.1.3.4) 498 0 R (subparagraph.4.4.1.3.5) 502 0 R] +/Limits [(section.4) (subparagraph.4.4.1.3.5)] +>> endobj +1895 0 obj << +/Names [(subparagraph.4.4.1.3.6) 506 0 R (subparagraph.4.4.1.4.1) 514 0 R (subparagraph.4.4.1.4.2) 518 0 R (subparagraph.4.4.1.4.3) 522 0 R (subsection.1.1) 10 0 R (subsection.1.2) 14 0 R] +/Limits [(subparagraph.4.4.1.3.6) (subsection.1.2)] +>> endobj +1896 0 obj << +/Names [(subsection.1.3) 18 0 R (subsection.1.4) 22 0 R (subsection.1.5) 26 0 R (subsection.1.6) 30 0 R (subsection.2.1) 50 0 R (subsection.2.10) 110 0 R] +/Limits [(subsection.1.3) (subsection.2.10)] +>> endobj +1897 0 obj << +/Names [(subsection.2.11) 114 0 R (subsection.2.12) 118 0 R (subsection.2.13) 122 0 R (subsection.2.14) 126 0 R (subsection.2.2) 54 0 R (subsection.2.3) 58 0 R] +/Limits [(subsection.2.11) (subsection.2.3)] +>> endobj +1898 0 obj << +/Names [(subsection.2.4) 62 0 R (subsection.2.5) 66 0 R (subsection.2.6) 70 0 R (subsection.2.7) 74 0 R (subsection.2.8) 78 0 R (subsection.2.9) 106 0 R] +/Limits [(subsection.2.4) (subsection.2.9)] +>> endobj +1899 0 obj << +/Names [(subsection.3.1) 134 0 R (subsection.3.2) 166 0 R (subsection.3.3) 210 0 R (subsection.3.4) 222 0 R (subsection.4.1) 278 0 R (subsection.4.10) 634 0 R] +/Limits [(subsection.3.1) (subsection.4.10)] +>> endobj +1900 0 obj << +/Names [(subsection.4.11) 710 0 R (subsection.4.2) 326 0 R (subsection.4.3) 438 0 R (subsection.4.4) 466 0 R (subsection.4.5) 558 0 R (subsection.4.6) 562 0 R] +/Limits [(subsection.4.11) (subsection.4.6)] +>> endobj +1901 0 obj << +/Names [(subsection.4.7) 574 0 R (subsection.4.8) 594 0 R (subsection.4.9) 614 0 R (subsection.A.1) 762 0 R (subsection.E.1) 782 0 R (subsection.E.2) 786 0 R] +/Limits [(subsection.4.7) (subsection.E.2)] +>> endobj +1902 0 obj << +/Names [(subsubsection.1.6.1) 34 0 R (subsubsection.1.6.2) 38 0 R (subsubsection.1.6.3) 42 0 R (subsubsection.2.8.1) 82 0 R (subsubsection.2.8.2) 86 0 R (subsubsection.2.8.3) 98 0 R] +/Limits [(subsubsection.1.6.1) (subsubsection.2.8.3)] +>> endobj +1903 0 obj << +/Names [(subsubsection.2.8.4) 102 0 R (subsubsection.3.1.1) 138 0 R (subsubsection.3.1.2) 154 0 R (subsubsection.3.1.3) 158 0 R (subsubsection.3.1.4) 162 0 R (subsubsection.3.2.1) 170 0 R] +/Limits [(subsubsection.2.8.4) (subsubsection.3.2.1)] +>> endobj +1904 0 obj << +/Names [(subsubsection.3.2.2) 174 0 R (subsubsection.3.2.3) 178 0 R (subsubsection.3.2.4) 182 0 R (subsubsection.3.2.5) 194 0 R (subsubsection.3.3.1) 214 0 R (subsubsection.3.3.2) 218 0 R] +/Limits [(subsubsection.3.2.2) (subsubsection.3.3.2)] +>> endobj +1905 0 obj << +/Names [(subsubsection.3.4.1) 226 0 R (subsubsection.3.4.2) 238 0 R (subsubsection.3.4.3) 242 0 R (subsubsection.3.4.4) 262 0 R (subsubsection.4.1.1) 282 0 R (subsubsection.4.1.2) 286 0 R] +/Limits [(subsubsection.3.4.1) (subsubsection.4.1.2)] +>> endobj +1906 0 obj << +/Names [(subsubsection.4.10.1) 638 0 R (subsubsection.4.10.2) 642 0 R (subsubsection.4.10.3) 646 0 R (subsubsection.4.10.4) 706 0 R (subsubsection.4.11.1) 714 0 R (subsubsection.4.11.2) 718 0 R] +/Limits [(subsubsection.4.10.1) (subsubsection.4.11.2)] +>> endobj +1907 0 obj << +/Names [(subsubsection.4.2.1) 330 0 R (subsubsection.4.2.2) 350 0 R (subsubsection.4.2.3) 358 0 R (subsubsection.4.2.4) 382 0 R (subsubsection.4.2.5) 410 0 R (subsubsection.4.2.6) 422 0 R] +/Limits [(subsubsection.4.2.1) (subsubsection.4.2.6)] +>> endobj +1908 0 obj << +/Names [(subsubsection.4.3.1) 442 0 R (subsubsection.4.3.2) 462 0 R (subsubsection.4.4.1) 470 0 R (subsubsection.4.4.2) 530 0 R (subsubsection.4.4.3) 554 0 R (subsubsection.4.6.1) 566 0 R] +/Limits [(subsubsection.4.3.1) (subsubsection.4.6.1)] +>> endobj +1909 0 obj << +/Names [(subsubsection.4.6.2) 570 0 R (subsubsection.4.7.1) 578 0 R (subsubsection.4.7.2) 590 0 R (subsubsection.4.8.1) 598 0 R (subsubsection.4.9.1) 618 0 R (subsubsection.4.9.2) 630 0 R] +/Limits [(subsubsection.4.6.2) (subsubsection.4.9.2)] +>> endobj +1910 0 obj << +/Names [(subsubsection.E.2.1) 790 0 R (subsubsection.E.2.2) 794 0 R (subsubsection.E.2.3) 798 0 R (subsubsection.E.2.4) 802 0 R (subsubsection.E.2.5) 806 0 R (subsubsection.E.2.6) 810 0 R] +/Limits [(subsubsection.E.2.1) (subsubsection.E.2.6)] +>> endobj +1911 0 obj << +/Kids [1844 0 R 1845 0 R 1846 0 R 1847 0 R 1848 0 R 1849 0 R] +/Limits [(Doc-Start) (Item.40)] +>> endobj +1912 0 obj << +/Kids [1850 0 R 1851 0 R 1852 0 R 1853 0 R 1854 0 R 1855 0 R] +/Limits [(Item.41) (appendix.A)] +>> endobj +1913 0 obj << +/Kids [1856 0 R 1857 0 R 1858 0 R 1859 0 R 1860 0 R 1861 0 R] +/Limits [(appendix.B) (page.136)] +>> endobj +1914 0 obj << +/Kids [1862 0 R 1863 0 R 1864 0 R 1865 0 R 1866 0 R 1867 0 R] +/Limits [(page.138) (page.45)] +>> endobj +1915 0 obj << +/Kids [1868 0 R 1869 0 R 1870 0 R 1871 0 R 1872 0 R 1873 0 R] +/Limits [(page.46) (page.78)] +>> endobj +1916 0 obj << +/Kids [1874 0 R 1875 0 R 1876 0 R 1877 0 R 1878 0 R 1879 0 R] +/Limits [(page.79) (paragraph.3.4.3.1)] +>> endobj +1917 0 obj << +/Kids [1880 0 R 1881 0 R 1882 0 R 1883 0 R 1884 0 R 1885 0 R] +/Limits [(paragraph.3.4.3.2) (paragraph.4.11.2.8)] +>> endobj +1918 0 obj << +/Kids [1886 0 R 1887 0 R 1888 0 R 1889 0 R 1890 0 R 1891 0 R] +/Limits [(paragraph.4.11.2.9) (paragraph.4.4.2.5)] +>> endobj +1919 0 obj << +/Kids [1892 0 R 1893 0 R 1894 0 R 1895 0 R 1896 0 R 1897 0 R] +/Limits [(paragraph.4.7.1.1) (subsection.2.3)] +>> endobj +1920 0 obj << +/Kids [1898 0 R 1899 0 R 1900 0 R 1901 0 R 1902 0 R 1903 0 R] +/Limits [(subsection.2.4) (subsubsection.3.2.1)] +>> endobj +1921 0 obj << +/Kids [1904 0 R 1905 0 R 1906 0 R 1907 0 R 1908 0 R 1909 0 R] +/Limits [(subsubsection.3.2.2) (subsubsection.4.9.2)] +>> endobj +1922 0 obj << +/Kids [1910 0 R] +/Limits [(subsubsection.E.2.1) (subsubsection.E.2.6)] +>> endobj +1923 0 obj << +/Kids [1911 0 R 1912 0 R 1913 0 R 1914 0 R 1915 0 R 1916 0 R] +/Limits [(Doc-Start) (paragraph.3.4.3.1)] +>> endobj +1924 0 obj << +/Kids [1917 0 R 1918 0 R 1919 0 R 1920 0 R 1921 0 R 1922 0 R] +/Limits [(paragraph.3.4.3.2) (subsubsection.E.2.6)] +>> endobj +1925 0 obj << +/Kids [1923 0 R 1924 0 R] +/Limits [(Doc-Start) (subsubsection.E.2.6)] +>> endobj +1926 0 obj << +/Dests 1925 0 R +>> endobj +1927 0 obj << +/Type /Catalog +/Pages 1842 0 R +/Outlines 1843 0 R +/Names 1926 0 R +/PageMode/UseOutlines +/OpenAction 817 0 R +>> endobj +1928 0 obj << +/Author()/Title(ZSDOS 1.0)/Subject()/Creator(LaTeX with hyperref package)/Producer(pdfTeX-1.40.3)/Keywords(cp/m, zsdos) +/CreationDate (D:20090422211120-07'00') +/ModDate (D:20090422211120-07'00') +/Trapped /False +/PTEX.Fullbanner (This is pdfTeX using libpoppler, Version 3.141592-1.40.3-2.2 (Web2C 7.5.6) kpathsea version 3.5.6) +>> endobj +xref +0 1929 +0000000001 65535 f +0000000002 00000 f +0000000003 00000 f +0000000004 00000 f +0000000000 00000 f +0000000015 00000 n +0000074103 00000 n +0000498884 00000 n +0000000060 00000 n +0000000092 00000 n +0000074155 00000 n +0000498812 00000 n +0000000142 00000 n +0000000182 00000 n +0000074212 00000 n +0000498726 00000 n +0000000233 00000 n +0000000270 00000 n +0000077926 00000 n +0000498640 00000 n +0000000321 00000 n +0000000364 00000 n +0000080718 00000 n +0000498554 00000 n +0000000415 00000 n +0000000473 00000 n +0000080771 00000 n +0000498468 00000 n +0000000524 00000 n +0000000592 00000 n +0000083521 00000 n +0000498358 00000 n +0000000643 00000 n +0000000693 00000 n +0000083577 00000 n +0000498284 00000 n +0000000749 00000 n +0000000801 00000 n +0000086673 00000 n +0000498197 00000 n +0000000857 00000 n +0000000895 00000 n +0000088001 00000 n +0000498123 00000 n +0000000951 00000 n +0000000996 00000 n +0000091114 00000 n +0000497995 00000 n +0000001042 00000 n +0000001071 00000 n +0000091167 00000 n +0000497921 00000 n +0000001122 00000 n +0000001165 00000 n +0000091224 00000 n +0000497834 00000 n +0000001216 00000 n +0000001262 00000 n +0000095142 00000 n +0000497747 00000 n +0000001313 00000 n +0000001361 00000 n +0000095199 00000 n +0000497660 00000 n +0000001412 00000 n +0000001461 00000 n +0000095256 00000 n +0000497573 00000 n +0000001512 00000 n +0000001556 00000 n +0000098354 00000 n +0000497486 00000 n +0000001607 00000 n +0000001653 00000 n +0000098411 00000 n +0000497399 00000 n +0000001704 00000 n +0000001743 00000 n +0000098468 00000 n +0000497273 00000 n +0000001794 00000 n +0000001834 00000 n +0000102833 00000 n +0000497199 00000 n +0000001890 00000 n +0000001928 00000 n +0000102890 00000 n +0000497075 00000 n +0000001984 00000 n +0000002035 00000 n +0000102947 00000 n +0000497001 00000 n +0000002089 00000 n +0000002152 00000 n +0000103004 00000 n +0000496927 00000 n +0000002206 00000 n +0000002264 00000 n +0000107146 00000 n +0000496838 00000 n +0000002320 00000 n +0000002359 00000 n +0000107203 00000 n +0000496761 00000 n +0000002416 00000 n +0000002472 00000 n +0000113714 00000 n +0000496670 00000 n +0000002524 00000 n +0000002573 00000 n +0000113772 00000 n +0000496578 00000 n +0000002626 00000 n +0000002676 00000 n +0000113830 00000 n +0000496486 00000 n +0000002729 00000 n +0000002777 00000 n +0000117805 00000 n +0000496394 00000 n +0000002830 00000 n +0000002880 00000 n +0000117862 00000 n +0000496302 00000 n +0000002933 00000 n +0000002980 00000 n +0000121403 00000 n +0000496224 00000 n +0000003033 00000 n +0000003088 00000 n +0000126942 00000 n +0000496092 00000 n +0000003135 00000 n +0000003173 00000 n +0000126996 00000 n +0000495974 00000 n +0000003225 00000 n +0000003280 00000 n +0000127054 00000 n +0000495856 00000 n +0000003337 00000 n +0000003393 00000 n +0000129293 00000 n +0000495777 00000 n +0000003448 00000 n +0000003490 00000 n +0000137014 00000 n +0000495684 00000 n +0000003545 00000 n +0000003593 00000 n +0000137071 00000 n +0000495605 00000 n +0000003648 00000 n +0000003699 00000 n +0000142645 00000 n +0000495512 00000 n +0000003756 00000 n +0000003809 00000 n +0000145771 00000 n +0000495419 00000 n +0000003866 00000 n +0000003920 00000 n +0000145829 00000 n +0000495340 00000 n +0000003977 00000 n +0000004024 00000 n +0000146005 00000 n +0000495208 00000 n +0000004076 00000 n +0000004133 00000 n +0000149716 00000 n +0000495129 00000 n +0000004190 00000 n +0000004240 00000 n +0000152366 00000 n +0000495036 00000 n +0000004297 00000 n +0000004359 00000 n +0000161708 00000 n +0000494943 00000 n +0000004416 00000 n +0000004459 00000 n +0000164946 00000 n +0000494811 00000 n +0000004516 00000 n +0000004583 00000 n +0000165000 00000 n +0000494732 00000 n +0000004638 00000 n +0000004688 00000 n +0000165058 00000 n +0000494653 00000 n +0000004743 00000 n +0000004788 00000 n +0000167340 00000 n +0000494535 00000 n +0000004845 00000 n +0000004915 00000 n +0000167394 00000 n +0000494456 00000 n +0000004970 00000 n +0000005022 00000 n +0000167452 00000 n +0000494363 00000 n +0000005077 00000 n +0000005124 00000 n +0000167510 00000 n +0000494284 00000 n +0000005179 00000 n +0000005229 00000 n +0000170214 00000 n +0000494152 00000 n +0000005281 00000 n +0000005341 00000 n +0000170272 00000 n +0000494073 00000 n +0000005398 00000 n +0000005465 00000 n +0000170330 00000 n +0000493994 00000 n +0000005522 00000 n +0000005574 00000 n +0000172611 00000 n +0000493876 00000 n +0000005626 00000 n +0000005682 00000 n +0000172669 00000 n +0000493758 00000 n +0000005739 00000 n +0000005801 00000 n +0000172727 00000 n +0000493679 00000 n +0000005856 00000 n +0000005901 00000 n +0000176860 00000 n +0000493600 00000 n +0000005956 00000 n +0000006002 00000 n +0000176914 00000 n +0000493507 00000 n +0000006059 00000 n +0000006113 00000 n +0000176971 00000 n +0000493375 00000 n +0000006170 00000 n +0000006240 00000 n +0000177029 00000 n +0000493296 00000 n +0000006295 00000 n +0000006350 00000 n +0000181240 00000 n +0000493203 00000 n +0000006405 00000 n +0000006473 00000 n +0000184906 00000 n +0000493110 00000 n +0000006528 00000 n +0000006599 00000 n +0000188815 00000 n +0000493031 00000 n +0000006654 00000 n +0000006720 00000 n +0000188873 00000 n +0000492913 00000 n +0000006777 00000 n +0000006844 00000 n +0000188931 00000 n +0000492834 00000 n +0000006899 00000 n +0000006956 00000 n +0000188989 00000 n +0000492755 00000 n +0000007011 00000 n +0000007048 00000 n +0000192596 00000 n +0000492621 00000 n +0000007095 00000 n +0000007132 00000 n +0000192650 00000 n +0000492503 00000 n +0000007184 00000 n +0000007226 00000 n +0000195963 00000 n +0000492424 00000 n +0000007283 00000 n +0000007319 00000 n +0000198868 00000 n +0000492306 00000 n +0000007376 00000 n +0000007414 00000 n +0000202582 00000 n +0000492227 00000 n +0000007469 00000 n +0000007511 00000 n +0000202640 00000 n +0000492134 00000 n +0000007566 00000 n +0000007615 00000 n +0000202697 00000 n +0000492041 00000 n +0000007670 00000 n +0000007718 00000 n +0000202755 00000 n +0000491948 00000 n +0000007773 00000 n +0000007821 00000 n +0000202813 00000 n +0000491855 00000 n +0000007876 00000 n +0000007925 00000 n +0000206070 00000 n +0000491762 00000 n +0000007980 00000 n +0000008020 00000 n +0000206124 00000 n +0000491669 00000 n +0000008075 00000 n +0000008122 00000 n +0000206182 00000 n +0000491576 00000 n +0000008177 00000 n +0000008218 00000 n +0000206240 00000 n +0000491497 00000 n +0000008273 00000 n +0000008338 00000 n +0000206298 00000 n +0000491365 00000 n +0000008390 00000 n +0000008440 00000 n +0000206356 00000 n +0000491247 00000 n +0000008497 00000 n +0000008531 00000 n +0000209155 00000 n +0000491168 00000 n +0000008586 00000 n +0000008629 00000 n +0000212335 00000 n +0000491075 00000 n +0000008684 00000 n +0000008745 00000 n +0000212393 00000 n +0000490982 00000 n +0000008800 00000 n +0000008851 00000 n +0000215901 00000 n +0000490903 00000 n +0000008906 00000 n +0000008954 00000 n +0000218546 00000 n +0000490771 00000 n +0000009011 00000 n +0000009051 00000 n +0000221203 00000 n +0000490706 00000 n +0000009106 00000 n +0000009150 00000 n +0000221261 00000 n +0000490574 00000 n +0000009207 00000 n +0000009257 00000 n +0000221319 00000 n +0000490495 00000 n +0000009312 00000 n +0000009363 00000 n +0000224504 00000 n +0000490402 00000 n +0000009418 00000 n +0000009462 00000 n +0000224562 00000 n +0000490309 00000 n +0000009517 00000 n +0000009567 00000 n +0000230208 00000 n +0000490216 00000 n +0000009622 00000 n +0000009664 00000 n +0000232944 00000 n +0000490137 00000 n +0000009719 00000 n +0000009769 00000 n +0000233002 00000 n +0000490005 00000 n +0000009826 00000 n +0000009872 00000 n +0000233060 00000 n +0000489926 00000 n +0000009927 00000 n +0000009973 00000 n +0000233118 00000 n +0000489833 00000 n +0000010028 00000 n +0000010070 00000 n +0000235983 00000 n +0000489740 00000 n +0000010125 00000 n +0000010174 00000 n +0000236037 00000 n +0000489647 00000 n +0000010229 00000 n +0000010275 00000 n +0000236095 00000 n +0000489554 00000 n +0000010330 00000 n +0000010374 00000 n +0000236151 00000 n +0000489475 00000 n +0000010429 00000 n +0000010495 00000 n +0000236327 00000 n +0000489343 00000 n +0000010552 00000 n +0000010608 00000 n +0000236385 00000 n +0000489264 00000 n +0000010663 00000 n +0000010703 00000 n +0000242918 00000 n +0000489185 00000 n +0000010758 00000 n +0000010799 00000 n +0000246402 00000 n +0000489067 00000 n +0000010856 00000 n +0000010903 00000 n +0000246456 00000 n +0000488988 00000 n +0000010958 00000 n +0000011010 00000 n +0000246514 00000 n +0000488895 00000 n +0000011065 00000 n +0000011109 00000 n +0000246572 00000 n +0000488816 00000 n +0000011164 00000 n +0000011214 00000 n +0000249667 00000 n +0000488684 00000 n +0000011266 00000 n +0000011327 00000 n +0000249721 00000 n +0000488566 00000 n +0000011384 00000 n +0000011424 00000 n +0000249779 00000 n +0000488487 00000 n +0000011479 00000 n +0000011532 00000 n +0000249837 00000 n +0000488394 00000 n +0000011587 00000 n +0000011636 00000 n +0000249895 00000 n +0000488301 00000 n +0000011691 00000 n +0000011735 00000 n +0000252986 00000 n +0000488222 00000 n +0000011790 00000 n +0000011833 00000 n +0000254783 00000 n +0000488143 00000 n +0000011890 00000 n +0000011939 00000 n +0000257972 00000 n +0000488011 00000 n +0000011991 00000 n +0000012045 00000 n +0000258026 00000 n +0000487893 00000 n +0000012102 00000 n +0000012143 00000 n +0000260345 00000 n +0000487814 00000 n +0000012198 00000 n +0000012249 00000 n +0000260399 00000 n +0000487721 00000 n +0000012304 00000 n +0000012360 00000 n +0000260457 00000 n +0000487589 00000 n +0000012415 00000 n +0000012459 00000 n +0000262842 00000 n +0000487510 00000 n +0000012519 00000 n +0000012564 00000 n +0000265838 00000 n +0000487417 00000 n +0000012624 00000 n +0000012684 00000 n +0000265892 00000 n +0000487324 00000 n +0000012744 00000 n +0000012795 00000 n +0000265950 00000 n +0000487231 00000 n +0000012855 00000 n +0000012893 00000 n +0000266008 00000 n +0000487138 00000 n +0000012953 00000 n +0000013003 00000 n +0000266066 00000 n +0000487059 00000 n +0000013063 00000 n +0000013115 00000 n +0000266124 00000 n +0000486927 00000 n +0000013170 00000 n +0000013226 00000 n +0000268391 00000 n +0000486848 00000 n +0000013286 00000 n +0000013331 00000 n +0000268445 00000 n +0000486755 00000 n +0000013391 00000 n +0000013426 00000 n +0000271270 00000 n +0000486676 00000 n +0000013486 00000 n +0000013535 00000 n +0000271328 00000 n +0000486597 00000 n +0000013590 00000 n +0000013646 00000 n +0000274005 00000 n +0000486465 00000 n +0000013703 00000 n +0000013744 00000 n +0000274059 00000 n +0000486386 00000 n +0000013799 00000 n +0000013842 00000 n +0000274117 00000 n +0000486293 00000 n +0000013897 00000 n +0000013954 00000 n +0000276688 00000 n +0000486200 00000 n +0000014009 00000 n +0000014068 00000 n +0000276746 00000 n +0000486107 00000 n +0000014123 00000 n +0000014173 00000 n +0000276804 00000 n +0000486028 00000 n +0000014228 00000 n +0000014279 00000 n +0000279365 00000 n +0000485949 00000 n +0000014336 00000 n +0000014385 00000 n +0000282342 00000 n +0000485856 00000 n +0000014437 00000 n +0000014487 00000 n +0000282400 00000 n +0000485724 00000 n +0000014539 00000 n +0000014587 00000 n +0000282458 00000 n +0000485645 00000 n +0000014644 00000 n +0000014678 00000 n +0000284807 00000 n +0000485566 00000 n +0000014735 00000 n +0000014778 00000 n +0000287024 00000 n +0000485434 00000 n +0000014830 00000 n +0000014875 00000 n +0000287082 00000 n +0000485316 00000 n +0000014932 00000 n +0000014968 00000 n +0000287140 00000 n +0000485237 00000 n +0000015023 00000 n +0000015075 00000 n +0000290302 00000 n +0000485158 00000 n +0000015130 00000 n +0000015169 00000 n +0000290356 00000 n +0000485079 00000 n +0000015226 00000 n +0000015271 00000 n +0000290414 00000 n +0000484947 00000 n +0000015323 00000 n +0000015376 00000 n +0000290472 00000 n +0000484843 00000 n +0000015433 00000 n +0000015470 00000 n +0000292614 00000 n +0000484764 00000 n +0000015525 00000 n +0000015574 00000 n +0000292672 00000 n +0000484671 00000 n +0000015629 00000 n +0000015677 00000 n +0000295792 00000 n +0000484592 00000 n +0000015732 00000 n +0000015772 00000 n +0000295849 00000 n +0000484460 00000 n +0000015824 00000 n +0000015870 00000 n +0000295906 00000 n +0000484342 00000 n +0000015927 00000 n +0000015963 00000 n +0000295964 00000 n +0000484263 00000 n +0000016018 00000 n +0000016069 00000 n +0000297925 00000 n +0000484184 00000 n +0000016124 00000 n +0000016166 00000 n +0000299373 00000 n +0000484105 00000 n +0000016223 00000 n +0000016281 00000 n +0000301853 00000 n +0000483973 00000 n +0000016334 00000 n +0000016403 00000 n +0000301911 00000 n +0000483894 00000 n +0000016461 00000 n +0000016513 00000 n +0000304476 00000 n +0000483801 00000 n +0000016571 00000 n +0000016618 00000 n +0000308881 00000 n +0000483668 00000 n +0000016676 00000 n +0000016719 00000 n +0000308939 00000 n +0000483589 00000 n +0000016775 00000 n +0000016836 00000 n +0000308997 00000 n +0000483496 00000 n +0000016892 00000 n +0000016965 00000 n +0000310717 00000 n +0000483403 00000 n +0000017021 00000 n +0000017094 00000 n +0000310775 00000 n +0000483310 00000 n +0000017150 00000 n +0000017220 00000 n +0000310833 00000 n +0000483217 00000 n +0000017276 00000 n +0000017344 00000 n +0000313309 00000 n +0000483124 00000 n +0000017400 00000 n +0000017473 00000 n +0000313367 00000 n +0000483031 00000 n +0000017529 00000 n +0000017588 00000 n +0000316594 00000 n +0000482938 00000 n +0000017644 00000 n +0000017717 00000 n +0000319519 00000 n +0000482845 00000 n +0000017773 00000 n +0000017851 00000 n +0000319577 00000 n +0000482752 00000 n +0000017908 00000 n +0000017982 00000 n +0000322263 00000 n +0000482659 00000 n +0000018039 00000 n +0000018101 00000 n +0000324597 00000 n +0000482566 00000 n +0000018158 00000 n +0000018225 00000 n +0000327117 00000 n +0000482473 00000 n +0000018282 00000 n +0000018346 00000 n +0000327175 00000 n +0000482394 00000 n +0000018403 00000 n +0000018467 00000 n +0000329609 00000 n +0000482315 00000 n +0000018525 00000 n +0000018575 00000 n +0000329667 00000 n +0000482197 00000 n +0000018628 00000 n +0000018685 00000 n +0000329725 00000 n +0000482118 00000 n +0000018743 00000 n +0000018779 00000 n +0000333356 00000 n +0000482000 00000 n +0000018837 00000 n +0000018875 00000 n +0000333414 00000 n +0000481921 00000 n +0000018931 00000 n +0000018985 00000 n +0000333472 00000 n +0000481828 00000 n +0000019041 00000 n +0000019089 00000 n +0000335934 00000 n +0000481735 00000 n +0000019145 00000 n +0000019205 00000 n +0000335992 00000 n +0000481642 00000 n +0000019261 00000 n +0000019311 00000 n +0000336046 00000 n +0000481549 00000 n +0000019367 00000 n +0000019413 00000 n +0000336104 00000 n +0000481456 00000 n +0000019469 00000 n +0000019518 00000 n +0000336162 00000 n +0000481363 00000 n +0000019574 00000 n +0000019620 00000 n +0000336220 00000 n +0000481270 00000 n +0000019676 00000 n +0000019719 00000 n +0000337382 00000 n +0000481191 00000 n +0000019775 00000 n +0000019816 00000 n +0000340269 00000 n +0000481058 00000 n +0000019864 00000 n +0000019917 00000 n +0000343822 00000 n +0000480993 00000 n +0000019969 00000 n +0000020021 00000 n +0000345666 00000 n +0000480899 00000 n +0000020069 00000 n +0000020121 00000 n +0000347620 00000 n +0000480805 00000 n +0000020169 00000 n +0000020222 00000 n +0000349428 00000 n +0000480711 00000 n +0000020270 00000 n +0000020326 00000 n +0000355607 00000 n +0000480578 00000 n +0000020374 00000 n +0000020411 00000 n +0000355661 00000 n +0000480499 00000 n +0000020463 00000 n +0000020512 00000 n +0000358641 00000 n +0000480381 00000 n +0000020564 00000 n +0000020611 00000 n +0000358695 00000 n +0000480302 00000 n +0000020668 00000 n +0000020722 00000 n +0000358753 00000 n +0000480209 00000 n +0000020779 00000 n +0000020837 00000 n +0000361012 00000 n +0000480116 00000 n +0000020894 00000 n +0000020950 00000 n +0000361066 00000 n +0000480023 00000 n +0000021007 00000 n +0000021059 00000 n +0000361124 00000 n +0000479930 00000 n +0000021116 00000 n +0000021165 00000 n +0000361181 00000 n +0000479851 00000 n +0000021222 00000 n +0000021272 00000 n +0000363695 00000 n +0000479771 00000 n +0000021320 00000 n +0000021367 00000 n +0000022625 00000 n +0000022843 00000 n +0000021420 00000 n +0000022737 00000 n +0000022790 00000 n +0000475494 00000 n +0000475930 00000 n +0000476364 00000 n +0000475785 00000 n +0000476655 00000 n +0000025206 00000 n +0000025417 00000 n +0000025074 00000 n +0000022953 00000 n +0000025364 00000 n +0000475640 00000 n +0000026251 00000 n +0000026086 00000 n +0000025514 00000 n +0000026198 00000 n +0000026696 00000 n +0000026531 00000 n +0000026322 00000 n +0000026643 00000 n +0000028480 00000 n +0000028630 00000 n +0000028785 00000 n +0000028941 00000 n +0000029097 00000 n +0000029253 00000 n +0000029409 00000 n +0000029565 00000 n +0000029727 00000 n +0000029888 00000 n +0000030050 00000 n +0000030201 00000 n +0000030356 00000 n +0000030511 00000 n +0000030667 00000 n +0000030823 00000 n +0000030979 00000 n +0000031135 00000 n +0000031291 00000 n +0000031446 00000 n +0000031608 00000 n +0000031770 00000 n +0000031930 00000 n +0000032090 00000 n +0000032251 00000 n +0000032411 00000 n +0000032567 00000 n +0000032724 00000 n +0000032881 00000 n +0000033038 00000 n +0000033195 00000 n +0000035276 00000 n +0000033461 00000 n +0000028108 00000 n +0000026767 00000 n +0000033351 00000 n +0000033404 00000 n +0000475348 00000 n +0000035427 00000 n +0000035583 00000 n +0000035745 00000 n +0000035904 00000 n +0000036064 00000 n +0000036224 00000 n +0000036385 00000 n +0000036547 00000 n +0000036708 00000 n +0000036864 00000 n +0000037026 00000 n +0000037187 00000 n +0000037349 00000 n +0000037511 00000 n +0000037671 00000 n +0000037831 00000 n +0000037993 00000 n +0000038153 00000 n +0000038312 00000 n +0000038471 00000 n +0000038627 00000 n +0000038789 00000 n +0000038951 00000 n +0000039107 00000 n +0000039269 00000 n +0000039429 00000 n +0000039589 00000 n +0000039749 00000 n +0000039910 00000 n +0000040070 00000 n +0000040230 00000 n +0000040390 00000 n +0000042312 00000 n +0000040603 00000 n +0000034888 00000 n +0000033558 00000 n +0000040550 00000 n +0000042473 00000 n +0000042633 00000 n +0000042793 00000 n +0000042944 00000 n +0000043100 00000 n +0000043262 00000 n +0000043424 00000 n +0000043584 00000 n +0000043744 00000 n +0000043903 00000 n +0000044063 00000 n +0000044222 00000 n +0000044382 00000 n +0000044542 00000 n +0000044702 00000 n +0000044862 00000 n +0000045018 00000 n +0000045180 00000 n +0000045340 00000 n +0000045499 00000 n +0000045659 00000 n +0000045819 00000 n +0000045980 00000 n +0000046140 00000 n +0000046302 00000 n +0000046462 00000 n +0000046622 00000 n +0000046782 00000 n +0000046942 00000 n +0000047100 00000 n +0000047262 00000 n +0000049243 00000 n +0000047474 00000 n +0000041932 00000 n +0000040687 00000 n +0000047421 00000 n +0000476773 00000 n +0000049403 00000 n +0000049563 00000 n +0000049723 00000 n +0000049883 00000 n +0000050043 00000 n +0000050205 00000 n +0000050365 00000 n +0000050525 00000 n +0000050686 00000 n +0000050846 00000 n +0000051006 00000 n +0000051166 00000 n +0000051322 00000 n +0000051484 00000 n +0000051644 00000 n +0000051804 00000 n +0000051963 00000 n +0000052123 00000 n +0000052285 00000 n +0000052440 00000 n +0000052602 00000 n +0000052762 00000 n +0000052922 00000 n +0000053082 00000 n +0000053246 00000 n +0000053410 00000 n +0000053574 00000 n +0000053738 00000 n +0000053901 00000 n +0000054065 00000 n +0000054225 00000 n +0000054389 00000 n +0000056382 00000 n +0000054605 00000 n +0000048855 00000 n +0000047558 00000 n +0000054552 00000 n +0000056546 00000 n +0000056706 00000 n +0000056868 00000 n +0000057028 00000 n +0000057188 00000 n +0000057348 00000 n +0000057504 00000 n +0000057664 00000 n +0000057826 00000 n +0000057982 00000 n +0000058139 00000 n +0000058302 00000 n +0000058464 00000 n +0000058621 00000 n +0000058784 00000 n +0000058945 00000 n +0000059104 00000 n +0000059267 00000 n +0000059423 00000 n +0000059585 00000 n +0000059745 00000 n +0000059906 00000 n +0000060067 00000 n +0000060224 00000 n +0000060387 00000 n +0000060548 00000 n +0000060709 00000 n +0000060871 00000 n +0000061028 00000 n +0000061190 00000 n +0000061354 00000 n +0000061518 00000 n +0000063566 00000 n +0000061735 00000 n +0000055968 00000 n +0000054676 00000 n +0000061680 00000 n +0000063726 00000 n +0000063888 00000 n +0000064050 00000 n +0000064212 00000 n +0000064373 00000 n +0000064535 00000 n +0000064696 00000 n +0000064858 00000 n +0000065021 00000 n +0000065184 00000 n +0000065346 00000 n +0000065509 00000 n +0000065672 00000 n +0000065836 00000 n +0000065994 00000 n +0000066158 00000 n +0000066321 00000 n +0000066483 00000 n +0000066644 00000 n +0000066806 00000 n +0000066968 00000 n +0000067130 00000 n +0000067292 00000 n +0000067454 00000 n +0000067616 00000 n +0000067778 00000 n +0000067931 00000 n +0000068088 00000 n +0000068241 00000 n +0000068394 00000 n +0000069507 00000 n +0000068601 00000 n +0000063160 00000 n +0000061807 00000 n +0000068546 00000 n +0000069660 00000 n +0000069817 00000 n +0000069974 00000 n +0000070137 00000 n +0000070299 00000 n +0000070462 00000 n +0000070625 00000 n +0000070788 00000 n +0000070951 00000 n +0000071158 00000 n +0000069290 00000 n +0000068686 00000 n +0000071103 00000 n +0000074268 00000 n +0000073933 00000 n +0000071243 00000 n +0000074048 00000 n +0000077983 00000 n +0000077755 00000 n +0000074366 00000 n +0000077871 00000 n +0000476895 00000 n +0000080828 00000 n +0000080547 00000 n +0000078068 00000 n +0000080663 00000 n +0000476220 00000 n +0000083634 00000 n +0000083350 00000 n +0000080939 00000 n +0000083466 00000 n +0000476508 00000 n +0000086730 00000 n +0000086502 00000 n +0000083746 00000 n +0000086618 00000 n +0000087789 00000 n +0000088054 00000 n +0000087652 00000 n +0000086829 00000 n +0000087946 00000 n +0000091281 00000 n +0000090943 00000 n +0000088153 00000 n +0000091059 00000 n +0000094609 00000 n +0000094766 00000 n +0000094929 00000 n +0000095313 00000 n +0000094454 00000 n +0000091393 00000 n +0000095087 00000 n +0000477020 00000 n +0000098142 00000 n +0000098820 00000 n +0000098005 00000 n +0000095398 00000 n +0000098299 00000 n +0000098525 00000 n +0000098584 00000 n +0000098643 00000 n +0000098702 00000 n +0000098761 00000 n +0000101994 00000 n +0000102156 00000 n +0000102314 00000 n +0000102467 00000 n +0000102621 00000 n +0000106613 00000 n +0000103061 00000 n +0000101821 00000 n +0000098905 00000 n +0000102778 00000 n +0000476075 00000 n +0000106774 00000 n +0000106928 00000 n +0000107261 00000 n +0000106458 00000 n +0000103160 00000 n +0000107091 00000 n +0000110401 00000 n +0000110230 00000 n +0000107360 00000 n +0000110346 00000 n +0000113319 00000 n +0000113888 00000 n +0000113182 00000 n +0000110487 00000 n +0000113482 00000 n +0000113537 00000 n +0000113596 00000 n +0000113655 00000 n +0000117439 00000 n +0000117596 00000 n +0000117920 00000 n +0000117293 00000 n +0000113986 00000 n +0000117750 00000 n +0000477145 00000 n +0000121036 00000 n +0000121193 00000 n +0000121461 00000 n +0000120890 00000 n +0000118018 00000 n +0000121348 00000 n +0000122480 00000 n +0000122309 00000 n +0000121559 00000 n +0000122425 00000 n +0000124973 00000 n +0000125129 00000 n +0000125284 00000 n +0000125440 00000 n +0000125597 00000 n +0000125757 00000 n +0000125916 00000 n +0000126076 00000 n +0000126235 00000 n +0000126398 00000 n +0000126561 00000 n +0000126724 00000 n +0000129077 00000 n +0000127112 00000 n +0000124737 00000 n +0000122552 00000 n +0000126887 00000 n +0000129351 00000 n +0000128940 00000 n +0000127210 00000 n +0000129238 00000 n +0000131557 00000 n +0000131769 00000 n +0000131420 00000 n +0000129463 00000 n +0000131714 00000 n +0000133928 00000 n +0000134142 00000 n +0000133791 00000 n +0000131855 00000 n +0000134087 00000 n +0000477270 00000 n +0000136800 00000 n +0000137129 00000 n +0000136663 00000 n +0000134228 00000 n +0000136959 00000 n +0000139722 00000 n +0000139885 00000 n +0000140101 00000 n +0000139576 00000 n +0000137228 00000 n +0000140046 00000 n +0000142433 00000 n +0000145399 00000 n +0000142703 00000 n +0000142296 00000 n +0000140187 00000 n +0000142590 00000 n +0000145557 00000 n +0000146063 00000 n +0000145253 00000 n +0000142802 00000 n +0000145716 00000 n +0000145887 00000 n +0000145946 00000 n +0000149178 00000 n +0000149341 00000 n +0000149503 00000 n +0000149774 00000 n +0000149023 00000 n +0000146175 00000 n +0000149661 00000 n +0000151992 00000 n +0000152149 00000 n +0000152424 00000 n +0000151846 00000 n +0000149873 00000 n +0000152311 00000 n +0000477395 00000 n +0000155034 00000 n +0000155195 00000 n +0000155358 00000 n +0000158267 00000 n +0000155570 00000 n +0000154879 00000 n +0000152537 00000 n +0000155515 00000 n +0000158420 00000 n +0000158583 00000 n +0000158795 00000 n +0000158112 00000 n +0000155656 00000 n +0000158740 00000 n +0000161766 00000 n +0000161537 00000 n +0000158894 00000 n +0000161653 00000 n +0000164733 00000 n +0000165116 00000 n +0000164596 00000 n +0000161865 00000 n +0000164891 00000 n +0000167568 00000 n +0000167169 00000 n +0000165229 00000 n +0000167285 00000 n +0000170388 00000 n +0000170043 00000 n +0000167681 00000 n +0000170159 00000 n +0000477520 00000 n +0000172235 00000 n +0000172395 00000 n +0000172785 00000 n +0000172089 00000 n +0000170500 00000 n +0000172556 00000 n +0000176316 00000 n +0000176479 00000 n +0000176642 00000 n +0000177087 00000 n +0000176161 00000 n +0000172910 00000 n +0000176805 00000 n +0000180536 00000 n +0000180699 00000 n +0000180860 00000 n +0000181023 00000 n +0000181298 00000 n +0000180372 00000 n +0000177199 00000 n +0000181185 00000 n +0000184200 00000 n +0000184362 00000 n +0000184525 00000 n +0000184688 00000 n +0000184964 00000 n +0000184036 00000 n +0000181397 00000 n +0000184851 00000 n +0000188128 00000 n +0000188291 00000 n +0000188449 00000 n +0000188602 00000 n +0000189047 00000 n +0000187964 00000 n +0000185063 00000 n +0000188760 00000 n +0000192226 00000 n +0000192384 00000 n +0000195593 00000 n +0000192708 00000 n +0000192080 00000 n +0000189146 00000 n +0000192541 00000 n +0000477645 00000 n +0000195751 00000 n +0000196021 00000 n +0000195447 00000 n +0000192819 00000 n +0000195908 00000 n +0000198650 00000 n +0000198924 00000 n +0000198513 00000 n +0000196120 00000 n +0000198813 00000 n +0000202047 00000 n +0000202210 00000 n +0000202364 00000 n +0000202871 00000 n +0000201892 00000 n +0000199023 00000 n +0000202527 00000 n +0000206414 00000 n +0000205899 00000 n +0000202956 00000 n +0000206015 00000 n +0000208785 00000 n +0000208938 00000 n +0000209212 00000 n +0000208639 00000 n +0000206525 00000 n +0000209100 00000 n +0000212624 00000 n +0000212164 00000 n +0000209324 00000 n +0000212280 00000 n +0000212450 00000 n +0000212508 00000 n +0000212566 00000 n +0000477770 00000 n +0000215958 00000 n +0000215263 00000 n +0000212736 00000 n +0000215379 00000 n +0000215434 00000 n +0000215489 00000 n +0000215548 00000 n +0000215607 00000 n +0000215665 00000 n +0000215724 00000 n +0000215783 00000 n +0000215842 00000 n +0000218604 00000 n +0000218375 00000 n +0000216070 00000 n +0000218491 00000 n +0000221377 00000 n +0000221032 00000 n +0000218729 00000 n +0000221148 00000 n +0000224620 00000 n +0000224333 00000 n +0000221476 00000 n +0000224449 00000 n +0000227671 00000 n +0000227889 00000 n +0000227534 00000 n +0000224732 00000 n +0000227834 00000 n +0000230262 00000 n +0000230037 00000 n +0000227988 00000 n +0000230153 00000 n +0000477895 00000 n +0000233176 00000 n +0000232773 00000 n +0000230374 00000 n +0000232889 00000 n +0000236443 00000 n +0000235812 00000 n +0000233301 00000 n +0000235928 00000 n +0000236209 00000 n +0000236268 00000 n +0000238166 00000 n +0000237995 00000 n +0000236542 00000 n +0000238111 00000 n +0000240393 00000 n +0000240222 00000 n +0000238265 00000 n +0000240338 00000 n +0000242976 00000 n +0000242747 00000 n +0000240492 00000 n +0000242863 00000 n +0000246193 00000 n +0000249146 00000 n +0000246630 00000 n +0000246056 00000 n +0000243088 00000 n +0000246347 00000 n +0000478020 00000 n +0000249300 00000 n +0000249454 00000 n +0000249953 00000 n +0000248991 00000 n +0000246729 00000 n +0000249612 00000 n +0000253043 00000 n +0000252815 00000 n +0000250065 00000 n +0000252931 00000 n +0000254837 00000 n +0000254612 00000 n +0000253142 00000 n +0000254728 00000 n +0000257759 00000 n +0000260133 00000 n +0000258083 00000 n +0000257622 00000 n +0000254936 00000 n +0000257917 00000 n +0000260514 00000 n +0000259996 00000 n +0000258208 00000 n +0000260290 00000 n +0000262900 00000 n +0000262671 00000 n +0000260626 00000 n +0000262787 00000 n +0000478145 00000 n +0000266182 00000 n +0000265667 00000 n +0000262999 00000 n +0000265783 00000 n +0000268503 00000 n +0000268220 00000 n +0000266294 00000 n +0000268336 00000 n +0000271386 00000 n +0000271099 00000 n +0000268615 00000 n +0000271215 00000 n +0000274175 00000 n +0000273834 00000 n +0000271498 00000 n +0000273950 00000 n +0000276862 00000 n +0000276517 00000 n +0000274274 00000 n +0000276633 00000 n +0000279423 00000 n +0000279017 00000 n +0000276961 00000 n +0000279133 00000 n +0000279188 00000 n +0000279247 00000 n +0000279306 00000 n +0000478270 00000 n +0000281973 00000 n +0000282130 00000 n +0000282516 00000 n +0000281827 00000 n +0000279522 00000 n +0000282287 00000 n +0000284865 00000 n +0000284636 00000 n +0000282628 00000 n +0000284752 00000 n +0000287198 00000 n +0000286853 00000 n +0000284964 00000 n +0000286969 00000 n +0000290089 00000 n +0000290530 00000 n +0000289952 00000 n +0000287310 00000 n +0000290247 00000 n +0000292730 00000 n +0000292443 00000 n +0000290628 00000 n +0000292559 00000 n +0000295423 00000 n +0000295580 00000 n +0000296022 00000 n +0000295277 00000 n +0000292829 00000 n +0000295737 00000 n +0000478395 00000 n +0000297983 00000 n +0000297754 00000 n +0000296134 00000 n +0000297870 00000 n +0000299431 00000 n +0000299202 00000 n +0000298082 00000 n +0000299318 00000 n +0000301329 00000 n +0000301486 00000 n +0000301640 00000 n +0000301969 00000 n +0000301174 00000 n +0000299530 00000 n +0000301798 00000 n +0000304257 00000 n +0000304534 00000 n +0000304120 00000 n +0000302081 00000 n +0000304421 00000 n +0000305997 00000 n +0000305826 00000 n +0000304633 00000 n +0000305942 00000 n +0000308512 00000 n +0000308664 00000 n +0000309055 00000 n +0000308366 00000 n +0000306082 00000 n +0000308826 00000 n +0000478520 00000 n +0000310890 00000 n +0000310546 00000 n +0000309154 00000 n +0000310662 00000 n +0000312932 00000 n +0000313093 00000 n +0000313425 00000 n +0000312786 00000 n +0000310989 00000 n +0000313254 00000 n +0000316381 00000 n +0000316652 00000 n +0000316244 00000 n +0000313524 00000 n +0000316539 00000 n +0000319301 00000 n +0000319635 00000 n +0000319164 00000 n +0000316764 00000 n +0000319464 00000 n +0000322047 00000 n +0000322321 00000 n +0000321910 00000 n +0000319748 00000 n +0000322208 00000 n +0000324655 00000 n +0000324426 00000 n +0000322434 00000 n +0000324542 00000 n +0000478645 00000 n +0000327233 00000 n +0000326946 00000 n +0000324768 00000 n +0000327062 00000 n +0000329783 00000 n +0000329438 00000 n +0000327346 00000 n +0000329554 00000 n +0000332833 00000 n +0000332991 00000 n +0000333148 00000 n +0000333530 00000 n +0000332678 00000 n +0000329909 00000 n +0000333301 00000 n +0000336278 00000 n +0000335763 00000 n +0000333629 00000 n +0000335879 00000 n +0000337436 00000 n +0000337211 00000 n +0000336377 00000 n +0000337327 00000 n +0000337918 00000 n +0000337747 00000 n +0000337535 00000 n +0000337863 00000 n +0000478770 00000 n +0000340323 00000 n +0000340098 00000 n +0000337990 00000 n +0000340214 00000 n +0000342421 00000 n +0000342250 00000 n +0000340421 00000 n +0000342366 00000 n +0000343876 00000 n +0000343651 00000 n +0000342506 00000 n +0000343767 00000 n +0000345720 00000 n +0000345495 00000 n +0000343974 00000 n +0000345611 00000 n +0000347674 00000 n +0000347449 00000 n +0000345818 00000 n +0000347565 00000 n +0000349482 00000 n +0000349257 00000 n +0000347759 00000 n +0000349373 00000 n +0000478895 00000 n +0000351634 00000 n +0000351463 00000 n +0000349567 00000 n +0000351579 00000 n +0000353159 00000 n +0000352988 00000 n +0000351733 00000 n +0000353104 00000 n +0000355719 00000 n +0000355436 00000 n +0000353258 00000 n +0000355552 00000 n +0000358811 00000 n +0000358470 00000 n +0000355818 00000 n +0000358586 00000 n +0000361238 00000 n +0000360841 00000 n +0000358909 00000 n +0000360957 00000 n +0000364456 00000 n +0000363524 00000 n +0000361323 00000 n +0000363640 00000 n +0000363749 00000 n +0000363808 00000 n +0000363867 00000 n +0000363926 00000 n +0000363985 00000 n +0000364044 00000 n +0000364103 00000 n +0000364161 00000 n +0000364220 00000 n +0000364279 00000 n +0000364338 00000 n +0000364397 00000 n +0000479020 00000 n +0000367945 00000 n +0000367071 00000 n +0000364567 00000 n +0000367187 00000 n +0000367242 00000 n +0000367297 00000 n +0000367355 00000 n +0000367414 00000 n +0000367473 00000 n +0000367532 00000 n +0000367591 00000 n +0000367650 00000 n +0000367709 00000 n +0000367768 00000 n +0000367827 00000 n +0000367886 00000 n +0000371241 00000 n +0000370249 00000 n +0000368030 00000 n +0000370365 00000 n +0000370420 00000 n +0000370475 00000 n +0000370534 00000 n +0000370593 00000 n +0000370652 00000 n +0000370711 00000 n +0000370770 00000 n +0000370829 00000 n +0000370888 00000 n +0000370947 00000 n +0000371006 00000 n +0000371065 00000 n +0000371124 00000 n +0000371183 00000 n +0000373032 00000 n +0000372512 00000 n +0000371326 00000 n +0000372628 00000 n +0000372683 00000 n +0000372738 00000 n +0000372796 00000 n +0000372855 00000 n +0000372914 00000 n +0000372973 00000 n +0000375233 00000 n +0000375384 00000 n +0000375535 00000 n +0000375684 00000 n +0000375834 00000 n +0000375984 00000 n +0000376134 00000 n +0000376283 00000 n +0000376434 00000 n +0000376586 00000 n +0000376738 00000 n +0000376889 00000 n +0000377040 00000 n +0000377192 00000 n +0000377343 00000 n +0000377494 00000 n +0000377645 00000 n +0000377796 00000 n +0000377945 00000 n +0000378095 00000 n +0000378244 00000 n +0000378394 00000 n +0000378543 00000 n +0000378692 00000 n +0000378842 00000 n +0000378992 00000 n +0000379142 00000 n +0000379293 00000 n +0000379442 00000 n +0000379593 00000 n +0000379745 00000 n +0000379894 00000 n +0000380043 00000 n +0000380194 00000 n +0000380344 00000 n +0000380495 00000 n +0000380645 00000 n +0000380795 00000 n +0000380946 00000 n +0000381096 00000 n +0000381247 00000 n +0000381399 00000 n +0000381550 00000 n +0000381700 00000 n +0000381851 00000 n +0000382002 00000 n +0000382153 00000 n +0000382305 00000 n +0000382455 00000 n +0000382606 00000 n +0000382756 00000 n +0000382906 00000 n +0000383055 00000 n +0000383205 00000 n +0000383355 00000 n +0000383503 00000 n +0000383653 00000 n +0000383804 00000 n +0000383954 00000 n +0000384105 00000 n +0000384257 00000 n +0000384407 00000 n +0000384557 00000 n +0000384704 00000 n +0000384850 00000 n +0000385000 00000 n +0000385151 00000 n +0000385302 00000 n +0000385452 00000 n +0000385603 00000 n +0000385755 00000 n +0000385906 00000 n +0000386057 00000 n +0000386209 00000 n +0000386361 00000 n +0000386512 00000 n +0000386663 00000 n +0000386814 00000 n +0000386966 00000 n +0000387118 00000 n +0000387269 00000 n +0000387420 00000 n +0000387571 00000 n +0000387723 00000 n +0000387874 00000 n +0000388025 00000 n +0000388175 00000 n +0000388325 00000 n +0000388475 00000 n +0000388625 00000 n +0000388774 00000 n +0000388924 00000 n +0000389074 00000 n +0000389225 00000 n +0000389375 00000 n +0000389527 00000 n +0000389676 00000 n +0000389826 00000 n +0000389977 00000 n +0000390127 00000 n +0000390393 00000 n +0000374205 00000 n +0000373117 00000 n +0000390279 00000 n +0000390334 00000 n +0000390676 00000 n +0000390643 00000 n +0000390610 00000 n +0000390577 00000 n +0000390544 00000 n +0000390511 00000 n +0000390478 00000 n +0000390709 00000 n +0000390863 00000 n +0000391255 00000 n +0000391318 00000 n +0000391958 00000 n +0000391994 00000 n +0000392622 00000 n +0000392833 00000 n +0000393426 00000 n +0000394080 00000 n +0000408670 00000 n +0000409124 00000 n +0000421668 00000 n +0000422114 00000 n +0000423923 00000 n +0000424158 00000 n +0000442345 00000 n +0000442953 00000 n +0000451414 00000 n +0000451770 00000 n +0000454516 00000 n +0000454746 00000 n +0000456680 00000 n +0000456902 00000 n +0000458477 00000 n +0000458736 00000 n +0000474731 00000 n +0000479136 00000 n +0000479260 00000 n +0000479386 00000 n +0000479512 00000 n +0000479602 00000 n +0000479694 00000 n +0000498994 00000 n +0000499173 00000 n +0000499350 00000 n +0000499525 00000 n +0000499700 00000 n +0000499877 00000 n +0000500053 00000 n +0000500230 00000 n +0000500406 00000 n +0000500583 00000 n +0000500759 00000 n +0000500936 00000 n +0000501115 00000 n +0000501302 00000 n +0000501485 00000 n +0000501668 00000 n +0000501853 00000 n +0000502037 00000 n +0000502221 00000 n +0000502400 00000 n +0000502575 00000 n +0000502752 00000 n +0000502926 00000 n +0000503100 00000 n +0000503277 00000 n +0000503452 00000 n +0000503629 00000 n +0000503804 00000 n +0000503981 00000 n +0000504156 00000 n +0000504333 00000 n +0000504508 00000 n +0000504685 00000 n +0000504860 00000 n +0000505055 00000 n +0000505305 00000 n +0000505556 00000 n +0000505807 00000 n +0000506058 00000 n +0000506318 00000 n +0000506580 00000 n +0000506839 00000 n +0000507098 00000 n +0000507351 00000 n +0000507602 00000 n +0000507853 00000 n +0000508104 00000 n +0000508355 00000 n +0000508606 00000 n +0000508857 00000 n +0000509060 00000 n +0000509325 00000 n +0000509590 00000 n +0000509814 00000 n +0000510044 00000 n +0000510266 00000 n +0000510495 00000 n +0000510724 00000 n +0000510951 00000 n +0000511212 00000 n +0000511479 00000 n +0000511746 00000 n +0000512013 00000 n +0000512288 00000 n +0000512555 00000 n +0000512822 00000 n +0000513089 00000 n +0000513356 00000 n +0000513474 00000 n +0000513593 00000 n +0000513713 00000 n +0000513830 00000 n +0000513946 00000 n +0000514072 00000 n +0000514209 00000 n +0000514346 00000 n +0000514479 00000 n +0000514614 00000 n +0000514754 00000 n +0000514849 00000 n +0000514977 00000 n +0000515115 00000 n +0000515209 00000 n +0000515249 00000 n +0000515381 00000 n +trailer +<< /Size 1929 +/Root 1927 0 R +/Info 1928 0 R +/ID [<97AA13A313DA3EACE2EBC67A44CC1966> <97AA13A313DA3EACE2EBC67A44CC1966>] >> +startxref +515733 +%%EOF diff --git a/trunk/FixPowerShell.cmd b/trunk/FixPowerShell.cmd new file mode 100644 index 00000000..eade5553 --- /dev/null +++ b/trunk/FixPowerShell.cmd @@ -0,0 +1,10 @@ +@echo off +echo Setting PowerShell ExecutionPolicy = Unrestricted... +echo. +PowerShell Set-ExecutionPolicy Unrestricted +echo PowerShell ExecutionPolicy is now: +PowerShell Get-ExecutionPolicy +echo. +echo The execution policy should be "Unrestricted" +echo. +pause \ No newline at end of file diff --git a/trunk/Make.cmd b/trunk/Make.cmd new file mode 100644 index 00000000..666aa393 --- /dev/null +++ b/trunk/Make.cmd @@ -0,0 +1,4 @@ +@echo off +pushd Source +call .\Make.cmd %* +popd \ No newline at end of file diff --git a/trunk/ReadMe.txt b/trunk/ReadMe.txt new file mode 100644 index 00000000..ffc207bf --- /dev/null +++ b/trunk/ReadMe.txt @@ -0,0 +1,127 @@ +************************************************************ +*** R o m W B W *** +*** *** +*** System Software for N8VEM Z80 Projects *** +************************************************************ + +Builders: Wayne Warthen (wwarthen@gmail.com) + Douglas Goodall (douglas_goodall@mac.com) + David Giles (vk5dg@internode.on.net) + +Updated: 2012-08-28 +Version: 2.1.1 + +This is an adaptation of CP/M-80 2.2 and ZSDOS/ZCPR +targeting ROMs for all N8VEM Z80 hardware variations +including SBC, Zeta, and N8. + +NOTE: This is very much a work-in-progress. It is +severely lacking appropriate documentation. I am +happy to answer questions and provide support though. + +Acknowledgements +---------------- + +While I have heavily modified much of the code, I want +to acknowledge that much of this is derived or +copied from the work of others in the N8VEM +project including Andrew Lynch, Dan Werner, Max Scane, +David Giles, John Coffman, and probably many others +I am not clearly aware of. + +I especially want to credit Douglas Goodall for +contributing code, time, testing, and advice. +He has created an entire suite of application +programs that substantially enhance this ROM. Everything +in the Apps folder of the distribution came directly +from Douglas and the list includes cpmname, writesys, +assign, slices, termtype, drives, and others. + +David Giles has contributed support for building the +ROM under Linux and the CSIO support in the SD Card driver. + +Usage Instructions +------------------ + +The distribution includes many pre-built ROM +images in the Output directory. The simplest way of +using this ROM is to simply pick the pre-built ROM +that most closely matches your preferences, burn it, +and use it. + +Refer to the file called RomList.txt for a complete +list of the ROMs that are included and the required +hardware configuration that they support. + +CPU Speed & Baud Rate +--------------------- + +The startup serial port baud rate in all pre-built +RomWBW variants is 38.4Kbps. While this speed is +nice in that it provides great display and file +transfer performance, it does push the limits of +slower hardware. Specifically, XModem v12.5 (the +default XM.COM) on the distribution is unable to +service the serial port fast enough if the CPU is +running at 4MHz. Your options are to 1) use the +old version of XModem (XM5.COM), put a faster CPU +oscillator in your system (6MHz or above), or +3) decrease the baud rate by building a custom +ROM. + +CP/M vs. ZSystem +---------------- + +There are two OS variants included in this distribution +and you may choose which one you prefer to use. + +The traditional Digital Research (DRI) CP/M code is the first +choice. The ROM images that DO NOT end in "_z" are built +with the traditional CP/M components from DRI. The Doc +directory contains a manual for CP/M usage (cpm22-m.pdf). +If you are new to the N8VEM systems, I would currently +recommend using the CP/M ROMs to start with simply +because they have gone through more testing and you +are less likely to encounter problems. + +The other choice is to use the most popular non-DRI +CP/M "clone" which is generally referred to as +ZSystem. The ROM images with a "_z" suffix are built +using the ZSystem components (specifically ZSDOS 1.2 +and ZCPR 1.0). These are intended to be +functionally equivalent to CP/M and should run all +CP/M 2.2 code. They are optimized for the Z80 CPU +(as opposed to 8080 for CP/M) and have some potentially +useful improvements. Please refer to the Doc directory +and look at the files for zsdos and zcpr (zsdos.pdf & +zcpr.doc as well as ZSystem.txt). + +ZSystem builds contain ZSDOS specific files in the +ROM Disk. + +Building a Custom ROM +--------------------- + +I strongly suggest you start with burning one of the +pre-built ROMs and making sure that works first. Once +you have gotten past that hurdle, you should consider +building a custom ROM. It is very easy and the +distribution comes with everything that is needed to +run a build on a Windows 32 bit or 64 bit system -- +basically Windows XP or above. There is also a +Linux build now available. + +Creating a custom ROM allows you to customize a lot +of useful stuff like adding support for a DSKY if +you have one. + +Please refer to the Build.txt file in the Doc directory +for detailed instructions for building a custom ROM. If +you are using Linux, also read the LinuxBuild.txt file. + +Notes +----- + +I realize these instructions are very minimal. I am happy to answer +questions. You will find the Google Group 'N8VEM' to be a great +source of information as well. \ No newline at end of file diff --git a/trunk/RomDsk/CPM_1024KB/ASM.COM b/trunk/RomDsk/CPM_1024KB/ASM.COM new file mode 100644 index 00000000..a63e5aec Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/ASM.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/CLRDIR.COM b/trunk/RomDsk/CPM_1024KB/CLRDIR.COM new file mode 100644 index 00000000..d1f2a7d6 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/CLRDIR.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/CR.COM b/trunk/RomDsk/CPM_1024KB/CR.COM new file mode 100644 index 00000000..8a824bcc Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/CR.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/DDT.COM b/trunk/RomDsk/CPM_1024KB/DDT.COM new file mode 100644 index 00000000..83f8603f Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/DDT.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/DDTZ.COM b/trunk/RomDsk/CPM_1024KB/DDTZ.COM new file mode 100644 index 00000000..e30a34c0 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/DDTZ.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/DDTZ.DOC b/trunk/RomDsk/CPM_1024KB/DDTZ.DOC new file mode 100644 index 00000000..e4470528 --- /dev/null +++ b/trunk/RomDsk/CPM_1024KB/DDTZ.DOC @@ -0,0 +1,564 @@ + + DDTZ v2.7 + by C.B. Falconer + edited by George A. Havach + +Introduction: +============ +DDTZ v2.7 is a complete replacement for DDT, Digital Research's +famous Dynamic Debugging Tool, with improved functionality, bug +extermination, and full Z80 support. In general, DDTZ is fully +compatible with the original utility, but it has extra and +extended commands and many fewer quirks. All Z80-specific +instructions can be (dis)assembled, though in Intel rather then +Zilog format. Furthermore, DDTZ will correctly trace ('T' and 'U' +commands) both 8080 and Z80 instructions, depending on which CPU +is operating. On startup, the program announces which CPU it is +running on. + +DDTZ v2.7 now handles the 64180 added opcodes. It does NOT test +for a 64180 CPU, since this cannot be done without executing +illegal Z80 instructions, which in turn will crash some +simulators. However v2.7 does not execute any 64180 instructions +internally, only in the subject program. + +This issue supplies the "M" version assembled, to avoid errors +when switching between MSDOS and CPM systems. The command table +is updated accordingly. Most CPM users are also MSDOS users, but +not vice-versa. + +The program is invoked by typing + + ddtz +or + ddtz [d:]filespec + +In the second form, DDTZ will load the specified file into +memory starting at 0100H, unless it's a .HEX file that sets its +own load address. Besides reporting the NEXT free address and +the PC (program counter) after a successful load, DDTZ also shows +the number of memory pages needed for a SAVE. Instead of having +to write all this down, just use the 'X' command at any time to +redisplay these three values for the current application. + +NOTE: loading more code above the NEXT pointer revises these + values. + +As in DDT, when a program is loaded above the area holding the +'A' and 'U' (and now 'W') command code, these commands are +disabled, and the extra memory is released to the user. Thus, +DDTZ can occupy as little as 3K total memory space. Unlike DDT, +however, DDTZ will not overwrite itself or the system on program +loads (except .HEX files). + +At initialization, the stack pointer (SP) points to a return to +DDTZ, just like for the CCP. Thus, programs that normally return +to the CCP will be returned to DDTZ. The 'B' command +reinitializes this condition. + + +The intercept vector copies the BDOS version number, etc., so +an object program does not know that DDTZ is running (except +for BIOS-BDOS vector size). Thus, programs that check the version +number should execute correctly under DDTZ. + +All input parameters can now be entered in any of three formats: + + (1) hexadecimal (as in DDT), + (2) decimal, by adding a leading '#' character, + (3) ASCII, by enclosing between either single or double + quotes; either one or two characters are allowed. + +Leading blanks in command lines and parameters are absorbed. +Either a comma or a (single) space is a valid delimiter. +Either uppercase or lowercase input is accepted. + +The default command (for anything not otherwise recognizable) +is 'H'. This allows convenient calculation, along with the other +features described below. So, to convert a number, just enter +it! + +As in DDT, the prompt character is '-', and the only error +message is the query ('?'), which generally kicks you back to +command mode. + +New Commands (Over DDT): +======================= + +NOTE: letters in parenthesis, e.g. "(U)", show the equivalent + command for DDTZM version (compatible with MSDOS debug). + + @ Sets or shows (with no parameter) the internally stored + "base" value. Also used with the 'S' and 'D' commands as + an optional parameter (though without the '@') to display + memory from an arbitrary base marker (offset). When set to + zero (the default), it does not affect any screen displays. + + B B)egin: resets the USER stack pointer to its initial value, + such that any program that exits by an RET will return to + DDTZ. DDTZ provides a default stack space of + approximately 24 bytes for user programs. + + C C)ompare first_address,last_address,against_address: shows + all the byte differences between two memory areas, in the + format + + XXXX aa YYYY bb + + where XXXX and YYYY are the comparative memory addresses, + and aa and bb are the corresponding byte values. Can be + used to verify the identity of two files by first + loading them into different memory areas with the 'R' + command (see below). + + + W Write: stores the modified memory area to disk under the + (K) filename specified by the 'I' command, overwriting the + original file from which it was loaded (the user is queried + before doing so). By default, the image of memory from + 0100H through the "NEXT" value -1 is saved. "K first_addr, + last_address" overrides this and allows writing ANY memory + area to a file. Almost a necessity for CPM 3.0 (no SAVE!). + K)eep on DDTZ + + X eXamine: redisplays the "NEXT PC SAVE" report at any time. + (Q) Q)uery size on DDTZ. + + S S)earch first_address, last_addr, value: searches the + (W) specified memory area for the value (a 16-bit word, not a + byte) and shows the locations of all such. Very useful for + finding CALL's or JMP's to a particular address, etc. + W)here on DDTZ + + Y Y)our_option parm1,parm2,address: executes an arbitrary + routine at the specified address, with the BC and DE + registers set to parm1 and parm2, respectively. + + Z Displays (but does not alter) the Z80's alternate register + set, including the index registers (disabled if running on + an 8080). On Z80's, automatically included as the last + part of the display by the 'X' command. + + +Based (Offset) Displays: +======================= + +The 'D' and 'E' commands can use a stored base value (offset), +as set by the '@' command. The current @ value may be +overridden for a single execution of these commands by adding the +base as an extra parameter in the command line. The effect is +to add this value to the first/last address and display +accordingly. The address listing on the left becomes XXXX:YYYY, +where XXXX is the offset address and YYYY is the actual memory +address being displayed. For example, if you have a data area +located at 42B7H and wish to preserve easy access, just enter +"@42b7". Now, "d0,3f" will dump memory starting at 4237H. + + +Further Changes from DDT: +======================== + + A A)ssemble now accepts the full Z80 as well as 8080 + instruction set, although it expects them in Intel rather + than Zilog format (see notes below under the 'L' + command). When in doubt, see the mnemnonic list below. + + D D)isplay or D)ump will accept an optional third parameter + to set the base value for a single execution only. Format + has been cleaned up. + + H H)ex_arithmetic on two values also shows their + difference in decimal. With only one value, converts to + hexadecimal, decimal, and ASCII (low-order byte only). + + + N N)ame now allows drive specification (d:...) and sets up + (I) the complete command line, including both FCB's (at + addresses 005CH and 006CH). The tail (stored at 0081H up) + is NOT upshifted. + I)nput on DDTZ + + U U)nassemble now displays the raw hexcode, especially handy + (L) when examining non-code areas. Intel (8080 style) mnemonics + are used, so some disassembled instructions may look + strange. E.g., the Z80's 'IN B,(C)' and 'OUT (C),B' become + 'INP B' and 'OUTP B', respectively; 'LD (nnnn),BC' becomes + 'SBCD nnnn', 'ADD IX, BC' becomes 'DADX B', and 'JP (IX)' + becomes 'PCIX'. + L)ist on DDTZ + + L L)oad now permits loading a file into memory with an + (R) offset, which is added to the default load address of + 0100H. When reading in a .HEX file with a preset bias, + the 'R' command will not transfer control to an invalid + execution point. Another execution of the 'R' command will + reread the input file, e.g.: + + n blah + l + ...modify the code and generally mess about... + l + + The original file is reloaded, and the modifications are + removed. + R)ead on DDTZ + + E E)nter, like D)isplay, now accepts an optional second + (S) parameter to set the base value for a single execution + only. + S)ubstitute or S)et on DDTZ + + T T)rap/trace on termination now shows the complete CPU + state. Traps and traces no longer lock up when a user RST + 7 instruction is executed. Tracing of BDOS/BIOS calls is + heavily trun cated, avoiding clutter and preventing system + crashes. + +NOTE: Most of the UNDOCUMENTED Z80 op-codes are handled. Others + can crash the system. + + R R)egisters also shows what two-byte values the HL and SP + (X) registers are actually pointing to. On Z80's, displays the + alternate register set. + eX)amine on DDTZ + +NOTE: Any use of the 'W' or 'L' command resets the system DMA + transfer address to the standard default value of 0080H. + + +; This is the output of DDTZ when disassembling OPTYPE.TRY +NOP LDA 06A4 MOV M,H +LXI B,06A4 DCX SP MOV M,L +STAX B INR A HLT +INX B DCR A MOV M,A +INR B MVI A,20 MOV A,B +DCR B CMC MOV A,C +MVI B,20 MOV B,B MOV A,D +RLC MOV B,C MOV A,E +EXAF MOV B,D MOV A,H +DAD B MOV B,E MOV A,L +LDAX B MOV B,H MOV A,M +DCX B MOV B,L MOV A,A +INR C MOV B,M ADD B +DCR C MOV B,A ADD C +MVI C,20 MOV C,B ADD D +RRC MOV C,C ADD E +DJNZ 0134 MOV C,D ADD H +LXI D,06A4 MOV C,E ADD L +STAX D MOV C,H ADD M +INX D MOV C,L ADD A +INR D MOV C,M ADC B +DCR D MOV C,A ADC C +MVI D,20 MOV D,B ADC D +RAL MOV D,C ADC E +JR 0134 MOV D,D ADC H +DAD D MOV D,E ADC L +LDAX D MOV D,H ADC M +DCX D MOV D,L ADC A +INR E MOV D,M SUB B +DCR E MOV D,A SUB C +MVI E,20 MOV E,B SUB D +RAR MOV E,C SUB E +JRNZ 0134 MOV E,D SUB H +LXI H,06A4 MOV E,E SUB L +SHLD 06A4 MOV E,H SUB M +INX H MOV E,L SUB A +INR H MOV E,M SBB B +DCR H MOV E,A SBB C +MVI H,20 MOV H,B SBB D +DAA MOV H,C SBB E +JRZ 0134 MOV H,D SBB H +DAD H MOV H,E SBB L +LHLD 06A4 MOV H,H SBB M +DCX H MOV H,L SBB A +INR L MOV H,M ANA B +DCR L MOV H,A ANA C +MVI L,20 MOV L,B ANA D +CMA MOV L,C ANA E +JRNC 0134 MOV L,D ANA H +LXI SP,06A4 MOV L,E ANA L +STA 06A4 MOV L,H ANA M +INX SP MOV L,L ANA A +INR M MOV L,M XRA B +DCR M MOV L,A XRA C +MVI M,20 MOV M,B XRA D +STC MOV M,C XRA E +JRC 0134 MOV M,D XRA H +DAD SP MOV M,E XRA L + + +XRA M JPE 06A4 SLAR M +XRA A XCHG SLAR A +ORA B CPE 06A4 SRAR B +ORA C XRI 20 SRAR C +ORA D RST 5 SRAR D +ORA E RP SRAR E +ORA H POP PSW SRAR H +ORA L JP 06A4 SRAR L +ORA M DI SRAR M +ORA A CP 06A4 SRAR A +CMP B PUSH PSW SLLR B +CMP C ORI 20 SLLR C +CMP D RST 6 SLLR D +CMP E RM SLLR E +CMP H SPHL SLLR H +CMP L JM 06A4 SLLR L +CMP M EI SLLR M +CMP A CM 06A4 SLLR A +RNZ CPI 20 SRLR B +POP B RST 7 SRLR C +JNZ 06A4 RLCR B SRLR D +JMP 06A4 RLCR C SRLR E +CNZ 06A4 RLCR D SRLR H +PUSH B RLCR E SRLR L +ADI 20 RLCR H SRLR M +RST 0 RLCR L SRLR A +RZ RLCR M BIT 0,B +RET RLCR A BIT 0,C +JZ 06A4 RRCR B BIT 0,D +CZ 06A4 RRCR C BIT 0,E +CALL 06A4 RRCR D BIT 0,H +ACI 20 RRCR E BIT 0,L +RST 1 RRCR H BIT 0,M +RNC RRCR L BIT 0,A +POP D RRCR M BIT 1,B +JNC 06A4 RRCR A BIT 1,C +OUT 20 RALR B BIT 1,D +CNC 06A4 RALR C BIT 1,E +PUSH D RALR D BIT 1,H +SUI 20 RALR E BIT 1,L +RST 2 RALR H BIT 1,M +RC RALR L BIT 1,A +EXX RALR M BIT 2,B +JC 06A4 RALR A BIT 2,C +IN 20 RARR B BIT 2,D +CC 06A4 RARR C BIT 2,E +SBI 20 RARR D BIT 2,H +RST 3 RARR E BIT 2,L +RPO RARR H BIT 2,M +POP H RARR L BIT 2,A +JPO 06A4 RARR M BIT 3,B +XTHL RARR A BIT 3,C +CPO 06A4 SLAR B BIT 3,D +PUSH H SLAR C BIT 3,E +ANI 20 SLAR D BIT 3,H +RST 4 SLAR E BIT 3,L +RPE SLAR H BIT 3,M +PCHL SLAR L BIT 3,A + + +BIT 4,B RES 3,D SET 2,H +BIT 4,C RES 3,E SET 2,L +BIT 4,D RES 3,H SET 2,M +BIT 4,E RES 3,L SET 2,A +BIT 4,H RES 3,M SET 3,B +BIT 4,L RES 3,A SET 3,C +BIT 4,M RES 4,B SET 3,D +BIT 4,A RES 4,C SET 3,E +BIT 5,B RES 4,D SET 3,H +BIT 5,C RES 4,E SET 3,L +BIT 5,D RES 4,H SET 3,M +BIT 5,E RES 4,L SET 3,A +BIT 5,H RES 4,M SET 4,B +BIT 5,L RES 4,A SET 4,C +BIT 5,M RES 5,B SET 4,D +BIT 5,A RES 5,C SET 4,E +BIT 6,B RES 5,D SET 4,H +BIT 6,C RES 5,E SET 4,L +BIT 6,D RES 5,H SET 4,M +BIT 6,E RES 5,L SET 4,A +BIT 6,H RES 5,M SET 5,B +BIT 6,L RES 5,A SET 5,C +BIT 6,M RES 6,B SET 5,D +BIT 6,A RES 6,C SET 5,E +BIT 7,B RES 6,D SET 5,H +BIT 7,C RES 6,E SET 5,L +BIT 7,D RES 6,H SET 5,M +BIT 7,E RES 6,L SET 5,A +BIT 7,H RES 6,M SET 6,B +BIT 7,L RES 6,A SET 6,C +BIT 7,M RES 7,B SET 6,D +BIT 7,A RES 7,C SET 6,E +RES 0,B RES 7,D SET 6,H +RES 0,C RES 7,E SET 6,L +RES 0,D RES 7,H SET 6,M +RES 0,E RES 7,L SET 6,A +RES 0,H RES 7,M SET 7,B +RES 0,L RES 7,A SET 7,C +RES 0,M SET 0,B SET 7,D +RES 0,A SET 0,C SET 7,E +RES 1,B SET 0,D SET 7,H +RES 1,C SET 0,E SET 7,L +RES 1,D SET 0,H SET 7,M +RES 1,E SET 0,L SET 7,A +RES 1,H SET 0,M DADX B +RES 1,L SET 0,A DADX D +RES 1,M SET 1,B LXI X,06A4 +RES 1,A SET 1,C SIXD 06A4 +RES 2,B SET 1,D INX X +RES 2,C SET 1,E DADX X +RES 2,D SET 1,H LIXD 06A4 +RES 2,E SET 1,L DCX X +RES 2,H SET 1,M INR [X+05] +RES 2,L SET 1,A DCR [X+05] +RES 2,M SET 2,B MVI [X+05],20 +RES 2,A SET 2,C DADX SP +RES 3,B SET 2,D MOV B,[X+05] +RES 3,C SET 2,E MOV C,[X+05] + + +MOV D,[X+05] DSBC B DADY B +MOV E,[X+05] SBCD 06A4 DADY D +MOV H,[X+05] NEG LXI Y,06A4 +MOV L,[X+05] RETN SIYD 06A4 +MOV [X+05],B IM0 INX Y +MOV [X+05],C LDIA DADY Y +MOV [X+05],D INP C LIYD 06A4 +MOV [X+05],E OUTP C DCX Y +MOV [X+05],H DADC B INR [Y+05] +MOV [X+05],L LBCD 06A4 DCR [Y+05] +MOV [X+05],A RETI MVI [Y+05],2 +MOV A,[X+05] LDRA DADY SP +ADD [X+05] INP D MOV B,[Y+05] +ADC [X+05] OUTP D MOV C,[Y+05] +SUB [X+05] DSBC D MOV D,[Y+05] +SBB [X+05] SDED 06A4 MOV E,[Y+05] +ANA [X+05] IM1 MOV H,[Y+05] +XRA [X+05] LDAI MOV L,[Y+05] +ORA [X+05] INP E MOV [Y+05],B +CMP [X+05] OUTP E MOV [Y+05],C +POP X DADC D MOV [Y+05],D +XTIX LDED 06A4 MOV [Y+05],E +PUSH X IM2 MOV [Y+05],H +PCIX LDAR MOV [Y+05],L +SPIX INP H MOV [Y+05],A +RLCR [X+05] OUTP H MOV A,[Y+05] +RRCR [X+05] DSBC H ADD [Y+05] +RALR [X+05] shld 06A4 ADC [Y+05] +RARR [X+05] RRD SUB [Y+05] +SLAR [X+05] INP L SBB [Y+05] +SRAR [X+05] OUTP L ANA [Y+05] +SRLR [X+05] DADC H XRA [Y+05] +BIT 0,[X+05] lhld 06A4 ORA [Y+05] +BIT 1,[X+05] RLD CMP [Y+05] +BIT 2,[X+05] INP M POP Y +BIT 3,[X+05] OUTP M XTIY +BIT 4,[X+05] DSBC SP PUSH Y +BIT 5,[X+05] SSPD 06A4 PCIY +BIT 6,[X+05] INP A SPIY +BIT 7,[X+05] OUTP A RLCR [Y+05] +RES 0,[X+05] DADC SP RRCR [Y+05] +RES 1,[X+05] LSPD 06A4 RALR [Y+05] +RES 2,[X+05] LDI RARR [Y+05] +RES 3,[X+05] CCI SLAR [Y+05] +RES 4,[X+05] INI SRAR [Y+05] +RES 5,[X+05] OTI SRLR [Y+05] +RES 6,[X+05] LDD BIT 0,[Y+05] +RES 7,[X+05] CCD BIT 1,[Y+05] +SET 0,[X+05] IND BIT 2,[Y+05] +SET 1,[X+05] OTD BIT 3,[Y+05] +SET 2,[X+05] LDIR BIT 4,[Y+05] +SET 3,[X+05] CCIR BIT 5,[Y+05] +SET 4,[X+05] INIR BIT 6,[Y+05] +SET 5,[X+05] OTIR BIT 7,[Y+05] +SET 6,[X+05] LDDR RES 0,[Y+05] +SET 7,[X+05] CCDR RES 1,[Y+05] +INP B INDR RES 2,[Y+05] +OUTP B OTDR RES 3,[Y+05] + + +RES 4,[Y+05] SET 0,[Y+05] SET 4,[Y+05] +RES 5,[Y+05] SET 1,[Y+05] SET 5,[Y+05] +RES 6,[Y+05] SET 2,[Y+05] SET 6,[Y+05] +RES 7,[Y+05] SET 3,[Y+05] SET 7,[Y+05] + +; These are the result of disassembling 64180OPS.TRY +; These opcodes are available ONLY on the 64180 CPU +; DDTZ will both assemble and disassemble these. +IN0 B,20 TST E MLT B +OUT0 20,B IN0 H,20 MLT D +TST B OUT0 20,H TSTI 20 +IN0 C,20 TST H MLT H +OUT0 20,C IN0 L,20 TSIO 20 +TST C OUT0 20,L SLP +IN0 D,20 TST L MLT SP +OUT0 20,D TST M OTIM +TST D IN0 A,20 OTDM +IN0 E,20 OUT0 20,A OIMR +OUT0 20,E TST A ODMR + +; The following are UNDOCUMENTED z80 opcodes from XTDOPS.TRY. +; DDTZ will disassemble these, but will not assemble them. +; They use xh/xl (or yh/yl) as separate byte registers. +; Use these at your own risk. +INRX H ACXR H MOVY H,B +DCRX H ACXR L MOVY H,C +MVIX H,20 SUXR H MOVY H,D +INRX L SUXR L MOVY H,E +DCRX L SBXR H MOVY H,A +MVIX L,20 SBXR L MOVY L,B +MOVX B,H NDXR H MOVY L,C +MOVX B,L NDXR L MOVY L,D +MOVX C,H XRXR H MOVY L,E +MOVX C,L XRXR L MOVY L,A +MOVX D,H ORXR H MOVY A,H +MOVX D,L ORXR L MOVY A,L +MOVX E,H CPXR H ADYR H +MOVX E,L CPXR L ADYR L +MOVX H,B INRY H ACYR H +MOVX H,C DCRY H ACYR L +MOVX H,D MVIY H,20 SUYR H +MOVX H,E INRY L SUYR L +MOVX H,A DCRY L SBYR H +MOVX L,B MVIY L,20 SBYR L +MOVX L,C MOVY B,H NDYR H +MOVX L,D MOVY B,L NDYR L +MOVX L,E MOVY C,H XRYR H +MOVX L,A MOVY C,L XRYR L +MOVX A,H MOVY D,H ORYR H +MOVX A,L MOVY D,L ORYR L +ADXR H MOVY E,H CPYR H +ADXR L MOVY E,L CPYR L + + +Command Summary: +=============== + +DDTZM command DDTZ command +============= ============ +@ (base) +A)ssemble first_address A +B)egin {i.e., initialize stack and return} B +C)ompare first_address,last_address,against_address C +D)ump first_address[,last_address[,base]] D +E)nter_in_memory first_address[,base] S)ubstitute +F)ill first_address,last_address,value F +G)o_to [address][,trap1[,trap2]] G +H)ex_arithmetic value1(,value2) H +L)oad_file (offset) R)ead +M)ove first_address,last_address,destination M +N)nput FCBs_command_line I)nput +Q)uit (not avail) +R)egister examine/change [register|flag] X)amine +S)earch first_address,last_address,word W)hereis +T)race_execution [count] T + Untrace_execution [count] (i.e. do count instr) U)ntrace +U)nassemble_code first_address[,last_address] L)ist code +W)rite [first_address,last_address] K)eep +X)amine {i.e. display memory parameters for application} Q)uery +Y)our_option BC:=parm1,DE:=parm2,call_address Y +Z)80_register_display Z + + +If you find this program useful, contributions will be gratefully +accepted and will encourage further development and release of +useful CPM programs. My practice is to include source. + +C.B. Falconer +680 Hartford Turnpike, +Hamden, Conn. 06517 (203) 281-1438 + +DDTZ and its associated documentation and other files are +copyright (c) 1980-1988 by C.B. Falconer. They may be freely +copied and used for non-commercial purposes ONLY. + diff --git a/trunk/RomDsk/CPM_1024KB/DIF.COM b/trunk/RomDsk/CPM_1024KB/DIF.COM new file mode 100644 index 00000000..87b89d75 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/DIF.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/DIRX.COM b/trunk/RomDsk/CPM_1024KB/DIRX.COM new file mode 100644 index 00000000..413bceca Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/DIRX.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/DUMP.COM b/trunk/RomDsk/CPM_1024KB/DUMP.COM new file mode 100644 index 00000000..03a77c3c Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/DUMP.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/ED.COM b/trunk/RomDsk/CPM_1024KB/ED.COM new file mode 100644 index 00000000..a0f0f541 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/ED.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/FLASH.MAN b/trunk/RomDsk/CPM_1024KB/FLASH.MAN new file mode 100644 index 00000000..e57de5c2 --- /dev/null +++ b/trunk/RomDsk/CPM_1024KB/FLASH.MAN @@ -0,0 +1,35 @@ +NAME + flash - in-situ 29F040 flash ROM programmer for N8VEM, Zeta and N8 computers +SYNOPSIS + flashz + flashn8 +DESCRIPTION + The flashz and flashn8 erase and program the FLASH ROM chip from an + image file. flashz is used for the N8VEM Z80-SBC and Zeta computers. + flashn8 is used with the N8 home computer. Both function the same + except in the way memory is addressed. + + flash expects a 512k file in the same directory containing the image + that will be programmed into the ROM. This file must have the + unimaginative filename of ROM.IMG. The whole process of erasing and + programming the ROM takes less than a minute - far less than the time + taken to upload your new image. + + This program is only suitable for 29F040 512k FLASH ROMs. + + Assemble with TASM using the command + tasm -t80 -g3 flashz.asm flashz.com + tasm -t80 -g3 flashn8.asm flashn8.com + +JUMPERS + The following jumpers must be in place on the boards to allow the + 29F040 to be programmed. + For the N8VEM Z8-SBC MK-II: K1 1-2, K6 2-3, K8 2-3 + For the N8: K3 1-2, K4 2-3, K5 2-3 + For the Zeta, no jumpers need (or can) be set. + +AUTHOR + Written by David Giles so he doesn't have to open the box his Zeta + lives in so often. Reports to N8VEM group or vk5dg@internode.on.net + + diff --git a/trunk/RomDsk/CPM_1024KB/LBREXT.COM b/trunk/RomDsk/CPM_1024KB/LBREXT.COM new file mode 100644 index 00000000..c0c950e3 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/LBREXT.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/LIB.COM b/trunk/RomDsk/CPM_1024KB/LIB.COM new file mode 100644 index 00000000..45d7fb21 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/LIB.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/LINK.COM b/trunk/RomDsk/CPM_1024KB/LINK.COM new file mode 100644 index 00000000..e188fb92 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/LINK.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/LOAD.COM b/trunk/RomDsk/CPM_1024KB/LOAD.COM new file mode 100644 index 00000000..b9601e00 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/LOAD.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/MAC.COM b/trunk/RomDsk/CPM_1024KB/MAC.COM new file mode 100644 index 00000000..f49e835a Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/MAC.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/MBASIC.COM b/trunk/RomDsk/CPM_1024KB/MBASIC.COM new file mode 100644 index 00000000..c9ec3cd3 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/MBASIC.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/NULU.COM b/trunk/RomDsk/CPM_1024KB/NULU.COM new file mode 100644 index 00000000..fc5594b1 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/NULU.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/PIP.COM b/trunk/RomDsk/CPM_1024KB/PIP.COM new file mode 100644 index 00000000..4b2ce4b6 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/PIP.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/RMAC.COM b/trunk/RomDsk/CPM_1024KB/RMAC.COM new file mode 100644 index 00000000..9ab7206b Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/RMAC.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/SID.COM b/trunk/RomDsk/CPM_1024KB/SID.COM new file mode 100644 index 00000000..3b073ba5 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/SID.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/STAT.COM b/trunk/RomDsk/CPM_1024KB/STAT.COM new file mode 100644 index 00000000..1de359f2 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/STAT.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/SUBMIT.COM b/trunk/RomDsk/CPM_1024KB/SUBMIT.COM new file mode 100644 index 00000000..2e788827 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/SUBMIT.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/SUPERSUB.COM b/trunk/RomDsk/CPM_1024KB/SUPERSUB.COM new file mode 100644 index 00000000..a25d60a6 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/SUPERSUB.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/UNARC.COM b/trunk/RomDsk/CPM_1024KB/UNARC.COM new file mode 100644 index 00000000..8cc90746 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/UNARC.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/UNCR.COM b/trunk/RomDsk/CPM_1024KB/UNCR.COM new file mode 100644 index 00000000..42385ddd Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/UNCR.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/UNZIP.COM b/trunk/RomDsk/CPM_1024KB/UNZIP.COM new file mode 100644 index 00000000..afde7204 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/UNZIP.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/VIDATT.Z80 b/trunk/RomDsk/CPM_1024KB/VIDATT.Z80 new file mode 100644 index 00000000..073bb84f --- /dev/null +++ b/trunk/RomDsk/CPM_1024KB/VIDATT.Z80 @@ -0,0 +1,69 @@ + title WordStar 4.0 Video Attributes Driver + +strngout equ 0283h + +esc equ 1bh +dim equ 1 +blink equ 2 +invert equ 4 +uline equ 8 + + aseg + org 03c1h + +vidatt: + xor a + ld hl,funtbl + ld b,8 +getloop: + rr c + jr nc,getnext + or a,(hl) +getnext: + inc hl + djnz getloop +; + ld hl,string+2 ; attribute #1 on/off indicator + push hl + ld b,4 + ld de,'?!' ; ? = attribute off, ! = attribute on +setloop: + rra + jr nc,attroff + ld (hl),e ; attribute on + jr setnext +attroff: + ld (hl),d ; attribute off +setnext: + inc hl + inc hl + inc hl ; advance to next on/off indicator + djnz setloop +; + pop hl ; hl --> dim on/off + ld a,d ; attribute off + cp (hl) ; dim off? + jr nz,setdim + ld a,e ; attribute on +setdim: + ld (hl),a + ld hl,string + jp strngout ; ws string routine +; +; +funtbl: + defb dim ; strike out + defb invert or blink ; warnings & errors + defb invert ; block + defb uline ; underline + defb blink ; subscript + defb blink or uline ; superscript + defb invert ; menu, headline, bold, double + defb invert or uline ; italics, RET, backspace +; +string: + defb 12,esc,' 2',esc,' 3',esc,' 4',esc,' 5' +; +finis equ $ + end + \ No newline at end of file diff --git a/trunk/RomDsk/CPM_1024KB/WS.COM b/trunk/RomDsk/CPM_1024KB/WS.COM new file mode 100644 index 00000000..aa028bc3 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WS.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/WS.OVR b/trunk/RomDsk/CPM_1024KB/WS.OVR new file mode 100644 index 00000000..5e3c8773 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WS.OVR differ diff --git a/trunk/RomDsk/CPM_1024KB/WSCHANGE.COM b/trunk/RomDsk/CPM_1024KB/WSCHANGE.COM new file mode 100644 index 00000000..bc85c1fc Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WSCHANGE.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/WSCHANGE.OVR b/trunk/RomDsk/CPM_1024KB/WSCHANGE.OVR new file mode 100644 index 00000000..4f707c63 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WSCHANGE.OVR differ diff --git a/trunk/RomDsk/CPM_1024KB/WSCHHELP.OVR b/trunk/RomDsk/CPM_1024KB/WSCHHELP.OVR new file mode 100644 index 00000000..49becf77 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WSCHHELP.OVR differ diff --git a/trunk/RomDsk/CPM_1024KB/WSHELP.OVR b/trunk/RomDsk/CPM_1024KB/WSHELP.OVR new file mode 100644 index 00000000..02634675 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WSHELP.OVR differ diff --git a/trunk/RomDsk/CPM_1024KB/WSMSGS.OVR b/trunk/RomDsk/CPM_1024KB/WSMSGS.OVR new file mode 100644 index 00000000..84625d8e Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WSMSGS.OVR differ diff --git a/trunk/RomDsk/CPM_1024KB/WSPRINT.OVR b/trunk/RomDsk/CPM_1024KB/WSPRINT.OVR new file mode 100644 index 00000000..83bef6ea Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WSPRINT.OVR differ diff --git a/trunk/RomDsk/CPM_1024KB/WSREADME.TXT b/trunk/RomDsk/CPM_1024KB/WSREADME.TXT new file mode 100644 index 00000000..7a75b22c --- /dev/null +++ b/trunk/RomDsk/CPM_1024KB/WSREADME.TXT @@ -0,0 +1,880 @@ + --THE README FILE-- + ------------------------ + +README contains late-breaking news and tips about WordStar, +and information about printers. + + +THE DISKS THAT CAME IN YOUR PACKAGE +----------------------------------- + +The file HOMONYMS.TXT is included on the Speller disk +contrary to what is listed in Appendix D. + + +INSTALLATION +------------ + +WINSTALL and WSCHANGE + + WordStar has two installation programs: + + o WINSTALL contains the basic choices to install WordStar. + It is recommended for all users. + + Be sure and install your valid disk drives since WordStar + running under CP/M cannot recover from attempts to access non- + existent disk drives. + + o WSCHANGE contains every installation and customization + choice. It is designed for advanced users and users who + want to customize WordStar after they're familiar with it. + Use the menu listing below for a directory of the menus + in WSCHANGE. + +Directory of WSCHANGE Menus + + The chart below shows the organization of menus in WSCHANGE. + Print it out and refer to it as you customize WordStar. + + Main Installation Menu + + A Console + A Monitor + A Monitor selection + B Monitor name + C Screen sizing + B Function keys + C Monitor patches + A Special characters + B Cursor control + C Screen control + D Keyboard patches + A Function keys + B Save function keys + E Interface patches + A Console busy handshaking + B Special I/O subroutines + B Printer + A Printer choices + A Printer selection + B Printer name + C Default printer driver + B Printer driver library + A Select library file + B Create smaller library + C Add new printer driver + D Change printer driver data + C WS printer patches + A Custom print controls, printer initialization + + NOTE: Disregard the "CUSTOM & SIMPLE Controls Save CUSTOM/SIMPLE + Controls" option shown. This is not available from this menu. + + D Printing defaults + E Printer interface + A Printer port selection + B Printer busy handshaking + C Printer subroutines + C Computer + A Disk drives + A Valid disk drives + B Maximum valid user number + C Delay disk access if typing + B Operating system + A Single-user system + B Multi-user MP/M + C Multi-user Turbo DOS + D ZCPR3 + C Memory usage + D WordStar files + E Directory display + F Computer patches + D WordStar + A Page layout + A Page sizing & margins + B Headers & footers + C Tabs + B Editing settings + A Edit screen & help level + B Typing + C Paragraph alignment + D Blocks + E Erase & unerase + F Lines & characters + G Find & replace + H WordStar 3.3 compatibility + I Printing defaults + C Other features + A Spelling checks + B Nondocument mode + C Indexing + D Shorthand (key macros) + E Merge printing + F Miscellaneous + E Patching + A Auto patcher + B Save settings + C Reset all settings + +MEMORY USAGE +------------ + + WordStar requires a minimum TPA size of 50 kbytes to run + using the factory defaults. The TPA is the amount of memory + available in your computer for use by programs that have a + file type of COM. To see how big the TPA is in your computer, + press the question mark key (?) at the Opening Menu. + + The amount of memory required by WordStar can be reduced by + approximately 3 kbytes if necessary. Use the WSCHANGE program + to select the minimum memory configuration option. The menu + will show you what capabilities are being reduced. + + WordStar uses a general-purpose buffer for a variety of + tasks. WordStar allocates memory to this buffer for editing, + for merge printing, and at the Opening Menu (see BFSIZE in + PATCH.LST). The buffer used for editing is usually the most + sensitive to a reduced TPA size. (You may be able to use the + Opening Menu and print, but there may be insufficient memory + for editing.) + + The merge print buffer is used only to hold merge print + variable names and data. Increase it if you run out of memory + while merge printing. + + The Opening Menu buffer is used primarily to hold the file + directory, and for miscellaneous tasks. + + +LOW-MEMORY INDICATOR IN STATUS LINE +----------------------------------- + + If the Low-Memory indicator appears in the status line, it + means that WordStar was unable to complete some function. + The most common symptoms are: the line number in the + status line is wrong, or a paragraph alignment could not be + completed. You may correct the line counter by saving your + file, exiting WordStar, and re-loading your file. To correct + the paragraph alignment, move your cursor to the point where + paragraph alignment stopped, and then press ^B again. + + The reason this comes up is that WordStar was not able to fit + a big enough chunk of text into memory at one time. + + When you first begin editing, WordStar uses the value from + EDSIZE in the user area to determine the minimum amount + of memory required for a page of text. The default + is set for approximately a 55 line by 66 column page. If + your page size is routinely larger than this, you may want + to increase EDSIZE. Multiply the number of lines by the + number of columns, and divide by 128. + + If the Low-Memory indicator comes on while printing, it is due + to either the same reasons as for editing, or there is + insufficient memory to print the text proportionally spaced. + The amount of memory required depends on which printer + driver you are using. If you aren't using the .PS ON dot + command to turn proportional spacing on in your document, + low memory won't be a problem. Also, WordStar uses more + memory for merge printing than it does for regular printing + (around 2.5 kbytes more). + + The Low-Memory indicator will also appear when a full disk error + is encountered during editing. Treat the disk-full error as you + would normally. + + +RAM-RESIDENT PROGRAMS +--------------------- + + RAM-resident programs, such as SmartKey, reduce the amount of + working memory (TPA) that WordStar can use. The new features in + WordStar, such as shorthand, may reduce the need for these + RAM-resident programs, thus freeing memory for WordStar. + + +ZCPR3 SUPPORT +------------- + + In order to enable the ZCPR facilities within WordStar, the user + must use the Z3INS utility provided with ZCPR to install the + address of the ZCPR "environment" into WordStar. The environment + contains information that WordStar uses to support ZCPR-specific + functions. + + Generally, the user should log onto the drive containing the file + WS.COM, and issue the command: + + Z3INS SYS.ENV WS.COM + + The user should also run either WINSTALL or WSCHANGE to further + install WordStar for ZCPR. However, this is not mandatory because + the only thing that happens is that the WordStar sign-on says + "ZCPR3," and the LGLUSR location in the user area is changed for a + maximum user number of 31. (The normal default for LGLUSR is 15.) + + Once the user has installed WordStar for use with ZCPR, the user + will be able to use the following ZCPR features: + + - A named directory may be used when logging onto a new drive/user. + + - A named directory may be used instead of a drive/user as part + of any file name. + + - The drive/user always appears above file directories. (For CP/M + only the drive letter is shown if the user number is zero.) + + - The directory name also appears above the directory if one has + been defined for the currently logged drive/user. + + - If WordStar does not find its OVR files on the current drive and + user, it will search the drives and user numbers in the ZCPR + search path rather than using its standard search pattern. + + - WordStar installs itself as a ZCPR "shell" process which lets the + user enter any legal ZCPR command when running a program. (CP/M + can only run programs that are COM files.) + + +OSBORNE USERS +------------- + + The command to change a hard carriage return to a soft carriage + return (document mode) or to turn Auto-indent ON (nondocument + mode) does not function on the Osborne because of a limitation + in its BIOS. The following patch can be applied to change the + command from ^^ to ^- (Ctrl-Hyphen): + + Using DDT or SID in the file WSMSGS.OVR: + + At 02DA replace 1E with a 1D + At 02EF replace 1E with a 1D + At 0359 replace 1E with a 1D + At 06B2 replace 1E with a 1D + At 06C9 replace 1E with a 1D + + At the system prompt type SAVE 53 WSMSGS.OVR + + For more information on how to use SID or DDT, see your CP/M + reference guide. As always, be sure and apply the patch to a + COPY of the file. + + +INSTRUCTIONS FOR TWO FLOPPY DISK COMPUTERS +------------------------------------------ + + Do not remove the Program disk while you are using WordStar. + + The Printer Driver Library file (WSPRINT.OVR) on the WordStar + program disk is much smaller than the Printer Driver Library + file contained on the disk labeled PRINTER. Be sure to read the + section in "Starting" that discusses the printer library file. + + +RUN A PROGRAM +------------- + + Once you press R you can type the drive and user number for the + program you want to run. You may run only .COM files. CCP commands, + such as DIR cannot be used. + + +INDEXING +-------- + +Using StarIndex + + StarIndex 1.01 works with files created with this release of + WordStar. + +"Can't Use That Printer" Message + + When WordStar creates an index or table of contents, it uses + the printer drivers $INDEX and $TOC. If you created a smaller + WSPRINT.OVR file, you may have left these drivers out. To + return them to the file, copy the original WSPRINT.OVR file + onto your disk. When you create a smaller file again, be sure + to save these drivers. See Appendix C in the WordStar manual + for a list of other drivers to save. + + +SPELL CHECKING +-------------- + + Dual floppy disk users: + + Unless you have sufficient room on your working WordStar program + disk for the files TW.COM, SPELL.COM, MARKFIX.COM, REVIEW.COM and + MAINDICT.CMP you will not be able to run a spell check from the + Opening Menu. You will need to exit WordStar and replace the + working WordStar program disk with the dictionary disk you created + during installation. This disk should contain the files listed + above. Make sure the disk in drive B has the file you want to + spell-check. + + Follow the directions for running a spell check in The WORD Plus + manual. + + +UPGRADING FROM A PREVIOUS RELEASE +--------------------------------- + + This release of WordStar contains many new features and commands. + See the "What's New" booklet for a complete list. The following + changes came in too late to be included in the documentation. + +Printer Patches + + Previous versions of WordStar treat most dot matrix printers + and other non-daisy wheel printers as a DRAFT printer with a + few patchable items. Because of this, many users have used + these patches to be able to use certain features of their + printers. Sometimes the patches have been quite extensive, and + some users have many files that count on them. + + The printer drivers of WordStar Release 4, on the other hand, + are very powerful. Almost every driver recognizes all the print + controls and all the dot commands. In fact, if a document is + written to be printed on one kind of printer, it is likely that + it will also print fine on some other printer. + + However, if you want to use your existing files with WordStar + 4, and those files rely on the user area being patched in a + special way, you can probably do so by moving the patches into + WordStar 4, and using the CUSTOM or SIMPLE printer driver. + + On the INSTALL disk is a program called MOVEPRN.COM that + copies the printer driver portion of the previous release's + user area into files that can be installed into Release 4 with + the "auto patcher" feature. + + Copy the program MOVEPRN.COM onto the disk containing the + WS.COM file for the previous version. Type + + MOVEPRN WS.COM FILE1.PAT FILE2.PAT + + MOVEPRN extracts the proper portions of the user area and + writes them into two files that may then be used with the "auto + patcher" feature of WSCHANGE. + + FILE1.PAT is to be used with the general patching menu + (Choose E "Patching" on the WSCHANGE Main Menu, then A "Auto + Patcher"). FILE2.PAT should be used to install strings first + into the SIMPLE driver, and then into the CUSTOM driver (choose + B "Printer" on the WSCHANGE Main Menu, then B "Printer driver + library", D "Change printer driver data" and D "Driver auto + patcher"). + + Test print your document first with the SIMPLE driver, and then + with the CUSTOM driver to see which one produces the most + satisfactory results. + + Also read Appendix C for more information on using the Auto + Patcher. + + +Hanging Indents + + For WordStar Professional Release 4, MailMerge reformats indented + text created with ^OG to the current margins. If you want the text + to remain indented, use embedded ruler lines or the .RM, .LM, + and .PM commands. See the "Reference Guide" for more information. + + Pressing ^OG to wrap back to the first tab on the ruler line after + having reached the last tab works the same way it did in previous + versions of WordStar, contrary to what is stated in the manual. + + +TERMINALS +--------- + + WordStar comes installed for an "idealized" special terminal. + WINSTALL and WSCHANGE allow you to install many terminals by + name, thus allowing WordStar to take advantage of the special + features that the terminal might support, such as underlining + or the function keys. + + Use either WINSTALL or WSCHANGE to pick your specific terminal + or computer screen from the Monitor menu. If your terminal + isn't on the menu, it probably emulates one of those that is + there. Look in your terminal documentation to find out. + + After you install WordStar for the proper terminal, run + WordStar and open the file PRINT.TST to see which attributes + (such as bold and underline) work on your screen. + WordStar will highlight the following in some way... + + Bold (^PB) + Underline (^PS) + Strike-out (^PX) + Subscript (^PV) + Superscript (^PT) + Doublestrike (^PD) + Italics (^PY) + Blocks (^KB, ^KK) + Error messages + + Most of the time, normal text will be shown in dim intensity, + and highlighted text will be shown in bright intensity. You + may have to use a brightness and/or contrast knob to adjust + your screen the first time you use WordStar this way. + + If your dim intensity is too dim to see well, and you can't + adjust it, you can change the BRITE flag to ON using WSCHANGE. + This will invert bright and dim in your text, so that regular + text is displayed bright, and highlighted text will be + displayed as dim. However, text in the menus is not affected. + + +DISPLAY PROBLEMS WITH TERMINALS +------------------------------- + + Once you have installed WordStar for the proper terminal, you + may still experience display problems. + + If text from the previous screen remains after WordStar + displays a new screenful of text, the most likely cause is + cursor wrap. Basically, WordStar must know what happens to the + cursor when a character is displayed at the rightmost position + of the screen. It can either remain at the right edge, or it + can wrap to the beginning of the next line. The WRAP flag in + WordStar must be set either on or off to correspond to the + way the terminal works. (It is generally set for the + terminal's factory default, but the default can usually be + changed using the terminal's setup mode.) + + Another possible cause for display problems is your terminal's + incomplete emulation of some other terminal. The most + common differences are... + + Line insert (LININS), line delete (LINDEL), + Erase to end of screen (ERAEOS), + Erase to end of line (ERAEOL), + And, erase screen (ERASCR). + + Look in the manual for your terminal and use WSCHANGE to see + if the control sequences match. + + +PRINTERS +-------- + +WHAT'S IN THIS SECTION + + This section contains the following information: + + Choosing a Printer + Setting Up Your Printer + Printer Drivers + Proportional Printing + Laser Printers + Information on Specific Printers + +CHOOSING A PRINTER + + WordStar is ready to work with over 100 printers. The printer you + choose during installation becomes your default printer. However, + when you print a document, you can choose any other printer. To + choose a default printer, follow these steps: + + 1. Look at the Printer Information brochure that came in your + package. The first chart shows the printers listed on the + Printer Selection Menus. If your printer is on the menu, + simply choose it during installation. + + 2. If your printer isn't listed on the menu, it may work like a + printer that is. Refer to the second chart in the Printer + Information brochure for a list of printers that work like + printers on the menu. When WordStar asks you to choose a + printer, choose the printer that works like yours. + + 3. If neither chart lists your printer, choose Typewriter Printer + (if your printer can backspace) or Draft Printer (if it can't). + These choices may not take advantage of all your printer's + features, but they will work with almost any printer. + + Note: If you choose Draft or Typewriter, you can modify custom + print controls and printer initialization. + + If you want to make more modifications to take advantage of your + printer's feature, choose the Custom or Simple drivers, then use + the WS Printer Patches section of WSCHANGE to tell WordStar the + codes for your printer. Refer to your printer manual for these + codes. Some printers work better with the Custom driver and some + with the Simple driver. Try using both and see which works better + with your printer. See the "Reference Guide" for more information. + +SETTING UP YOUR PRINTER + +Choosing a Printer Port + + Each printer is connected to a printer port at the back of + the computer. WordStar looks for printers on the LST: port. + If your printer is connected to a different port, use + WSCHANGE to tell WordStar the correct port. + +Testing Your Printer Connection + + At the operating system prompt, type "PIP LST:=READ.ME." This + file should be printed by your printer. If it is not, your printer + may be connected to a different port. See your computer reference + manual, and the section on the STAT command in your CP/M + reference manual for more information. + + +PRINTER DRIVERS + + The WSPRINT.OVR file on the Printers disk contains a printer + driver for each printer on the Printer Selection Menu. The printer + driver for a printer contains all the codes WordStar needs to work + with that printer. + + Each printer driver has a short name. If you choose a printer when + you print a document, you see the names of the printer drivers, not + the names of the printers. + +PROPORTIONAL PRINTING + + WordStar supports proportional printing on a number of printers. + To turn on proportional printing, either install WordStar to + default to proportional printing, or place a ".PS on" command + in your document. At print time, WordStar selects the + appropriate proportional font based on the character width + (.CW) currently in effect. + + The specific printer descriptions later in this section show + recommended character widths for proportional typefaces. + These widths are for a normal mix of upper- and lowercase + letters. If you have many words or phrases all in uppercase + or if you want your text less densely printed, choose a larger + character width. + + While WordStar mostly sets character widths based on the + proportional-width table in the driver, on the more advanced + daisy wheel printers, WordStar uses the printer's proportional- + spacing mode. WordStar determines how much white space is needed + to right-justify the line based on its own proportional width + tables. If the table values don't match the wheel installed, + WordStar won't be able to justify the line correctly. + + WordStar sends standard ASCII characters; if a proportional wheel + uses a different spoke mapping, set up the printer to handle this. + +LASER PRINTERS + + WordStar supports laser printer features such as font changes + and proportional spacing. + + WordStar supports several laser printers: the Canon LPB-8 A1 & A2; + the Hewlett-Packard LaserJet, LaserJet+, and LaserJet 500+; + and the Ricoh LP4080. Refer to the "Specific Printer + Information" section of this file for information on these + printers. General notes about using laser printers are given below. + +Paper Size and Margins + + Laser printers come with preset page margins. You need to + compensate for these margins by changing page length in your + WordStar documents. The chart below shows the recommended + settings for 8 1/2 X 11 inch paper for both portrait and landscape + orientations. These settings allow 55 lines of text for portrait + orientation and 40 lines of text for landscape orientation (at 6 + lines per inch). They also allow for a footer of up to 3 lines + and a one-line header. If you use multiple-line headers, adjust + the top margin accordingly. + + Dot Default Portrait Landscape + Setting Command Value Orientation Orientation + ------- ------- ------- ----------- ----------- + page length .PL 66 62 47 + top margin .MT 3 2 2 + bottom margin .MB 8 5 5 + header margin .HM 2 1 1 + footer margin .FM 2 2 2 + + If the laser printer is your primary printer, you can use WSCHANGE + to make these settings the defaults. + + Because laser printers leave small margins at the left and right + sides of the page, you may want to use a smaller page offset + setting (the default is .PO 8). + +Form Feeds + + When you print with a laser printer, answer Y for yes to the "Use + form feeds (Y/N)?" prompt at print time. (The default is NO.) If + the laser printer is your primary printer, you can use WSCHANGE to + change the default to yes. + +WordStar Commands for Font Selection + + The WordStar dot commands and print control commands listed below + determine the fonts used for printing a document. + + .PR .PR OR=L selects landscape orientation; .PR OR=P (or just + .PR OR) selects portrait orientation (the default). If + either of these commands appears after the first printing + line on a page, the orientation will not change until the + following page. + + .PS .PS ON selects proportionally spaced characters; .PS OFF + (the default) selects fixed-spaced characters. + + .CW The character-width setting (.CW followed by the width in + 120ths of an inch) determines the character pitch and font + selected for fixed-width printing. For proportional fonts, it + determines the point size and proportional-width table + selected. + + .LQ .LQ ON selects near letter quality print (if supported by + your printer). LQ OFF selects draft quality print. Default + is ON. + + ^PY The italic print control toggles between normal and italic + characters when the appropriate italic font is available. + + ^PB The boldface print control toggles between normal and bold + characters when the appropriate bold font is available. + + ^PD The double strike print control used with the laser printers + toggles overprinting with a horizontal offset of 1/120" + between the two character images. This allows a bold effect + where no bold font is available. + + ^PA ^PA turns alternate pitch on. Use .CW to assign different + character widths to normal pitch (see ^PN below) and alternate + pitch so that each pitch accesses a different font. You can + then change fonts by switching between the two pitches. This + is the only way to use two fonts on the same line. + (See "Character width" and "Pitch" in the "Reference Guide.") + + ^PN ^PN turns normal pitch on. You can use it with ^PA as + described above. + + ^P@ When working with columns, if you use alternate and normal + pitch for two fonts, or if you use proportional spacing, you + may need to use ^P@ to make sure the columns line up. + Remember that the column position set with ^P@ is determined + by the normal pitch character width. (See "Columns" and + "Proportional spacing" in the "Reference Guide." + +INFORMATION ON SPECIFIC PRINTERS + + This section describes the capabilities of each printer listed on + the Printer Selection Menu. The printers are listed in alphabetical + order (except for the generic printers such as "Draft," + "Typewriter," "Custom," "Simple," and the various print-to-disk + options, which are listed first). + + There is a chart for each printer explaining how features work and + listing any special notes about the printer. Each printer is + described in the following format: + +PRINTER NAME ----- Driver: (short name) + + ^PY Effect of italics/ribbon color print control + ^PT/V Subscript/superscript information + .CW Information on available character widths and fonts. The + chart shows the .CW, .LQ, and .PS settings required to use + different fonts. + + .LQ OFF .LQ ON .PS ON Font Name + ------- ------ ------ --------- + .cw val .cw val recommended value (range) font 1 + .cw val .cw val recommended value (range) font 2 + + .UL Continuous-underline information (if restrictions) + .UJ Microspace-justification information (if restrictions) + + N/A means a command has no effect on this printer. + + NOTES Switch settings, special features, anomalies. + +DRAFT PRINTER (nonbackspacing) ----- Driver: DRAFT + + ^PD Overprints the line twice + ^PB Overprints the line three times + ^PS Overprints the underscore character in a separate pass + ^PT/V Prints super/subscripts with a full line between + super/subscript and text + .LH Sets line height only in multiples of full lines + .CW N/A + .PS N/A + .LQ N/A + .UJ N/A + + NOTES This driver works with any printer that doesn't automatically + perform a line feed when it receives a carriage return command. All + overprinting is done by returning the carriage and passing over the + line again. + +TYPEWRITER PRINTER (backspacing) ----- Driver: TYPEWR + + ^PD Backspaces and overprints each character twice + ^PB Backspaces and overprints each character three times + ^PS Backspaces and overprints the underscore character + ^PT/V Prints super/subscripts with a full line between + super/subscript and text + .LH Sets line height only in multiples of full lines + .CW N/A + .PS N/A + .LQ N/A + .UJ N/A + + NOTES This driver works with any printer that doesn't automatically + perform a line feed when a it receives a carriage return command, + and responds to a backspace character. Overprinting is done by + backspacing. + +AUTO LINE FEED PRINTER (backspacing) ----- Driver: AUTOLF + + ^PD Backspaces and overprints each character twice + ^PB Backspaces and overprints each character three times + ^PS Backspaces and overprints the underscore character + ^PT/V Prints super/subscripts with a full line between + super/subscript and text + .LH Sets line height only in multiples of full lines + .CW N/A + .PS N/A + .LQ N/A + .UJ N/A + + NOTES This driver works with any printer that automatically + performs a line feed when it receives a carriage return character, + and responds to a backspace command. Overprinting is done by + backspacing. + +SIMPLE CUSTOMIZABLE PRINTERS ----- Driver: SIMPLE + + All print controls cause control strings (on and off) in + the user area to be sent to the printer. These strings + are used by both the SIMPLE and CUSTOM drivers. They can + be installed with the WSCHANGE program. + + .LQ Controlled by user area strings + .PS Controlled by user area strings + .CW N/A + .UJ N/A + .LH N/A + + NOTES This printer driver prints the line in one pass, sending + control strings from the user area to select print enhancements. + +CUSTOMIZABLE PRINTERS ----- Driver: CUSTOM + + All print controls cause control strings (on and off) in + the user area to be sent to the printer. These strings + are used by both the SIMPLE and CUSTOM drivers. They can + be installed with the WSCHANGE program. + + .LQ ON/OFF controlled by user area strings + .PS ON/OFF controlled by user area strings + .LH Sets line height only in multiples of full lines + .UJ N/A + .CW N/A + + NOTES This driver prints the line in multiple passes, sending + control strings from the user area to select print enhancements. + +PREVIEW TO DISK ----- Driver: PRVIEW + + This driver prints documents to the PREVIEW.WS file to allow + you to preview the format and appearance of a document before + printing. Headers, footers, and pagination are shown correctly + and print controls remain in the file to display onscreen + attributes. Dot commands are not printed. + +PRINT TO DISK WITHOUT PRINT CONTROLS ----- Driver: ASCII + + This driver prints to the ASCII.WS file, stripping headers and + footers, high bits, and print controls. + +PRINT TO DISK WITHOUT HEADERS AND FOOTERS ----- Driver: XTRACT + + This driver prints to the XTRACT.WS disk file, stripping headers + and footers, but preserving high bits and print controls. + +ANADEX 9500A, 9500B ----- Driver: 9500 + + ^PY N/A + ^PT/V Even superscript roll + + .CW .CW Font name + --- --------- + 9 13.3 cpi + 10 12 cpi + 12 10 cpi + 18 6.7 cpi + 20 6 cpi + 24 5 cpi + + .LH 1/24" resolution, use even values + .UJ This printer has no incremental horizontal positioning + .PS N/A + .LQ N/A + +ANADEX 9501B, INTEQ 5100B ----- Driver: 9501B + + ^PY N/A + ^PT/V Even superscript roll + + .CW .CW Font name + --- --------- + 7 16.7 cpi + 8 15 cpi + 10 12.5 cpi + 12 10 cpi + 14 8.3 cpi + 16 7.5 cpi + 20 6.2 cpi + 24 5 cpi + + .LH 1/24" resolution, use even values + .UJ This printer has no incremental horizontal positioning + .PS N/A + .LQ N/A + +C. ITOH STARWRITER 1550 AND 8510 ----- Driver: C1550 + + ^PY N/A + ^PT/V Prints full-size characters with roll + + .CW .CW Font Name + --- --------- + 7 compressed + 10 elite + 12 pica + 14 expanded compressed + 20 expanded elite + 24 expanded pica + + .LQ N/A + .PS N/A + .UL Continuous underlining suppresses microspace justification + +C. ITOH F10 STARWRITER ----- Driver: QUME + + See Diablo 630, 1610, 1620 Daisy Wheel. + + Note: Proportional printing was tested with a Theme 10 wheel. + +CANON LBP-8A1 AND LBP-8A2 LASER PRINTER ----- Driver: LBP8 + + ^PY Selects italics if appropriate font installed + ^PT/V Prints full-size characters with roll + .PS .PS + .CW OFF ON Font Name + --- -- --------- + 6 - 20 cpi + 8 - 15 cpi + 9 - 13.3 cpi + 10 - 12 cpi (elite) + 12 - 10 cpi + 20 - 6 cpi + 24 - 5 cpi + 16 - 7.5 cpi + - 7 (0-8) Garland 8 point + - 10 (9-11) Garland 12 point + - 14 (12-17) Expanded 8 point + - 20 (18-30) Expand \ No newline at end of file diff --git a/trunk/RomDsk/CPM_1024KB/WSSHORT.OVR b/trunk/RomDsk/CPM_1024KB/WSSHORT.OVR new file mode 100644 index 00000000..b44f1480 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WSSHORT.OVR differ diff --git a/trunk/RomDsk/CPM_1024KB/WSU.COM b/trunk/RomDsk/CPM_1024KB/WSU.COM new file mode 100644 index 00000000..39830fdf Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/WSU.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/XSUB.COM b/trunk/RomDsk/CPM_1024KB/XSUB.COM new file mode 100644 index 00000000..15e86abf Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/XSUB.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/ZAP.COM b/trunk/RomDsk/CPM_1024KB/ZAP.COM new file mode 100644 index 00000000..47ffcbb8 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/ZAP.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/ZDE.COM b/trunk/RomDsk/CPM_1024KB/ZDE.COM new file mode 100644 index 00000000..8814a523 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/ZDE.COM differ diff --git a/trunk/RomDsk/CPM_1024KB/ZDENST.COM b/trunk/RomDsk/CPM_1024KB/ZDENST.COM new file mode 100644 index 00000000..8ccc9767 Binary files /dev/null and b/trunk/RomDsk/CPM_1024KB/ZDENST.COM differ diff --git a/trunk/RomDsk/CPM_512KB/ASM.COM b/trunk/RomDsk/CPM_512KB/ASM.COM new file mode 100644 index 00000000..a63e5aec Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/ASM.COM differ diff --git a/trunk/RomDsk/CPM_512KB/CLRDIR.COM b/trunk/RomDsk/CPM_512KB/CLRDIR.COM new file mode 100644 index 00000000..d1f2a7d6 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/CLRDIR.COM differ diff --git a/trunk/RomDsk/CPM_512KB/CR.COM b/trunk/RomDsk/CPM_512KB/CR.COM new file mode 100644 index 00000000..8a824bcc Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/CR.COM differ diff --git a/trunk/RomDsk/CPM_512KB/DDT.COM b/trunk/RomDsk/CPM_512KB/DDT.COM new file mode 100644 index 00000000..83f8603f Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/DDT.COM differ diff --git a/trunk/RomDsk/CPM_512KB/DDTZ.COM b/trunk/RomDsk/CPM_512KB/DDTZ.COM new file mode 100644 index 00000000..e30a34c0 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/DDTZ.COM differ diff --git a/trunk/RomDsk/CPM_512KB/DIF.COM b/trunk/RomDsk/CPM_512KB/DIF.COM new file mode 100644 index 00000000..87b89d75 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/DIF.COM differ diff --git a/trunk/RomDsk/CPM_512KB/DIRX.COM b/trunk/RomDsk/CPM_512KB/DIRX.COM new file mode 100644 index 00000000..413bceca Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/DIRX.COM differ diff --git a/trunk/RomDsk/CPM_512KB/DUMP.COM b/trunk/RomDsk/CPM_512KB/DUMP.COM new file mode 100644 index 00000000..03a77c3c Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/DUMP.COM differ diff --git a/trunk/RomDsk/CPM_512KB/ED.COM b/trunk/RomDsk/CPM_512KB/ED.COM new file mode 100644 index 00000000..a0f0f541 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/ED.COM differ diff --git a/trunk/RomDsk/CPM_512KB/FLASH.MAN b/trunk/RomDsk/CPM_512KB/FLASH.MAN new file mode 100644 index 00000000..e57de5c2 --- /dev/null +++ b/trunk/RomDsk/CPM_512KB/FLASH.MAN @@ -0,0 +1,35 @@ +NAME + flash - in-situ 29F040 flash ROM programmer for N8VEM, Zeta and N8 computers +SYNOPSIS + flashz + flashn8 +DESCRIPTION + The flashz and flashn8 erase and program the FLASH ROM chip from an + image file. flashz is used for the N8VEM Z80-SBC and Zeta computers. + flashn8 is used with the N8 home computer. Both function the same + except in the way memory is addressed. + + flash expects a 512k file in the same directory containing the image + that will be programmed into the ROM. This file must have the + unimaginative filename of ROM.IMG. The whole process of erasing and + programming the ROM takes less than a minute - far less than the time + taken to upload your new image. + + This program is only suitable for 29F040 512k FLASH ROMs. + + Assemble with TASM using the command + tasm -t80 -g3 flashz.asm flashz.com + tasm -t80 -g3 flashn8.asm flashn8.com + +JUMPERS + The following jumpers must be in place on the boards to allow the + 29F040 to be programmed. + For the N8VEM Z8-SBC MK-II: K1 1-2, K6 2-3, K8 2-3 + For the N8: K3 1-2, K4 2-3, K5 2-3 + For the Zeta, no jumpers need (or can) be set. + +AUTHOR + Written by David Giles so he doesn't have to open the box his Zeta + lives in so often. Reports to N8VEM group or vk5dg@internode.on.net + + diff --git a/trunk/RomDsk/CPM_512KB/LBREXT.COM b/trunk/RomDsk/CPM_512KB/LBREXT.COM new file mode 100644 index 00000000..c0c950e3 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/LBREXT.COM differ diff --git a/trunk/RomDsk/CPM_512KB/LIB.COM b/trunk/RomDsk/CPM_512KB/LIB.COM new file mode 100644 index 00000000..45d7fb21 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/LIB.COM differ diff --git a/trunk/RomDsk/CPM_512KB/LINK.COM b/trunk/RomDsk/CPM_512KB/LINK.COM new file mode 100644 index 00000000..e188fb92 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/LINK.COM differ diff --git a/trunk/RomDsk/CPM_512KB/LOAD.COM b/trunk/RomDsk/CPM_512KB/LOAD.COM new file mode 100644 index 00000000..b9601e00 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/LOAD.COM differ diff --git a/trunk/RomDsk/CPM_512KB/MBASIC.COM b/trunk/RomDsk/CPM_512KB/MBASIC.COM new file mode 100644 index 00000000..c9ec3cd3 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/MBASIC.COM differ diff --git a/trunk/RomDsk/CPM_512KB/NULU.COM b/trunk/RomDsk/CPM_512KB/NULU.COM new file mode 100644 index 00000000..fc5594b1 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/NULU.COM differ diff --git a/trunk/RomDsk/CPM_512KB/PIP.COM b/trunk/RomDsk/CPM_512KB/PIP.COM new file mode 100644 index 00000000..4b2ce4b6 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/PIP.COM differ diff --git a/trunk/RomDsk/CPM_512KB/RMAC.COM b/trunk/RomDsk/CPM_512KB/RMAC.COM new file mode 100644 index 00000000..9ab7206b Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/RMAC.COM differ diff --git a/trunk/RomDsk/CPM_512KB/SID.COM b/trunk/RomDsk/CPM_512KB/SID.COM new file mode 100644 index 00000000..3b073ba5 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/SID.COM differ diff --git a/trunk/RomDsk/CPM_512KB/STAT.COM b/trunk/RomDsk/CPM_512KB/STAT.COM new file mode 100644 index 00000000..1de359f2 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/STAT.COM differ diff --git a/trunk/RomDsk/CPM_512KB/SUBMIT.COM b/trunk/RomDsk/CPM_512KB/SUBMIT.COM new file mode 100644 index 00000000..2e788827 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/SUBMIT.COM differ diff --git a/trunk/RomDsk/CPM_512KB/SUPERSUB.COM b/trunk/RomDsk/CPM_512KB/SUPERSUB.COM new file mode 100644 index 00000000..a25d60a6 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/SUPERSUB.COM differ diff --git a/trunk/RomDsk/CPM_512KB/UNARC.COM b/trunk/RomDsk/CPM_512KB/UNARC.COM new file mode 100644 index 00000000..8cc90746 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/UNARC.COM differ diff --git a/trunk/RomDsk/CPM_512KB/UNCR.COM b/trunk/RomDsk/CPM_512KB/UNCR.COM new file mode 100644 index 00000000..42385ddd Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/UNCR.COM differ diff --git a/trunk/RomDsk/CPM_512KB/UNZIP.COM b/trunk/RomDsk/CPM_512KB/UNZIP.COM new file mode 100644 index 00000000..afde7204 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/UNZIP.COM differ diff --git a/trunk/RomDsk/CPM_512KB/XSUB.COM b/trunk/RomDsk/CPM_512KB/XSUB.COM new file mode 100644 index 00000000..15e86abf Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/XSUB.COM differ diff --git a/trunk/RomDsk/CPM_512KB/ZAP.COM b/trunk/RomDsk/CPM_512KB/ZAP.COM new file mode 100644 index 00000000..47ffcbb8 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/ZAP.COM differ diff --git a/trunk/RomDsk/CPM_512KB/ZDE.COM b/trunk/RomDsk/CPM_512KB/ZDE.COM new file mode 100644 index 00000000..8814a523 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/ZDE.COM differ diff --git a/trunk/RomDsk/CPM_512KB/ZDENST.COM b/trunk/RomDsk/CPM_512KB/ZDENST.COM new file mode 100644 index 00000000..8ccc9767 Binary files /dev/null and b/trunk/RomDsk/CPM_512KB/ZDENST.COM differ diff --git a/trunk/RomDsk/ReadMe.txt b/trunk/RomDsk/ReadMe.txt new file mode 100644 index 00000000..0a74378c --- /dev/null +++ b/trunk/RomDsk/ReadMe.txt @@ -0,0 +1,32 @@ +This is the parent directory for all files to +be included in the rom disk when the ROM is built. + +When constructing the ROM disk as part of a build, +the build process first grabs all of the "standard" +files for the size of ROM being built and the type +of the OS being used. So, if you are building a +ZSystem, 1MB ROM, all of the files in zsys_1024KB +will be pulled in. If you are building a CP/M +512KB ROM, then all the files in cpm_512KB will +be pulled in. + +After adding all of the standard files for the +size of ROM being built, the build process will +add the files from the appropriate configuration +directory. So, if you are building the "zeta" +configuration, all of the files in the cfg_zeta +directory will be added. + +Finally, the build process will gather all of the +custom applications created by Douglas in the +Apps directory and add those. + +If you are building your own ROM, you will need to +add a new directory of the name cfg_xxx where xxx +is the name of your configuration that matches the +config_xxx.asm file in the Source directory. You +will want to add any specific files you want added +to your ROM build to this directory. Note that the +build will complain if there are no files in your +custom configuration directory, but it is not a +real problem (error can be ignored). \ No newline at end of file diff --git a/trunk/RomDsk/ZSYS_1024KB/ASM.COM b/trunk/RomDsk/ZSYS_1024KB/ASM.COM new file mode 100644 index 00000000..a63e5aec Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ASM.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/CLOCKS.DAT b/trunk/RomDsk/ZSYS_1024KB/CLOCKS.DAT new file mode 100644 index 00000000..f44fa3c0 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/CLOCKS.DAT differ diff --git a/trunk/RomDsk/ZSYS_1024KB/CLRDIR.COM b/trunk/RomDsk/ZSYS_1024KB/CLRDIR.COM new file mode 100644 index 00000000..d1f2a7d6 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/CLRDIR.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/COPY.CFG b/trunk/RomDsk/ZSYS_1024KB/COPY.CFG new file mode 100644 index 00000000..3d5310ac Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/COPY.CFG differ diff --git a/trunk/RomDsk/ZSYS_1024KB/COPY.COM b/trunk/RomDsk/ZSYS_1024KB/COPY.COM new file mode 100644 index 00000000..87c0c2fb Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/COPY.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/COPY.UPD b/trunk/RomDsk/ZSYS_1024KB/COPY.UPD new file mode 100644 index 00000000..3725b0e8 --- /dev/null +++ b/trunk/RomDsk/ZSYS_1024KB/COPY.UPD @@ -0,0 +1,43 @@ + 11 Dec 88 + +Some changes have been made to COPY since the manual was written. +Comparison of dates with Existence testing ON has been changed to +use the Creation date when no Modified date exists, and print +"Undated" when neither exists, yet both source and destination +disks support file date stamping. Additionally, the /X option +has been re-defined, and a new /R option has been added to +Version 1.4. Please replace Paragraph 4.1.2.9 on page 55 of your +ZSDOS manual with the following two paragraphs describing the new +options. + + +4.1.2.9.1 ERASE SOURCE FILE AFTER COPY. + +When you want to "move" a file from one area to another, the "X" +option may be used. This option causes a file or group of files +to be copied in the manner described by the default or specified +options, but after the copy and optional verify, the source file +or files are erased. You will be notified that the file has been +erased by the status "(X)" being printed on your console. To +minimize the possibility of deleting a good file when errors +exist in the copy, the Verify option should always be active, +either by default, or specified. When Verify is active, any +errors detected will disable the "X" option for that file so that +a good source file will not be deleted. The "X" option has no +configurable value, and is always assumed to be "Off" requiring +the option in the command line list to be effective. + + +4.1.2.9.2 COPY ONLY FILES WHICH EXIST (REPLACE). + +Occasionally, you may wish to update selected files to a destina- +tion in a simpler manner than naming each file, or using the +Inspect option. The "R" (Replace) option, when active, tells +COPY to transfer only files which exist on the destination direc- +tory. If the Archive option (A) is added in conjunction with the +Replace option, only files which have not been archived, AND +already exist on the destination will be archived. It should be +noted that the No Replacement (N) option is incompatible with +both the Replace and Archive options, and is disabled when either +"R" or "A" are active. + \ No newline at end of file diff --git a/trunk/RomDsk/ZSYS_1024KB/CR.COM b/trunk/RomDsk/ZSYS_1024KB/CR.COM new file mode 100644 index 00000000..8a824bcc Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/CR.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/DATSWEEP.COM b/trunk/RomDsk/ZSYS_1024KB/DATSWEEP.COM new file mode 100644 index 00000000..5d298c0b Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/DATSWEEP.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/DDT.COM b/trunk/RomDsk/ZSYS_1024KB/DDT.COM new file mode 100644 index 00000000..83f8603f Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/DDT.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/DDTZ.COM b/trunk/RomDsk/ZSYS_1024KB/DDTZ.COM new file mode 100644 index 00000000..e30a34c0 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/DDTZ.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/DDTZ.DOC b/trunk/RomDsk/ZSYS_1024KB/DDTZ.DOC new file mode 100644 index 00000000..e4470528 --- /dev/null +++ b/trunk/RomDsk/ZSYS_1024KB/DDTZ.DOC @@ -0,0 +1,564 @@ + + DDTZ v2.7 + by C.B. Falconer + edited by George A. Havach + +Introduction: +============ +DDTZ v2.7 is a complete replacement for DDT, Digital Research's +famous Dynamic Debugging Tool, with improved functionality, bug +extermination, and full Z80 support. In general, DDTZ is fully +compatible with the original utility, but it has extra and +extended commands and many fewer quirks. All Z80-specific +instructions can be (dis)assembled, though in Intel rather then +Zilog format. Furthermore, DDTZ will correctly trace ('T' and 'U' +commands) both 8080 and Z80 instructions, depending on which CPU +is operating. On startup, the program announces which CPU it is +running on. + +DDTZ v2.7 now handles the 64180 added opcodes. It does NOT test +for a 64180 CPU, since this cannot be done without executing +illegal Z80 instructions, which in turn will crash some +simulators. However v2.7 does not execute any 64180 instructions +internally, only in the subject program. + +This issue supplies the "M" version assembled, to avoid errors +when switching between MSDOS and CPM systems. The command table +is updated accordingly. Most CPM users are also MSDOS users, but +not vice-versa. + +The program is invoked by typing + + ddtz +or + ddtz [d:]filespec + +In the second form, DDTZ will load the specified file into +memory starting at 0100H, unless it's a .HEX file that sets its +own load address. Besides reporting the NEXT free address and +the PC (program counter) after a successful load, DDTZ also shows +the number of memory pages needed for a SAVE. Instead of having +to write all this down, just use the 'X' command at any time to +redisplay these three values for the current application. + +NOTE: loading more code above the NEXT pointer revises these + values. + +As in DDT, when a program is loaded above the area holding the +'A' and 'U' (and now 'W') command code, these commands are +disabled, and the extra memory is released to the user. Thus, +DDTZ can occupy as little as 3K total memory space. Unlike DDT, +however, DDTZ will not overwrite itself or the system on program +loads (except .HEX files). + +At initialization, the stack pointer (SP) points to a return to +DDTZ, just like for the CCP. Thus, programs that normally return +to the CCP will be returned to DDTZ. The 'B' command +reinitializes this condition. + + +The intercept vector copies the BDOS version number, etc., so +an object program does not know that DDTZ is running (except +for BIOS-BDOS vector size). Thus, programs that check the version +number should execute correctly under DDTZ. + +All input parameters can now be entered in any of three formats: + + (1) hexadecimal (as in DDT), + (2) decimal, by adding a leading '#' character, + (3) ASCII, by enclosing between either single or double + quotes; either one or two characters are allowed. + +Leading blanks in command lines and parameters are absorbed. +Either a comma or a (single) space is a valid delimiter. +Either uppercase or lowercase input is accepted. + +The default command (for anything not otherwise recognizable) +is 'H'. This allows convenient calculation, along with the other +features described below. So, to convert a number, just enter +it! + +As in DDT, the prompt character is '-', and the only error +message is the query ('?'), which generally kicks you back to +command mode. + +New Commands (Over DDT): +======================= + +NOTE: letters in parenthesis, e.g. "(U)", show the equivalent + command for DDTZM version (compatible with MSDOS debug). + + @ Sets or shows (with no parameter) the internally stored + "base" value. Also used with the 'S' and 'D' commands as + an optional parameter (though without the '@') to display + memory from an arbitrary base marker (offset). When set to + zero (the default), it does not affect any screen displays. + + B B)egin: resets the USER stack pointer to its initial value, + such that any program that exits by an RET will return to + DDTZ. DDTZ provides a default stack space of + approximately 24 bytes for user programs. + + C C)ompare first_address,last_address,against_address: shows + all the byte differences between two memory areas, in the + format + + XXXX aa YYYY bb + + where XXXX and YYYY are the comparative memory addresses, + and aa and bb are the corresponding byte values. Can be + used to verify the identity of two files by first + loading them into different memory areas with the 'R' + command (see below). + + + W Write: stores the modified memory area to disk under the + (K) filename specified by the 'I' command, overwriting the + original file from which it was loaded (the user is queried + before doing so). By default, the image of memory from + 0100H through the "NEXT" value -1 is saved. "K first_addr, + last_address" overrides this and allows writing ANY memory + area to a file. Almost a necessity for CPM 3.0 (no SAVE!). + K)eep on DDTZ + + X eXamine: redisplays the "NEXT PC SAVE" report at any time. + (Q) Q)uery size on DDTZ. + + S S)earch first_address, last_addr, value: searches the + (W) specified memory area for the value (a 16-bit word, not a + byte) and shows the locations of all such. Very useful for + finding CALL's or JMP's to a particular address, etc. + W)here on DDTZ + + Y Y)our_option parm1,parm2,address: executes an arbitrary + routine at the specified address, with the BC and DE + registers set to parm1 and parm2, respectively. + + Z Displays (but does not alter) the Z80's alternate register + set, including the index registers (disabled if running on + an 8080). On Z80's, automatically included as the last + part of the display by the 'X' command. + + +Based (Offset) Displays: +======================= + +The 'D' and 'E' commands can use a stored base value (offset), +as set by the '@' command. The current @ value may be +overridden for a single execution of these commands by adding the +base as an extra parameter in the command line. The effect is +to add this value to the first/last address and display +accordingly. The address listing on the left becomes XXXX:YYYY, +where XXXX is the offset address and YYYY is the actual memory +address being displayed. For example, if you have a data area +located at 42B7H and wish to preserve easy access, just enter +"@42b7". Now, "d0,3f" will dump memory starting at 4237H. + + +Further Changes from DDT: +======================== + + A A)ssemble now accepts the full Z80 as well as 8080 + instruction set, although it expects them in Intel rather + than Zilog format (see notes below under the 'L' + command). When in doubt, see the mnemnonic list below. + + D D)isplay or D)ump will accept an optional third parameter + to set the base value for a single execution only. Format + has been cleaned up. + + H H)ex_arithmetic on two values also shows their + difference in decimal. With only one value, converts to + hexadecimal, decimal, and ASCII (low-order byte only). + + + N N)ame now allows drive specification (d:...) and sets up + (I) the complete command line, including both FCB's (at + addresses 005CH and 006CH). The tail (stored at 0081H up) + is NOT upshifted. + I)nput on DDTZ + + U U)nassemble now displays the raw hexcode, especially handy + (L) when examining non-code areas. Intel (8080 style) mnemonics + are used, so some disassembled instructions may look + strange. E.g., the Z80's 'IN B,(C)' and 'OUT (C),B' become + 'INP B' and 'OUTP B', respectively; 'LD (nnnn),BC' becomes + 'SBCD nnnn', 'ADD IX, BC' becomes 'DADX B', and 'JP (IX)' + becomes 'PCIX'. + L)ist on DDTZ + + L L)oad now permits loading a file into memory with an + (R) offset, which is added to the default load address of + 0100H. When reading in a .HEX file with a preset bias, + the 'R' command will not transfer control to an invalid + execution point. Another execution of the 'R' command will + reread the input file, e.g.: + + n blah + l + ...modify the code and generally mess about... + l + + The original file is reloaded, and the modifications are + removed. + R)ead on DDTZ + + E E)nter, like D)isplay, now accepts an optional second + (S) parameter to set the base value for a single execution + only. + S)ubstitute or S)et on DDTZ + + T T)rap/trace on termination now shows the complete CPU + state. Traps and traces no longer lock up when a user RST + 7 instruction is executed. Tracing of BDOS/BIOS calls is + heavily trun cated, avoiding clutter and preventing system + crashes. + +NOTE: Most of the UNDOCUMENTED Z80 op-codes are handled. Others + can crash the system. + + R R)egisters also shows what two-byte values the HL and SP + (X) registers are actually pointing to. On Z80's, displays the + alternate register set. + eX)amine on DDTZ + +NOTE: Any use of the 'W' or 'L' command resets the system DMA + transfer address to the standard default value of 0080H. + + +; This is the output of DDTZ when disassembling OPTYPE.TRY +NOP LDA 06A4 MOV M,H +LXI B,06A4 DCX SP MOV M,L +STAX B INR A HLT +INX B DCR A MOV M,A +INR B MVI A,20 MOV A,B +DCR B CMC MOV A,C +MVI B,20 MOV B,B MOV A,D +RLC MOV B,C MOV A,E +EXAF MOV B,D MOV A,H +DAD B MOV B,E MOV A,L +LDAX B MOV B,H MOV A,M +DCX B MOV B,L MOV A,A +INR C MOV B,M ADD B +DCR C MOV B,A ADD C +MVI C,20 MOV C,B ADD D +RRC MOV C,C ADD E +DJNZ 0134 MOV C,D ADD H +LXI D,06A4 MOV C,E ADD L +STAX D MOV C,H ADD M +INX D MOV C,L ADD A +INR D MOV C,M ADC B +DCR D MOV C,A ADC C +MVI D,20 MOV D,B ADC D +RAL MOV D,C ADC E +JR 0134 MOV D,D ADC H +DAD D MOV D,E ADC L +LDAX D MOV D,H ADC M +DCX D MOV D,L ADC A +INR E MOV D,M SUB B +DCR E MOV D,A SUB C +MVI E,20 MOV E,B SUB D +RAR MOV E,C SUB E +JRNZ 0134 MOV E,D SUB H +LXI H,06A4 MOV E,E SUB L +SHLD 06A4 MOV E,H SUB M +INX H MOV E,L SUB A +INR H MOV E,M SBB B +DCR H MOV E,A SBB C +MVI H,20 MOV H,B SBB D +DAA MOV H,C SBB E +JRZ 0134 MOV H,D SBB H +DAD H MOV H,E SBB L +LHLD 06A4 MOV H,H SBB M +DCX H MOV H,L SBB A +INR L MOV H,M ANA B +DCR L MOV H,A ANA C +MVI L,20 MOV L,B ANA D +CMA MOV L,C ANA E +JRNC 0134 MOV L,D ANA H +LXI SP,06A4 MOV L,E ANA L +STA 06A4 MOV L,H ANA M +INX SP MOV L,L ANA A +INR M MOV L,M XRA B +DCR M MOV L,A XRA C +MVI M,20 MOV M,B XRA D +STC MOV M,C XRA E +JRC 0134 MOV M,D XRA H +DAD SP MOV M,E XRA L + + +XRA M JPE 06A4 SLAR M +XRA A XCHG SLAR A +ORA B CPE 06A4 SRAR B +ORA C XRI 20 SRAR C +ORA D RST 5 SRAR D +ORA E RP SRAR E +ORA H POP PSW SRAR H +ORA L JP 06A4 SRAR L +ORA M DI SRAR M +ORA A CP 06A4 SRAR A +CMP B PUSH PSW SLLR B +CMP C ORI 20 SLLR C +CMP D RST 6 SLLR D +CMP E RM SLLR E +CMP H SPHL SLLR H +CMP L JM 06A4 SLLR L +CMP M EI SLLR M +CMP A CM 06A4 SLLR A +RNZ CPI 20 SRLR B +POP B RST 7 SRLR C +JNZ 06A4 RLCR B SRLR D +JMP 06A4 RLCR C SRLR E +CNZ 06A4 RLCR D SRLR H +PUSH B RLCR E SRLR L +ADI 20 RLCR H SRLR M +RST 0 RLCR L SRLR A +RZ RLCR M BIT 0,B +RET RLCR A BIT 0,C +JZ 06A4 RRCR B BIT 0,D +CZ 06A4 RRCR C BIT 0,E +CALL 06A4 RRCR D BIT 0,H +ACI 20 RRCR E BIT 0,L +RST 1 RRCR H BIT 0,M +RNC RRCR L BIT 0,A +POP D RRCR M BIT 1,B +JNC 06A4 RRCR A BIT 1,C +OUT 20 RALR B BIT 1,D +CNC 06A4 RALR C BIT 1,E +PUSH D RALR D BIT 1,H +SUI 20 RALR E BIT 1,L +RST 2 RALR H BIT 1,M +RC RALR L BIT 1,A +EXX RALR M BIT 2,B +JC 06A4 RALR A BIT 2,C +IN 20 RARR B BIT 2,D +CC 06A4 RARR C BIT 2,E +SBI 20 RARR D BIT 2,H +RST 3 RARR E BIT 2,L +RPO RARR H BIT 2,M +POP H RARR L BIT 2,A +JPO 06A4 RARR M BIT 3,B +XTHL RARR A BIT 3,C +CPO 06A4 SLAR B BIT 3,D +PUSH H SLAR C BIT 3,E +ANI 20 SLAR D BIT 3,H +RST 4 SLAR E BIT 3,L +RPE SLAR H BIT 3,M +PCHL SLAR L BIT 3,A + + +BIT 4,B RES 3,D SET 2,H +BIT 4,C RES 3,E SET 2,L +BIT 4,D RES 3,H SET 2,M +BIT 4,E RES 3,L SET 2,A +BIT 4,H RES 3,M SET 3,B +BIT 4,L RES 3,A SET 3,C +BIT 4,M RES 4,B SET 3,D +BIT 4,A RES 4,C SET 3,E +BIT 5,B RES 4,D SET 3,H +BIT 5,C RES 4,E SET 3,L +BIT 5,D RES 4,H SET 3,M +BIT 5,E RES 4,L SET 3,A +BIT 5,H RES 4,M SET 4,B +BIT 5,L RES 4,A SET 4,C +BIT 5,M RES 5,B SET 4,D +BIT 5,A RES 5,C SET 4,E +BIT 6,B RES 5,D SET 4,H +BIT 6,C RES 5,E SET 4,L +BIT 6,D RES 5,H SET 4,M +BIT 6,E RES 5,L SET 4,A +BIT 6,H RES 5,M SET 5,B +BIT 6,L RES 5,A SET 5,C +BIT 6,M RES 6,B SET 5,D +BIT 6,A RES 6,C SET 5,E +BIT 7,B RES 6,D SET 5,H +BIT 7,C RES 6,E SET 5,L +BIT 7,D RES 6,H SET 5,M +BIT 7,E RES 6,L SET 5,A +BIT 7,H RES 6,M SET 6,B +BIT 7,L RES 6,A SET 6,C +BIT 7,M RES 7,B SET 6,D +BIT 7,A RES 7,C SET 6,E +RES 0,B RES 7,D SET 6,H +RES 0,C RES 7,E SET 6,L +RES 0,D RES 7,H SET 6,M +RES 0,E RES 7,L SET 6,A +RES 0,H RES 7,M SET 7,B +RES 0,L RES 7,A SET 7,C +RES 0,M SET 0,B SET 7,D +RES 0,A SET 0,C SET 7,E +RES 1,B SET 0,D SET 7,H +RES 1,C SET 0,E SET 7,L +RES 1,D SET 0,H SET 7,M +RES 1,E SET 0,L SET 7,A +RES 1,H SET 0,M DADX B +RES 1,L SET 0,A DADX D +RES 1,M SET 1,B LXI X,06A4 +RES 1,A SET 1,C SIXD 06A4 +RES 2,B SET 1,D INX X +RES 2,C SET 1,E DADX X +RES 2,D SET 1,H LIXD 06A4 +RES 2,E SET 1,L DCX X +RES 2,H SET 1,M INR [X+05] +RES 2,L SET 1,A DCR [X+05] +RES 2,M SET 2,B MVI [X+05],20 +RES 2,A SET 2,C DADX SP +RES 3,B SET 2,D MOV B,[X+05] +RES 3,C SET 2,E MOV C,[X+05] + + +MOV D,[X+05] DSBC B DADY B +MOV E,[X+05] SBCD 06A4 DADY D +MOV H,[X+05] NEG LXI Y,06A4 +MOV L,[X+05] RETN SIYD 06A4 +MOV [X+05],B IM0 INX Y +MOV [X+05],C LDIA DADY Y +MOV [X+05],D INP C LIYD 06A4 +MOV [X+05],E OUTP C DCX Y +MOV [X+05],H DADC B INR [Y+05] +MOV [X+05],L LBCD 06A4 DCR [Y+05] +MOV [X+05],A RETI MVI [Y+05],2 +MOV A,[X+05] LDRA DADY SP +ADD [X+05] INP D MOV B,[Y+05] +ADC [X+05] OUTP D MOV C,[Y+05] +SUB [X+05] DSBC D MOV D,[Y+05] +SBB [X+05] SDED 06A4 MOV E,[Y+05] +ANA [X+05] IM1 MOV H,[Y+05] +XRA [X+05] LDAI MOV L,[Y+05] +ORA [X+05] INP E MOV [Y+05],B +CMP [X+05] OUTP E MOV [Y+05],C +POP X DADC D MOV [Y+05],D +XTIX LDED 06A4 MOV [Y+05],E +PUSH X IM2 MOV [Y+05],H +PCIX LDAR MOV [Y+05],L +SPIX INP H MOV [Y+05],A +RLCR [X+05] OUTP H MOV A,[Y+05] +RRCR [X+05] DSBC H ADD [Y+05] +RALR [X+05] shld 06A4 ADC [Y+05] +RARR [X+05] RRD SUB [Y+05] +SLAR [X+05] INP L SBB [Y+05] +SRAR [X+05] OUTP L ANA [Y+05] +SRLR [X+05] DADC H XRA [Y+05] +BIT 0,[X+05] lhld 06A4 ORA [Y+05] +BIT 1,[X+05] RLD CMP [Y+05] +BIT 2,[X+05] INP M POP Y +BIT 3,[X+05] OUTP M XTIY +BIT 4,[X+05] DSBC SP PUSH Y +BIT 5,[X+05] SSPD 06A4 PCIY +BIT 6,[X+05] INP A SPIY +BIT 7,[X+05] OUTP A RLCR [Y+05] +RES 0,[X+05] DADC SP RRCR [Y+05] +RES 1,[X+05] LSPD 06A4 RALR [Y+05] +RES 2,[X+05] LDI RARR [Y+05] +RES 3,[X+05] CCI SLAR [Y+05] +RES 4,[X+05] INI SRAR [Y+05] +RES 5,[X+05] OTI SRLR [Y+05] +RES 6,[X+05] LDD BIT 0,[Y+05] +RES 7,[X+05] CCD BIT 1,[Y+05] +SET 0,[X+05] IND BIT 2,[Y+05] +SET 1,[X+05] OTD BIT 3,[Y+05] +SET 2,[X+05] LDIR BIT 4,[Y+05] +SET 3,[X+05] CCIR BIT 5,[Y+05] +SET 4,[X+05] INIR BIT 6,[Y+05] +SET 5,[X+05] OTIR BIT 7,[Y+05] +SET 6,[X+05] LDDR RES 0,[Y+05] +SET 7,[X+05] CCDR RES 1,[Y+05] +INP B INDR RES 2,[Y+05] +OUTP B OTDR RES 3,[Y+05] + + +RES 4,[Y+05] SET 0,[Y+05] SET 4,[Y+05] +RES 5,[Y+05] SET 1,[Y+05] SET 5,[Y+05] +RES 6,[Y+05] SET 2,[Y+05] SET 6,[Y+05] +RES 7,[Y+05] SET 3,[Y+05] SET 7,[Y+05] + +; These are the result of disassembling 64180OPS.TRY +; These opcodes are available ONLY on the 64180 CPU +; DDTZ will both assemble and disassemble these. +IN0 B,20 TST E MLT B +OUT0 20,B IN0 H,20 MLT D +TST B OUT0 20,H TSTI 20 +IN0 C,20 TST H MLT H +OUT0 20,C IN0 L,20 TSIO 20 +TST C OUT0 20,L SLP +IN0 D,20 TST L MLT SP +OUT0 20,D TST M OTIM +TST D IN0 A,20 OTDM +IN0 E,20 OUT0 20,A OIMR +OUT0 20,E TST A ODMR + +; The following are UNDOCUMENTED z80 opcodes from XTDOPS.TRY. +; DDTZ will disassemble these, but will not assemble them. +; They use xh/xl (or yh/yl) as separate byte registers. +; Use these at your own risk. +INRX H ACXR H MOVY H,B +DCRX H ACXR L MOVY H,C +MVIX H,20 SUXR H MOVY H,D +INRX L SUXR L MOVY H,E +DCRX L SBXR H MOVY H,A +MVIX L,20 SBXR L MOVY L,B +MOVX B,H NDXR H MOVY L,C +MOVX B,L NDXR L MOVY L,D +MOVX C,H XRXR H MOVY L,E +MOVX C,L XRXR L MOVY L,A +MOVX D,H ORXR H MOVY A,H +MOVX D,L ORXR L MOVY A,L +MOVX E,H CPXR H ADYR H +MOVX E,L CPXR L ADYR L +MOVX H,B INRY H ACYR H +MOVX H,C DCRY H ACYR L +MOVX H,D MVIY H,20 SUYR H +MOVX H,E INRY L SUYR L +MOVX H,A DCRY L SBYR H +MOVX L,B MVIY L,20 SBYR L +MOVX L,C MOVY B,H NDYR H +MOVX L,D MOVY B,L NDYR L +MOVX L,E MOVY C,H XRYR H +MOVX L,A MOVY C,L XRYR L +MOVX A,H MOVY D,H ORYR H +MOVX A,L MOVY D,L ORYR L +ADXR H MOVY E,H CPYR H +ADXR L MOVY E,L CPYR L + + +Command Summary: +=============== + +DDTZM command DDTZ command +============= ============ +@ (base) +A)ssemble first_address A +B)egin {i.e., initialize stack and return} B +C)ompare first_address,last_address,against_address C +D)ump first_address[,last_address[,base]] D +E)nter_in_memory first_address[,base] S)ubstitute +F)ill first_address,last_address,value F +G)o_to [address][,trap1[,trap2]] G +H)ex_arithmetic value1(,value2) H +L)oad_file (offset) R)ead +M)ove first_address,last_address,destination M +N)nput FCBs_command_line I)nput +Q)uit (not avail) +R)egister examine/change [register|flag] X)amine +S)earch first_address,last_address,word W)hereis +T)race_execution [count] T + Untrace_execution [count] (i.e. do count instr) U)ntrace +U)nassemble_code first_address[,last_address] L)ist code +W)rite [first_address,last_address] K)eep +X)amine {i.e. display memory parameters for application} Q)uery +Y)our_option BC:=parm1,DE:=parm2,call_address Y +Z)80_register_display Z + + +If you find this program useful, contributions will be gratefully +accepted and will encourage further development and release of +useful CPM programs. My practice is to include source. + +C.B. Falconer +680 Hartford Turnpike, +Hamden, Conn. 06517 (203) 281-1438 + +DDTZ and its associated documentation and other files are +copyright (c) 1980-1988 by C.B. Falconer. They may be freely +copied and used for non-commercial purposes ONLY. + diff --git a/trunk/RomDsk/ZSYS_1024KB/DIF.COM b/trunk/RomDsk/ZSYS_1024KB/DIF.COM new file mode 100644 index 00000000..87b89d75 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/DIF.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/DSCONFIG.COM b/trunk/RomDsk/ZSYS_1024KB/DSCONFIG.COM new file mode 100644 index 00000000..b77dd008 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/DSCONFIG.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/DUMP.COM b/trunk/RomDsk/ZSYS_1024KB/DUMP.COM new file mode 100644 index 00000000..03a77c3c Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/DUMP.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ED.COM b/trunk/RomDsk/ZSYS_1024KB/ED.COM new file mode 100644 index 00000000..a0f0f541 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ED.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/FA16.CFG b/trunk/RomDsk/ZSYS_1024KB/FA16.CFG new file mode 100644 index 00000000..b7974d36 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/FA16.CFG differ diff --git a/trunk/RomDsk/ZSYS_1024KB/FA16.DOC b/trunk/RomDsk/ZSYS_1024KB/FA16.DOC new file mode 100644 index 00000000..08b46875 --- /dev/null +++ b/trunk/RomDsk/ZSYS_1024KB/FA16.DOC @@ -0,0 +1,264 @@ + + FILEATTR + Version 1.6 + + Gene Pizzetta + January 18, 1992 + A ZSDOS utility, copyright (c) 1988 by Carson Wilson. + + +FILEATTR (FA) is a utility that allows rapid settin, resetting, +or displaying of file attributes under ZSDOS, ZRDOS, and CP/M +2.2. Several additional features are available under ZCPR3, +including error flag setting, error handler invocation, an +enhanced display, and better error detection. + +FA will not run under CP/M 3.0 or Z3PLUS. + +USAGE: + + FILEATTR {dir:}{afn} {{/}options} + +If a DIR or DU specification is not given, the current directory +is assumed (under vanilla CP/M only the drive is significant). +If no ambiguous or unambiguous filename is given, all files +("*.*") are matched. + +If no attribute options are given, FILEATTR merely displays the +current state of each file's attributes. Files are displayed in +the order that they appear in the directory. + +Once operation begins, FA cannot be aborted by the user. If a ^C +is entered at the keyboard, all screen output stops, but file +attribute operations continue to completion. If that was not the +case, attributes might be set on some entries for a file and not +on others. Nevertheless, suppressing screen output speeds things +up a bit. + +OPTIONS: A leading slash is required unless the option list is +the second parameter on the command line. Options may be +separated by spaces, commas, or nothing at all. + +ATTRIBUTE OPTIONS: These options set (turn on) corresponding +attributes on files matching the file specification. Attributes +not specified by an attribute option remain unchanged. + +If the option is preceded by a minus ("-") or by an "N", the +corresponding attribute is reset (turned off). + + 1 F1. This is a user attribute which has no predefined + meaning. + + P Public (f2). Under ZSDOS, when this attribute is set, + a file is available from any user area of the disk on + which it resides. A file cannot be made public if + another file with the same name exists in any other + user area on that drive. In that case FA will issue an + error message and leave the attribute off. + + D Inhibit access datestamp (f3). Under ZSDOS, when this + attribute is set, the file's access datestamp will not + be updated, which may speed file access slightly. If + the attribute is turned off, normal access datestamping + resumes. + + 4 F4. This is a user attribute which has no predefined + meaning. + + W Wheel protect (f8). Under ZSDOS, when this attribute + is set, the file becomes read-only when the wheel byte + is off and cannot be erased. If the wheel byte is on, + the file can be erased normally. + + R Read only (t1). When this attribute is set, the file + cannot be erased or modified by most programs. + + S System (t2). When this attribute is set, the file + becomes a "hidden" file that will not be found by most + directory programs or by most well-behaved utilities + that accept ambiguous filenames. (FA must find system + files, of course.) + + A Archive (t3). When this attribute is set, it signals + some archival programs that the file has not been + modified since it was last backed up. If a file is + modified, ZSDOS and ZRDOS turn this attribute off. + CP/M does not fully support this attribute, however. + +OTHER OPTIONS: These options affect only the screen display. + + Q Quiet mode. Console output is suppressed unless there + is an error. All other operations are performed + normally. + + X Screen paging off. With this option, screen paging is + turned off. The screen can still be paused by pressing + any key except ^C. + +ERRORS: Under ZCPR3, errors will cause FA to set the program +error flag and to invoke the error handler. The error flag will +be set to the following values: + 2 invalid directory specification + 4 miscellaneous (conflicting file, no files on disk) + 10 no matching files found (no error handler) + 18 Disk read-only + 19 Invalid option + +For error code 10 (no matching files found), the error flag is +set, but the error handler is not called. + +In addition, under ZCPR 3.3 and above, an invalid directory +specification will abort FA to the error handler, but no message +is printed. + +The following error messages may be seen: + +Conflicting entry, can't set public attribute + If there are files with the same name in other user areas of + the disk, the public attribute cannot be set. + +No files on disk + The disk directory is empty. + +Bad Option: /o + The command line option shown is unknown to FILEATTR. + +Drive R/O + The drive is set to read-only by the operating system and + attributes cannot be changed. + +CP/M version 2.x required + FILEATTR will not run on this system. + +BIOS write error near directory sector n + An error occurred at or near the given directory sector, + which is expressed as a decimal offset from the beginning of + the directory. + +BIOS set track detected - FA aborting + A background program is attempting to modify the current + track setting. The background program must be removeed + before running FA again. + +Not Wheel + Under ZCPR3 the wheel byte must be set before FILEATTR can + be run. + +CONFIGURATION: While no installation is necessary, all options +can be set as defaults, if you prefer, using ZCNFG. The +configuration options are fully explained on the ZCNFG help +screens. + +It is best not to change the name of the configuration file. Its +special name assures that ZCNFG will always find the correct CFG +file, even if the name of FA has been changed or if more than one +version of FA is online. + +HISTORY: + +Version 1.6 -- April 14, 1991 -- Gene Pizzetta + Now displays target DU and directory name in summary. Fixed + bug that caused "GO" to be displayed as program name, if it + was re-invoked with the GO command. + +Version 1.5 -- March 27, 1991 -- Gene Pizzetta + Now calls CP/M version checking routine (it was there, but + it wasn't called). Changed error codes: 10, no matching + files found. "No files on disk" error now gets + miscellaneous error code (4). Error 10 does not invoke + error handler. Not released. + +Version 1.4 -- March 20, 1991 -- Gene Pizzetta, Howard Goldstein + Code to check module data byte (S2) was replaced by Howard + Goldstein's elegant solution which uses a "true" extent + number: ((data_mod * 32) + extent). Entering a ^C no + longer really aborts FILEATTR; instead FA immediately prints + "Wait..." on the screen, turns off paging, turns on quiet + mode, sets the results flag, and finishes what it was doing. + All this is to prevent unexpected results when only some of + a file's directory entries are changed. All errors + including a conflicting file found during a PUBLIC request, + now set the program error flag and invoke the error handler + so an active SUBMIT or ZEX script can be aborted. The error + flag will have the following values: 2, invalid directory; + 10, no files on disk; 18, disk is read-only; 19, invalid + option; 4, all other errors. If no matching files are + found, the program error flag will be set to FFh, but the + error handler will not be invoked. A few other code changes + were made, including a check for CP/M-Plus, under which + FILEATTR will not work. Not released. + +Version 1.3 -- February 22, 1991 -- Gene Pizzetta + Corrected bug that caused faulty operation on large files: + The module data byte (S2) byte was not being checked, so + such files appeared 2 or more times in the directory display + and the public routine was often not finding conflicting + files. Added configuration byte and command line option (X) + for screen paging (paging is suppressed in quiet mode). + Made quiet mode responsive to ZCPR quiet flag and changed Q + command line option to toggle. Usage screen reflects + current effect of X and Q toggles. Attribute configuration + area changed to be compatible with ZCNFG TOGL3 routine. + Actions of D and ND options reversed so they work the same + as the others. Added configuration byte for printing + summary line even in quiet mode, as suggested by Howard + Goldstein. Removed blank lines from screen display, + allowing three more filenames to be shown. Removed tabs + from usage screen so PRINT and PSTR are not needed. + Eliminated leading zero from user number display. Now + prints "file" instead of "files" in summary when only 1 + matching file is found. Ditto for attribute(s) altered. + +Version 1.2 -- November 30, 1988 -- Carson Wilson + Fixed bug of no program name display when FILEATTR's name + was 8 characters long. + +Version 1.1 -- October 30, 1988 -- Carson Wilson + Now wildcards the command forms "FA d: /options" and "FA d: + options." + +Version 1.0 -- September 26, 1988 -- Carson Wilson + If a filespec is given, no leading slash is required before + the options. Link with version 4 libraries. Removed /X + option--ZSDOS 10T always closes the first extent when a file + is written to. Changed summary to read "files matched". + +Version 0.9 -- July 7, 1988 -- Carson Wilson + Increased length of search FCB (AMBFIL) by one byte. Set up + AMBFIL as '?' + 35 binary 0's. ZRDOS and CP/M zero the + drive byte (FCB+0) during search next calls, so reinitialize + it to '?' before rescanning the directory. PROGID now + prints stored name on GO/JUMP. + +Version 0.8 -- June 26, 1988 -- Carson Wilson + Use SYSLIB PRINT for help display. VPRINT does not expand + tabs. Now traps disk track changes at the BIOS level. + Allows '-' as well as 'N' for "negate option." Auto- + wildcards FCB1 for attribute set as well as display. + +Version 0.7 -- May 24, 1988 -- Carson Wilson + Cosmetic changes to help, display. Made public routines + faster by 1/2 directory scan average. Consolidated file + attribute setting/resetting routines for efficiency and + clarity. + +Version 0.6 -- May 14, 1988 -- Carson Wilson + Changed "Publ" to "Publc" and "Priv" to "Privt". Added Q + and X options, made options installable. Added test for bad + ZCPR directory & chain to error handler. + +Version 0.5 -- May 4, 1988 -- Carson Wilson + Fixed bug at CHKRO inherited from MAKE.ASM. Uses Bridger + Mitchell's FRESET to reset disks. Uses ZCPR invocation name + in signon, help, etc. Added F4 attribute. Now includes all + valid ZSDOS attributes. Help now fully "smart" under ZCPR. + Reworked VID3.Z80 and VID4.Z80 from VLIB11 and moved them + into FA.Z80 (see end of file). Put STNDOUT mode ON by + default at beginning of each attribute display sequence for + faster ZCPR displays. + +Version 0.4 -- April 27, 1988 -- Carson Wilson + Tests for matching files at other user areas before setting + the public attribit. + +Version 0.3 -- April 26, 1988 -- Carson Wilson diff --git a/trunk/RomDsk/ZSYS_1024KB/FA16A.FOR b/trunk/RomDsk/ZSYS_1024KB/FA16A.FOR new file mode 100644 index 00000000..e9ed3d43 --- /dev/null +++ b/trunk/RomDsk/ZSYS_1024KB/FA16A.FOR @@ -0,0 +1,6 @@ +An update and bug-fix of FILEATTR (FA), a ZSDOS utility that +allows rapid setting, resetting, or displaying of file attributes +under ZSDOS, ZRDOS, and CP/M 2.2. Several additional features +are available under ZCPR3, including error flag setting, error +handler invocation, and an enhanced display. Version 1.6A adds +documentation; otherwise, same as 1.6. diff --git a/trunk/RomDsk/ZSYS_1024KB/FA16CFG.TXT b/trunk/RomDsk/ZSYS_1024KB/FA16CFG.TXT new file mode 100644 index 00000000..4067b9ba --- /dev/null +++ b/trunk/RomDsk/ZSYS_1024KB/FA16CFG.TXT @@ -0,0 +1,39 @@ + +Option Q -- If the ZCPR quiet flag is set, FILEATTR will always default to +quiet mode. To make quiet mode the default at all times, even when running +under CP/M, set this configuration option to "Yes". Whatever is selected +here can be toggled with the command line "Q" option. + +Option X -- A "Yes" will cause FILEATTR to page screen output by default. +A "No" will default to continuous scrolling. The chosen default can be +toggled with the command line "X" option. Screen paging is always turned +off in quiet mode. + +Option R -- As distributed, FILEATTR prints nothing to the screen when it +is operating in quiet mode. If this configuration option is "Yes", the +results summary line that gives the number of matching files found and the +number of attributes changed will be printed even in quiet mode. + +Option S -- Enter the number of lines on your video display screen. Under +ZCPR 3.3 and higher, the number of screen lines for paging is obtained from +the environment descriptor. This configuration parameter is used only if +running under CP/M. + + + Attribute Configuration Options + +As distributed, FILEATTR will not change any file attribute unless +explicitly commanded to do so by a command line option. To configure +FILEATTR to turn a file attribute ON or OFF by default, toggle the +appropriate configuration selection. + +For example, to make FILEATTR set all matching files to Public by default, +change the "Public attribute" setting to "Turn On". Then FILEATTR will set +the specified files to Public unless the /NP command line option is given +(which would cause the files to be set to Private). Since there is no +command which tells FILEATTR not to change an attribute, however, the +program will now insist on turning the Public attribute either on (default) +or off (through the /NP option). + +Most users will have neither need nor desire to change the configuration +default as distributed which will "Leave As-Is" all matching files. diff --git a/trunk/RomDsk/ZSYS_1024KB/FILEATTR.COM b/trunk/RomDsk/ZSYS_1024KB/FILEATTR.COM new file mode 100644 index 00000000..4527d090 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/FILEATTR.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/FILEDATE.CFG b/trunk/RomDsk/ZSYS_1024KB/FILEDATE.CFG new file mode 100644 index 00000000..da1ca45f Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/FILEDATE.CFG differ diff --git a/trunk/RomDsk/ZSYS_1024KB/FILEDATE.COM b/trunk/RomDsk/ZSYS_1024KB/FILEDATE.COM new file mode 100644 index 00000000..11b83616 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/FILEDATE.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/FLASH.MAN b/trunk/RomDsk/ZSYS_1024KB/FLASH.MAN new file mode 100644 index 00000000..e57de5c2 --- /dev/null +++ b/trunk/RomDsk/ZSYS_1024KB/FLASH.MAN @@ -0,0 +1,35 @@ +NAME + flash - in-situ 29F040 flash ROM programmer for N8VEM, Zeta and N8 computers +SYNOPSIS + flashz + flashn8 +DESCRIPTION + The flashz and flashn8 erase and program the FLASH ROM chip from an + image file. flashz is used for the N8VEM Z80-SBC and Zeta computers. + flashn8 is used with the N8 home computer. Both function the same + except in the way memory is addressed. + + flash expects a 512k file in the same directory containing the image + that will be programmed into the ROM. This file must have the + unimaginative filename of ROM.IMG. The whole process of erasing and + programming the ROM takes less than a minute - far less than the time + taken to upload your new image. + + This program is only suitable for 29F040 512k FLASH ROMs. + + Assemble with TASM using the command + tasm -t80 -g3 flashz.asm flashz.com + tasm -t80 -g3 flashn8.asm flashn8.com + +JUMPERS + The following jumpers must be in place on the boards to allow the + 29F040 to be programmed. + For the N8VEM Z8-SBC MK-II: K1 1-2, K6 2-3, K8 2-3 + For the N8: K3 1-2, K4 2-3, K5 2-3 + For the Zeta, no jumpers need (or can) be set. + +AUTHOR + Written by David Giles so he doesn't have to open the box his Zeta + lives in so often. Reports to N8VEM group or vk5dg@internode.on.net + + diff --git a/trunk/RomDsk/ZSYS_1024KB/INITDIR.CFG b/trunk/RomDsk/ZSYS_1024KB/INITDIR.CFG new file mode 100644 index 00000000..96baa986 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/INITDIR.CFG differ diff --git a/trunk/RomDsk/ZSYS_1024KB/INITDIR.COM b/trunk/RomDsk/ZSYS_1024KB/INITDIR.COM new file mode 100644 index 00000000..fd46387a Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/INITDIR.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/LBREXT.COM b/trunk/RomDsk/ZSYS_1024KB/LBREXT.COM new file mode 100644 index 00000000..c0c950e3 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/LBREXT.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/LIB.COM b/trunk/RomDsk/ZSYS_1024KB/LIB.COM new file mode 100644 index 00000000..45d7fb21 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/LIB.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/LINK.COM b/trunk/RomDsk/ZSYS_1024KB/LINK.COM new file mode 100644 index 00000000..e188fb92 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/LINK.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/LOAD.COM b/trunk/RomDsk/ZSYS_1024KB/LOAD.COM new file mode 100644 index 00000000..b9601e00 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/LOAD.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/MAC.COM b/trunk/RomDsk/ZSYS_1024KB/MAC.COM new file mode 100644 index 00000000..f49e835a Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/MAC.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/MBASIC.COM b/trunk/RomDsk/ZSYS_1024KB/MBASIC.COM new file mode 100644 index 00000000..c9ec3cd3 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/MBASIC.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/NULU.COM b/trunk/RomDsk/ZSYS_1024KB/NULU.COM new file mode 100644 index 00000000..fc5594b1 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/NULU.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/PIP.COM b/trunk/RomDsk/ZSYS_1024KB/PIP.COM new file mode 100644 index 00000000..4b2ce4b6 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/PIP.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/PUTBG.COM b/trunk/RomDsk/ZSYS_1024KB/PUTBG.COM new file mode 100644 index 00000000..970e2d8a Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/PUTBG.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/PUTDS.COM b/trunk/RomDsk/ZSYS_1024KB/PUTDS.COM new file mode 100644 index 00000000..c0ceba64 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/PUTDS.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/RELOG.COM b/trunk/RomDsk/ZSYS_1024KB/RELOG.COM new file mode 100644 index 00000000..13ffc62e Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/RELOG.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/RMAC.COM b/trunk/RomDsk/ZSYS_1024KB/RMAC.COM new file mode 100644 index 00000000..9ab7206b Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/RMAC.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/SETTERM.COM b/trunk/RomDsk/ZSYS_1024KB/SETTERM.COM new file mode 100644 index 00000000..eca19bf9 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/SETTERM.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/SETUPZST.COM b/trunk/RomDsk/ZSYS_1024KB/SETUPZST.COM new file mode 100644 index 00000000..35e4b589 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/SETUPZST.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/SID.COM b/trunk/RomDsk/ZSYS_1024KB/SID.COM new file mode 100644 index 00000000..3b073ba5 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/SID.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/STAMPS.DAT b/trunk/RomDsk/ZSYS_1024KB/STAMPS.DAT new file mode 100644 index 00000000..23cd9bd7 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/STAMPS.DAT differ diff --git a/trunk/RomDsk/ZSYS_1024KB/STAT.COM b/trunk/RomDsk/ZSYS_1024KB/STAT.COM new file mode 100644 index 00000000..1de359f2 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/STAT.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/SUBMIT.COM b/trunk/RomDsk/ZSYS_1024KB/SUBMIT.COM new file mode 100644 index 00000000..2e788827 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/SUBMIT.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/SUPERSUB.COM b/trunk/RomDsk/ZSYS_1024KB/SUPERSUB.COM new file mode 100644 index 00000000..a25d60a6 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/SUPERSUB.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/TD.CFG b/trunk/RomDsk/ZSYS_1024KB/TD.CFG new file mode 100644 index 00000000..ab44bab9 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/TD.CFG differ diff --git a/trunk/RomDsk/ZSYS_1024KB/TD.COM b/trunk/RomDsk/ZSYS_1024KB/TD.COM new file mode 100644 index 00000000..552aba67 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/TD.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/TERMBASE.DAT b/trunk/RomDsk/ZSYS_1024KB/TERMBASE.DAT new file mode 100644 index 00000000..358d61c0 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/TERMBASE.DAT differ diff --git a/trunk/RomDsk/ZSYS_1024KB/TESTCLOK.COM b/trunk/RomDsk/ZSYS_1024KB/TESTCLOK.COM new file mode 100644 index 00000000..d547e2b8 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/TESTCLOK.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/UNARC.COM b/trunk/RomDsk/ZSYS_1024KB/UNARC.COM new file mode 100644 index 00000000..8cc90746 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/UNARC.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/UNCR.COM b/trunk/RomDsk/ZSYS_1024KB/UNCR.COM new file mode 100644 index 00000000..42385ddd Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/UNCR.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/UNZIP.COM b/trunk/RomDsk/ZSYS_1024KB/UNZIP.COM new file mode 100644 index 00000000..afde7204 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/UNZIP.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/XSUB.COM b/trunk/RomDsk/ZSYS_1024KB/XSUB.COM new file mode 100644 index 00000000..15e86abf Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/XSUB.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZAP.COM b/trunk/RomDsk/ZSYS_1024KB/ZAP.COM new file mode 100644 index 00000000..47ffcbb8 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZAP.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZCAL.COM b/trunk/RomDsk/ZSYS_1024KB/ZCAL.COM new file mode 100644 index 00000000..a5add241 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZCAL.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZCNFG.COM b/trunk/RomDsk/ZSYS_1024KB/ZCNFG.COM new file mode 100644 index 00000000..ae423dc5 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZCNFG.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZCNFG24.CFG b/trunk/RomDsk/ZSYS_1024KB/ZCNFG24.CFG new file mode 100644 index 00000000..1bfe49bf Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZCNFG24.CFG differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZDE.COM b/trunk/RomDsk/ZSYS_1024KB/ZDE.COM new file mode 100644 index 00000000..8814a523 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZDE.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZDENST.COM b/trunk/RomDsk/ZSYS_1024KB/ZDENST.COM new file mode 100644 index 00000000..8ccc9767 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZDENST.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZPATH.COM b/trunk/RomDsk/ZSYS_1024KB/ZPATH.COM new file mode 100644 index 00000000..5c0aa503 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZPATH.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZSCONFIG.COM b/trunk/RomDsk/ZSYS_1024KB/ZSCONFIG.COM new file mode 100644 index 00000000..2cc26074 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZSCONFIG.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZSVSTAMP.COM b/trunk/RomDsk/ZSYS_1024KB/ZSVSTAMP.COM new file mode 100644 index 00000000..026d5d7a Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZSVSTAMP.COM differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZSVSTAMP.DOC b/trunk/RomDsk/ZSYS_1024KB/ZSVSTAMP.DOC new file mode 100644 index 00000000..2a8a7c1e --- /dev/null +++ b/trunk/RomDsk/ZSYS_1024KB/ZSVSTAMP.DOC @@ -0,0 +1,118 @@ + ZSVSTAMP USAGE NOTES + + + +1.0 INTRODUCTION + + ZSVSTAMP is a utility program that saves the create +date/time stamp of a given file in memory. At a later time, +ZSVSTAMP can restore the create stamp to a file. This can be +useful when modifying a file with an editor that actually creates +a new copy of the file rather than modifying it in place. +ZSVSTAMP allows the original creation date of the document to be +retained. + + In order to support all types of date stamping under ZSDOS, +ZSVSTAMP uses the get/set stamp functions of ZSDOS (or ZDDOS) and +thus may only be run under these operating systems. It also +requires ZCPR3 with multiple command line, external FCB and +message buffer. If an attempt is made to run ZSVSTAMP on a +system that does not meet these requirements, the program will +abort with an error message. + + + +2.0 OPERATION + + ZSVSTAMP has two modes of operation -- Manual and Automatic. + + + +2.1 Automatic Mode + + This mode is the most commonly used. It is extremely well +suited for use in alias scripts and can make the whole process of +saving and restoring date stamps virtually transparent to the +user. The syntax is: + + ZSVSTAMP approg [ufn] + +where "approg" is the program, such as an editor, that you wish +to run and "ufn" is an unambiguous file name to be modified by +"approg." When a command of this type is given, ZSVSTAMP saves +"ufn"'s creation date in protected memory. It then causes +"approg" to be run, and when "approg" finishes, ZSVSTAMP is +automatically run again to restore the original create stamp to +"ufn." If "ufn" does not exist, or if the disk does not support +date stamping, ZSVSTAMP displays a warning message and +immediately passes control to "approg" without attempting to save +a stamp. In this situation, ZSVSTAMP is not rerun when "approg" +completes execution. + + Some editors allow a syntax such as + + EDIT oldfile newfile + +When ZSVSTAMP is invoked with more than one parameter following +the application name, no stamps are saved or restored. This +feature can be disabled if desired, (see the section on +customization). + + + +2.2 Manual Mode + + Manual mode can be used to save or restore a file's create +stamp. The syntax is: + + ZSVSTAMP ufn /G or /S + +to Get or Save a file's create stamp, or: + + ZSVSTAMP ufn /P or /R + +to Put or Restore a saved stamp back onto a file. + + + +3.0 CUSTOMIZING ZSVSTAMP + +There are five configuration flags located near the beginning of +the program. Each flag is preceeded by an ASCII string to help +identify its function. These flags may be patched to customize +ZSVSTAMP as desired. + + The first four flags determine whether or not various +warning messages can be displayed when ZSVSTAMP is being run in +Automatic Mode. Setting a flag to 0 disables its associated +message; any other value enables the message. The flags are +labeled "NOSTMP," "NOFILE," "READERR," and "UPDTERR," and they +affect the "Disk has no time/date stamps," "File not found," +"Can't read time/date stamp," and "Can't update time/date stamp" +messages respectively. The program is distributed with all four +messages enabled. Please note that these flags have no effect in +Manual Mode where error messages are always enabled. + + The fifth and final configuration flag is labeled +"REPLALWS." It determines what ZSVSTAMP will do when more than +one parameter follows the application name in an Automatic Mode +command. If the byte following the "REPLALWS" label equals 0, +ZSVSTAMP checks to see if there is more than one parameter +following the application program name. If there is, ZSVSTAMP +simply exits to the application without saving or updating any +stamps. (This is the default setting in the distributed +version.) If the "REPLALWS" flag is non-zero, no such check is +made. + + + +4.0 CONTACTING THE AUTHOR + + Howard Goldstein may be contacted at: + + Newton Centre Z-Node, (Z-Node 3): 617/965-7259 + + Ladera Z-Node, (Z-Node 2): 213/670-9465 + + Home phone, (voice): 203/787-1918 + \ No newline at end of file diff --git a/trunk/RomDsk/ZSYS_1024KB/ZXD.CFG b/trunk/RomDsk/ZSYS_1024KB/ZXD.CFG new file mode 100644 index 00000000..f202ae59 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZXD.CFG differ diff --git a/trunk/RomDsk/ZSYS_1024KB/ZXD.COM b/trunk/RomDsk/ZSYS_1024KB/ZXD.COM new file mode 100644 index 00000000..20395673 Binary files /dev/null and b/trunk/RomDsk/ZSYS_1024KB/ZXD.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/CLRDIR.COM b/trunk/RomDsk/ZSYS_512KB/CLRDIR.COM new file mode 100644 index 00000000..d1f2a7d6 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/CLRDIR.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/COPY.CFG b/trunk/RomDsk/ZSYS_512KB/COPY.CFG new file mode 100644 index 00000000..3d5310ac Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/COPY.CFG differ diff --git a/trunk/RomDsk/ZSYS_512KB/COPY.COM b/trunk/RomDsk/ZSYS_512KB/COPY.COM new file mode 100644 index 00000000..87c0c2fb Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/COPY.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/DDT.COM b/trunk/RomDsk/ZSYS_512KB/DDT.COM new file mode 100644 index 00000000..83f8603f Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/DDT.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/DIF.COM b/trunk/RomDsk/ZSYS_512KB/DIF.COM new file mode 100644 index 00000000..87b89d75 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/DIF.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/DSCONFIG.COM b/trunk/RomDsk/ZSYS_512KB/DSCONFIG.COM new file mode 100644 index 00000000..b77dd008 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/DSCONFIG.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/DUMP.COM b/trunk/RomDsk/ZSYS_512KB/DUMP.COM new file mode 100644 index 00000000..03a77c3c Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/DUMP.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/ED.COM b/trunk/RomDsk/ZSYS_512KB/ED.COM new file mode 100644 index 00000000..a0f0f541 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ED.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/FA16.CFG b/trunk/RomDsk/ZSYS_512KB/FA16.CFG new file mode 100644 index 00000000..b7974d36 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/FA16.CFG differ diff --git a/trunk/RomDsk/ZSYS_512KB/FILEATTR.COM b/trunk/RomDsk/ZSYS_512KB/FILEATTR.COM new file mode 100644 index 00000000..4527d090 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/FILEATTR.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/FILEDATE.CFG b/trunk/RomDsk/ZSYS_512KB/FILEDATE.CFG new file mode 100644 index 00000000..da1ca45f Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/FILEDATE.CFG differ diff --git a/trunk/RomDsk/ZSYS_512KB/FILEDATE.COM b/trunk/RomDsk/ZSYS_512KB/FILEDATE.COM new file mode 100644 index 00000000..11b83616 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/FILEDATE.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/FLASH.MAN b/trunk/RomDsk/ZSYS_512KB/FLASH.MAN new file mode 100644 index 00000000..e57de5c2 --- /dev/null +++ b/trunk/RomDsk/ZSYS_512KB/FLASH.MAN @@ -0,0 +1,35 @@ +NAME + flash - in-situ 29F040 flash ROM programmer for N8VEM, Zeta and N8 computers +SYNOPSIS + flashz + flashn8 +DESCRIPTION + The flashz and flashn8 erase and program the FLASH ROM chip from an + image file. flashz is used for the N8VEM Z80-SBC and Zeta computers. + flashn8 is used with the N8 home computer. Both function the same + except in the way memory is addressed. + + flash expects a 512k file in the same directory containing the image + that will be programmed into the ROM. This file must have the + unimaginative filename of ROM.IMG. The whole process of erasing and + programming the ROM takes less than a minute - far less than the time + taken to upload your new image. + + This program is only suitable for 29F040 512k FLASH ROMs. + + Assemble with TASM using the command + tasm -t80 -g3 flashz.asm flashz.com + tasm -t80 -g3 flashn8.asm flashn8.com + +JUMPERS + The following jumpers must be in place on the boards to allow the + 29F040 to be programmed. + For the N8VEM Z8-SBC MK-II: K1 1-2, K6 2-3, K8 2-3 + For the N8: K3 1-2, K4 2-3, K5 2-3 + For the Zeta, no jumpers need (or can) be set. + +AUTHOR + Written by David Giles so he doesn't have to open the box his Zeta + lives in so often. Reports to N8VEM group or vk5dg@internode.on.net + + diff --git a/trunk/RomDsk/ZSYS_512KB/INITDIR.CFG b/trunk/RomDsk/ZSYS_512KB/INITDIR.CFG new file mode 100644 index 00000000..96baa986 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/INITDIR.CFG differ diff --git a/trunk/RomDsk/ZSYS_512KB/INITDIR.COM b/trunk/RomDsk/ZSYS_512KB/INITDIR.COM new file mode 100644 index 00000000..fd46387a Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/INITDIR.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/LBREXT.COM b/trunk/RomDsk/ZSYS_512KB/LBREXT.COM new file mode 100644 index 00000000..c0c950e3 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/LBREXT.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/LOAD.COM b/trunk/RomDsk/ZSYS_512KB/LOAD.COM new file mode 100644 index 00000000..b9601e00 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/LOAD.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/NULU.COM b/trunk/RomDsk/ZSYS_512KB/NULU.COM new file mode 100644 index 00000000..fc5594b1 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/NULU.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/PIP.COM b/trunk/RomDsk/ZSYS_512KB/PIP.COM new file mode 100644 index 00000000..4b2ce4b6 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/PIP.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/PUTDS.COM b/trunk/RomDsk/ZSYS_512KB/PUTDS.COM new file mode 100644 index 00000000..c0ceba64 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/PUTDS.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/RELOG.COM b/trunk/RomDsk/ZSYS_512KB/RELOG.COM new file mode 100644 index 00000000..13ffc62e Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/RELOG.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/SETTERM.COM b/trunk/RomDsk/ZSYS_512KB/SETTERM.COM new file mode 100644 index 00000000..eca19bf9 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/SETTERM.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/SETUPZST.COM b/trunk/RomDsk/ZSYS_512KB/SETUPZST.COM new file mode 100644 index 00000000..35e4b589 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/SETUPZST.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/STAT.COM b/trunk/RomDsk/ZSYS_512KB/STAT.COM new file mode 100644 index 00000000..1de359f2 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/STAT.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/SUBMIT.COM b/trunk/RomDsk/ZSYS_512KB/SUBMIT.COM new file mode 100644 index 00000000..2e788827 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/SUBMIT.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/SUPERSUB.COM b/trunk/RomDsk/ZSYS_512KB/SUPERSUB.COM new file mode 100644 index 00000000..a25d60a6 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/SUPERSUB.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/TD.CFG b/trunk/RomDsk/ZSYS_512KB/TD.CFG new file mode 100644 index 00000000..ab44bab9 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/TD.CFG differ diff --git a/trunk/RomDsk/ZSYS_512KB/TD.COM b/trunk/RomDsk/ZSYS_512KB/TD.COM new file mode 100644 index 00000000..552aba67 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/TD.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/TERMBASE.DAT b/trunk/RomDsk/ZSYS_512KB/TERMBASE.DAT new file mode 100644 index 00000000..358d61c0 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/TERMBASE.DAT differ diff --git a/trunk/RomDsk/ZSYS_512KB/TESTCLOK.COM b/trunk/RomDsk/ZSYS_512KB/TESTCLOK.COM new file mode 100644 index 00000000..d547e2b8 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/TESTCLOK.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/UNARC.COM b/trunk/RomDsk/ZSYS_512KB/UNARC.COM new file mode 100644 index 00000000..8cc90746 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/UNARC.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/UNCR.COM b/trunk/RomDsk/ZSYS_512KB/UNCR.COM new file mode 100644 index 00000000..42385ddd Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/UNCR.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/XSUB.COM b/trunk/RomDsk/ZSYS_512KB/XSUB.COM new file mode 100644 index 00000000..15e86abf Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/XSUB.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZAP.COM b/trunk/RomDsk/ZSYS_512KB/ZAP.COM new file mode 100644 index 00000000..47ffcbb8 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZAP.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZCAL.COM b/trunk/RomDsk/ZSYS_512KB/ZCAL.COM new file mode 100644 index 00000000..a5add241 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZCAL.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZCNFG.COM b/trunk/RomDsk/ZSYS_512KB/ZCNFG.COM new file mode 100644 index 00000000..ae423dc5 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZCNFG.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZCNFG24.CFG b/trunk/RomDsk/ZSYS_512KB/ZCNFG24.CFG new file mode 100644 index 00000000..1bfe49bf Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZCNFG24.CFG differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZDE.COM b/trunk/RomDsk/ZSYS_512KB/ZDE.COM new file mode 100644 index 00000000..8814a523 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZDE.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZPATH.COM b/trunk/RomDsk/ZSYS_512KB/ZPATH.COM new file mode 100644 index 00000000..5c0aa503 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZPATH.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZSCONFIG.COM b/trunk/RomDsk/ZSYS_512KB/ZSCONFIG.COM new file mode 100644 index 00000000..2cc26074 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZSCONFIG.COM differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZXD.CFG b/trunk/RomDsk/ZSYS_512KB/ZXD.CFG new file mode 100644 index 00000000..f202ae59 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZXD.CFG differ diff --git a/trunk/RomDsk/ZSYS_512KB/ZXD.COM b/trunk/RomDsk/ZSYS_512KB/ZXD.COM new file mode 100644 index 00000000..20395673 Binary files /dev/null and b/trunk/RomDsk/ZSYS_512KB/ZXD.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/FDTST.COM b/trunk/RomDsk/cfg_n8_2312/FDTST.COM new file mode 100644 index 00000000..5cd9f77c Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/FDTST.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/FLASHN8.COM b/trunk/RomDsk/cfg_n8_2312/FLASHN8.COM new file mode 100644 index 00000000..61c5789d Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/FLASHN8.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/LDTIM.COM b/trunk/RomDsk/cfg_n8_2312/LDTIM.COM new file mode 100644 index 00000000..1ce1dfc7 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/RTC.COM b/trunk/RomDsk/cfg_n8_2312/RTC.COM new file mode 100644 index 00000000..0ac25a6a Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/SURVEY.COM b/trunk/RomDsk/cfg_n8_2312/SURVEY.COM new file mode 100644 index 00000000..2b0bf4e4 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/SURVEY.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/XM-A0.COM b/trunk/RomDsk/cfg_n8_2312/XM-A0.COM new file mode 100644 index 00000000..6afb31f3 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/XM-A0.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/XM-A1.COM b/trunk/RomDsk/cfg_n8_2312/XM-A1.COM new file mode 100644 index 00000000..42a67c31 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/XM-A1.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/XM5-A0.COM b/trunk/RomDsk/cfg_n8_2312/XM5-A0.COM new file mode 100644 index 00000000..e233bee9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/XM5-A0.COM differ diff --git a/trunk/RomDsk/cfg_n8_2312/XM5-A1.COM b/trunk/RomDsk/cfg_n8_2312/XM5-A1.COM new file mode 100644 index 00000000..625e06ac Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2312/XM5-A1.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/FDTST.COM b/trunk/RomDsk/cfg_n8_2511/FDTST.COM new file mode 100644 index 00000000..5cd9f77c Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/FDTST.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/FLASHN8.COM b/trunk/RomDsk/cfg_n8_2511/FLASHN8.COM new file mode 100644 index 00000000..61c5789d Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/FLASHN8.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/LDTIM.COM b/trunk/RomDsk/cfg_n8_2511/LDTIM.COM new file mode 100644 index 00000000..1ce1dfc7 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/RTC.COM b/trunk/RomDsk/cfg_n8_2511/RTC.COM new file mode 100644 index 00000000..0ac25a6a Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/SURVEY.COM b/trunk/RomDsk/cfg_n8_2511/SURVEY.COM new file mode 100644 index 00000000..2b0bf4e4 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/SURVEY.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/XM-A0.COM b/trunk/RomDsk/cfg_n8_2511/XM-A0.COM new file mode 100644 index 00000000..6afb31f3 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/XM-A0.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/XM-A1.COM b/trunk/RomDsk/cfg_n8_2511/XM-A1.COM new file mode 100644 index 00000000..42a67c31 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/XM-A1.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/XM5-A0.COM b/trunk/RomDsk/cfg_n8_2511/XM5-A0.COM new file mode 100644 index 00000000..e233bee9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/XM5-A0.COM differ diff --git a/trunk/RomDsk/cfg_n8_2511/XM5-A1.COM b/trunk/RomDsk/cfg_n8_2511/XM5-A1.COM new file mode 100644 index 00000000..625e06ac Binary files /dev/null and b/trunk/RomDsk/cfg_n8_2511/XM5-A1.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/1200.COM b/trunk/RomDsk/cfg_n8vem/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/1200.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/38400.COM b/trunk/RomDsk/cfg_n8vem/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/38400.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/9600.COM b/trunk/RomDsk/cfg_n8vem/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/9600.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/FLASHZ.COM b/trunk/RomDsk/cfg_n8vem/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/LDTIM.COM b/trunk/RomDsk/cfg_n8vem/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/RTC.COM b/trunk/RomDsk/cfg_n8vem/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/T5.COM b/trunk/RomDsk/cfg_n8vem/T5.COM new file mode 100644 index 00000000..ab55d759 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/T5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/VT3.COM b/trunk/RomDsk/cfg_n8vem/VT3.COM new file mode 100644 index 00000000..6290a6d3 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/VT3.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/XM.COM b/trunk/RomDsk/cfg_n8vem/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/XM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem/XM5.COM b/trunk/RomDsk/cfg_n8vem/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem/XM5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/1200.COM b/trunk/RomDsk/cfg_n8vem_dide/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/1200.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/38400.COM b/trunk/RomDsk/cfg_n8vem_dide/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/38400.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/9600.COM b/trunk/RomDsk/cfg_n8vem_dide/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/9600.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/FDTST.COM b/trunk/RomDsk/cfg_n8vem_dide/FDTST.COM new file mode 100644 index 00000000..cf9544eb Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/FDTST.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/FLASHZ.COM b/trunk/RomDsk/cfg_n8vem_dide/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/LDTIM.COM b/trunk/RomDsk/cfg_n8vem_dide/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/RTC.COM b/trunk/RomDsk/cfg_n8vem_dide/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/T5.COM b/trunk/RomDsk/cfg_n8vem_dide/T5.COM new file mode 100644 index 00000000..ab55d759 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/T5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/XM.COM b/trunk/RomDsk/cfg_n8vem_dide/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/XM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_dide/XM5.COM b/trunk/RomDsk/cfg_n8vem_dide/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_dide/XM5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/1200.COM b/trunk/RomDsk/cfg_n8vem_diskio/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/1200.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/38400.COM b/trunk/RomDsk/cfg_n8vem_diskio/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/38400.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/9600.COM b/trunk/RomDsk/cfg_n8vem_diskio/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/9600.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/ECIDETST.COM b/trunk/RomDsk/cfg_n8vem_diskio/ECIDETST.COM new file mode 100644 index 00000000..f0140c58 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/ECIDETST.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/FDCMON.COM b/trunk/RomDsk/cfg_n8vem_diskio/FDCMON.COM new file mode 100644 index 00000000..197af733 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/FDCMON.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/FDTST.COM b/trunk/RomDsk/cfg_n8vem_diskio/FDTST.COM new file mode 100644 index 00000000..ebea0d52 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/FDTST.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/FLASHZ.COM b/trunk/RomDsk/cfg_n8vem_diskio/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/LDTIM.COM b/trunk/RomDsk/cfg_n8vem_diskio/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/RTC.COM b/trunk/RomDsk/cfg_n8vem_diskio/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/T5.COM b/trunk/RomDsk/cfg_n8vem_diskio/T5.COM new file mode 100644 index 00000000..ab55d759 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/T5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/TP-IDE.COM b/trunk/RomDsk/cfg_n8vem_diskio/TP-IDE.COM new file mode 100644 index 00000000..726efd5b Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/TP-IDE.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/XM.COM b/trunk/RomDsk/cfg_n8vem_diskio/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/XM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio/XM5.COM b/trunk/RomDsk/cfg_n8vem_diskio/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio/XM5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/1200.COM b/trunk/RomDsk/cfg_n8vem_diskio3/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/1200.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/38400.COM b/trunk/RomDsk/cfg_n8vem_diskio3/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/38400.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/9600.COM b/trunk/RomDsk/cfg_n8vem_diskio3/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/9600.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/FDTST.COM b/trunk/RomDsk/cfg_n8vem_diskio3/FDTST.COM new file mode 100644 index 00000000..6e85b8f8 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/FDTST.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/FLASHZ.COM b/trunk/RomDsk/cfg_n8vem_diskio3/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/LDTIM.COM b/trunk/RomDsk/cfg_n8vem_diskio3/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/RTC.COM b/trunk/RomDsk/cfg_n8vem_diskio3/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/T5.COM b/trunk/RomDsk/cfg_n8vem_diskio3/T5.COM new file mode 100644 index 00000000..ab55d759 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/T5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/XM.COM b/trunk/RomDsk/cfg_n8vem_diskio3/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/XM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_diskio3/XM5.COM b/trunk/RomDsk/cfg_n8vem_diskio3/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_diskio3/XM5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/1200.COM b/trunk/RomDsk/cfg_n8vem_ppide/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/1200.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/38400.COM b/trunk/RomDsk/cfg_n8vem_ppide/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/38400.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/9600.COM b/trunk/RomDsk/cfg_n8vem_ppide/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/9600.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/FLASHZ.COM b/trunk/RomDsk/cfg_n8vem_ppide/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/LDTIM.COM b/trunk/RomDsk/cfg_n8vem_ppide/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/PPIDETST.COM b/trunk/RomDsk/cfg_n8vem_ppide/PPIDETST.COM new file mode 100644 index 00000000..1cfc72b7 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/PPIDETST.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/RTC.COM b/trunk/RomDsk/cfg_n8vem_ppide/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/T5.COM b/trunk/RomDsk/cfg_n8vem_ppide/T5.COM new file mode 100644 index 00000000..ab55d759 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/T5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/VT3.COM b/trunk/RomDsk/cfg_n8vem_ppide/VT3.COM new file mode 100644 index 00000000..6290a6d3 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/VT3.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/XM.COM b/trunk/RomDsk/cfg_n8vem_ppide/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/XM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppide/XM5.COM b/trunk/RomDsk/cfg_n8vem_ppide/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppide/XM5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/1200.COM b/trunk/RomDsk/cfg_n8vem_ppisd/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/1200.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/38400.COM b/trunk/RomDsk/cfg_n8vem_ppisd/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/38400.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/9600.COM b/trunk/RomDsk/cfg_n8vem_ppisd/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/9600.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/FLASHZ.COM b/trunk/RomDsk/cfg_n8vem_ppisd/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/LDTIM.COM b/trunk/RomDsk/cfg_n8vem_ppisd/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/RTC.COM b/trunk/RomDsk/cfg_n8vem_ppisd/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/T5.COM b/trunk/RomDsk/cfg_n8vem_ppisd/T5.COM new file mode 100644 index 00000000..ab55d759 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/T5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/VT3.COM b/trunk/RomDsk/cfg_n8vem_ppisd/VT3.COM new file mode 100644 index 00000000..6290a6d3 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/VT3.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/XM.COM b/trunk/RomDsk/cfg_n8vem_ppisd/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/XM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_ppisd/XM5.COM b/trunk/RomDsk/cfg_n8vem_ppisd/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_ppisd/XM5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/1200.COM b/trunk/RomDsk/cfg_n8vem_propio/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/1200.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/38400.COM b/trunk/RomDsk/cfg_n8vem_propio/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/38400.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/9600.COM b/trunk/RomDsk/cfg_n8vem_propio/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/9600.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/FLASHZ.COM b/trunk/RomDsk/cfg_n8vem_propio/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/LDTIM.COM b/trunk/RomDsk/cfg_n8vem_propio/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/RTC.COM b/trunk/RomDsk/cfg_n8vem_propio/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/T5.COM b/trunk/RomDsk/cfg_n8vem_propio/T5.COM new file mode 100644 index 00000000..ab55d759 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/T5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/XM.COM b/trunk/RomDsk/cfg_n8vem_propio/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/XM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_propio/XM5.COM b/trunk/RomDsk/cfg_n8vem_propio/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_propio/XM5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/1200.COM b/trunk/RomDsk/cfg_n8vem_vdu/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/1200.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/38400.COM b/trunk/RomDsk/cfg_n8vem_vdu/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/38400.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/9600.COM b/trunk/RomDsk/cfg_n8vem_vdu/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/9600.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/FLASHZ.COM b/trunk/RomDsk/cfg_n8vem_vdu/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/LDTIM.COM b/trunk/RomDsk/cfg_n8vem_vdu/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/RTC.COM b/trunk/RomDsk/cfg_n8vem_vdu/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/RTC.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/T5.COM b/trunk/RomDsk/cfg_n8vem_vdu/T5.COM new file mode 100644 index 00000000..ab55d759 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/T5.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/XM.COM b/trunk/RomDsk/cfg_n8vem_vdu/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/XM.COM differ diff --git a/trunk/RomDsk/cfg_n8vem_vdu/XM5.COM b/trunk/RomDsk/cfg_n8vem_vdu/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_n8vem_vdu/XM5.COM differ diff --git a/trunk/RomDsk/cfg_simh/HDIR.COM b/trunk/RomDsk/cfg_simh/HDIR.COM new file mode 100644 index 00000000..8901335c Binary files /dev/null and b/trunk/RomDsk/cfg_simh/HDIR.COM differ diff --git a/trunk/RomDsk/cfg_simh/LDTIM.COM b/trunk/RomDsk/cfg_simh/LDTIM.COM new file mode 100644 index 00000000..d2959fae Binary files /dev/null and b/trunk/RomDsk/cfg_simh/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_simh/R.COM b/trunk/RomDsk/cfg_simh/R.COM new file mode 100644 index 00000000..2e4b504f Binary files /dev/null and b/trunk/RomDsk/cfg_simh/R.COM differ diff --git a/trunk/RomDsk/cfg_simh/RSETSIMH.COM b/trunk/RomDsk/cfg_simh/RSETSIMH.COM new file mode 100644 index 00000000..e055f07a Binary files /dev/null and b/trunk/RomDsk/cfg_simh/RSETSIMH.COM differ diff --git a/trunk/RomDsk/cfg_simh/TIMER.COM b/trunk/RomDsk/cfg_simh/TIMER.COM new file mode 100644 index 00000000..83e6e688 Binary files /dev/null and b/trunk/RomDsk/cfg_simh/TIMER.COM differ diff --git a/trunk/RomDsk/cfg_simh/URL.COM b/trunk/RomDsk/cfg_simh/URL.COM new file mode 100644 index 00000000..45446079 Binary files /dev/null and b/trunk/RomDsk/cfg_simh/URL.COM differ diff --git a/trunk/RomDsk/cfg_simh/W.COM b/trunk/RomDsk/cfg_simh/W.COM new file mode 100644 index 00000000..342f07ad Binary files /dev/null and b/trunk/RomDsk/cfg_simh/W.COM differ diff --git a/trunk/RomDsk/cfg_zeta/1200.COM b/trunk/RomDsk/cfg_zeta/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/1200.COM differ diff --git a/trunk/RomDsk/cfg_zeta/38400.COM b/trunk/RomDsk/cfg_zeta/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/38400.COM differ diff --git a/trunk/RomDsk/cfg_zeta/9600.COM b/trunk/RomDsk/cfg_zeta/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/9600.COM differ diff --git a/trunk/RomDsk/cfg_zeta/FDTST.COM b/trunk/RomDsk/cfg_zeta/FDTST.COM new file mode 100644 index 00000000..30e36f60 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/FDTST.COM differ diff --git a/trunk/RomDsk/cfg_zeta/FLASHZ.COM b/trunk/RomDsk/cfg_zeta/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_zeta/LDTIM.COM b/trunk/RomDsk/cfg_zeta/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_zeta/PPIDETST.COM b/trunk/RomDsk/cfg_zeta/PPIDETST.COM new file mode 100644 index 00000000..1cfc72b7 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/PPIDETST.COM differ diff --git a/trunk/RomDsk/cfg_zeta/RTC.COM b/trunk/RomDsk/cfg_zeta/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/RTC.COM differ diff --git a/trunk/RomDsk/cfg_zeta/SURVEY.COM b/trunk/RomDsk/cfg_zeta/SURVEY.COM new file mode 100644 index 00000000..2b0bf4e4 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/SURVEY.COM differ diff --git a/trunk/RomDsk/cfg_zeta/XM.COM b/trunk/RomDsk/cfg_zeta/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/XM.COM differ diff --git a/trunk/RomDsk/cfg_zeta/XM5.COM b/trunk/RomDsk/cfg_zeta/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta/XM5.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/1200.COM b/trunk/RomDsk/cfg_zeta_ppp/1200.COM new file mode 100644 index 00000000..d00960b0 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/1200.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/38400.COM b/trunk/RomDsk/cfg_zeta_ppp/38400.COM new file mode 100644 index 00000000..6d81bc17 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/38400.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/9600.COM b/trunk/RomDsk/cfg_zeta_ppp/9600.COM new file mode 100644 index 00000000..4727badf Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/9600.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/FDTST.COM b/trunk/RomDsk/cfg_zeta_ppp/FDTST.COM new file mode 100644 index 00000000..30e36f60 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/FDTST.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/FLASHZ.COM b/trunk/RomDsk/cfg_zeta_ppp/FLASHZ.COM new file mode 100644 index 00000000..853ae7d9 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/FLASHZ.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/LDTIM.COM b/trunk/RomDsk/cfg_zeta_ppp/LDTIM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/LDTIM.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/RTC.COM b/trunk/RomDsk/cfg_zeta_ppp/RTC.COM new file mode 100644 index 00000000..da0aebc1 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/RTC.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/SURVEY.COM b/trunk/RomDsk/cfg_zeta_ppp/SURVEY.COM new file mode 100644 index 00000000..2b0bf4e4 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/SURVEY.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/TSTPPP.COM b/trunk/RomDsk/cfg_zeta_ppp/TSTPPP.COM new file mode 100644 index 00000000..761e43e1 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/TSTPPP.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/XM.COM b/trunk/RomDsk/cfg_zeta_ppp/XM.COM new file mode 100644 index 00000000..abcc6828 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/XM.COM differ diff --git a/trunk/RomDsk/cfg_zeta_ppp/XM5.COM b/trunk/RomDsk/cfg_zeta_ppp/XM5.COM new file mode 100644 index 00000000..8ea2b661 Binary files /dev/null and b/trunk/RomDsk/cfg_zeta_ppp/XM5.COM differ diff --git a/trunk/RomList.txt b/trunk/RomList.txt new file mode 100644 index 00000000..79a9fd81 --- /dev/null +++ b/trunk/RomList.txt @@ -0,0 +1,252 @@ +You should find the following ROM +images in the Output driectory. +Refer to the descriptions below to select +one that matches your hardware +configuration, burn it, and use it. + +Note there are two set of rom builds +below, one for generic DRI CP/M (BDOS & CCP) +and one for ZSystem (ZSDOS & ZCPR) + +Note that all builds are now set for 512KB ROMs. +The builds will work fine in 1MB ROMs. If you +want to use the full 1MB ROM address space, just +do a cutom build. + +Note that all builds are now set for 38.4Kbsp +baud rate on the console with 8 data bits, no +parity, and 1 stop bit. The baud rate can be +changed in the config file if you want to do a +custom build. + +DRI CP/M (BDOS & CCP) +--------------------- + + n8vem.rom for N8VEM Z80 SBC V1/V2: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk (no floppy/IDE) + - Drives A:=ROM, B:=RAM + + n8vem_diskio.rom for N8VEM Z80 SBC V1/V2 + DISKIO: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via DISKIO + - IDE support via DISKIO + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=IDE0-00, F:=IDE0-01, G:=IDE0-02, H:=IDE0-03 + + n8vem_dide.rom for N8VEM Z80 SBC V1/V2 + DUAL IDE: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via DISKIO + - IDE support via DISKIO + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=IDE0-00, F:=IDE0-01, G:=IDE0-02, H:=IDE0-03 + + n8vem_diskio3.rom for N8VEM Z80 SBC V1/V2 + DISKIO3: + - EXPERIMENTAL! + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via DISKIO3 + - IDE support via DISKIO3 + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=IDE0-00, F:=IDE0-01, G:=IDE0-02, H:=IDE0-03 + + n8vem_ppide.rom for N8VEM Z80 SBC V1/V2 + PPIDE: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - IDE support via DISKIO + - Drives A:=ROM, B:=RAM, C:=PPIDE0-00, D:=PPIDE0-01, E:=PPIDE0-02, F:=PPIDE0-03 + + n8vem_ppisd.rom for N8VEM Z80 SBC V1/V2 + PPISD: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - PPISD support + - Drives A:=ROM, B:=RAM, C:=SD0-00, D:=SD0-01, E:=SD0-02, F:=SD0-03 + + n8vem_propio.rom for N8VEM Z80 SBC V1/V2 + PROPIO: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - SD Card support via PropIO + - VGA console support via PropIO + - PS/2 Keyboard support via PropIO + - Drives A:=ROM, B:=RAM, C:=PRPSD0-00, D:=PRPSD0-01, E:=PRPSD0-02, F:=PRPSD0-03 + - WARNING: You must use the RomWBW specific firmware + for the Propeller found in the Support directory! + - NOTE: Console defaults to VGA & PS/2 Keyboard. Short JP2 + (one bit input port) to use the serial port as the console. + + n8vem_vdu.rom for N8VEM Z80 SBC V1/V2: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - VDU board support + - Drives A:=ROM, B:=RAM + + zeta.rom for Zeta Z80 SBC: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via built-in FDC + - PPIDE support via built-in PPI + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=PPIDE00-0, F:=PPIDE0-01, G:=PPIDE0-02, H:=PPIDE0-03 + + zeta_ppp.rom for Zeta Z80 SBC w/ ParPortProp: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via built-in FDC + - SD Card support via ParPortProp + - VGA console support via ParPortProp + - PS/2 Keyboard support via ParPortProp + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=PPPSD0-00, F:=PPPSD0-01, F:=PPPSD0-02, G:=PPPSD0-03 + - WARNING: You must use the RomWBW specific firmware + for the Propeller found in the Support directory! + - NOTE: Console defaults to VGA & PS/2 Keyboard. Short JP1 (CONFIG) + to use the serial port as the console. + + n8_2511.rom for N8 2511 Z180: + - Assumes oscillator frequency of 18.432MHz + - CPU clock at X1 (18.432MHz) + - 512KB ROM, 1MB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via built-in FDC + - SD card support via built-in SD card slot + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=SD0-00, F:=SD0-01, G:=SD0-02, H:=SD0-03 + + n8_2312.rom for N8 2312 Z180: + - Assumes oscillator frequency of 18.432MHz + - CPU clock at X1 (18.432MHz) + - 512KB ROM, 1MB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via built-in FDC + - SD card support via built-in SD card slot + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=SD0-00, F:=SD0-01, G:=SD0-02, H:=SD0-03 + + simh.rom for N8VEM SIMH Simulator: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk (no floppy/IDE) + - Drives A:=ROM, B:=RAM, C:=HDSK0-00, D:=HDSK0-01, E:=HDSK0-02, F:=HDSK0-03 + +ZSYSTEM (ZSDOS & ZCPR) +---------------------- + + n8vem_z.rom for N8VEM Z80 SBC V1/V2: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk (no floppy/IDE) + - Drives A:=RAM, B:=ROM + + n8vem_diskio_z.rom for N8VEM Z80 SBC V1/V2 + DISKIO: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via DISKIO + - IDE support via DISKIO + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=IDE0-00, F:=IDE0-01, G:=IDE0-02, H:=IDE0-03 + + n8vem_dide_z.rom for N8VEM Z80 SBC V1/V2 + DUAL IDE: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via DISKIO + - IDE support via DISKIO + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=IDE0-00, F:=IDE0-01, G:=IDE0-02, H:=IDE0-03 + + n8vem_diskio3_z.rom for N8VEM Z80 SBC V1/V2 + DISKIO3: + - EXPERIMENTAL! + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via DISKIO3 + - IDE support via DISKIO3 + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=IDE0-00, F:=IDE0-01, G:=IDE0-02, H:=IDE0-03 + + n8vem_ppide_z.rom for N8VEM Z80 SBC V1/V2 + PPIDE: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - IDE support via DISKIO + - Drives A:=ROM, B:=RAM, C:=PPIDE0-00, D:=PPIDE0-01, E:=PPIDE0-02, F:=PPIDE0-03 + + n8vem_ppisd_z.rom for N8VEM Z80 SBC V1/V2 + PPISD: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - PPISD support + - Drives A:=ROM, B:=RAM, C:=SD0-00, D:=SD0-01, E:=SD0-02, F:=SD0-03 + + n8vem_propio_z.rom for N8VEM Z80 SBC V1/V2 + PROPIO: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - SD Card support via PropIO + - VGA console support via PropIO + - PS/2 Keyboard support via PropIO + - Drives A:=ROM, B:=RAM, C:=PRPSD0-00, D:=PRPSD0-01, E:=PRPSD0-02, F:=PRPSD0-03 + - WARNING: You must use the RomWBW specific firmware + for the Propeller found in the Support directory! + - NOTE: Console defaults to VGA & PS/2 Keyboard. Short JP2 + (one bit input port) to use the serial port as the console. + + n8vem_vdu_z.rom for N8VEM Z80 SBC V1/V2: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - VDU board support + - Drives A:=ROM, B:=RAM + + zeta_z.rom for Zeta Z80 SBC: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via built-in FDC + - PPIDE support via built-in PPI + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=PPIDE0-00, F:=PPIDE0-01, G:=PPIDE0-02, H:=PPIDE0-03 + + zeta_ppp_z.rom for Zeta Z80 SBC w/ ParPortProp: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via built-in FDC + - SD Card support via ParPortProp + - VGA console support via ParPortProp + - PS/2 Keyboard support via ParPortProp + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=PPPSD0-00, F:=PPPSD0-01, F:=PPPSD0-02, G:=PPPSD0-03 + - WARNING: You must use the RomWBW specific firmware + for the Propeller found in the Support directory! + - NOTE: Console defaults to VGA & PS/2 Keyboard. Short JP1 (CONFIG) + to use the serial port as the console. + + n8_2511_z.rom for N8 2511 Z180: + - Assumes oscillator frequency of 18.432MHz + - CPU clock at X1 (18.432MHz) + - 512KB ROM, 1MB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via built-in FDC + - SD card support via built-in SD card slot + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=SD0-00, F:=SD0-01, G:=SD0-02, H:=SD0-03 + + n8_2312_z.rom for N8 2312 Z180: + - Assumes oscillator frequency of 18.432MHz + - CPU clock at X1 (18.432MHz) + - 512KB ROM, 1MB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk + - Floppy support via built-in FDC + - SD card support via built-in SD card slot + - Drives A:=ROM, B:=RAM, C:=FD0, D:=FD1, E:=SD0-00, F:=SD0-01, G:=SD0-02, H:=SD0-03 + + simh_Z.rom for N8VEM SIMH Simulator: + - 512KB ROM, 512KB RAM + - 38.4KB serial console baud rate + - Basic ROM/RAM disk (no floppy/IDE) + - Drives A:=ROM, B:=RAM, C:=HDSK0-00, D:=HDSK0-01, E:=HDSK0-02, F:=HDSK0-03 \ No newline at end of file diff --git a/trunk/Source/Build.ps1 b/trunk/Source/Build.ps1 new file mode 100644 index 00000000..89ae2287 --- /dev/null +++ b/trunk/Source/Build.ps1 @@ -0,0 +1,143 @@ +param([string]$Config = "", [string]$RomSize = "", [string]$CPUType = "", [string]$SYS = "", [string]$RomName = "") + +while ($true) +{ + $ConfigFile = "config_${Config}.asm" + if (Test-Path $ConfigFile) {break} + if ($Config -ne "") {Write-Host "${ConfigFile} does not exist!"} + + "Configurations available:" + Get-Item config_*.asm | foreach {Write-Host " >", $_.Name.Substring(7,$_.Name.Length - 11)} + $Config = (Read-Host -prompt "Configuration").Trim() +} + +while ($true) +{ + if (($RomSize -eq "512") -or ($RomSize -eq "1024")) {break} + $RomSize = (Read-Host -prompt "ROM Size [512|1024]").Trim() +} + +while ($true) +{ + if (($CPUType -eq "80") -or ($CPUType -eq "180")) {break} + $CPUType = (Read-Host -prompt "CPU Type Z[80|180]").Trim() +} + +$SYS = $SYS.ToUpper() +while ($true) +{ + if (($SYS -eq "CPM") -or ($SYS -eq "ZSYS")) {break} + $SYS = (Read-Host -prompt "System [CPM|ZSYS]").Trim().ToUpper() +} + +if ($RomName -eq "") {$RomName = $Config} +while ($RomName -eq "") +{ + $CP = (Read-Host -prompt "ROM Name [${Config}]").Trim() + if ($RomName -eq "") {$RomName = $Config} +} + +$ErrorAction = 'Stop' + +$TasmPath = '..\tools\tasm32' +$CpmToolsPath = '..\tools\cpmtools' + +$env:TASMTABS = $TasmPath +$env:PATH = $TasmPath + ';' + $CpmToolsPath + ';' + $env:PATH + +$OutDir = "../Output" +$RomFmt = "rom${RomSize}KB" +$BlankFile = "blank${RomSize}KB.dat" +$ConfigFile = "Config_${Config}.asm" +$RomDiskFile = "RomDisk.tmp" +$RomFile = "${OutDir}/${RomName}.rom" +$SysImgFile = "${OutDir}/${RomName}.sys" +$LoaderFile = "${OutDir}/${RomName}.com" + +"" +"Building ${RomName}: ${ROMSize}KB ROM configuration ${Config} for Z${CPUType}..." +"" + +$TimeStamp = '"' + (Get-Date -Format 'yyMMddThhmm') + '"' +$Variant = '"RomWBW-' + $Env:UserName + '"' + +Function Asm($Component, $Opt, $Architecture=$CPUType, $Output="${Component}.bin") +{ + $Cmd = "tasm -t${Architecture} -g3 ${Opt} ${Component}.asm ${Output}" + $Cmd | write-host + Invoke-Expression $Cmd | write-host + if ($LASTEXITCODE -gt 0) {throw "TASM returned exit code $LASTEXITCODE"} +} + +Function Concat($InputFileList, $OutputFile) +{ + Set-Content $OutputFile -Value $null + foreach ($InputFile in $InputFileList) + { + Add-Content $OutputFile -Value ([System.IO.File]::ReadAllBytes($InputFile)) -Encoding byte + } +} + +# Generate the build settings include file + +@" +; RomWBW Configured for ${Config}, $(Get-Date) +; +#DEFINE TIMESTAMP ${TimeStamp} +#DEFINE VARIANT ${Variant} +; +ROMSIZE .EQU ${ROMSize} ; SIZE OF ROM IN KB +; +#INCLUDE "${ConfigFile}" +; +"@ | Out-File "build.inc" -Encoding ASCII + +# Build components + +if ($SYS -eq "CPM") +{ + Asm 'ccpb03' -Output 'cp.bin' + Asm 'bdosb01' -Output 'dos.bin' +} +if ($SYS -eq "ZSYS") +{ + Asm 'zcprw' -Architecture '85' -Output 'cp.bin' + Asm 'zsdos' -Output 'dos.bin' +} + +Asm 'syscfg' +Asm 'cbios' "-dBLD_SYS=SYS_${SYS}" +Asm 'dbgmon' +Asm 'prefix' +Asm 'bootrom' +Asm 'bootapp' +Asm 'loader' +Asm 'pgzero' +Asm 'bnk1' +Asm 'hbfill' +Asm 'romfill' + +# Generate result files using components above + +"Building ${RomName} output files..." + +Concat 'cp.bin','dos.bin','cbios.bin' 'os.bin' +Concat 'prefix.bin','os.bin' $SysImgFile +Concat 'pgzero.bin','bootrom.bin','syscfg.bin','loader.bin','romfill.bin','dbgmon.bin','os.bin','hbfill.bin' 'rom0.bin' +Concat 'pgzero.bin','bootrom.bin','syscfg.bin','loader.bin','bnk1.bin' 'rom1.bin' +Concat 'bootapp.bin','syscfg.bin','loader.bin','bnk1.bin','dbgmon.bin','os.bin' $LoaderFile + +# Create the RomDisk image + +"Building ${RomSize}KB ${RomName} ROM disk data file..." + +Copy-Item $BlankFile $RomDiskFile +cpmcp -f $RomFmt $RomDiskFile ../RomDsk/${SYS}_${RomSize}KB/*.* 0: +cpmcp -f $RomFmt $RomDiskFile ../RomDsk/cfg_${Config}/*.* 0: +cpmcp -f $RomFmt $RomDiskFile ../Apps/core/*.* 0: +cpmcp -f $RomFmt $RomDiskFile ../Output/${RomName}.sys 0:${SYS}.sys + +Concat 'rom0.bin','rom1.bin',$RomDiskFile $RomFile + +# Cleanup +Remove-Item $RomDiskFile \ No newline at end of file diff --git a/trunk/Source/Clean.cmd b/trunk/Source/Clean.cmd new file mode 100644 index 00000000..c354d414 --- /dev/null +++ b/trunk/Source/Clean.cmd @@ -0,0 +1,10 @@ +@echo off +if exist *.bin del *.bin +if exist *.com del *.com +if exist *.img del *.img +if exist *.rom del *.rom +if exist *.lst del *.lst +if exist *.exp del *.exp +if exist *.tmp del *.tmp +if exist *.mrk del *.mrk +if exist build.inc del build.inc \ No newline at end of file diff --git a/trunk/Source/Make.cmd b/trunk/Source/Make.cmd new file mode 100644 index 00000000..c161db34 --- /dev/null +++ b/trunk/Source/Make.cmd @@ -0,0 +1 @@ +@..\tools\gcc\mingw32-make %* \ No newline at end of file diff --git a/trunk/Source/MakeBlankROM.ps1 b/trunk/Source/MakeBlankROM.ps1 new file mode 100644 index 00000000..1bf64ea9 --- /dev/null +++ b/trunk/Source/MakeBlankROM.ps1 @@ -0,0 +1,4 @@ +# Create a "dummy" rom image, filled with hex E5 +# +Set-Content -Value ([byte[]](0xE5) * (512KB - 64KB)) -Encoding byte -Path 'blank512KB.dat' +Set-Content -Value ([byte[]](0xE5) * (1MB - 64KB)) -Encoding byte -Path 'blank1024KB.dat' \ No newline at end of file diff --git a/trunk/Source/bdosb01.asm b/trunk/Source/bdosb01.asm new file mode 100644 index 00000000..d468861a --- /dev/null +++ b/trunk/Source/bdosb01.asm @@ -0,0 +1,2586 @@ + .title "Digital Research BDOS, Version 2.2" + .page 49 + +ENDFIL .EQU 1 ;FILL FULL BDOS LENGTH +; +IOBYTE: .EQU 3 ; I/O DEFINITION BYTE. +TDRIVE: .EQU 4 ; CURRENT DRIVE NAME AND USER NUMBER. +ENTRY: .EQU 5 ; ENTRY POINT FOR THE CP/M BDOS. +TFCB: .EQU 5CH ; DEFAULT FILE CONTROL BLOCK. +TBUFF: .EQU 80H ; I/O BUFFER AND COMMAND LINE STORAGE. +TBASE: .EQU 100H ; TRANSIANT PROGRAM STORAGE AREA. +; +; SET CONTROL CHARACTER .EQUATES. +; +CNTRLC: .EQU 3 ; CONTROL-C +CNTRLE: .EQU 05H ; CONTROL-E +BS: .EQU 08H ; BACKSPACE +TAB: .EQU 09H ; TAB +LF: .EQU 0AH ; LINE FEED +FF: .EQU 0CH ; FORM FEED +CR: .EQU 0DH ; CARRIAGE RETURN +CNTRLP: .EQU 10H ; CONTROL-P +CNTRLR: .EQU 12H ; CONTROL-R +CNTRLS: .EQU 13H ; CONTROL-S +CNTRLU: .EQU 15H ; CONTROL-U +CNTRLX: .EQU 18H ; CONTROL-X +CNTRLZ: .EQU 1AH ; CONTROL-Z (END-OF-FILE MARK) +DEL: .EQU 7FH ; RUBOUT + +; CPM ORIGIN CALCULATE + +NK .EQU 59 ;SYSTEM SIZE +BASE .EQU (NK*1024)-5000H +CCPO .EQU BASE+3400H ;CCP ORIGIN +BDOSO .EQU BASE+3C00H ;BDOS ORIGIN +BIOSO .EQU BASE+4A00H ;BIOS ORIGIN + + .ORG BDOSO + .DB 0,0,0,0,0,0 ;OLD SERIAL NUMBER +; +;************************************************************** +;* +;* B D O S E N T R Y +;* +;************************************************************** +; +FBASE: JP FBASE1 +; +; BDOS ERROR TABLE. +; +BADSCTR:.DW ERROR1 ; BAD SECTOR ON READ OR WRITE. +BADSLCT:.DW ERROR2 ; BAD DISK SELECT. +RODISK: .DW ERROR3 ; DISK IS READ ONLY. +ROFILE: .DW ERROR4 ; FILE IS READ ONLY. +; +; ENTRY INTO BDOS. (DE) OR (E) ARE THE PARAMETERS PASSED. THE +; FUNCTION NUMBER DESIRED IS IN REGISTER (C). +; E contains drive number if passing this +FBASE1: EX DE,HL ; SAVE THE (DE) PARAMETERS. + LD (PARAMS),HL + EX DE,HL + LD A,E ; AND SAVE REGISTER (E) IN PARTICULAR. + LD (EPARAM),A + LD HL,0 + LD (STATUS),HL ; CLEAR RETURN STATUS. + ADD HL,SP + LD (USRSTACK),HL ; SAVE USERS STACK POINTER. + LD SP,STKAREA ; AND SET OUR OWN. + XOR A ; CLEAR AUTO SELECT STORAGE SPACE. + LD (AUTOFLAG),A + LD (AUTO),A + LD HL,GOBACK ; SET RETURN ADDRESS. + PUSH HL + LD A,C ; GET FUNCTION NUMBER. + CP NFUNCTS ; VALID FUNCTION NUMBER? + RET NC + LD C,E ; KEEP SINGLE REGISTER FUNCTION HERE. + LD HL,FUNCTNS ; NOW LOOK THRU THE FUNCTION TABLE. + LD E,A + LD D,0 ; (DE)=FUNCTION NUMBER. + ADD HL,DE + ADD HL,DE ; (HL)=(START OF TABLE)+2*(FUNCTION NUMBER). + LD E,(HL) + INC HL + LD D,(HL) ; NOW (DE)=ADDRESS FOR THIS FUNCTION. + LD HL,(PARAMS) ; RETRIEVE PARAMETERS. + EX DE,HL ; NOW (DE) HAS THE ORIGINAL PARAMETERS. + JP (HL) ; EXECUTE DESIRED FUNCTION. +; +; BDOS FUNCTION JUMP TABLE. +; +NFUNCTS:.EQU 41 ; NUMBER OF FUNCTIONS IN FOLLOWIN TABLE. +; +FUNCTNS:.DW WBOOT,GETCON,OUTCON,GETRDR,PUNCH,LIST,DIRCIO,GETIOB + .DW SETIOB,PRTSTR,R.DBUFF,GETCSTS,GETVER,RSTDSK,SETDSK,OPENFIL + .DW CLOSEFIL,GETFST,GETNXT,DELFILE,READSEQ,WRTSEQ,FCREATE + .DW RENFILE,GETLOG,GETCRNT,PUTDMA,GETALOC,WRTPRTD,GETROV,SETATTR + .DW GETPARM,GETUSER,RDRANDOM,WTRANDOM,FILESIZE,SETRAN,LOGOFF,RTN + .DW RTN,WTSPECL +; +; BDOS ERROR MESSAGE SECTION. +; +ERROR1: LD HL,BADSEC ; BAD SECTOR MESSAGE. + CALL PRTERR ; PRINT IT AND GET A 1 CHAR RESPONCE. + CP CNTRLC ; RE-BOOT REQUEST (CONTROL-C)? + JP Z,0 ; YES. + RET ; NO, RETURN TO RETRY I/O FUNCTION. + +ERROR2: LD HL,BADSEL ; BAD DRIVE SELECTED. + JP ERROR5 +; +ERROR3: LD HL,DISKRO ; DISK IS READ ONLY. + JP ERROR5 +; +ERROR4: LD HL,FILERO ; FILE IS READ ONLY. +; +ERROR5: CALL PRTERR + JP 0 ; ALWAYS REBOOT ON THESE ERRORS. +; +BDOSERR:.DB "BDOS ERR ON " +BDOSDRV:.DB " : $" +BADSEC: .DB "BAD SECTOR$" +BADSEL: .DB "SELECT$" +FILERO: .DB "FILE " +DISKRO: .DB "R/O$" +; +; PRINT BDOS ERROR MESSAGE. +; +PRTERR: PUSH HL ; SAVE SECOND MESSAGE POINTER. + CALL OUTCRLF ; SEND (CR)(LF). + LD A,(ACTIVE) ; GET ACTIVE DRIVE. + ADD A,'A' ; MAKE ASCII. + LD (BDOSDRV),A ; AND PUT IN MESSAGE. + LD BC,BDOSERR ; AND PRINT IT. + CALL PRTMESG + POP BC ; PRINT SECOND MESSAGE LINE NOW. + CALL PRTMESG +; +; GET AN INPUT CHARACTER. WE WILL CHECK OUR 1 CHARACTER +; BUFFER FIRST. THIS MAY BE SET BY THE CONSOLE STATUS ROUTINE. +; +GETCHAR:LD HL,CHARBUF ; CHECK CHARACTER BUFFER. + LD A,(HL) ; ANYTHING PRESENT ALREADY? + LD (HL),0 ; ...EITHER CASE CLEAR IT. + OR A + RET NZ ; YES, USE IT. + JP CONIN ; NOPE, GO GET A CHARACTER RESPONCE. +; +; INPUT AND ECHO A CHARACTER. +; +GETECHO:CALL GETCHAR ; INPUT A CHARACTER. + CALL CHKCHAR ; CARRIAGE CONTROL? + RET C ; NO, A REGULAR CONTROL CHAR SO DON'T ECHO. + PUSH AF ; OK, SAVE CHARACTER NOW. + LD C,A + CALL OUTCON ; AND ECHO IT. + POP AF ; GET CHARACTER AND RETURN. + RET +; +; CHECK CHARACTER IN (A). SET THE ZERO FLAG ON A CARRIAGE +; CONTROL CHARACTER AND THE CARRY FLAG ON ANY OTHER CONTROL +; CHARACTER. +; +CHKCHAR:CP CR ; CHECK FOR CARRIAGE RETURN, LINE FEED, BACKSPACE, + RET Z ; OR A TAB. + CP LF + RET Z + CP TAB + RET Z + CP BS + RET Z + CP ' ' ; OTHER CONTROL CHAR? SET CARRY FLAG. + RET +; +; CHECK THE CONSOLE DURING OUTPUT. HALT ON A CONTROL-S, THEN +; REBOOT ON A CONTROL-C. IF ANYTHING ELSE IS READY, CLEAR THE +; ZERO FLAG AND RETURN (THE CALLING ROUTINE MAY WANT TO DO +; SOMETHING). +; +CKCONSOL: + LD A,(CHARBUF) ; CHECK BUFFER. + OR A ; IF ANYTHING, JUST RETURN WITHOUT CHECKING. + JP NZ,CKCON2 + CALL CONST ; NOTHING IN BUFFER. CHECK CONSOLE. + AND 01H ; LOOK AT BIT 0. + RET Z ; RETURN IF NOTHING. + CALL CONIN ; OK, GET IT. + CP CNTRLS ; IF NOT CONTROL-S, RETURN WITH ZERO CLEARED. + JP NZ,CKCON1 + CALL CONIN ; HALT PROCESSING UNTIL ANOTHER CHAR + CP CNTRLC ; IS TYPED. CONTROL-C? + JP Z,0 ; YES, REBOOT NOW. + XOR A ; NO, JUST PRETEND NOTHING WAS EVER READY. + RET +CKCON1: LD (CHARBUF),A ; SAVE CHARACTER IN BUFFER FOR LATER PROCESSING. +CKCON2: LD A,1 ; SET (A) TO NON ZERO TO MEAN SOMETHING IS READY. + RET +; +; OUTPUT (C) TO THE SCREEN. IF THE PRINTER FLIP-FLOP FLAG +; IS SET, WE WILL SEND CHARACTER TO PRINTER ALSO. THE CONSOLE +; WILL BE CHECKED IN THE PROCESS. +; +OUTCHAR:LD A,(OUTFLAG) ; CHECK OUTPUT FLAG. + OR A ; ANYTHING AND WE WON'T GENERATE OUTPUT. + JP NZ,OUTCHR1 + PUSH BC + CALL CKCONSOL ; CHECK CONSOLE (WE DON'T CARE WHATS THERE). + POP BC + PUSH BC + CALL CONOUT ; OUTPUT (C) TO THE SCREEN. + POP BC + PUSH BC + LD A,(PRTFLAG) ; CHECK PRINTER FLIP-FLOP FLAG. + OR A + CALL NZ,LIST ; PRINT IT ALSO IF NON-ZERO. + POP BC +OUTCHR1:LD A,C ; UPDATE CURSORS POSITION. + LD HL,CURPOS + CP DEL ; RUBOUTS DON'T DO ANYTHING HERE. + RET Z + INC (HL) ; BUMP LINE POINTER. + CP ' ' ; AND RETURN IF A NORMAL CHARACTER. + RET NC + DEC (HL) ; RESTORE AND CHECK FOR THE START OF THE LINE. + LD A,(HL) + OR A + RET Z ; INGNORE CONTROL CHARACTERS AT THE START OF THE LINE. + LD A,C + CP BS ; IS IT A BACKSPACE? + JP NZ,OUTCHR2 + DEC (HL) ; YES, BACKUP POINTER. + RET +OUTCHR2:CP LF ; IS IT A LINE FEED? + RET NZ ; IGNORE ANYTHING ELSE. + LD (HL),0 ; RESET POINTER TO START OF LINE. + RET +; +; OUTPUT (A) TO THE SCREEN. IF IT IS A CONTROL CHARACTER +; (OTHER THAN CARRIAGE CONTROL), USE ^X FORMAT. +; +SHOWIT: LD A,C + CALL CHKCHAR ; CHECK CHARACTER. + JP NC,OUTCON ; NOT A CONTROL, USE NORMAL OUTPUT. + PUSH AF + LD C,'^' ; FOR A CONTROL CHARACTER, PRECEED IT WITH '^'. + CALL OUTCHAR + POP AF + OR '@' ; AND THEN USE THE LETTER .EQUIVELANT. + LD C,A +; +; FUNCTION TO OUTPUT (C) TO THE CONSOLE DEVICE AND EXPAND TABS +; IF NECESSARY. +; +OUTCON: LD A,C + CP TAB ; IS IT A TAB? + JP NZ,OUTCHAR ; USE REGULAR OUTPUT. +OUTCON1:LD C,' ' ; YES IT IS, USE SPACES INSTEAD. + CALL OUTCHAR + LD A,(CURPOS) ; GO UNTIL THE CURSOR IS AT A MULTIPLE OF 8 + + AND 07H ; POSITION. + JP NZ,OUTCON1 + RET +; +; ECHO A BACKSPACE CHARACTER. ERASE THE PREVOIUS CHARACTER +; ON THE SCREEN. +; +BACKUP: CALL BACKUP1 ; BACKUP THE SCREEN 1 PLACE. + LD C,' ' ; THEN BLANK THAT CHARACTER. + CALL CONOUT +BACKUP1:LD C,BS ; THEN BACK SPACE ONCE MORE. + JP CONOUT +; +; SIGNAL A DELETED LINE. PRINT A '#' AT THE END AND START +; OVER. +; +NEWLINE:LD C,'#' + CALL OUTCHAR ; PRINT THIS. + CALL OUTCRLF ; START NEW LINE. +NEWLN1: LD A,(CURPOS) ; MOVE THE CURSOR TO THE STARTING POSITION. + LD HL,STARTING + CP (HL) + RET NC ; THERE YET? + LD C,' ' + CALL OUTCHAR ; NOPE, KEEP GOING. + JP NEWLN1 +; +; OUTPUT A (CR) (LF) TO THE CONSOLE DEVICE (SCREEN). +; +OUTCRLF:LD C,CR + CALL OUTCHAR + LD C,LF + JP OUTCHAR +; +; PRINT MESSAGE POINTED TO BY (BC). IT WILL END WITH A '$'. +; +PRTMESG:LD A,(BC) ; CHECK FOR TERMINATING CHARACTER. + CP '$' + RET Z + INC BC + PUSH BC ; OTHERWISE, BUMP POINTER AND PRINT IT. + LD C,A + CALL OUTCON + POP BC + JP PRTMESG +; +; FUNCTION TO EXECUTE A BUFFERED READ. +; +R.DBUFF: LD A,(CURPOS) ; USE PRESENT LOCATION AS STARTING ONE. + LD (STARTING),A + LD HL,(PARAMS) ; GET THE MAXIMUM BUFFER SPACE. + LD C,(HL) + INC HL ; POINT TO FIRST AVAILABLE SPACE. + PUSH HL ; AND SAVE. + LD B,0 ; KEEP A CHARACTER COUNT. +R.DBUF1: PUSH BC + PUSH HL +R.DBUF2: CALL GETCHAR ; GET THE NEXT INPUT CHARACTER. + AND 7FH ; STRIP BIT 7. + POP HL ; RESET REGISTERS. + POP BC + CP CR ; EN OF THE LINE? + JP Z,R.DBUF17 + CP LF + JP Z,R.DBUF17 + CP BS ; HOW ABOUT A BACKSPACE? + JP NZ,R.DBUF3 + LD A,B ; YES, BUT IGNORE AT THE BEGINNING OF THE LINE. + OR A + JP Z,R.DBUF1 + DEC B ; OK, UPDATE COUNTER. + LD A,(CURPOS) ; IF WE BACKSPACE TO THE START OF THE LINE, + LD (OUTFLAG),A ; TREAT AS A CANCEL (CONTROL-X). + JP R.DBUF10 +R.DBUF3: CP DEL ; USER TYPED A RUBOUT? + JP NZ,R.DBUF4 + LD A,B ; IGNORE AT THE START OF THE LINE. + OR A + JP Z,R.DBUF1 + LD A,(HL) ; OK, ECHO THE PREVOIUS CHARACTER. + DEC B ; AND RESET POINTERS (COUNTERS). + DEC HL + JP R.DBUF15 +R.DBUF4: CP CNTRLE ; PHYSICAL END OF LINE? + JP NZ,R.DBUF5 + PUSH BC ; YES, DO IT. + PUSH HL + CALL OUTCRLF + XOR A ; AND UPDATE STARTING POSITION. + LD (STARTING),A + JP R.DBUF2 +R.DBUF5: CP CNTRLP ; CONTROL-P? + JP NZ,R.DBUF6 + PUSH HL ; YES, FLIP THE PRINT FLAG FILP-FLOP BYTE. + LD HL,PRTFLAG + LD A,1 ; PRTFLAG=1-PRTFLAG + SUB (HL) + LD (HL),A + POP HL + JP R.DBUF1 +R.DBUF6: CP CNTRLX ; CONTROL-X (CANCEL)? + JP NZ,R.DBUF8 + POP HL +R.DBUF7: LD A,(STARTING) ; YES, BACKUP THE CURSOR TO HERE. + LD HL,CURPOS + CP (HL) + JP NC,R.DBUFF ; DONE YET? + DEC (HL) ; NO, DECREMENT POINTER AND OUTPUT BACK UP ONE SPACE. + CALL BACKUP + JP R.DBUF7 +R.DBUF8: CP CNTRLU ; CNTROL-U (CANCEL LINE)? + JP NZ,R.DBUF9 + CALL NEWLINE ; START A NEW LINE. + POP HL + JP R.DBUFF +R.DBUF9: CP CNTRLR ; CONTROL-R? + JP NZ,R.DBUF14 +R.DBUF10:PUSH BC ; YES, START A NEW LINE AND RETYPE THE OLD ONE. + CALL NEWLINE + POP BC + POP HL + PUSH HL + PUSH BC +R.DBUF11:LD A,B ; DONE WHOLE LINE YET? + OR A + JP Z,R.DBUF12 + INC HL ; NOPE, GET NEXT CHARACTER. + LD C,(HL) + DEC B ; COUNT IT. + PUSH BC + PUSH HL + CALL SHOWIT ; AND DISPLAY IT. + POP HL + POP BC + JP R.DBUF11 +R.DBUF12:PUSH HL ; DONE WITH LINE. IF WE WERE DISPLAYING + LD A,(OUTFLAG) ; THEN UPDATE CURSOR POSITION. + OR A + JP Z,R.DBUF2 + LD HL,CURPOS ; BECAUSE THIS LINE IS SHORTER, WE MUST + SUB (HL) ; BACK UP THE CURSOR (NOT THE SCREEN HOWEVER) + LD (OUTFLAG),A ; SOME NUMBER OF POSITIONS. +R.DBUF13:CALL BACKUP ; NOTE THAT AS LONG AS (OUTFLAG) IS NON + LD HL,OUTFLAG ; ZERO, THE SCREEN WILL NOT BE CHANGED. + DEC (HL) + JP NZ,R.DBUF13 + JP R.DBUF2 ; NOW JUST GET THE NEXT CHARACTER. +; +; JUST A NORMAL CHARACTER, PUT THIS IN OUR BUFFER AND ECHO. +; +R.DBUF14:INC HL + LD (HL),A ; STORE CHARACTER. + INC B ; AND COUNT IT. +R.DBUF15:PUSH BC + PUSH HL + LD C,A ; ECHO IT NOW. + CALL SHOWIT + POP HL + POP BC + LD A,(HL) ; WAS IT AN ABORT REQUEST? + CP CNTRLC ; CONTROL-C ABORT? + LD A,B + JP NZ,R.DBUF16 + CP 1 ; ONLY IF AT START OF LINE. + JP Z,0 +R.DBUF16:CP C ; NOPE, HAVE WE FILLED THE BUFFER? + JP C,R.DBUF1 +R.DBUF17:POP HL ; YES END THE LINE AND RETURN. + LD (HL),B + LD C,CR + JP OUTCHAR ; OUTPUT (CR) AND RETURN. +; +; FUNCTION TO GET A CHARACTER FROM THE CONSOLE DEVICE. +; +GETCON: CALL GETECHO ; GET AND ECHO. + JP SETSTAT ; SAVE STATUS AND RETURN. +; +; FUNCTION TO GET A CHARACTER FROM THE TAPE READER DEVICE. +; +GETRDR: CALL READER ; GET A CHARACTER FROM READER, SET STATUS AND RETURN. + JP SETSTAT +; +; FUNCTION TO PERFORM DIRECT CONSOLE I/O. IF (C) CONTAINS (FF) +; THEN THIS IS AN INPUT REQUEST. IF (C) CONTAINS (FE) THEN +; THIS IS A STATUS REQUEST. OTHERWISE WE ARE TO OUTPUT (C). +; +DIRCIO: LD A,C ; TEST FOR (FF). + INC A + JP Z,DIRC1 + INC A ; TEST FOR (FE). + JP Z,CONST + JP CONOUT ; JUST OUTPUT (C). +DIRC1: CALL CONST ; THIS IS AN INPUT REQUEST. + OR A + JP Z,GOBACK1 ; NOT READY? JUST RETURN (DIRECTLY). + CALL CONIN ; YES, GET CHARACTER. + JP SETSTAT ; SET STATUS AND RETURN. +; +; FUNCTION TO RETURN THE I/O BYTE. +; +GETIOB: LD A,(IOBYTE) + JP SETSTAT +; +; FUNCTION TO SET THE I/O BYTE. +; +SETIOB: LD HL,IOBYTE + LD (HL),C + RET +; +; FUNCTION TO PRINT THE CHARACTER STRING POINTED TO BY (DE) +; ON THE CONSOLE DEVICE. THE STRING ENDS WITH A '$'. +; +PRTSTR: EX DE,HL + LD C,L + LD B,H ; NOW (BC) POINTS TO IT. + JP PRTMESG +; +; FUNCTION TO INTERIGATE THE CONSOLE DEVICE. +; +GETCSTS:CALL CKCONSOL +; +; GET HERE TO SET THE STATUS AND RETURN TO THE CLEANUP +; SECTION. THEN BACK TO THE USER. +; +SETSTAT:LD (STATUS),A +RTN: RET +; +; SET THE STATUS TO 1 (READ OR WRITE ERROR CODE). +; +IOERR1: LD A,1 + JP SETSTAT +; +OUTFLAG:.DB 0 ; OUTPUT FLAG (NON ZERO MEANS NO OUTPUT). +STARTING: + .DB 2 ; STARTING POSITION FOR CURSOR. +CURPOS: .DB 0 ; CURSOR POSITION (0=START OF LINE). +PRTFLAG:.DB 0 ; PRINTER FLAG (CONTROL-P TOGGLE). LIST IF NON ZERO. +CHARBUF:.DB 0 ; SINGLE INPUT CHARACTER BUFFER. +; +; STACK AREA FOR BDOS CALLS. +; +USRSTACK: + .DW 0 ; SAVE USERS STACK POINTER HERE. +; + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +STKAREA:.EQU $ ; END OF STACK AREA. +; +USERNO: .DB 0 ; CURRENT USER NUMBER. +ACTIVE: .DB 0 ; CURRENTLY ACTIVE DRIVE. +PARAMS: .DW 0 ; SAVE (DE) PARAMETERS HERE ON ENTRY. +STATUS: .DW 0 ; STATUS RETURNED FROM BDOS FUNCTION. +; +; SELECT ERROR OCCURED, JUMP TO ERROR ROUTINE. +; +SLCTERR:LD HL,BADSLCT +; +; JUMP TO (HL) INDIRECTLY. +; +JUMPHL: LD E,(HL) + INC HL + LD D,(HL) ; NOW (DE) CONTAIN THE DESIRED ADDRESS. + EX DE,HL + JP (HL) +; +; BLOCK MOVE. (DE) TO (HL), (C) BYTES TOTAL. +; +DE2HL: INC C ; IS COUNT DOWN TO ZERO? +DE2HL1: DEC C + RET Z ; YES, WE ARE DONE. + LD A,(DE) ; NO, MOVE ONE MORE BYTE. + LD (HL),A + INC DE + INC HL + JP DE2HL1 ; AND REPEAT. +; +; SELECT THE DESIRED DRIVE. +; +SELECT: LD A,(ACTIVE) ; GET ACTIVE DISK. + LD C,A + CALL SELDSK ; SELECT IT. + LD A,H ; VALID DRIVE? + OR L ; VALID DRIVE? + RET Z ; RETURN IF NOT. +; +; HERE, THE BIOS RETURNED THE ADDRESS OF THE PARAMETER BLOCK +; IN (HL). WE WILL EXTRACT THE NECESSARY POINTERS AND SAVE THEM. +; + LD E,(HL) ; YES, GET ADDRESS OF TRANSLATION TABLE INTO (DE). + INC HL + LD D,(HL) + INC HL + LD (SCRATCH1),HL ; SAVE POINTERS TO SCRATCH AREAS. + INC HL + INC HL + LD (SCRATCH2),HL ; DITTO. + INC HL + INC HL + LD (SCRATCH3),HL ; DITTO. + INC HL + INC HL + EX DE,HL ; NOW SAVE THE TRANSLATION TABLE ADDRESS. + LD (XLATE),HL + LD HL,DIRBUF ; PUT THE NEXT 8 BYTES HERE. + LD C,8 ; THEY CONSIST OF THE DIRECTORY BUFFER + CALL DE2HL ; POINTER, PARAMETER BLOCK POINTER, + LD HL,(DISKPB) ; CHECK AND ALLOCATION VECTORS. + EX DE,HL + LD HL,SECTORS ; MOVE PARAMETER BLOCK INTO OUR RAM. + LD C,15 ; IT IS 15 BYTES LONG. + CALL DE2HL + LD HL,(DSKSIZE) ; CHECK DISK SIZE. + LD A,H ; MORE THAN 256 BLOCKS ON THIS? + LD HL,BIGDISK + LD (HL),0FFH ; SET TO SAMLL. + OR A + JP Z,SELECT1 + LD (HL),0 ; WRONG, SET TO LARGE. +SELECT1:LD A,0FFH ; CLEAR THE ZERO FLAG. + OR A + RET +; +; ROUTINE TO HOME THE DISK TRACK HEAD AND CLEAR POINTERS. +; +HOMEDRV:CALL HOME ; HOME THE HEAD. + XOR A + LD HL,(SCRATCH2) ; SET OUR TRACK POINTER ALSO. + LD (HL),A + INC HL + LD (HL),A + LD HL,(SCRATCH3) ; AND OUR SECTOR POINTER. + LD (HL),A + INC HL + LD (HL),A + RET +; +; DO THE ACTUAL DISK READ AND CHECK THE ERROR RETURN STATUS. +; +DOREAD: CALL READ + JP IORET +; +; DO THE ACTUAL DISK WRITE AND HANDLE ANY BIOS ERROR. +; +DOWRITE:CALL WRITE +IORET: OR A + RET Z ; RETURN UNLESS AN ERROR OCCURED. + LD HL,BADSCTR ; BAD READ/WRITE ON THIS SECTOR. + JP JUMPHL +; +; ROUTINE TO SELECT THE TRACK AND SECTOR THAT THE DESIRED +; BLOCK NUMBER FALLS IN. +; +TRKSEC: LD HL,(FILEPOS) ; GET POSITION OF LAST ACCESSED FILE + LD C,2 ; IN DIRECTORY AND COMPUTE SECTOR #. + CALL SHIFTR ; SECTOR #=FILE-POSITION/4. + LD (BLKNMBR),HL ; SAVE THIS AS THE BLOCK NUMBER OF INTEREST. + LD (CKSUMTBL),HL ; WHAT'S IT DOING HERE TOO? +; +; IF THE SECTOR NUMBER HAS ALREADY BEEN SET (BLKNMBR), ENTER +; AT THIS POINT. +; +TRKSEC1:LD HL,BLKNMBR + LD C,(HL) ; MOVE SECTOR NUMBER INTO (BC). + INC HL + LD B,(HL) + LD HL,(SCRATCH3) ; GET CURRENT SECTOR NUMBER AND + LD E,(HL) ; MOVE THIS INTO (DE). + INC HL + LD D,(HL) + LD HL,(SCRATCH2) ; GET CURRENT TRACK NUMBER. + LD A,(HL) ; AND THIS INTO (HL). + INC HL + LD H,(HL) + LD L,A +TRKSEC2:LD A,C ; IS DESIRED SECTOR BEFORE CURRENT ONE? + SUB E + LD A,B + SBC A,D + JP NC,TRKSEC3 + PUSH HL ; YES, DECREMENT SECTORS BY ONE TRACK. + LD HL,(SECTORS) ; GET SECTORS PER TRACK. + LD A,E + SUB L + LD E,A + LD A,D + SBC A,H + LD D,A ; NOW WE HAVE BACKED UP ONE FULL TRACK. + POP HL + DEC HL ; ADJUST TRACK COUNTER. + JP TRKSEC2 +TRKSEC3:PUSH HL ; DESIRED SECTOR IS AFTER CURRENT ONE. + LD HL,(SECTORS) ; GET SECTORS PER TRACK. + ADD HL,DE ; BUMP SECTOR POINTER TO NEXT TRACK. + JP C,TRKSEC4 + LD A,C ; IS DESIRED SECTOR NOW BEFORE CURRENT ONE? + SUB L + LD A,B + SBC A,H + JP C,TRKSEC4 + EX DE,HL ; NOT YES, INCREMENT TRACK COUNTER + POP HL ; AND CONTINUE UNTIL IT IS. + INC HL + JP TRKSEC3 +; +; HERE WE HAVE DETERMINED THE TRACK NUMBER THAT CONTAINS THE +; DESIRED SECTOR. +; +TRKSEC4:POP HL ; GET TRACK NUMBER (HL). + PUSH BC + PUSH DE + PUSH HL + EX DE,HL + LD HL,(OFFSET) ; ADJUST FOR FIRST TRACK OFFSET. + ADD HL,DE + LD B,H + LD C,L + CALL SETTRK ; SELECT THIS TRACK. + POP DE ; RESET CURRENT TRACK POINTER. + LD HL,(SCRATCH2) + LD (HL),E + INC HL + LD (HL),D + POP DE + LD HL,(SCRATCH3) ; RESET THE FIRST SECTOR ON THIS TRACK. + LD (HL),E + INC HL + LD (HL),D + POP BC + LD A,C ; NOW SUBTRACT THE DESIRED ONE. + SUB E ; TO MAKE IT RELATIVE (1-# SECTORS/TRACK). + LD C,A + LD A,B + SBC A,D + LD B,A + LD HL,(XLATE) ; TRANSLATE THIS SECTOR ACCORDING TO THIS TABLE. + EX DE,HL + CALL SECTRN ; LET THE BIOS TRANSLATE IT. + LD C,L + LD B,H + JP SETSEC ; AND SELECT IT. +; +; COMPUTE BLOCK NUMBER FROM RECORD NUMBER (SAVNREC) AND +; EXTENT NUMBER (SAVEXT). +; +GETBLOCK: + LD HL,BLKSHFT ; GET LOGICAL TO PHYSICAL CONVERSION. + LD C,(HL) ; NOTE THAT THIS IS BASE 2 LOG OF RATIO. + LD A,(SAVNREC) ; GET RECORD NUMBER. +GETBLK1:OR A ; COMPUTE (A)=(A)/2^BLKSHFT. + RRA + DEC C + JP NZ,GETBLK1 + LD B,A ; SAVE RESULT IN (B). + LD A,8 + SUB (HL) + LD C,A ; COMPUTE (C)=8-BLKSHFT. + LD A,(SAVEXT) +GETBLK2:DEC C ; COMPUTE (A)=SAVEXT*2^(8-BLKSHFT). + JP Z,GETBLK3 + OR A + RLA + JP GETBLK2 +GETBLK3:ADD A,B + RET +; +; ROUTINE TO EXTRACT THE (BC) BLOCK BYTE FROM THE FCB POINTED +; TO BY (PARAMS). IF THIS IS A BIG-DISK, THEN THESE ARE 16 BIT +; BLOCK NUMBERS, ELSE THEY ARE 8 BIT NUMBERS. +; NUMBER IS RETURNED IN (HL). +; +EXTBLK: LD HL,(PARAMS) ; GET FCB ADDRESS. + LD DE,16 ; BLOCK NUMBERS START 16 BYTES INTO FCB. + ADD HL,DE + ADD HL,BC + LD A,(BIGDISK) ; ARE WE USING A BIG-DISK? + OR A + JP Z,EXTBLK1 + LD L,(HL) ; NO, EXTRACT AN 8 BIT NUMBER FROM THE FCB. + LD H,0 + RET +EXTBLK1:ADD HL,BC ; YES, EXTRACT A 16 BIT NUMBER. + LD E,(HL) + INC HL + LD D,(HL) + EX DE,HL ; RETURN IN (HL). + RET +; +; COMPUTE BLOCK NUMBER. +; +COMBLK: CALL GETBLOCK + LD C,A + LD B,0 + CALL EXTBLK + LD (BLKNMBR),HL + RET +; +; CHECK FOR A ZERO BLOCK NUMBER (UNUSED). +; +CHKBLK: LD HL,(BLKNMBR) + LD A,L ; IS IT ZERO? + OR H + RET +; +; ADJUST PHYSICAL BLOCK (BLKNMBR) AND CONVERT TO LOGICAL +; SECTOR (LOGSECT). THIS IS THE STARTING SECTOR OF THIS BLOCK. +; THE ACTUAL SECTOR OF INTEREST IS THEN ADDED TO THIS AND THE +; RESULTING SECTOR NUMBER IS STORED BACK IN (BLKNMBR). THIS +; WILL STILL HAVE TO BE ADJUSTED FOR THE TRACK NUMBER. +; +LOGICAL:LD A,(BLKSHFT) ; GET LOG2(PHYSICAL/LOGICAL SECTORS). + LD HL,(BLKNMBR) ; GET PHYSICAL SECTOR DESIRED. +LOGICL1:ADD HL,HL ; COMPUTE LOGICAL SECTOR NUMBER. + DEC A ; NOTE LOGICAL SECTORS ARE 128 BYTES LONG. + JP NZ,LOGICL1 + LD (LOGSECT),HL ; SAVE LOGICAL SECTOR. + LD A,(BLKMASK) ; GET BLOCK MASK. + LD C,A + LD A,(SAVNREC) ; GET NEXT SECTOR TO ACCESS. + AND C ; EXTRACT THE RELATIVE POSITION WITHIN PHYSICAL BLOCK. + OR L ; AND ADD IT TOO LOGICAL SECTOR. + LD L,A + LD (BLKNMBR),HL ; AND STORE. + RET +; +; SET (HL) TO POINT TO EXTENT BYTE IN FCB. +; +SETEXT: LD HL,(PARAMS) + LD DE,12 ; IT IS THE TWELTH BYTE. + ADD HL,DE + RET +; +; SET (HL) TO POINT TO RECORD COUNT BYTE IN FCB AND (DE) TO +; NEXT RECORD NUMBER BYTE. +; +SETHLDE:LD HL,(PARAMS) + LD DE,15 ; RECORD COUNT BYTE (#15). + ADD HL,DE + EX DE,HL + LD HL,17 ; NEXT RECORD NUMBER (#32). + ADD HL,DE + RET +; +; SAVE CURRENT FILE DATA FROM FCB. +; +STRDATA:CALL SETHLDE + LD A,(HL) ; GET AND STORE RECORD COUNT BYTE. + LD (SAVNREC),A + EX DE,HL + LD A,(HL) ; GET AND STORE NEXT RECORD NUMBER BYTE. + LD (SAVNXT),A + CALL SETEXT ; POINT TO EXTENT BYTE. + LD A,(EXTMASK) ; GET EXTENT MASK. + AND (HL) + LD (SAVEXT),A ; AND SAVE EXTENT HERE. + RET +; +; SET THE NEXT RECORD TO ACCESS. IF (MODE) IS SET TO 2, THEN +; THE LAST RECORD BYTE (SAVNREC) HAS THE CORRECT NUMBER TO ACCESS. +; FOR S.EQUENTIAL ACCESS, (MODE) WILL BE .EQUAL TO 1. +; +SETNREC:CALL SETHLDE + LD A,(MODE) ; GET S.EQUENTIAL FLAG (=1). + CP 2 ; A 2 INDICATES THAT NO ADDER IS NEEDED. + JP NZ,STNREC1 + XOR A ; CLEAR ADDER (RANDOM ACCESS?). +STNREC1:LD C,A + LD A,(SAVNREC) ; GET LAST RECORD NUMBER. + ADD A,C ; INCREMENT RECORD COUNT. + LD (HL),A ; AND SET FCB'S NEXT RECORD BYTE. + EX DE,HL + LD A,(SAVNXT) ; GET NEXT RECORD BYTE FROM STORAGE. + LD (HL),A ; AND PUT THIS INTO FCB AS NUMBER OF RECORDS USED. + RET +; +; SHIFT (HL) RIGHT (C) BITS. +; +SHIFTR: INC C +SHIFTR1:DEC C + RET Z + LD A,H + OR A + RRA + LD H,A + LD A,L + RRA + LD L,A + JP SHIFTR1 +; +; COMPUTE THE CHECK-SUM FOR THE DIRECTORY BUFFER. RETURN +; INTEGER SUM IN (A). +; +CHECKSUM: + LD C,128 ; LENGTH OF BUFFER. + LD HL,(DIRBUF) ; GET ITS LOCATION. + XOR A ; CLEAR SUMMATION BYTE. +CHKSUM1:ADD A,(HL) ; AND COMPUTE SUM IGNORING CARRIES. + INC HL + DEC C + JP NZ,CHKSUM1 + RET +; +; SHIFT (HL) LEFT (C) BITS. +; +SHIFTL: INC C +SHIFTL1:DEC C + RET Z + ADD HL,HL ; SHIFT LEFT 1 BIT. + JP SHIFTL1 +; +; ROUTINE TO SET A BIT IN A 16 BIT VALUE CONTAINED IN (BC). +; THE BIT SET DEPENDS ON THE CURRENT DRIVE SELECTION. +; +SETBIT: PUSH BC ; SAVE 16 BIT WORD. + LD A,(ACTIVE) ; GET ACTIVE DRIVE. + LD C,A + LD HL,1 + CALL SHIFTL ; SHIFT BIT 0 INTO PLACE. + POP BC ; NOW 'OR' THIS WITH THE ORIGINAL WORD. + LD A,C + OR L + LD L,A ; LOW BYTE DONE, DO HIGH BYTE. + LD A,B + OR H + LD H,A + RET +; +; EXTRACT THE WRITE PROTECT STATUS BIT FOR THE CURRENT DRIVE. +; THE RESULT IS RETURNED IN (A), BIT 0. +; +GETWPRT:LD HL,(WRTPRT) ; GET STATUS BYTES. + LD A,(ACTIVE) ; WHICH DRIVE IS CURRENT? + LD C,A + CALL SHIFTR ; SHIFT STATUS SUCH THAT BIT 0 IS THE + LD A,L ; ONE OF INTEREST FOR THIS DRIVE. + AND 01H ; AND ISOLATE IT. + RET +; +; FUNCTION TO WRITE PROTECT THE CURRENT DISK. +; +WRTPRTD:LD HL,WRTPRT ; POINT TO STATUS WORD. + LD C,(HL) ; SET (BC) .EQUAL TO THE STATUS. + INC HL + LD B,(HL) + CALL SETBIT ; AND SET THIS BIT ACCORDING TO CURRENT DRIVE. + LD (WRTPRT),HL ; THEN SAVE. + LD HL,(DIRSIZE) ; NOW SAVE DIRECTORY SIZE LIMIT. + INC HL ; REMEMBER THE LAST ONE. + EX DE,HL + LD HL,(SCRATCH1) ; AND STORE IT HERE. + LD (HL),E ; PUT LOW BYTE. + INC HL + LD (HL),D ; THEN HIGH BYTE. + RET +; +; CHECK FOR A READ ONLY FILE. +; +CHKROFL:CALL FCB2HL ; SET (HL) TO FILE ENTRY IN DIRECTORY BUFFER. +CKROF1: LD DE,9 ; LOOK AT BIT 7 OF THE NINTH BYTE. + ADD HL,DE + LD A,(HL) + RLA + RET NC ; RETURN IF OK. + LD HL,ROFILE ; ELSE, PRINT ERROR MESSAGE AND TERMINATE. + JP JUMPHL +; +; CHECK THE WRITE PROTECT STATUS OF THE ACTIVE DISK. +; +CHKWPRT:CALL GETWPRT + RET Z ; RETURN IF OK. + LD HL,RODISK ; ELSE PRINT MESSAGE AND TERMINATE. + JP JUMPHL +; +; ROUTINE TO SET (HL) POINTING TO THE PROPER ENTRY IN THE +; DIRECTORY BUFFER. +; +FCB2HL: LD HL,(DIRBUF) ; GET ADDRESS OF BUFFER. + LD A,(FCBPOS) ; RELATIVE POSITION OF FILE. +; +; ROUTINE TO ADD (A) TO (HL). +; +ADDA2HL:ADD A,L + LD L,A + RET NC + INC H ; TAKE CARE OF ANY CARRY. + RET +; +; ROUTINE TO GET THE 'S2' BYTE FROM THE FCB SUPPLIED IN +; THE INITIAL PARAMETER SPECIFICATION. +; +GETS2: LD HL,(PARAMS) ; GET ADDRESS OF FCB. + LD DE,14 ; RELATIVE POSITION OF 'S2'. + ADD HL,DE + LD A,(HL) ; EXTRACT THIS BYTE. + RET +; +; CLEAR THE 'S2' BYTE IN THE FCB. +; +CLEARS2:CALL GETS2 ; THIS SETS (HL) POINTING TO IT. + LD (HL),0 ; NOW CLEAR IT. + RET +; +; SET BIT 7 IN THE 'S2' BYTE OF THE FCB. +; +SETS2B7:CALL GETS2 ; GET THE BYTE. + OR 80H ; AND SET BIT 7. + LD (HL),A ; THEN STORE. + RET +; +; COMPARE (FILEPOS) WITH (SCRATCH1) AND SET FLAGS BASED ON +; THE DIFFERENCE. THIS CHECKS TO SEE IF THERE ARE MORE FILE +; NAMES IN THE DIRECTORY. WE ARE AT (FILEPOS) AND THERE ARE +; (SCRATCH1) OF THEM TO CHECK. +; +MOREFLS:LD HL,(FILEPOS) ; WE ARE HERE. + EX DE,HL + LD HL,(SCRATCH1) ; AND DON'T GO PAST HERE. + LD A,E ; COMPUTE DIFFERENCE BUT DON'T KEEP. + SUB (HL) + INC HL + LD A,D + SBC A,(HL) ; SET CARRY IF NO MORE NAMES. + RET +; +; CALL THIS ROUTINE TO PREVENT (SCRATCH1) FROM BEING GREATER +; THAN (FILEPOS). +; +CHKNMBR:CALL MOREFLS ; SCRATCH1 TOO BIG? + RET C + INC DE ; YES, RESET IT TO (FILEPOS). + LD (HL),D + DEC HL + LD (HL),E + RET +; +; COMPUTE (HL)=(DE)-(HL) +; +SUBHL: LD A,E ; COMPUTE DIFFERENCE. + SUB L + LD L,A ; STORE LOW BYTE. + LD A,D + SBC A,H + LD H,A ; AND THEN HIGH BYTE. + RET +; +; SET THE DIRECTORY CHECKSUM BYTE. +; +SETDIR: LD C,0FFH +; +; ROUTINE TO SET OR COMPARE THE DIRECTORY CHECKSUM BYTE. IF +; (C)=0FFH, THEN THIS WILL SET THE CHECKSUM BYTE. ELSE THE BYTE +; WILL BE CHECKED. IF THE CHECK FAILS (THE DISK HAS BEEN CHANGED), +; THEN THIS DISK WILL BE WRITE PROTECTED. +; +CHECKDIR: + LD HL,(CKSUMTBL) + EX DE,HL + LD HL,(ALLOC1) + CALL SUBHL + RET NC ; OK IF (CKSUMTBL) > (ALLOC1), SO RETURN. + PUSH BC + CALL CHECKSUM ; ELSE COMPUTE CHECKSUM. + LD HL,(CHKVECT) ; GET ADDRESS OF CHECKSUM TABLE. + EX DE,HL + LD HL,(CKSUMTBL) + ADD HL,DE ; SET (HL) TO POINT TO BYTE FOR THIS DRIVE. + POP BC + INC C ; SET OR CHECK ? + JP Z,CHKDIR1 + CP (HL) ; CHECK THEM. + RET Z ; RETURN IF THEY ARE THE SAME. + CALL MOREFLS ; NOT THE SAME, DO WE CARE? + RET NC + CALL WRTPRTD ; YES, MARK THIS AS WRITE PROTECTED. + RET +CHKDIR1:LD (HL),A ; JUST SET THE BYTE. + RET +; +; DO A WRITE TO THE DIRECTORY OF THE CURRENT DISK. +; +DIRWRITE: + CALL SETDIR ; SET CHECKSUM BYTE. + CALL DIRDMA ; SET DIRECTORY DMA ADDRESS. + LD C,1 ; TELL THE BIOS TO ACTUALLY WRITE. + CALL DOWRITE ; THEN DO THE WRITE. + JP DEFDMA +; +; READ FROM THE DIRECTORY. +; +DIRREAD:CALL DIRDMA ; SET THE DIRECTORY DMA ADDRESS. + CALL DOREAD ; AND READ IT. +; +; ROUTINE TO SET THE DMA ADDRESS TO THE USERS CHOICE. +; +DEFDMA: LD HL,USERDMA ; RESET THE DEFAULT DMA ADDRESS AND RETURN. + JP DIRDMA1 +; +; ROUTINE TO SET THE DMA ADDRESS FOR DIRECTORY WORK. +; +DIRDMA: LD HL,DIRBUF +; +; SET THE DMA ADDRESS. ON ENTRY, (HL) POINTS TO +; WORD CONTAINING THE DESIRED DMA ADDRESS. +; +DIRDMA1:LD C,(HL) + INC HL + LD B,(HL) ; SETUP (BC) AND GO TO THE BIOS TO SET IT. + JP SETDMA +; +; MOVE THE DIRECTORY BUFFER INTO USER'S DMA SPACE. +; +MOVEDIR:LD HL,(DIRBUF) ; BUFFER IS LOCATED HERE, AND + EX DE,HL + LD HL,(USERDMA) ; PUT IT HERE. + LD C,128 ; THIS IS ITS LENGTH. + JP DE2HL ; MOVE IT NOW AND RETURN. +; +; CHECK (FILEPOS) AND SET THE ZERO FLAG IF IT .EQUALS 0FFFFH. +; +CKFILPOS: + LD HL,FILEPOS + LD A,(HL) + INC HL + CP (HL) ; ARE BOTH BYTES THE SAME? + RET NZ + INC A ; YES, BUT ARE THEY EACH 0FFH? + RET +; +; SET LOCATION (FILEPOS) TO 0FFFFH. +; +STFILPOS: + LD HL,0FFFFH + LD (FILEPOS),HL + RET +; +; MOVE ON TO THE NEXT FILE POSITION WITHIN THE CURRENT +; DIRECTORY BUFFER. IF NO MORE EXIST, SET POINTER TO 0FFFFH +; AND THE CALLING ROUTINE WILL CHECK FOR THIS. ENTER WITH (C) +; .EQUAL TO 0FFH TO CAUSE THE CHECKSUM BYTE TO BE SET, ELSE WE +; WILL CHECK THIS DISK AND SET WRITE PROTECT IF CHECKSUMS ARE +; NOT THE SAME (APPLIES ONLY IF ANOTHER DIRECTORY SECTOR MUST +; BE READ). +; +NXENTRY:LD HL,(DIRSIZE) ; GET DIRECTORY ENTRY SIZE LIMIT. + EX DE,HL + LD HL,(FILEPOS) ; GET CURRENT COUNT. + INC HL ; GO ON TO THE NEXT ONE. + LD (FILEPOS),HL + CALL SUBHL ; (HL)=(DIRSIZE)-(FILEPOS) + JP NC,NXENT1 ; IS THERE MORE ROOM LEFT? + JP STFILPOS ; NO. SET THIS FLAG AND RETURN. +NXENT1: LD A,(FILEPOS) ; GET FILE POSITION WITHIN DIRECTORY. + AND 03H ; ONLY LOOK WITHIN THIS SECTOR (ONLY 4 ENTRIES FIT). + LD B,5 ; CONVERT TO RELATIVE POSITION (32 BYTES EACH). +NXENT2: ADD A,A ; NOTE THAT THIS IS NOT EFFICIENT CODE. + DEC B ; 5 'ADD A'S WOULD BE BETTER. + JP NZ,NXENT2 + LD (FCBPOS),A ; SAVE IT AS POSITION OF FCB. + OR A + RET NZ ; RETURN IF WE ARE WITHIN BUFFER. + PUSH BC + CALL TRKSEC ; WE NEED THE NEXT DIRECTORY SECTOR. + CALL DIRREAD + POP BC + JP CHECKDIR +; +; ROUTINE TO TO GET A BIT FROM THE DISK SPACE ALLOCATION +; MAP. IT IS RETURNED IN (A), BIT POSITION 0. ON ENTRY TO HERE, +; SET (BC) TO THE BLOCK NUMBER ON THE DISK TO CHECK. +; ON RETURN, (D) WILL CONTAIN THE ORIGINAL BIT POSITION FOR +; THIS BLOCK NUMBER AND (HL) WILL POINT TO THE ADDRESS FOR IT. +; +CKBITMAP: + LD A,C ; DETERMINE BIT NUMBER OF INTEREST. + AND 07H ; COMPUTE (D)=(E)=(C AND 7)+1. + INC A + LD E,A ; SAVE PARTICULAR BIT NUMBER. + LD D,A +; +; COMPUTE (BC)=(BC)/8. +; + LD A,C + RRCA ; NOW SHIFT RIGHT 3 BITS. + RRCA + RRCA + AND 1FH ; AND CLEAR BITS 7,6,5. + LD C,A + LD A,B + ADD A,A ; NOW SHIFT (B) INTO BITS 7,6,5. + ADD A,A + ADD A,A + ADD A,A + ADD A,A + OR C ; AND ADD IN (C). + LD C,A ; OK, (C) HA BEEN COMPLETED. + LD A,B ; IS THERE A BETTER WAY OF DOING THIS? + RRCA + RRCA + RRCA + AND 1FH + LD B,A ; AND NOW (B) IS COMPLETED. +; +; USE THIS AS AN OFFSET INTO THE DISK SPACE ALLOCATION +; TABLE. +; + LD HL,(ALOCVECT) + ADD HL,BC + LD A,(HL) ; NOW GET CORRECT BYTE. +CKBMAP1:RLCA ; GET CORRECT BIT INTO POSITION 0. + DEC E + JP NZ,CKBMAP1 + RET +; +; SET OR CLEAR THE BIT MAP SUCH THAT BLOCK NUMBER (BC) WILL BE MARKED +; AS USED. ON ENTRY, IF (E)=0 THEN THIS BIT WILL BE CLEARED, IF IT .EQUALS +; 1 THEN IT WILL BE SET (DON'T USE ANYOTHER VALUES). +; +STBITMAP: + PUSH DE + CALL CKBITMAP ; GET THE BYTE OF INTEREST. + AND 0FEH ; CLEAR THE AFFECTED BIT. + POP BC + OR C ; AND NOW SET IT ACORDING TO (C). +; +; ENTRY TO RESTORE THE ORIGINAL BIT POSITION AND THEN STORE +; IN TABLE. (A) CONTAINS THE VALUE, (D) CONTAINS THE BIT +; POSITION (1-8), AND (HL) POINTS TO THE ADDRESS WITHIN THE +; SPACE ALLOCATION TABLE FOR THIS BYTE. +; +STBMAP1:RRCA ; RESTORE ORIGINAL BIT POSITION. + DEC D + JP NZ,STBMAP1 + LD (HL),A ; AND STOR BYTE IN TABLE. + RET +; +; SET/CLEAR SPACE USED BITS IN ALLOCATION MAP FOR THIS FILE. +; ON ENTRY, (C)=1 TO SET THE MAP AND (C)=0 TO CLEAR IT. +; +SETFILE:CALL FCB2HL ; GET ADDRESS OF FCB + LD DE,16 + ADD HL,DE ; GET TO BLOCK NUMBER BYTES. + PUSH BC + LD C,17 ; CHECK ALL 17 BYTES (MAX) OF TABLE. +SETFL1: POP DE + DEC C ; DONE ALL BYTES YET? + RET Z + PUSH DE + LD A,(BIGDISK) ; CHECK DISK SIZE FOR 16 BIT BLOCK NUMBERS. + OR A + JP Z,SETFL2 + PUSH BC ; ONLY 8 BIT NUMBERS. SET (BC) TO THIS ONE. + PUSH HL + LD C,(HL) ; GET LOW BYTE FROM TABLE, ALWAYS + LD B,0 ; SET HIGH BYTE TO ZERO. + JP SETFL3 +SETFL2: DEC C ; FOR 16 BIT BLOCK NUMBERS, ADJUST COUNTER. + PUSH BC + LD C,(HL) ; NOW GET BOTH THE LOW AND HIGH BYTES. + INC HL + LD B,(HL) + PUSH HL +SETFL3: LD A,C ; BLOCK USED? + OR B + JP Z,SETFL4 + LD HL,(DSKSIZE) ; IS THIS BLOCK NUMBER WITHIN THE + LD A,L ; SPACE ON THE DISK? + SUB C + LD A,H + SBC A,B + CALL NC,STBITMAP ; YES, SET THE PROPER BIT. +SETFL4: POP HL ; POINT TO NEXT BLOCK NUMBER IN FCB. + INC HL + POP BC + JP SETFL1 +; +; CONSTRUCT THE SPACE USED ALLOCATION BIT MAP FOR THE ACTIVE +; DRIVE. IF A FILE NAME STARTS WITH '$' AND IT IS UNDER THE +; CURRENT USER NUMBER, THEN (STATUS) IS SET TO MINUS 1. OTHERWISE +; IT IS NOT SET AT ALL. +; +BITMAP: LD HL,(DSKSIZE) ; COMPUTE SIZE OF ALLOCATION TABLE. + LD C,3 + CALL SHIFTR ; (HL)=(HL)/8. + INC HL ; AT LEASE 1 BYTE. + LD B,H + LD C,L ; SET (BC) TO THE ALLOCATION TABLE LENGTH. +; +; INITIALIZE THE BITMAP FOR THIS DRIVE. RIGHT NOW, THE FIRST +; TWO BYTES ARE SPECIFIED BY THE DISK PARAMETER BLOCK. HOWEVER +; A PATCH COULD BE ENTERED HERE IF IT WERE NECESSARY TO SETUP +; THIS TABLE IN A SPECIAL MANNOR. FOR EXAMPLE, THE BIOS COULD +; DETERMINE LOCATIONS OF 'BAD BLOCKS' AND SET THEM AS ALREADY +; 'USED' IN THE MAP. +; + LD HL,(ALOCVECT) ; NOW ZERO OUT THE TABLE NOW. +BITMAP1:LD (HL),0 + INC HL + DEC BC + LD A,B + OR C + JP NZ,BITMAP1 + LD HL,(ALLOC0) ; GET INITIAL SPACE USED BY DIRECTORY. + EX DE,HL + LD HL,(ALOCVECT) ; AND PUT THIS INTO MAP. + LD (HL),E + INC HL + LD (HL),D +; +; END OF INITIALIZATION PORTION. +; + CALL HOMEDRV ; NOW HOME THE DRIVE. + LD HL,(SCRATCH1) + LD (HL),3 ; FORCE NEXT DIRECTORY REQUEST TO READ + INC HL ; IN A SECTOR. + LD (HL),0 + CALL STFILPOS ; CLEAR INITIAL FILE POSITION ALSO. +BITMAP2:LD C,0FFH ; READ NEXT FILE NAME IN DIRECTORY + CALL NXENTRY ; AND SET CHECKSUM BYTE. + CALL CKFILPOS ; IS THERE ANOTHER FILE? + RET Z + CALL FCB2HL ; YES, GET ITS ADDRESS. + LD A,0E5H + CP (HL) ; EMPTY FILE ENTRY? + JP Z,BITMAP2 + LD A,(USERNO) ; NO, CORRECT USER NUMBER? + CP (HL) + JP NZ,BITMAP3 + INC HL + LD A,(HL) ; YES, DOES NAME START WITH A '$'? + SUB '$' + JP NZ,BITMAP3 + DEC A ; YES, SET ATATUS TO MINUS ONE. + LD (STATUS),A +BITMAP3:LD C,1 ; NOW SET THIS FILE'S SPACE AS USED IN BIT MAP. + CALL SETFILE + CALL CHKNMBR ; KEEP (SCRATCH1) IN BOUNDS. + JP BITMAP2 +; +; SET THE STATUS (STATUS) AND RETURN. +; +STSTATUS: + LD A,(FNDSTAT) + JP SETSTAT +; +; CHECK EXTENTS IN (A) AND (C). SET THE ZERO FLAG IF THEY +; ARE THE SAME. THE NUMBER OF 16K CHUNKS OF DISK SPACE THAT +; THE DIRECTORY EXTENT COVERS IS EXPRESSAD IS (EXTMASK+1). +; NO REGISTERS ARE MODIFIED. +; +SAMEXT: PUSH BC + PUSH AF + LD A,(EXTMASK) ; GET EXTENT MASK AND USE IT TO + CPL ; TO COMPARE BOTH EXTENT NUMBERS. + LD B,A ; SAVE RESULTING MASK HERE. + LD A,C ; MASK FIRST EXTENT AND SAVE IN (C). + AND B + LD C,A + POP AF ; NOW MASK SECOND EXTENT AND COMPARE + AND B ; WITH THE FIRST ONE. + SUB C + AND 1FH ; (* ONLY CHECK BUTS 0-4 *) + POP BC ; THE ZERO FLAG IS SET IF THEY ARE THE SAME. + RET ; RESTORE (BC) AND RETURN. +; +; SEARCH FOR THE FIRST OCCURENCE OF A FILE NAME. ON ENTRY, +; REGISTER (C) SHOULD CONTAIN THE NUMBER OF BYTES OF THE FCB +; THAT MUST MATCH. +; +FINDFST:LD A,0FFH + LD (FNDSTAT),A + LD HL,COUNTER ; SAVE CHARACTER COUNT. + LD (HL),C + LD HL,(PARAMS) ; GET FILENAME TO MATCH. + LD (SAVEFCB),HL ; AND SAVE. + CALL STFILPOS ; CLEAR INITIAL FILE POSITION (SET TO 0FFFFH). + CALL HOMEDRV ; HOME THE DRIVE. +; +; ENTRY TO LOCATE THE NEXT OCCURENCE OF A FILENAME WITHIN THE +; DIRECTORY. THE DISK IS NOT EXPECTED TO HAVE BEEN CHANGED. IF +; IT WAS, THEN IT WILL BE WRITE PROTECTED. +; +FINDNXT:LD C,0 ; WRITE PROTECT THE DISK IF CHANGED. + CALL NXENTRY ; GET NEXT FILENAME ENTRY IN DIRECTORY. + CALL CKFILPOS ; IS FILE POSITION = 0FFFFH? + JP Z,FNDNXT6 ; YES, EXIT NOW THEN. + LD HL,(SAVEFCB) ; SET (DE) POINTING TO FILENAME TO MATCH. + EX DE,HL + LD A,(DE) + CP 0E5H ; EMPTY DIRECTORY ENTRY? + JP Z,FNDNXT1 ; (* ARE WE TRYING TO RESERECT ERASED ENTRIES? *) + PUSH DE + CALL MOREFLS ; MORE FILES IN DIRECTORY? + POP DE + JP NC,FNDNXT6 ; NO MORE. EXIT NOW. +FNDNXT1:CALL FCB2HL ; GET ADDRESS OF THIS FCB IN DIRECTORY. + LD A,(COUNTER) ; GET NUMBER OF BYTES (CHARACTERS) TO CHECK. + LD C,A + LD B,0 ; INITIALIZE BYTE POSITION COUNTER. +FNDNXT2:LD A,C ; ARE WE DONE WITH THE COMPARE? + OR A + JP Z,FNDNXT5 + LD A,(DE) ; NO, CHECK NEXT BYTE. + CP '?' ; DON'T CARE ABOUT THIS CHARACTER? + JP Z,FNDNXT4 + LD A,B ; GET BYTES POSITION IN FCB. + CP 13 ; DON'T CARE ABOUT THE THIRTEENTH BYTE EITHER. + JP Z,FNDNXT4 + CP 12 ; EXTENT BYTE? + LD A,(DE) + JP Z,FNDNXT3 + SUB (HL) ; OTHERWISE COMPARE CHARACTERS. + AND 7FH + JP NZ,FINDNXT ; NOT THE SAME, CHECK NEXT ENTRY. + JP FNDNXT4 ; SO FAR SO GOOD, KEEP CHECKING. +FNDNXT3:PUSH BC ; CHECK THE EXTENT BYTE HERE. + LD C,(HL) + CALL SAMEXT + POP BC + JP NZ,FINDNXT ; NOT THE SAME, LOOK SOME MORE. +; +; SO FAR THE NAMES COMPARE. BUMP POINTERS TO THE NEXT BYTE +; AND CONTINUE UNTIL ALL (C) CHARACTERS HAVE BEEN CHECKED. +; +FNDNXT4:INC DE ; BUMP POINTERS. + INC HL + INC B + DEC C ; ADJUST CHARACTER COUNTER. + JP FNDNXT2 +FNDNXT5:LD A,(FILEPOS) ; RETURN THE POSITION OF THIS ENTRY. + AND 03H + LD (STATUS),A + LD HL,FNDSTAT + LD A,(HL) + RLA + RET NC + XOR A + LD (HL),A + RET +; +; FILENAME WAS NOT FOUND. SET APPROPRIATE STATUS. +; +FNDNXT6:CALL STFILPOS ; SET (FILEPOS) TO 0FFFFH. + LD A,0FFH ; SAY NOT LOCATED. + JP SETSTAT +; +; ERASE FILES FROM THE DIRECTORY. ONLY THE FIRST BYTE OF THE +; FCB WILL BE AFFECTED. IT IS SET TO (E5). +; +ERAFILE:CALL CHKWPRT ; IS DISK WRITE PROTECTED? + LD C,12 ; ONLY COMPARE FILE NAMES. + CALL FINDFST ; GET FIRST FILE NAME. +ERAFIL1:CALL CKFILPOS ; ANY FOUND? + RET Z ; NOPE, WE MUST BE DONE. + CALL CHKROFL ; IS FILE READ ONLY? + CALL FCB2HL ; NOPE, GET ADDRESS OF FCB AND + LD (HL),0E5H ; SET FIRST BYTE TO 'EMPTY'. + LD C,0 ; CLEAR THE SPACE FROM THE BIT MAP. + CALL SETFILE + CALL DIRWRITE ; NOW WRITE THE DIRECTORY SECTOR BACK OUT. + CALL FINDNXT ; FIND THE NEXT FILE NAME. + JP ERAFIL1 ; AND REPEAT PROCESS. +; +; LOOK THROUGH THE SPACE ALLOCATION MAP (BIT MAP) FOR THE +; NEXT AVAILABLE BLOCK. START SEARCHING AT BLOCK NUMBER (BC-1). +; THE SEARCH PROCEDURE IS TO LOOK FOR AN EMPTY BLOCK THAT IS +; BEFORE THE STARTING BLOCK. IF NOT EMPTY, LOOK AT A LATER +; BLOCK NUMBER. IN THIS WAY, WE RETURN THE CLOSEST EMPTY BLOCK +; ON EITHER SIDE OF THE 'TARGET' BLOCK NUMBER. THIS WILL SPEED +; ACCESS ON RANDOM DEVICES. FOR SERIAL DEVICES, THIS SHOULD BE +; CHANGED TO LOOK IN THE FORWARD DIRECTION FIRST AND THEN START +; AT THE FRONT AND SEARCH SOME MORE. +; +; ON RETURN, (DE)= BLOCK NUMBER THAT IS EMPTY AND (HL) =0 +; IF NO EMPRY BLOCK WAS FOUND. +; +FNDSPACE: + LD D,B ; SET (DE) AS THE BLOCK THAT IS CHECKED. + LD E,C +; +; LOOK BEFORE TARGET BLOCK. REGISTERS (BC) ARE USED AS THE LOWER +; POINTER AND (DE) AS THE UPPER POINTER. +; +FNDSPA1:LD A,C ; IS BLOCK 0 SPECIFIED? + OR B + JP Z,FNDSPA2 + DEC BC ; NOPE, CHECK PREVIOUS BLOCK. + PUSH DE + PUSH BC + CALL CKBITMAP + RRA ; IS THIS BLOCK EMPTY? + JP NC,FNDSPA3 ; YES. USE THIS. +; +; NOTE THAT THE ABOVE LOGIC GETS THE FIRST BLOCK THAT IT FINDS +; THAT IS EMPTY. THUS A FILE COULD BE WRITTEN 'BACKWARD' MAKING +; IT VERY SLOW TO ACCESS. THIS COULD BE CHANGED TO LOOK FOR THE +; FIRST EMPTY BLOCK AND THEN CONTINUE UNTIL THE START OF THIS +; EMPTY SPACE IS LOCATED AND THEN USED THAT STARTING BLOCK. +; THIS SHOULD HELP SPEED UP ACCESS TO SOME FILES ESPECIALLY ON +; A WELL USED DISK WITH LOTS OF FAIRLY SMALL 'HOLES'. +; + POP BC ; NOPE, CHECK SOME MORE. + POP DE +; +; NOW LOOK AFTER TARGET BLOCK. +; +FNDSPA2:LD HL,(DSKSIZE) ; IS BLOCK (DE) WITHIN DISK LIMITS? + LD A,E + SUB L + LD A,D + SBC A,H + JP NC,FNDSPA4 + INC DE ; YES, MOVE ON TO NEXT ONE. + PUSH BC + PUSH DE + LD B,D + LD C,E + CALL CKBITMAP ; CHECK IT. + RRA ; EMPTY? + JP NC,FNDSPA3 + POP DE ; NOPE, CONTINUE SEARCHING. + POP BC + JP FNDSPA1 +; +; EMPTY BLOCK FOUND. SET IT AS USED AND RETURN WITH (HL) +; POINTING TO IT (TRUE?). +; +FNDSPA3:RLA ; RESET BYTE. + INC A ; AND SET BIT 0. + CALL STBMAP1 ; UPDATE BIT MAP. + POP HL ; SET RETURN REGISTERS. + POP DE + RET +; +; FREE BLOCK WAS NOT FOUND. IF (BC) IS NOT ZERO, THEN WE HAVE +; NOT CHECKED ALL OF THE DISK SPACE. +; +FNDSPA4:LD A,C + OR B + JP NZ,FNDSPA1 + LD HL,0 ; SET 'NOT FOUND' STATUS. + RET +; +; MOVE A COMPLETE FCB ENTRY INTO THE DIRECTORY AND WRITE IT. +; +FCBSET: LD C,0 + LD E,32 ; LENGTH OF EACH ENTRY. +; +; MOVE (E) BYTES FROM THE FCB POINTED TO BY (PARAMS) INTO +; FCB IN DIRECTORY STARTING AT RELATIVE BYTE (C). THIS UPDATED +; DIRECTORY BUFFER IS THEN WRITTEN TO THE DISK. +; +UPDATE: PUSH DE + LD B,0 ; SET (BC) TO RELATIVE BYTE POSITION. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + ADD HL,BC ; COMPUTE STARTING BYTE. + EX DE,HL + CALL FCB2HL ; GET ADDRESS OF FCB TO UPDATE IN DIRECTORY. + POP BC ; SET (C) TO NUMBER OF BYTES TO CHANGE. + CALL DE2HL +UPDATE1:CALL TRKSEC ; DETERMINE THE TRACK AND SECTOR AFFECTED. + JP DIRWRITE ; THEN WRITE THIS SECTOR OUT. +; +; ROUTINE TO CHANGE THE NAME OF ALL FILES ON THE DISK WITH A +; SPECIFIED NAME. THE FCB CONTAINS THE CURRENT NAME AS THE +; FIRST 12 CHARACTERS AND THE NEW NAME 16 BYTES INTO THE FCB. +; +CHGNAMES: + CALL CHKWPRT ; CHECK FOR A WRITE PROTECTED DISK. + LD C,12 ; MATCH FIRST 12 BYTES OF FCB ONLY. + CALL FINDFST ; GET FIRST NAME. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + LD A,(HL) ; GET USER NUMBER. + LD DE,16 ; MOVE OVER TO DESIRED NAME. + ADD HL,DE + LD (HL),A ; KEEP SAME USER NUMBER. +CHGNAM1:CALL CKFILPOS ; ANY MATCHING FILE FOUND? + RET Z ; NO, WE MUST BE DONE. + CALL CHKROFL ; CHECK FOR READ ONLY FILE. + LD C,16 ; START 16 BYTES INTO FCB. + LD E,12 ; AND UPDATE THE FIRST 12 BYTES OF DIRECTORY. + CALL UPDATE + CALL FINDNXT ; GET TE NEXT FILE NAME. + JP CHGNAM1 ; AND CONTINUE. +; +; UPDATE A FILES ATTRIBUTES. THE PROCEDURE IS TO SEARCH FOR +; EVERY FILE WITH THE SAME NAME AS SHOWN IN FCB (IGNORING BIT 7) +; AND THEN TO UPDATE IT (WHICH INCLUDES BIT 7). NO OTHER CHANGES +; ARE MADE. +; +SAVEATTR: + LD C,12 ; MATCH FIRST 12 BYTES. + CALL FINDFST ; LOOK FOR FIRST FILENAME. +SAVATR1:CALL CKFILPOS ; WAS ONE FOUND? + RET Z ; NOPE, WE MUST BE DONE. + LD C,0 ; YES, UPDATE THE FIRST 12 BYTES NOW. + LD E,12 + CALL UPDATE ; UPDATE FILENAME AND WRITE DIRECTORY. + CALL FINDNXT ; AND GET THE NEXT FILE. + JP SAVATR1 ; THEN CONTINUE UNTIL DONE. +; +; OPEN A FILE (NAME SPECIFIED IN FCB). +; +OPENIT: LD C,15 ; COMPARE THE FIRST 15 BYTES. + CALL FINDFST ; GET THE FIRST ONE IN DIRECTORY. + CALL CKFILPOS ; ANY AT ALL? + RET Z +OPENIT1:CALL SETEXT ; POINT TO EXTENT BYTE WITHIN USERS FCB. + LD A,(HL) ; AND GET IT. + PUSH AF ; SAVE IT AND ADDRESS. + PUSH HL + CALL FCB2HL ; POINT TO FCB IN DIRECTORY. + EX DE,HL + LD HL,(PARAMS) ; THIS IS THE USERS COPY. + LD C,32 ; MOVE IT INTO USERS SPACE. + PUSH DE + CALL DE2HL + CALL SETS2B7 ; SET BIT 7 IN 'S2' BYTE (UNMODIFIED). + POP DE ; NOW GET THE EXTENT BYTE FROM THIS FCB. + LD HL,12 + ADD HL,DE + LD C,(HL) ; INTO (C). + LD HL,15 ; NOW GET THE RECORD COUNT BYTE INTO (B). + ADD HL,DE + LD B,(HL) + POP HL ; KEEP THE SAME EXTENT AS THE USER HAD ORIGINALLY. + POP AF + LD (HL),A + LD A,C ; IS IT THE SAME AS IN THE DIRECTORY FCB? + CP (HL) + LD A,B ; IF YES, THEN USE THE SAME RECORD COUNT. + JP Z,OPENIT2 + LD A,0 ; IF THE USER SPECIFIED AN EXTENT GREATER THAN + JP C,OPENIT2 ; THE ONE IN THE DIRECTORY, THEN SET RECORD COUNT TO 0. + LD A,128 ; OTHERWISE SET TO MAXIMUM. +OPENIT2:LD HL,(PARAMS) ; SET RECORD COUNT IN USERS FCB TO (A). + LD DE,15 + ADD HL,DE ; COMPUTE RELATIVE POSITION. + LD (HL),A ; AND SET THE RECORD COUNT. + RET +; +; MOVE TWO BYTES FROM (DE) TO (HL) IF (AND ONLY IF) (HL) +; POINT TO A ZERO VALUE (16 BIT). +; RETURN WITH ZERO FLAG SET IT (DE) WAS MOVED. REGISTERS (DE) +; AND (HL) ARE NOT CHANGED. HOWEVER (A) IS. +; +MOVEWORD: + LD A,(HL) ; CHECK FOR A ZERO WORD. + INC HL + OR (HL) ; BOTH BYTES ZERO? + DEC HL + RET NZ ; NOPE, JUST RETURN. + LD A,(DE) ; YES, MOVE TWO BYTES FROM (DE) INTO + LD (HL),A ; THIS ZERO SPACE. + INC DE + INC HL + LD A,(DE) + LD (HL),A + DEC DE ; DON'T DISTURB THESE REGISTERS. + DEC HL + RET +; +; GET HERE TO CLOSE A FILE SPECIFIED BY (FCB). +; +CLOSEIT:XOR A ; CLEAR STATUS AND FILE POSITION BYTES. + LD (STATUS),A + LD (FILEPOS),A + LD (FILEPOS+1),A + CALL GETWPRT ; GET WRITE PROTECT BIT FOR THIS DRIVE. + RET NZ ; JUST RETURN IF IT IS SET. + CALL GETS2 ; ELSE GET THE 'S2' BYTE. + AND 80H ; AND LOOK AT BIT 7 (FILE UNMODIFIED?). + RET NZ ; JUST RETURN IF SET. + LD C,15 ; ELSE LOOK UP THIS FILE IN DIRECTORY. + CALL FINDFST + CALL CKFILPOS ; WAS IT FOUND? + RET Z ; JUST RETURN IF NOT. + LD BC,16 ; SET (HL) POINTING TO RECORDS USED SECTION. + CALL FCB2HL + ADD HL,BC + EX DE,HL + LD HL,(PARAMS) ; DO THE SAME FOR USERS SPECIFIED FCB. + ADD HL,BC + LD C,16 ; THIS MANY BYTES ARE PRESENT IN THIS EXTENT. +CLOSEIT1: + LD A,(BIGDISK) ; 8 OR 16 BIT RECORD NUMBERS? + OR A + JP Z,CLOSEIT4 + LD A,(HL) ; JUST 8 BIT. GET ONE FROM USERS FCB. + OR A + LD A,(DE) ; NOW GET ONE FROM DIRECTORY FCB. + JP NZ,CLOSEIT2 + LD (HL),A ; USERS BYTE WAS ZERO. UPDATE FROM DIRECTORY. +CLOSEIT2: + OR A + JP NZ,CLOSEIT3 + LD A,(HL) ; DIRECTORIES BYTE WAS ZERO, UPDATE FROM USERS FCB. + LD (DE),A +CLOSEIT3: + CP (HL) ; IF NEITHER ONE OF THESE BYTES WERE ZERO, + JP NZ,CLOSEIT7 ; THEN CLOSE ERROR IF THEY ARE NOT THE SAME. + JP CLOSEIT5 ; OK SO FAR, GET TO NEXT BYTE IN FCBS. +CLOSEIT4: + CALL MOVEWORD ; UPDATE USERS FCB IF IT IS ZERO. + EX DE,HL + CALL MOVEWORD ; UPDATE DIRECTORIES FCB IF IT IS ZERO. + EX DE,HL + LD A,(DE) ; IF THESE TWO VALUES ARE NO DIFFERENT, + CP (HL) ; THEN A CLOSE ERROR OCCURED. + JP NZ,CLOSEIT7 + INC DE ; CHECK SECOND BYTE. + INC HL + LD A,(DE) + CP (HL) + JP NZ,CLOSEIT7 + DEC C ; REMEMBER 16 BIT VALUES. +CLOSEIT5: + INC DE ; BUMP TO NEXT ITEM IN TABLE. + INC HL + DEC C ; THERE ARE 16 ENTRIES ONLY. + JP NZ,CLOSEIT1 ; CONTINUE IF MORE TO DO. + LD BC,0FFECH ; BACKUP 20 PLACES (EXTENT BYTE). + ADD HL,BC + EX DE,HL + ADD HL,BC + LD A,(DE) + CP (HL) ; DIRECTORY'S EXTENT ALREADY GREATER THAN THE + JP C,CLOSEIT6 ; USERS EXTENT? + LD (HL),A ; NO, UPDATE DIRECTORY EXTENT. + LD BC,3 ; AND UPDATE THE RECORD COUNT BYTE IN + ADD HL,BC ; DIRECTORIES FCB. + EX DE,HL + ADD HL,BC + LD A,(HL) ; GET FROM USER. + LD (DE),A ; AND PUT IN DIRECTORY. +CLOSEIT6: + LD A,0FFH ; SET 'WAS OPEN AND IS NOW CLOSED' BYTE. + LD (CLOSEFLG),A + JP UPDATE1 ; UPDATE THE DIRECTORY NOW. +CLOSEIT7: + LD HL,STATUS ; SET RETURN STATUS AND THEN RETURN. + DEC (HL) + RET +; +; ROUTINE TO GET THE NEXT EMPTY SPACE IN THE DIRECTORY. IT +; WILL THEN BE CLEARED FOR USE. +; +GETEMPTY: + CALL CHKWPRT ; MAKE SURE DISK IS NOT WRITE PROTECTED. + LD HL,(PARAMS) ; SAVE CURRENT PARAMETERS (FCB). + PUSH HL + LD HL,EMPTYFCB ; USE SPECIAL ONE FOR EMPTY SPACE. + LD (PARAMS),HL + LD C,1 ; SEARCH FOR FIRST EMPTY SPOT IN DIRECTORY. + CALL FINDFST ; (* ONLY CHECK FIRST BYTE *) + CALL CKFILPOS ; NONE? + POP HL + LD (PARAMS),HL ; RESTORE ORIGINAL FCB ADDRESS. + RET Z ; RETURN IF NO MORE SPACE. + EX DE,HL + LD HL,15 ; POINT TO NUMBER OF RECORDS FOR THIS FILE. + ADD HL,DE + LD C,17 ; AND CLEAR ALL OF THIS SPACE. + XOR A +GETMT1: LD (HL),A + INC HL + DEC C + JP NZ,GETMT1 + LD HL,13 ; CLEAR THE 'S1' BYTE ALSO. + ADD HL,DE + LD (HL),A + CALL CHKNMBR ; KEEP (SCRATCH1) WITHIN BOUNDS. + CALL FCBSET ; WRITE OUT THIS FCB ENTRY TO DIRECTORY. + JP SETS2B7 ; SET 'S2' BYTE BIT 7 (UNMODIFIED AT PRESENT). +; +; ROUTINE TO CLOSE THE CURRENT EXTENT AND OPEN THE NEXT ONE +; FOR READING. +; +GETNEXT:XOR A + LD (CLOSEFLG),A ; CLEAR CLOSE FLAG. + CALL CLOSEIT ; CLOSE THIS EXTENT. + CALL CKFILPOS + RET Z ; NOT THERE??? + LD HL,(PARAMS) ; GET EXTENT BYTE. + LD BC,12 + ADD HL,BC + LD A,(HL) ; AND INCREMENT IT. + INC A + AND 1FH ; KEEP WITHIN RANGE 0-31. + LD (HL),A + JP Z,GTNEXT1 ; OVERFLOW? + LD B,A ; MASK EXTENT BYTE. + LD A,(EXTMASK) + AND B + LD HL,CLOSEFLG ; CHECK CLOSE FLAG (0FFH IS OK). + AND (HL) + JP Z,GTNEXT2 ; IF ZERO, WE MUST READ IN NEXT EXTENT. + JP GTNEXT3 ; ELSE, IT IS ALREADY IN MEMORY. +GTNEXT1:LD BC,2 ; POINT TO THE 'S2' BYTE. + ADD HL,BC + INC (HL) ; AND BUMP IT. + LD A,(HL) ; TOO MANY EXTENTS? + AND 0FH + JP Z,GTNEXT5 ; YES, SET ERROR CODE. +; +; GET HERE TO OPEN THE NEXT EXTENT. +; +GTNEXT2:LD C,15 ; SET TO CHECK FIRST 15 BYTES OF FCB. + CALL FINDFST ; FIND THE FIRST ONE. + CALL CKFILPOS ; NONE AVAILABLE? + JP NZ,GTNEXT3 + LD A,(R.DWRTFLG) ; NO EXTENT PRESENT. CAN WE OPEN AN EMPTY ONE? + INC A ; 0FFH MEANS READING (SO NOT POSSIBLE). + JP Z,GTNEXT5 ; OR AN ERROR. + CALL GETEMPTY ; WE ARE WRITING, GET AN EMPTY ENTRY. + CALL CKFILPOS ; NONE? + JP Z,GTNEXT5 ; ERROR IF TRUE. + JP GTNEXT4 ; ELSE WE ARE ALMOST DONE. +GTNEXT3:CALL OPENIT1 ; OPEN THIS EXTENT. +GTNEXT4:CALL STRDATA ; MOVE IN UPDATED DATA (REC #, EXTENT #, ETC.) + XOR A ; CLEAR STATUS AND RETURN. + JP SETSTAT +; +; ERROR IN EXTENDING THE FILE. TOO MANY EXTENTS WERE NEEDED +; OR NOT ENOUGH SPACE ON THE DISK. +; +GTNEXT5:CALL IOERR1 ; SET ERROR CODE, CLEAR BIT 7 OF 'S2' + JP SETS2B7 ; SO THIS IS NOT WRITTEN ON A CLOSE. +; +; READ A S.EQUENTIAL FILE. +; +RDSEQ: LD A,1 ; SET S.EQUENTIAL ACCESS MODE. + LD (MODE),A +RDSEQ1: LD A,0FFH ; DON'T ALLOW READING UNWRITTEN SPACE. + LD (R.DWRTFLG),A + CALL STRDATA ; PUT REC# AND EXT# INTO FCB. + LD A,(SAVNREC) ; GET NEXT RECORD TO READ. + LD HL,SAVNXT ; GET NUMBER OF RECORDS IN EXTENT. + CP (HL) ; WITHIN THIS EXTENT? + JP C,RDSEQ2 + CP 128 ; NO. IS THIS EXTENT FULLY USED? + JP NZ,RDSEQ3 ; NO. END-OF-FILE. + CALL GETNEXT ; YES, OPEN THE NEXT ONE. + XOR A ; RESET NEXT RECORD TO READ. + LD (SAVNREC),A + LD A,(STATUS) ; CHECK ON OPEN, SUCCESSFUL? + OR A + JP NZ,RDSEQ3 ; NO, ERROR. +RDSEQ2: CALL COMBLK ; OK. COMPUTE BLOCK NUMBER TO READ. + CALL CHKBLK ; CHECK IT. WITHIN BOUNDS? + JP Z,RDSEQ3 ; NO, ERROR. + CALL LOGICAL ; CONVERT (BLKNMBR) TO LOGICAL SECTOR (128 BYTE). + CALL TRKSEC1 ; SET THE TRACK AND SECTOR FOR THIS BLOCK #. + CALL DOREAD ; AND READ IT. + JP SETNREC ; AND SET THE NEXT RECORD TO BE ACCESSED. +; +; READ ERROR OCCURED. SET STATUS AND RETURN. +; +RDSEQ3: JP IOERR1 +; +; WRITE THE NEXT S.EQUENTIAL RECORD. +; +WTSEQ: LD A,1 ; SET S.EQUENTIAL ACCESS MODE. + LD (MODE),A +WTSEQ1: LD A,0 ; ALLOW AN ADDITION EMPTY EXTENT TO BE OPENED. + LD (R.DWRTFLG),A + CALL CHKWPRT ; CHECK WRITE PROTECT STATUS. + LD HL,(PARAMS) + CALL CKROF1 ; CHECK FOR READ ONLY FILE, (HL) ALREADY SET TO FCB. + CALL STRDATA ; PUT UPDATED DATA INTO FCB. + LD A,(SAVNREC) ; GET RECORD NUMBER TO WRITE. + CP 128 ; WITHIN RANGE? + JP NC,IOERR1 ; NO, ERROR(?). + CALL COMBLK ; COMPUTE BLOCK NUMBER. + CALL CHKBLK ; CHECK NUMBER. + LD C,0 ; IS THERE ONE TO WRITE TO? + JP NZ,WTSEQ6 ; YES, GO DO IT. + CALL GETBLOCK ; GET NEXT BLOCK NUMBER WITHIN FCB TO USE. + LD (RELBLOCK),A ; AND SAVE. + LD BC,0 ; START LOOKING FOR SPACE FROM THE START + OR A ; IF NONE ALLOCATED AS YET. + JP Z,WTSEQ2 + LD C,A ; EXTRACT PREVIOUS BLOCK NUMBER FROM FCB + DEC BC ; SO WE CAN BE CLOSEST TO IT. + CALL EXTBLK + LD B,H + LD C,L +WTSEQ2: CALL FNDSPACE ; FIND THE NEXT EMPTY BLOCK NEAREST NUMBER (BC). + LD A,L ; CHECK FOR A ZERO NUMBER. + OR H + JP NZ,WTSEQ3 + LD A,2 ; NO MORE SPACE? + JP SETSTAT +WTSEQ3: LD (BLKNMBR),HL ; SAVE BLOCK NUMBER TO ACCESS. + EX DE,HL ; PUT BLOCK NUMBER INTO (DE). + LD HL,(PARAMS) ; NOW WE MUST UPDATE THE FCB FOR THIS + LD BC,16 ; NEWLY ALLOCATED BLOCK. + ADD HL,BC + LD A,(BIGDISK) ; 8 OR 16 BIT BLOCK NUMBERS? + OR A + LD A,(RELBLOCK) ; (* UPDATE THIS ENTRY *) + JP Z,WTSEQ4 ; ZERO MEANS 16 BIT ONES. + CALL ADDA2HL ; (HL)=(HL)+(A) + LD (HL),E ; STORE NEW BLOCK NUMBER. + JP WTSEQ5 +WTSEQ4: LD C,A ; COMPUTE SPOT IN THIS 16 BIT TABLE. + LD B,0 + ADD HL,BC + ADD HL,BC + LD (HL),E ; STUFF BLOCK NUMBER (DE) THERE. + INC HL + LD (HL),D +WTSEQ5: LD C,2 ; SET (C) TO INDICATE WRITING TO UN-USED DISK SPACE. +WTSEQ6: LD A,(STATUS) ; ARE WE OK SO FAR? + OR A + RET NZ + PUSH BC ; YES, SAVE WRITE FLAG FOR BIOS (REGISTER C). + CALL LOGICAL ; CONVERT (BLKNMBR) OVER TO LOICAL SECTORS. + LD A,(MODE) ; GET ACCESS MODE FLAG (1=S.EQUENTIAL, + DEC A ; 0=RANDOM, 2=SPECIAL?). + DEC A + JP NZ,WTSEQ9 +; +; SPECIAL RANDOM I/O FROM FUNCTION #40. MAYBE FOR M/PM, BUT THE +; CURRENT BLOCK, IF IT HAS NOT BEEN WRITTEN TO, WILL BE ZEROED +; OUT AND THEN WRITTEN (REASON?). +; + POP BC + PUSH BC + LD A,C ; GET WRITE STATUS FLAG (2=WRITING UNUSED SPACE). + DEC A + DEC A + JP NZ,WTSEQ9 + PUSH HL + LD HL,(DIRBUF) ; ZERO OUT THE DIRECTORY BUFFER. + LD D,A ; NOTE THAT (A) IS ZERO HERE. +WTSEQ7: LD (HL),A + INC HL + INC D ; DO 128 BYTES. + JP P,WTSEQ7 + CALL DIRDMA ; TELL THE BIOS THE DMA ADDRESS FOR DIRECTORY ACCESS. + LD HL,(LOGSECT) ; GET SECTOR THAT STARTS CURRENT BLOCK. + LD C,2 ; SET 'WRITING TO UNUSED SPACE' FLAG. +WTSEQ8: LD (BLKNMBR),HL ; SAVE SECTOR TO WRITE. + PUSH BC + CALL TRKSEC1 ; DETERMINE ITS TRACK AND SECTOR NUMBERS. + POP BC + CALL DOWRITE ; NOW WRITE OUT 128 BYTES OF ZEROS. + LD HL,(BLKNMBR) ; GET SECTOR NUMBER. + LD C,0 ; SET NORMAL WRITE FLAG. + LD A,(BLKMASK) ; DETERMINE IF WE HAVE WRITTEN THE ENTIRE + LD B,A ; PHYSICAL BLOCK. + AND L + CP B + INC HL ; PREPARE FOR THE NEXT ONE. + JP NZ,WTSEQ8 ; CONTINUE UNTIL (BLKMASK+1) SECTORS WRITTEN. + POP HL ; RESET NEXT SECTOR NUMBER. + LD (BLKNMBR),HL + CALL DEFDMA ; AND RESET DMA ADDRESS. +; +; NORMAL DISK WRITE. SET THE DESIRED TRACK AND SECTOR THEN +; DO THE ACTUAL WRITE. +; +WTSEQ9: CALL TRKSEC1 ; DETERMINE TRACK AND SECTOR FOR THIS WRITE. + POP BC ; GET WRITE STATUS FLAG. + PUSH BC + CALL DOWRITE ; AND WRITE THIS OUT. + POP BC + LD A,(SAVNREC) ; GET NUMBER OF RECORDS IN FILE. + LD HL,SAVNXT ; GET LAST RECORD WRITTEN. + CP (HL) + JP C,WTSEQ10 + LD (HL),A ; WE HAVE TO UPDATE RECORD COUNT. + INC (HL) + LD C,2 +; +;* THIS AREA HAS BEEN PATCHED TO CORRECT DISK UPDATE PROBLEM +;* WHEN USING BLOCKING AND DE-BLOCKING IN THE BIOS. +; +WTSEQ10:NOP ; WAS 'DCR C' + NOP ; WAS 'DCR C' + LD HL,0 ; WAS 'JNZ WTSEQ99' +; +; * END OF PATCH. +; + PUSH AF + CALL GETS2 ; SET 'EXTENT WRITTEN TO' FLAG. + AND 7FH ; (* CLEAR BIT 7 *) + LD (HL),A + POP AF ; GET RECORD COUNT FOR THIS EXTENT. +WTSEQ99:CP 127 ; IS IT FULL? + JP NZ,WTSEQ12 + LD A,(MODE) ; YES, ARE WE IN S.EQUENTIAL MODE? + CP 1 + JP NZ,WTSEQ12 + CALL SETNREC ; YES, SET NEXT RECORD NUMBER. + CALL GETNEXT ; AND GET NEXT EMPTY SPACE IN DIRECTORY. + LD HL,STATUS ; OK? + LD A,(HL) + OR A + JP NZ,WTSEQ11 + DEC A ; YES, SET RECORD COUNT TO -1. + LD (SAVNREC),A +WTSEQ11:LD (HL),0 ; CLEAR STATUS. +WTSEQ12:JP SETNREC ; SET NEXT RECORD TO ACCESS. +; +; FOR RANDOM I/O, SET THE FCB FOR THE DESIRED RECORD NUMBER +; BASED ON THE 'R0,R1,R2' BYTES. THESE BYTES IN THE FCB ARE +; USED AS FOLLOWS: +; +; FCB+35 FCB+34 FCB+33 +; | 'R-2' | 'R-1' | 'R-0' | +; |7 0 | 7 0 | 7 0| +; |0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0| +; | OVERFLOW | | EXTRA | EXTENT | RECORD # | +; | ______________| |_EXTENT|__NUMBER___|_____________| +; ALSO 'S2' +; +; ON ENTRY, REGISTER (C) CONTAINS 0FFH IF THIS IS A READ +; AND THUS WE CAN NOT ACCESS UNWRITTEN DISK SPACE. OTHERWISE, +; ANOTHER EXTENT WILL BE OPENED (FOR WRITING) IF REQUIRED. +; +POSITION: + XOR A ; SET RANDOM I/O FLAG. + LD (MODE),A +; +; SPECIAL ENTRY (FUNCTION #40). M/PM ? +; +POSITN1:PUSH BC ; SAVE READ/WRITE FLAG. + LD HL,(PARAMS) ; GET ADDRESS OF FCB. + EX DE,HL + LD HL,33 ; NOW GET BYTE 'R0'. + ADD HL,DE + LD A,(HL) + AND 7FH ; KEEP BITS 0-6 FOR THE RECORD NUMBER TO ACCESS. + PUSH AF + LD A,(HL) ; NOW GET BIT 7 OF 'R0' AND BITS 0-3 OF 'R1'. + RLA + INC HL + LD A,(HL) + RLA + AND 1FH ; AND SAVE THIS IN BITS 0-4 OF (C). + LD C,A ; THIS IS THE EXTENT BYTE. + LD A,(HL) ; NOW GET THE EXTRA EXTENT BYTE. + RRA + RRA + RRA + RRA + AND 0FH + LD B,A ; AND SAVE IT IN (B). + POP AF ; GET RECORD NUMBER BACK TO (A). + INC HL ; CHECK OVERFLOW BYTE 'R2'. + LD L,(HL) + INC L + DEC L + LD L,6 ; PREPARE FOR ERROR. + JP NZ,POSITN5 ; OUT OF DISK SPACE ERROR. + LD HL,32 ; STORE RECORD NUMBER INTO FCB. + ADD HL,DE + LD (HL),A + LD HL,12 ; AND NOW CHECK THE EXTENT BYTE. + ADD HL,DE + LD A,C + SUB (HL) ; SAME EXTENT AS BEFORE? + JP NZ,POSITN2 + LD HL,14 ; YES, CHECK EXTRA EXTENT BYTE 'S2' ALSO. + ADD HL,DE + LD A,B + SUB (HL) + AND 7FH + JP Z,POSITN3 ; SAME, WE ARE ALMOST DONE THEN. +; +; GET HERE WHEN ANOTHER EXTENT IS REQUIRED. +; +POSITN2:PUSH BC + PUSH DE + CALL CLOSEIT ; CLOSE CURRENT EXTENT. + POP DE + POP BC + LD L,3 ; PREPARE FOR ERROR. + LD A,(STATUS) + INC A + JP Z,POSITN4 ; CLOSE ERROR. + LD HL,12 ; PUT DESIRED EXTENT INTO FCB NOW. + ADD HL,DE + LD (HL),C + LD HL,14 ; AND STORE EXTRA EXTENT BYTE 'S2'. + ADD HL,DE + LD (HL),B + CALL OPENIT ; TRY AND GET THIS EXTENT. + LD A,(STATUS) ; WAS IT THERE? + INC A + JP NZ,POSITN3 + POP BC ; NO. CAN WE CREATE A NEW ONE (WRITING?). + PUSH BC + LD L,4 ; PREPARE FOR ERROR. + INC C + JP Z,POSITN4 ; NOPE, READING UNWRITTEN SPACE ERROR. + CALL GETEMPTY ; YES WE CAN, TRY TO FIND SPACE. + LD L,5 ; PREPARE FOR ERROR. + LD A,(STATUS) + INC A + JP Z,POSITN4 ; OUT OF SPACE? +; +; NORMAL RETURN LOCATION. CLEAR ERROR CODE AND RETURN. +; +POSITN3:POP BC ; RESTORE STACK. + XOR A ; AND CLEAR ERROR CODE BYTE. + JP SETSTAT +; +; ERROR. SET THE 'S2' BYTE TO INDICATE THIS (WHY?). +; +POSITN4:PUSH HL + CALL GETS2 + LD (HL),0C0H + POP HL +; +; RETURN WITH ERROR CODE (PRESENTLY IN L). +; +POSITN5:POP BC + LD A,L ; GET ERROR CODE. + LD (STATUS),A + JP SETS2B7 +; +; READ A RANDOM RECORD. +; +READRAN:LD C,0FFH ; SET 'READ' STATUS. + CALL POSITION ; POSITION THE FILE TO PROPER RECORD. + CALL Z,RDSEQ1 ; AND READ IT AS USUAL (IF NO ERRORS). + RET +; +; WRITE TO A RANDOM RECORD. +; +WRITERAN: + LD C,0 ; SET 'WRITING' FLAG. + CALL POSITION ; POSITION THE FILE TO PROPER RECORD. + CALL Z,WTSEQ1 ; AND WRITE AS USUAL (IF NO ERRORS). + RET +; +; COMPUTE THE RANDOM RECORD NUMBER. ENTER WITH (HL) POINTING +; TO A FCB AN (DE) CONTAINS A RELATIVE LOCATION OF A RECORD +; NUMBER. ON EXIT, (C) CONTAINS THE 'R0' BYTE, (B) THE 'R1' +; BYTE, AND (A) THE 'R2' BYTE. +; +; ON RETURN, THE ZERO FLAG IS SET IF THE RECORD IS WITHIN +; BOUNDS. OTHERWISE, AN OVERFLOW OCCURED. +; +COMPRAND: + EX DE,HL ; SAVE FCB POINTER IN (DE). + ADD HL,DE ; COMPUTE RELATIVE POSITION OF RECORD #. + LD C,(HL) ; GET RECORD NUMBER INTO (BC). + LD B,0 + LD HL,12 ; NOW GET EXTENT. + ADD HL,DE + LD A,(HL) ; COMPUTE (BC)=(RECORD #)+(EXTENT)*128. + RRCA ; MOVE LOWER BIT INTO BIT 7. + AND 80H ; AND IGNORE ALL OTHER BITS. + ADD A,C ; ADD TO OUR RECORD NUMBER. + LD C,A + LD A,0 ; TAKE CARE OF ANY CARRY. + ADC A,B + LD B,A + LD A,(HL) ; NOW GET THE UPPER BITS OF EXTENT INTO + RRCA ; BIT POSITIONS 0-3. + AND 0FH ; AND IGNORE ALL OTHERS. + ADD A,B ; ADD THIS IN TO 'R1' BYTE. + LD B,A + LD HL,14 ; GET THE 'S2' BYTE (EXTRA EXTENT). + ADD HL,DE + LD A,(HL) + ADD A,A ; AND SHIFT IT LEFT 4 BITS (BITS 4-7). + ADD A,A + ADD A,A + ADD A,A + PUSH AF ; SAVE CARRY FLAG (BIT 0 OF FLAG BYTE). + ADD A,B ; NOW ADD EXTRA EXTENT INTO 'R1'. + LD B,A + PUSH AF ; AND SAVE CARRY (OVERFLOW BYTE 'R2'). + POP HL ; BIT 0 OF (L) IS THE OVERFLOW INDICATOR. + LD A,L + POP HL ; AND SAME FOR FIRST CARRY FLAG. + OR L ; EITHER ONE OF THESE SET? + AND 01H ; ONLY CHECK THE CARRY FLAGS. + RET +; +; ROUTINE TO SETUP THE FCB (BYTES 'R0', 'R1', 'R2') TO +; REFLECT THE LAST RECORD USED FOR A RANDOM (OR OTHER) FILE. +; THIS READS THE DIRECTORY AND LOOKS AT ALL EXTENTS COMPUTING +; THE LARGERST RECORD NUMBER FOR EACH AND KEEPING THE MAXIMUM +; VALUE ONLY. THEN 'R0', 'R1', AND 'R2' WILL REFLECT THIS +; MAXIMUM RECORD NUMBER. THIS IS USED TO COMPUTE THE SPACE USED +; BY A RANDOM FILE. +; +RANSIZE:LD C,12 ; LOOK THRU DIRECTORY FOR FIRST ENTRY WITH + CALL FINDFST ; THIS NAME. + LD HL,(PARAMS) ; ZERO OUT THE 'R0, R1, R2' BYTES. + LD DE,33 + ADD HL,DE + PUSH HL + LD (HL),D ; NOTE THAT (D)=0. + INC HL + LD (HL),D + INC HL + LD (HL),D +RANSIZ1:CALL CKFILPOS ; IS THERE AN EXTENT TO PROCESS? + JP Z,RANSIZ3 ; NO, WE ARE DONE. + CALL FCB2HL ; SET (HL) POINTING TO PROPER FCB IN DIR. + LD DE,15 ; POINT TO LAST RECORD IN EXTENT. + CALL COMPRAND ; AND COMPUTE RANDOM PARAMETERS. + POP HL + PUSH HL ; NOW CHECK THESE VALUES AGAINST THOSE + LD E,A ; ALREADY IN FCB. + LD A,C ; THE CARRY FLAG WILL BE SET IF THOSE + SUB (HL) ; IN THE FCB REPRESENT A LARGER SIZE THAN + INC HL ; THIS EXTENT DOES. + LD A,B + SBC A,(HL) + INC HL + LD A,E + SBC A,(HL) + JP C,RANSIZ2 + LD (HL),E ; WE FOUND A LARGER (IN SIZE) EXTENT. + DEC HL ; STUFF THESE VALUES INTO FCB. + LD (HL),B + DEC HL + LD (HL),C +RANSIZ2:CALL FINDNXT ; NOW GET THE NEXT EXTENT. + JP RANSIZ1 ; CONTINUE TIL ALL DONE. +RANSIZ3:POP HL ; WE ARE DONE, RESTORE THE STACK AND + RET ; RETURN. +; +; FUNCTION TO RETURN THE RANDOM RECORD POSITION OF A GIVEN +; FILE WHICH HAS BEEN READ IN S.EQUENTIAL MODE UP TO NOW. +; +SETRAN: LD HL,(PARAMS) ; POINT TO FCB. + LD DE,32 ; AND TO LAST USED RECORD. + CALL COMPRAND ; COMPUTE RANDOM POSITION. + LD HL,33 ; NOW STUFF THESE VALUES INTO FCB. + ADD HL,DE + LD (HL),C ; MOVE 'R0'. + INC HL + LD (HL),B ; AND 'R1'. + INC HL + LD (HL),A ; AND LASTLY 'R2'. + RET +; +; THIS ROUTINE SELECT THE DRIVE SPECIFIED IN (ACTIVE) AND +; UPDATE THE LOGIN VECTOR AND BITMAP TABLE IF THIS DRIVE WAS +; NOT ALREADY ACTIVE. +; +LOGINDRV: + LD HL,(LOGIN) ; GET THE LOGIN VECTOR. + LD A,(ACTIVE) ; GET THE DEFAULT DRIVE. + LD C,A + CALL SHIFTR ; POSITION ACTIVE BIT FOR THIS DRIVE + PUSH HL ; INTO BIT 0. + EX DE,HL + CALL SELECT ; SELECT THIS DRIVE. + POP HL + CALL Z,SLCTERR ; VALID DRIVE? + LD A,L ; IS THIS A NEWLY ACTIVATED DRIVE? + RRA + RET C + LD HL,(LOGIN) ; YES, UPDATE THE LOGIN VECTOR. + LD C,L + LD B,H + CALL SETBIT + LD (LOGIN),HL ; AND SAVE. + JP BITMAP ; NOW UPDATE THE BITMAP. +; +; FUNCTION TO SET THE ACTIVE DISK NUMBER. +; +SETDSK: LD A,(EPARAM) ; GET PARAMETER PASSED AND SEE IF THIS + LD HL,ACTIVE ; REPRESENTS A CHANGE IN DRIVES. + CP (HL) + RET Z + LD (HL),A ; YES IT DOES, LOG IT IN. + JP LOGINDRV +; +; THIS IS THE 'AUTO DISK SELECT' ROUTINE. THE FIRSST BYTE +; OF THE FCB IS EXAMINED FOR A DRIVE SPECIFICATION. IF NON +; ZERO THEN THE DRIVE WILL BE SELECTED AND LOGED IN. +; +AUTOSEL:LD A,0FFH ; SAY 'AUTO-SELECT ACTIVATED'. + LD (AUTO),A + LD HL,(PARAMS) ; GET DRIVE SPECIFIED. + LD A,(HL) + AND 1FH ; LOOK AT LOWER 5 BITS. + DEC A ; ADJUST FOR (1=A, 2=B) ETC. + LD (EPARAM),A ; AND SAVE FOR THE SELECT ROUTINE. + CP 1EH ; CHECK FOR 'NO CHANGE' CONDITION. + JP NC,AUTOSL1 ; YES, DON'T CHANGE. + LD A,(ACTIVE) ; WE MUST CHANGE, SAVE CURRENTLY ACTIVE + LD (OLDDRV),A ; DRIVE. + LD A,(HL) ; AND SAVE FIRST BYTE OF FCB ALSO. + LD (AUTOFLAG),A ; THIS MUST BE NON-ZERO. + AND 0E0H ; WHATS THIS FOR (BITS 6,7 ARE USED FOR + LD (HL),A ; SOMETHING)? + CALL SETDSK ; SELECT AND LOG IN THIS DRIVE. +AUTOSL1:LD A,(USERNO) ; MOVE USER NUMBER INTO FCB. + LD HL,(PARAMS) ; (* UPPER HALF OF FIRST BYTE *) + OR (HL) + LD (HL),A + RET ; AND RETURN (ALL DONE). +; +; FUNCTION TO RETURN THE CURRENT CP/M VERSION NUMBER. +; +GETVER: LD A,022H ; VERSION 2.2 + JP SETSTAT +; +; FUNCTION TO RESET THE DISK SYSTEM. +; +RSTDSK: LD HL,0 ; CLEAR WRITE PROTECT STATUS AND LOG + LD (WRTPRT),HL ; IN VECTOR. + LD (LOGIN),HL + XOR A ; SELECT DRIVE 'A'. + LD (ACTIVE),A + LD HL,TBUFF ; SETUP DEFAULT DMA ADDRESS. + LD (USERDMA),HL + CALL DEFDMA + JP LOGINDRV ; NOW LOG IN DRIVE 'A'. +; +; FUNCTION TO OPEN A SPECIFIED FILE. +; +OPENFIL:CALL CLEARS2 ; CLEAR 'S2' BYTE. + CALL AUTOSEL ; SELECT PROPER DISK. + JP OPENIT ; AND OPEN THE FILE. +; +; FUNCTION TO CLOSE A SPECIFIED FILE. +; +CLOSEFIL: + CALL AUTOSEL ; SELECT PROPER DISK. + JP CLOSEIT ; AND CLOSE THE FILE. +; +; FUNCTION TO RETURN THE FIRST OCCURENCE OF A SPECIFIED FILE +; NAME. IF THE FIRST BYTE OF THE FCB IS '?' THEN THE NAME WILL +; NOT BE CHECKED (GET THE FIRST ENTRY NO MATTER WHAT). +; +GETFST: LD C,0 ; PREPARE FOR SPECIAL SEARCH. + EX DE,HL + LD A,(HL) ; IS FIRST BYTE A '?'? + CP '?' + JP Z,GETFST1 ; YES, JUST GET VERY FIRST ENTRY (ZERO LENGTH MATCH). + CALL SETEXT ; GET THE EXTENSION BYTE FROM FCB. + LD A,(HL) ; IS IT '?'? IF YES, THEN WE WANT + CP '?' ; AN ENTRY WITH A SPECIFIC 'S2' BYTE. + CALL NZ,CLEARS2 ; OTHERWISE, LOOK FOR A ZERO 'S2' BYTE. + CALL AUTOSEL ; SELECT PROPER DRIVE. + LD C,15 ; COMPARE BYTES 0-14 IN FCB (12&13 EXCLUDED). +GETFST1:CALL FINDFST ; FIND AN ENTRY AND THEN MOVE IT INTO + JP MOVEDIR ; THE USERS DMA SPACE. +; +; FUNCTION TO RETURN THE NEXT OCCURENCE OF A FILE NAME. +; +GETNXT: LD HL,(SAVEFCB) ; RESTORE POINTERS. NOTE THAT NO + LD (PARAMS),HL ; OTHER .DBOS CALLS ARE ALLOWED. + CALL AUTOSEL ; NO ERROR WILL BE RETURNED, BUT THE + CALL FINDNXT ; RESULTS WILL BE WRONG. + JP MOVEDIR +; +; FUNCTION TO DELETE A FILE BY NAME. +; +DELFILE:CALL AUTOSEL ; SELECT PROPER DRIVE. + CALL ERAFILE ; ERASE THE FILE. + JP STSTATUS ; SET STATUS AND RETURN. +; +; FUNCTION TO EXECUTE A S.EQUENTIAL READ OF THE SPECIFIED +; RECORD NUMBER. +; +READSEQ:CALL AUTOSEL ; SELECT PROPER DRIVE THEN READ. + JP RDSEQ +; +; FUNCTION TO WRITE THE NET S.EQUENTIAL RECORD. +; +WRTSEQ: CALL AUTOSEL ; SELECT PROPER DRIVE THEN WRITE. + JP WTSEQ +; +; CREATE A FILE FUNCTION. +; +FCREATE:CALL CLEARS2 ; CLEAR THE 'S2' BYTE ON ALL CREATES. + CALL AUTOSEL ; SELECT PROPER DRIVE AND GET THE NEXT + JP GETEMPTY ; EMPTY DIRECTORY SPACE. +; +; FUNCTION TO RENAME A FILE. +; +RENFILE:CALL AUTOSEL ; SELECT PROPER DRIVE AND THEN SWITCH + CALL CHGNAMES ; FILE NAMES. + JP STSTATUS +; +; FUNCTION TO RETURN THE LOGIN VECTOR. +; +GETLOG: LD HL,(LOGIN) + JP GETPRM1 +; +; FUNCTION TO RETURN THE CURRENT DISK ASSIGNMENT. +; +GETCRNT:LD A,(ACTIVE) + JP SETSTAT +; +; FUNCTION TO SET THE DMA ADDRESS. +; +PUTDMA: EX DE,HL + LD (USERDMA),HL ; SAVE IN OUR SPACE AND THEN GET TO + JP DEFDMA ; THE BIOS WITH THIS ALSO. +; +; FUNCTION TO RETURN THE ALLOCATION VECTOR. +; +GETALOC:LD HL,(ALOCVECT) + JP GETPRM1 +; +; FUNCTION TO RETURN THE READ-ONLY STATUS VECTOR. +; +GETROV: LD HL,(WRTPRT) + JP GETPRM1 +; +; FUNCTION TO SET THE FILE ATTRIBUTES (READ-ONLY, SYSTEM). +; +SETATTR:CALL AUTOSEL ; SELECT PROPER DRIVE THEN SAVE ATTRIBUTES. + CALL SAVEATTR + JP STSTATUS +; +; FUNCTION TO RETURN THE ADDRESS OF THE DISK PARAMETER BLOCK +; FOR THE CURRENT DRIVE. +; +GETPARM:LD HL,(DISKPB) +GETPRM1:LD (STATUS),HL + RET +; +; FUNCTION TO GET OR SET THE USER NUMBER. IF (E) WAS (FF) +; THEN THIS IS A REQUEST TO RETURN THE CURRENT USER NUMBER. +; ELSE SET THE USER NUMBER FROM (E). +; +GETUSER:LD A,(EPARAM) ; GET PARAMETER. + CP 0FFH ; GET USER NUMBER? + JP NZ,SETUSER + LD A,(USERNO) ; YES, JUST DO IT. + JP SETSTAT +SETUSER:AND 1FH ; NO, WE SHOULD SET IT INSTEAD. KEEP LOW + LD (USERNO),A ; BITS (0-4) ONLY. + RET +; +; FUNCTION TO READ A RANDOM RECORD FROM A FILE. +; +RDRANDOM: + CALL AUTOSEL ; SELECT PROPER DRIVE AND READ. + JP READRAN +; +; FUNCTION TO COMPUTE THE FILE SIZE FOR RANDOM FILES. +; +WTRANDOM: + CALL AUTOSEL ; SELECT PROPER DRIVE AND WRITE. + JP WRITERAN +; +; FUNCTION TO COMPUTE THE SIZE OF A RANDOM FILE. +; +FILESIZE: + CALL AUTOSEL ; SELECT PROPER DRIVE AND CHECK FILE LENGTH + JP RANSIZE +; +; FUNCTION #37. THIS ALLOWS A PROGRAM TO LOG OFF ANY DRIVES. +; ON ENTRY, SET (DE) TO CONTAIN A WORD WITH BITS SET FOR THOSE +; DRIVES THAT ARE TO BE LOGGED OFF. THE LOG-IN VECTOR AND THE +; WRITE PROTECT VECTOR WILL BE UPDATED. THIS MUST BE A M/PM +; SPECIAL FUNCTION. +; +LOGOFF: LD HL,(PARAMS) ; GET DRIVES TO LOG OFF. + LD A,L ; FOR EACH BIT THAT IS SET, WE WANT + CPL ; TO CLEAR THAT BIT IN (LOGIN) + LD E,A ; AND (WRTPRT). + LD A,H + CPL + LD HL,(LOGIN) ; RESET THE LOGIN VECTOR. + AND H + LD D,A + LD A,L + AND E + LD E,A + LD HL,(WRTPRT) + EX DE,HL + LD (LOGIN),HL ; AND SAVE. + LD A,L ; NOW DO THE WRITE PROTECT VECTOR. + AND E + LD L,A + LD A,H + AND D + LD H,A + LD (WRTPRT),HL ; AND SAVE. ALL DONE. + RET +; +; GET HERE TO RETURN TO THE USER. +; +GOBACK: LD A,(AUTO) ; WAS AUTO SELECT ACTIVATED? + OR A + JP Z,GOBACK1 + LD HL,(PARAMS) ; YES, BUT WAS A CHANGE MADE? + LD (HL),0 ; (* RESET FIRST BYTE OF FCB *) + LD A,(AUTOFLAG) + OR A + JP Z,GOBACK1 + LD (HL),A ; YES, RESET FIRST BYTE PROPERLY. + LD A,(OLDDRV) ; AND GET THE OLD DRIVE AND SELECT IT. + LD (EPARAM),A + CALL SETDSK +GOBACK1:LD HL,(USRSTACK) ; RESET THE USERS STACK POINTER. + LD SP,HL + LD HL,(STATUS) ; GET RETURN STATUS. + LD A,L ; FORCE VERSION 1.4 COMPATABILITY. + LD B,H + RET ; AND GO BACK TO USER. +; +; FUNCTION #40. THIS IS A SPECIAL ENTRY TO DO RANDOM I/O. +; FOR THE CASE WHERE WE ARE WRITING TO UNUSED DISK SPACE, THIS +; SPACE WILL BE ZEROED OUT FIRST. THIS MUST BE A M/PM SPECIAL +; PURPOSE FUNCTION, BECAUSE WHY WOULD ANY NORMAL PROGRAM EVEN +; CARE ABOUT THE PREVIOUS CONTENTS OF A SECTOR ABOUT TO BE +; WRITTEN OVER. +; +WTSPECL:CALL AUTOSEL ; SELECT PROPER DRIVE. + LD A,2 ; USE SPECIAL WRITE MODE. + LD (MODE),A + LD C,0 ; SET WRITE INDICATOR. + CALL POSITN1 ; POSITION THE FILE. + CALL Z,WTSEQ1 ; AND WRITE (IF NO ERRORS). + RET +; +;************************************************************** +;* +;* BDOS DATA STORAGE POOL. +;* +;************************************************************** +; +EMPTYFCB: + .DB 0E5H ; EMPTY DIRECTORY SEGMENT INDICATOR. +WRTPRT: .DW 0 ; WRITE PROTECT STATUS FOR ALL 16 DRIVES. +LOGIN: .DW 0 ; DRIVE ACTIVE WORD (1 BIT PER DRIVE). +USERDMA:.DW 080H ; USER'S DMA ADDRESS (DEFAULTS TO 80H). +; +; SCRATCH AREAS FROM PARAMETER BLOCK. +; +SCRATCH1: + .DW 0 ; RELATIVE POSITION WITHIN DIR SEGMENT FOR FILE (0-3). +SCRATCH2: + .DW 0 ; LAST SELECTED TRACK NUMBER. +SCRATCH3: + .DW 0 ; LAST SELECTED SECTOR NUMBER. +; +; DISK STORAGE AREAS FROM PARAMETER BLOCK. +; +DIRBUF: .DW 0 ; ADDRESS OF DIRECTORY BUFFER TO USE. +DISKPB: .DW 0 ; CONTAINS ADDRESS OF DISK PARAMETER BLOCK. +CHKVECT:.DW 0 ; ADDRESS OF CHECK VECTOR. +ALOCVECT: + .DW 0 ; ADDRESS OF ALLOCATION VECTOR (BIT MAP). +; +; PARAMETER BLOCK RETURNED FROM THE BIOS. +; +SECTORS:.DW 0 ; SECTORS PER TRACK FROM BIOS. +BLKSHFT:.DB 0 ; BLOCK SHIFT. +BLKMASK:.DB 0 ; BLOCK MASK. +EXTMASK:.DB 0 ; EXTENT MASK. +DSKSIZE:.DW 0 ; DISK SIZE FROM BIOS (NUMBER OF BLOCKS-1). +DIRSIZE:.DW 0 ; DIRECTORY SIZE. +ALLOC0: .DW 0 ; STORAGE FOR FIRST BYTES OF BIT MAP (DIR SPACE USED). +ALLOC1: .DW 0 +OFFSET: .DW 0 ; FIRST USABLE TRACK NUMBER. +XLATE: .DW 0 ; SECTOR TRANSLATION TABLE ADDRESS. +; +; +CLOSEFLG: + .DB 0 ; CLOSE FLAG (=0FFH IS EXTENT WRITTEN OK). +R.DWRTFLG: + .DB 0 ; READ/WRITE FLAG (0FFH=READ, 0=WRITE). +FNDSTAT:.DB 0 ; FILENAME FOUND STATUS (0=FOUND FIRST ENTRY). +MODE: .DB 0 ; I/O MODE SELECT (0=RANDOM, 1=S.EQUENTIAL, 2=SPECIAL RANDOM). +EPARAM: .DB 0 ; STORAGE FOR REGISTER (E) ON ENTRY TO BDOS. +RELBLOCK: + .DB 0 ; RELATIVE POSITION WITHIN FCB OF BLOCK NUMBER WRITTEN. +COUNTER:.DB 0 ; BYTE COUNTER FOR DIRECTORY NAME SEARCHES. +SAVEFCB:.DW 0,0 ; SAVE SPACE FOR ADDRESS OF FCB (FOR DIRECTORY SEARCHES). +BIGDISK:.DB 0 ; IF =0 THEN DISK IS > 256 BLOCKS LONG. +AUTO: .DB 0 ; IF NON-ZERO, THEN AUTO SELECT ACTIVATED. +OLDDRV: .DB 0 ; ON AUTO SELECT, STORAGE FOR PREVIOUS DRIVE. +AUTOFLAG: + .DB 0 ; IF NON-ZERO, THEN AUTO SELECT CHANGED DRIVES. +SAVNXT: .DB 0 ; STORAGE FOR NEXT RECORD NUMBER TO ACCESS. +SAVEXT: .DB 0 ; STORAGE FOR EXTENT NUMBER OF FILE. +SAVNREC:.DW 0 ; STORAGE FOR NUMBER OF RECORDS IN FILE. +BLKNMBR:.DW 0 ; BLOCK NUMBER (PHYSICAL SECTOR) USED WITHIN A FILE OR LOGICAL SEC +LOGSECT:.DW 0 ; STARTING LOGICAL (128 BYTE) SECTOR OF BLOCK (PHYSICAL SECTOR). +FCBPOS: .DB 0 ; RELATIVE POSITION WITHIN BUFFER FOR FCB OF FILE OF INTEREST. +FILEPOS:.DW 0 ; FILES POSITION WITHIN DIRECTORY (0 TO MAX ENTRIES -1). +; +; DISK DIRECTORY BUFFER CHECKSUM BYTES. ONE FOR EACH OF THE +; 16 POSSIBLE DRIVES. +; +CKSUMTBL: + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +; +;************************************************************** +;* +;* B I O S J U M P T A B L E +;* +;************************************************************** +; +BIOS: .EQU BIOSO ;BIOS ORIGIN +; +BOOT: .EQU BIOS ;(BOOT) Cold boot entry +WBOOT: .EQU BIOS+3 ;Warm boot entry +CONST: .EQU BIOS+6 ;Console status +CONIN: .EQU BIOS+9 ;Console char in +CONOUT: .EQU BIOS+12 ;Console char out +LIST: .EQU BIOS+15 ;List char out +PUNCH: .EQU BIOS+18 ;Punch char out +READER: .EQU BIOS+21 ;Reader char in +HOME: .EQU BIOS+24 ;Home disk +SELDSK: .EQU BIOS+27 ;Select disk +SETTRK: .EQU BIOS+30 ;Set disk track addr +SETSEC: .EQU BIOS+33 ;Set disk sector addr +SETDMA: .EQU BIOS+36 ;Set DMA buffer addr +READ: .EQU BIOS+39 ;Read sector +WRITE: .EQU BIOS+42 ;Write sector +SECTRN: .EQU BIOS+48 ;Sector translation routine +; + .IF ENDFIL + .FILL ((BDOSO + 0E00H) - $),055H + .ENDIF + + .END diff --git a/trunk/Source/bioshdr.inc b/trunk/Source/bioshdr.inc new file mode 100644 index 00000000..4ee1e8e1 --- /dev/null +++ b/trunk/Source/bioshdr.inc @@ -0,0 +1,131 @@ +; bioshdr.inc 5/10/2012 dwg - offsets into the BIOS Header data + +B_BOOT .equ 0e600h +B_WBOOT .equ 0e603h +B_CONST .equ 0e606h +B_CONIN .equ 0e609h +B_CONOUT .equ 0e60ch +B_LIST .equ 0e60fh +B_PUNCH .equ 0e612h +B_READER .equ 0e615h +B_HOME .equ 0e618h +B_SELDSK .equ 0e61bh +B_SETTRK .equ 0e61eh +B_SETSEC .equ 0e621h +B_SETDMA .equ 0e624h +B_READ .equ 0e627h +B_WRITE .equ 0e62ah +B_LISTST .equ 0e62dh +B_SECTRN .equ 0e630h +B_BNKSEL .equ 0e633h +B_GETLU .equ 0e636h +B_SETLU .equ 0e639h +B_GETINFO .equ 0e63ch +B_RSVD1 .equ 0e63fh +B_RSVD2 .equ 0e642h +B_RSVD3 .equ 0e645h +B_RSVD4 .equ 0e648h + +B_CNFGDATA .equ 0e64bh + +B_RMJ .equ 0e64bh +B_RMN .equ 0e64ch +B_RUP .equ 0e64dh +B_RTP .equ 0e64eh +B_DSKBOOT .equ 0e64fh +B_BOOTDRV .equ 0e650h + +B_MONTH .equ 0e651h +B_DAY .equ 0e652h +B_YEAR .equ 0e653h + +B_HOUR .equ 0e654h +B_MIN .equ 0e655h +B_SEC .equ 0e656h + +; Config Proper Start Here + +B_FREQ .equ 0e657h +B_PLATFORM .equ B_FREQ+1 +B_DIOPLAT .equ B_PLATFORM+1 +B_VDUMODE .equ B_DIOPLAT+1 +B_ROMSIZE .equ B_VDUMODE+1 +B_RAMSIZE .equ B_ROMSIZE+2 +B_CLRRAMDSK .equ B_RAMSIZE+2 +B_DSKYENABLE .equ B_CLRRAMDSK+1 +B_UARTENABLE .equ B_DSKYENABLE+1 +B_VDUENABLE .equ B_UARTENABLE+1 +B_FDENABLE .equ B_VDUENABLE+1 +B_FDTRACE .equ B_FDENABLE+1 +B_FDMEDIA .equ B_FDTRACE+1 +B_FDMEDIAALT .equ B_FDMEDIA+1 +B_FDMAUTO .equ B_FDMEDIAALT+1 +B_IDEENABLE .equ B_FDMAUTO+1 +B_IDETRACE .equ B_IDEENABLE+1 +B_IDE8BIT .equ B_IDETRACE+1 +B_IDECAPACITY .equ B_IDE8BIT+1 +B_PPIDEENABLE .equ B_IDECAPACITY+2 +B_PPIDETRACE .equ B_PPIDEENABLE+1 +B_PPIDE8BIT .equ B_PPIDETRACE+1 +B_PPIDECAPACITY .equ B_PPIDE8BIT+1 +B_PPIDESLOW .equ B_PPIDECAPACITY+2 +B_BOOTTYPE .equ B_PPIDESLOW+1 +B_BAUDRATE .equ B_BOOTTYPE+1 +B_CLKDIV .equ B_BAUDRATE+2 + +B_MEMWAIT .equ B_CLKDIV+1 +B_IOWAIT .equ B_MEMWAIT+1 +B_CNTLB0 .equ B_IOWAIT+1 +B_CNTLB1 .equ B_CNTLB0+1 +B_SDCAPACITY .equ B_CNTLB1+1 +B_SDCSIO .equ B_SDCAPACITY+2 +B_SDCSIOFAST .equ B_SDCSIO+1 +B_DEFIOBYTE .equ B_SDCSIOFAST+1 +B_TERMTYPE .equ B_DEFIOBYTE+1 +B_REVISION .equ B_TERMTYPE+1 +B_PRPSDENABLE .equ B_REVISION+2 +B_PRPSDTRACE .equ B_PRPSDENABLE+1 +B_PRPSDCAPACITY .equ B_PRPSDTRACE+1 +B_PRPCONENABLE .equ B_PRPSDCAPACITY+2 +B_DATASIZE .equ B_PRPCONENABLE+1 + + +B_INFOVER .equ 0 +B_STRBANNER .equ B_INFOVER+2 +B_VARLOC .equ B_STRBANNER+2 +B_TSTLOC .equ B_VARLOC+2 +B_SECADR .equ B_TSTLOC+2 +B_SEKDSK .equ B_SECADR+2 +B_SEKTRK .equ B_SEKDSK+2 +B_SEKSEC .equ B_SEKTRK+2 +B_DSKOP .equ B_SEKSEC+2 +B_DMAADR .equ B_DSKOP+2 +B_DPHADR .equ B_DMAADR+2 +B_XLT .equ B_DPHADR+2 +B_HST .equ B_XLT+2 +B_DIRBF .equ B_HST+2 +B_DPBMAP .equ B_DIRBF+2 +B_DSKMAP .equ B_DPBMAP+2 +B_DPHMAP .equ B_DSKMAP+2 +B_CIOMAP .equ B_DPHMAP+2 +B_SECBUF .equ B_CIOMAP+2 +B_ORGFDDATA .equ B_SECBUF+2 +B_ORGIDEDATA .equ B_ORGFDDATA+2 +B_ORGSDDATA .equ B_ORGIDEDATA+2 +B_ORGPRPSDDATA .equ B_ORGSDDATA+2 +B_ORGPPPSDDATA .equ B_ORGPRPSDDATA+2 +B_INFOTBLSIZE .equ B_ORGPPPSDDATA+2 + +;;;;;;;;;;;;;;;;;;;;; +; eof - bioshdr.inc ; +;;;;;;;;;;;;;;;;;;;;; + + + + + + + + + + diff --git a/trunk/Source/blank1024KB.dat b/trunk/Source/blank1024KB.dat new file mode 100644 index 00000000..d4f7033b --- /dev/null +++ b/trunk/Source/blank1024KB.dat @@ -0,0 +1 @@ +ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ \ No newline at end of file diff --git a/trunk/Source/blank512KB.dat b/trunk/Source/blank512KB.dat new file mode 100644 index 00000000..f353b2bb --- /dev/null +++ b/trunk/Source/blank512KB.dat @@ -0,0 +1 @@ +ċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċċ \ No newline at end of file diff --git a/trunk/Source/bnk1.asm b/trunk/Source/bnk1.asm new file mode 100644 index 00000000..4fa1c395 --- /dev/null +++ b/trunk/Source/bnk1.asm @@ -0,0 +1,502 @@ +;__________________________________________________________________________________________________ +; +; BANK1 +;__________________________________________________________________________________________________ +; + +; bnk1.asm 5/23/2012 dwg Beta 4 - Enhanced SYS_GETCFG and SYS_SETCFG + + + .ORG 1000H +; +; INCLUDE GENERIC STUFF +; +#INCLUDE "std.asm" +; +;================================================================================================== +; BANK 1 ENTRY / JUMP TABLE +;================================================================================================== +; +; THIS IS THE ENTRY DISPATCH POINT FOR BANK1 +;__________________________________________________________________________________________________ +; + JP INITSYS + JP BIOS_DISPATCH +; +;================================================================================================== +; SYSTEM INITIALIZATION +;================================================================================================== +; +; AT THIS POINT, IT IS ASSUMED WE ARE OPERATING FROM RAM PAGE 1 +; +INITSYS: +; +; INSTALL HBIOS PROXY IN UPPER MEMORY +; + LD HL,HB_IMG + LD DE,HB_LOC + LD BC,HB_SIZ + LDIR +; + LD HL,$8000 ; DEFAULT DISK XFR BUF ADDRESS + LD (DIOBUF),HL ; SAVE IT +; +#IF (PLATFORM != PLT_N8) + IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER +; LD A,40H ; *DEBUG* SIMULATE JUMPER OPEN +; LD A,00H ; *DEBUG* SIMULATE JUMPER SHORTED + AND 40H ; ISOLATE BIT 6 + JR Z,INITSYS1 ; IF BIT6=0, SHORTED, USE ALT CONSOLE + LD A,DEFCON ; LOAD DEF CONSOLE DEVICE CODE + JR INITSYS2 ; CONTINUE +INITSYS1: + LD A,ALTCON ; LOAD ALT CONSOLE DEVICE CODE +INITSYS2: + LD (CONDEV),A ; SET THE ACTIVE CONSOLE DEVICE +#ENDIF +; +; PERFORM DEVICE INITIALIZATION +; +#IF (UARTENABLE) + CALL UART_INIT +#ENDIF +#IF (VDUENABLE) + CALL VDU_INIT +#ENDIF +#IF (PRPENABLE) + CALL PRP_INIT +#ENDIF +#IF (PPPENABLE) + CALL PPP_INIT +#ENDIF +#IF (DSKYENABLE) + CALL DSKY_INIT +#ENDIF +#IF (FDENABLE) + CALL FD_INIT +#ENDIF +#IF (IDEENABLE) + CALL IDE_INIT +#ENDIF +#IF (PPIDEENABLE) + CALL PPIDE_INIT +#ENDIF +#IF (SDENABLE) + CALL SD_INIT +#ENDIF +#IF (HDSKENABLE) + CALL HDSK_INIT +#ENDIF +; + RET +; +;================================================================================================== +; IDLE +;================================================================================================== +; +;__________________________________________________________________________________________________ +; +IDLE: +#IF (FDENABLE) + CALL FD_IDLE +#ENDIF + RET +; +;================================================================================================== +; BIOS FUNCTION DISPATCHER +;================================================================================================== +; +; MAIN BIOS FUNCTION +; B: FUNCTION +;__________________________________________________________________________________________________ +; +BIOS_DISPATCH: + LD A,B ; REQUESTED FUNCTION IS IN B + CP BF_CIO + $10 + JR C,CIO_DISPATCH + CP BF_DIO + $10 + JR C,DIO_DISPATCH + CP BF_CLK + $10 + JR C,CLK_DISPATCH + CP BF_VDU + $10 + JR C,CRT_DISPATCH + + CP BF_SYS ; SKIP TO BF_SYS VALUE AT $F0 + CALL C,PANIC ; PANIC IF LESS THAN BF_SYS + JR SYS_DISPATCH ; OTHERWISE SYS CALL + CALL PANIC ; THIS SHOULD NEVER BE REACHED +; +; SETUP AND CALL CHARACTER DRIVER +; B: FUNCTION +; C: DEVICE/UNIT +; E: CHARACTER IN/OUT +; +CIO_DISPATCH: + LD A,C ; REQUESTED DEVICE/UNIT IS IN C + AND $F0 ; ISOLATE THE DEVICE PORTION +#IF (UARTENABLE) + CP CIODEV_UART + JP Z,UART_DISPATCH +#ENDIF +#IF (PRPENABLE & PRPCONENABLE) + CP CIODEV_PRPCON + JP Z,PRPCON_DISPATCH +#ENDIF +#IF (PPPENABLE & PPPCONENABLE) + CP CIODEV_PPPCON + JP Z,PPPCON_DISPATCH +#ENDIF +#IF (VDUENABLE) + CP CIODEV_VDU + JP Z,VDU_DISPATCH +#ENDIF + CALL PANIC +; +; +; +DIO_DISPATCH: + LD A,B + + ; DIO FUNCTIONS STARTING AT $18 ARE COMMON + ; AND DO NOT DISPATCH TO DRIVERS + CP $18 + JR NC,DIO_COMMON + + ; DISPATCH FUCNTION TO APPROPRIATE DRIVER + AND $0F ; + + ; HACK TO FILL IN HSTTRK AND HSTSEC + ; BUT ONLY FOR READ/WRITE FUNCTION CALLS + ; ULTIMATELY, HSTTRK AND HSTSEC ARE TO BE REMOVED + CP 2 + JR NC,DIO_DISPATCH1 + LD (HSTTRK),HL + LD (HSTSEC),DE +DIO_DISPATCH1: + LD A,C ; REQUESTED DEVICE/UNIT IS IN C + LD (HSTDSK),A ; TEMP HACK TO FILL IN HSTDSK + AND $F0 ; ISOLATE THE DEVICE PORTION +#IF (FDENABLE) + CP DIODEV_FD + JP Z,FD_DISPATCH +#ENDIF +#IF (IDEENABLE) + CP DIODEV_IDE + JP Z,IDE_DISPATCH +#ENDIF +#IF (PPIDEENABLE) + CP DIODEV_PPIDE + JP Z,PPIDE_DISPATCH +#ENDIF +#IF (SDENABLE) + CP DIODEV_SD + JP Z,SD_DISPATCH +#ENDIF +#IF (PRPENABLE & PRPSDENABLE) + CP DIODEV_PRPSD + JP Z,PRPSD_DISPATCH +#ENDIF +#IF (PPPENABLE & PPPSDENABLE) + CP DIODEV_PPPSD + JP Z,PPPSD_DISPATCH +#ENDIF +#IF (HDSKENABLE) + CP DIODEV_HDSK + JP Z,HDSK_DISPATCH +#ENDIF + CALL PANIC +; +; HANDLE COMMON DISK FUNCTIONS (NOT DEVICE DRIVER SPECIFIC) +; +DIO_COMMON: + SUB $18 + JR Z,DIO_GBA + DEC A + JR Z,DIO_SBA + CALL PANIC +; +; DISK: GET BUFFER ADDRESS +; +DIO_GBA: + LD HL,(DIOBUF) + XOR A + RET +; +; DISK: SET BUFFER ADDRESS +; +DIO_SBA: + BIT 7,H ; IS HIGH ORDER BIT SET? + CALL Z,PANIC ; IF NOT, ADR IS IN LOWER 32K, NOT ALLOWED!!! + LD (DIOBUF),HL + XOR A + RET +; +; +; +CLK_DISPATCH: + CALL PANIC +; +; +; +CRT_DISPATCH: + CALL PANIC +; +; +; +SYS_DISPATCH: + LD A,B + CP BF_SYSGETCFG + JR Z,SYS_GETCFG + CP BF_SYSSETCFG + JR Z,SYS_SETCFG + CP BF_SYSBNKCPY + JR Z,SYS_BNKCPY + CALL PANIC +; +SYS_GETCFG: + LD HL,$0200 ; SETUP SOURCE OF CONFIG DATA + LD BC,$0100 ; SIZE OF CONFIG DATA + LDIR ; COPY IT + RET +; +SYS_SETCFG: + LD HL,$0200 ; SETUP SOURCE OF CONFIG DATA + LD BC,$0100 + EX DE,HL + LDIR + RET +; +SYS_BNKCPY: + LD A,C ; BANK SELECTION TO A + PUSH IX + POP BC ; BC = BYTE COUNT TO COPY + JP $FF03 ; JUST PASS CONTROL TO HBIOS STUB IN UPPER MEMORY +; +; COMMON ROUTINE THAT IS CALLED BY CHARACTER IO DRIVERS WHEN +; AN IDLE CONDITION IS DETECTED (WAIT FOR INPUT/OUTPUT) +; +CIO_IDLE: + LD HL,IDLECOUNT ; POINT TO IDLE COUNT + DEC (HL) ; 256 TIMES? + CALL Z,IDLE ; RUN IDLE PROCESS EVERY 256 ITERATIONS + XOR A ; SIGNAL NO CHAR READY + RET ; AND RETURN +; +;================================================================================================== +; DEVICE DRIVERS +;================================================================================================== +; +#IF (UARTENABLE) +ORG_UART .EQU $ + #INCLUDE "uart.asm" +SIZ_UART .EQU $ - ORG_UART + .ECHO "UART occupies " + .ECHO SIZ_UART + .ECHO " bytes.\n" +#ENDIF +; +#IF (VDUENABLE) +ORG_VDU .EQU $ + #INCLUDE "vdu.asm" +SIZ_VDU .EQU $ - ORG_VDU + .ECHO "VDU occupies " + .ECHO SIZ_VDU + .ECHO " bytes.\n" +#ENDIF +; +#IF (PRPENABLE) +ORG_PRP .EQU $ + #INCLUDE "prp.asm" +SIZ_PRP .EQU $ - ORG_PRP + .ECHO "PRP occupies " + .ECHO SIZ_PRP + .ECHO " bytes.\n" +#ENDIF +; +#IF (PPPENABLE) +ORG_PPP .EQU $ + #INCLUDE "ppp.asm" +SIZ_PPP .EQU $ - ORG_PPP + .ECHO "PPP occupies " + .ECHO SIZ_PPP + .ECHO " bytes.\n" +#ENDIF +; +#IF (FDENABLE) +ORG_FD .EQU $ + #INCLUDE "fd.asm" +SIZ_FD .EQU $ - ORG_FD + .ECHO "FD occupies " + .ECHO SIZ_FD + .ECHO " bytes.\n" +#ENDIF + +#IF (IDEENABLE) +ORG_IDE .EQU $ + #INCLUDE "ide.asm" +SIZ_IDE .EQU $ - ORG_IDE + .ECHO "IDE occupies " + .ECHO SIZ_IDE + .ECHO " bytes.\n" +#ENDIF + +#IF (PPIDEENABLE) +ORG_PPIDE .EQU $ + #INCLUDE "ppide.asm" +SIZ_PPIDE .EQU $ - ORG_PPIDE + .ECHO "PPIDE occupies " + .ECHO SIZ_PPIDE + .ECHO " bytes.\n" +#ENDIF + +#IF (SDENABLE) +ORG_SD .EQU $ + #INCLUDE "sd.asm" +SIZ_SD .EQU $ - ORG_SD + .ECHO "SD occupies " + .ECHO SIZ_SD + .ECHO " bytes.\n" +#ENDIF + +#IF (HDSKENABLE) +ORG_HDSK .EQU $ + #INCLUDE "hdsk.asm" +SIZ_HDSK .EQU $ - ORG_HDSK + .ECHO "HDSK occupies " + .ECHO SIZ_HDSK + .ECHO " bytes.\n" +#ENDIF +; +#DEFINE CIOMODE_CONSOLE +#DEFINE DSKY_KBD +#INCLUDE "util.asm" +; +;;;;#INCLUDE "memmgr.asm" +; +;================================================================================================== +; BANK ONE GLOBAL DATA +;================================================================================================== +; +CONDEV .DB DEFCON +; +IDLECOUNT .DB 0 +; +HSTDSK .DB 0 ; DISK IN BUFFER +HSTTRK .DW 0 ; TRACK IN BUFFER +HSTSEC .DW 0 ; SECTOR IN BUFFER +; +DIOBUF .DW $FD00 ; PTR TO 512 BYTE DISK XFR BUFFER +; +;================================================================================================== +; FILL REMAINDER OF BANK +;================================================================================================== +; +SLACK: .EQU (7F00H - $) + .FILL SLACK,0FFH +; + .ECHO "BNK1 space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; +;================================================================================================== +; HBIOS UPPER MEMORY STUB +;================================================================================================== +; +; THE FOLLOWING CODE IS RELOCATED TO THE TOP PAGE IN MEMORY TO HANDLE INVOCATION DISPATCHING +; +HB_IMG .EQU $ + .ORG HB_LOC +; +;================================================================================================== +; HBIOS DISPATCH +;================================================================================================== +; +; DISPATCH JUMP TABLE FOR UPPER MEMORY HBIOS FUNCTIONS +; + JP HB_INIT + JP HB_BNKCPY +; +; MEMORY MANAGER +; +#INCLUDE "memmgr.asm" +; +;================================================================================================== +; HBIOS BOOT ROUTINE +;================================================================================================== +; +; SETUP RST 08 TO HANDLE MAIN BIOS FUNCTIONS +; +HB_INIT: + LD A,0C3H ; $C3 = JP + LD (8H),A + LD HL,HB_ENTRY + LD (9H),HL + RET +; +;================================================================================================== +; HBIOS BNKCPY ROUTINE +;================================================================================================== +; +; SELECT A DESIGNATED RAM/ROM BANK INTO LOWER 32K, THEN PERFORM A BULK MEMORY COPY +; A: BANK SELECTION (BIT 7: 1=RAM/0=ROM, BITS 0-6: BANK NUMBER) +; DE: DESTINATION ADDRESS +; HL: SOURCE ADDRESS +; BC: COUNT OF BYTES TO COPY; +; +HB_BNKCPY: + BIT 7,A ; CHECK BIT 7 + JR NZ,HB_BNKCPY1 ; RAM PAGE +; + CALL ROMPG ; SELECT ROM PAGE + JR HB_BNKCPY2 ; GO TO COMMON STUFF +; +HB_BNKCPY1: + RES 7,A ; CLEAR BIT 7 + CALL RAMPG ; SELECT RAM PAGE AND FALL THRU +; +HB_BNKCPY2: + LDIR ; DO THE COPY + LD A,1 ; RESELECT RAM PAGE 1 + CALL RAMPG ; DO IT + RET ; BACK TO LOWER MEMORY +; +;================================================================================================== +; HBIOS ENTRY FOR RST 08 PROCESSING +;================================================================================================== +; +; ENTRY POINT FOR BIOS FUNCTIONS (TARGET OF RST 08) +; +HB_ENTRY: + LD (STACKSAV),SP ; SAVE ORIGINAL STACK FRAME + LD SP,STACK ; SETUP NEW STACK FRAME + + PGRAMF(1) ; MAP RAM PAGE 1 INTO LOWER 32K + + CALL 1003H ; CALL BANK 1 HBIOS FUNCTION DISPATCHER + + PUSH AF ; SAVE AF (FUNCTION RETURN) + PGRAMF(0) ; MAP RAM PAGE 0 INTO LOWER 32K + POP AF ; RESTORE AF + + LD SP,(STACKSAV) ; RESTORE ORIGINAL STACK FRAME + + RET ; RETURN TO CALLER +; +; PRIVATE DATA +; +STACKSAV .DW 0 +; +; JUST FOR FUN, PRIVATE STACK IS LOCATED AT TOP OF MEMORY... +; +STACK .EQU 0 +; +; +; +HB_SLACK .EQU (HB_END - $) + .ECHO "STACK space remaining: " + .ECHO HB_SLACK + .ECHO " bytes.\n" +; + .FILL HB_SLACK,0FFH +; + .END \ No newline at end of file diff --git a/trunk/Source/bootapp.asm b/trunk/Source/bootapp.asm new file mode 100644 index 00000000..1d0bdfda --- /dev/null +++ b/trunk/Source/bootapp.asm @@ -0,0 +1,119 @@ +;___BOOTAPP____________________________________________________________________________________________________________ +; +; APPLICATION BOOT MANAGER +; +; USED TO LOAD AN APPLICATION IMAGE BASED COPY OF THE SYSTEM +; REFER TO BANKEDBIOS.TXT FOR MORE INFORMATION. +;______________________________________________________________________________________________________________________ +; +; +#INCLUDE "std.asm" +; + .ORG 0100H +; + DI ; NO INTERRUPTS + IM 1 ; INTERRUPT MODE 1 + +; +; PERFORM MINIMAL Z180 SPECIFIC INITIALIZATION +; +#IF (PLATFORM == PLT_N8) + ; SET BASE FOR CPU IO REGISTERS + LD A,CPU_IOBASE + OUT0 (CPU_ICR),A + + ; SET CPU CLOCK DIV + LD A,Z180_CLKDIV << 7 + OUT0 (CPU_CCR),A + + ; SET WAIT STATES + LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) + OUT0 (CPU_DCNTL),A + + ; MMU SETUP + LD A,80H + OUT0 (CPU_CBAR),A ; SETUP FOR 32K/32K BANK CONFIG + XOR A + OUT0 (CPU_BBR),A ; BANK BASE = 0 + LD A,(RAMSIZE - 64) >> 2 + OUT0 (CPU_CBR),A ; COMMON BASE = LAST (TOP) BANK +#ENDIF + +; +; RELOCATE MONITOR/OS CODE FROM 8000H TO C000H +; - HBIOS PROXY AT $FF00 IS OVERLAID, BUT WE DON'T CARE +; ABOUT IT ANYMORE, IT WILL BE REFRESHED DURING HBIOS +; INIT LATER. +; + LD HL,8000H ; COPY MEMORY FROM 8000 + LD DE,0C000H ; TO C000 + LD BC,4000H ; COPY 16K + LDIR +; +; COPY FIRST $1000 BYTES TO $8000 (UPPER, NON-BANKED MEMORY) +; THIS INCLUDES OURSELVES AND THE LOADER CODE +; +; +; RELOCATE BOOT PHASE 2 AND LOADER CODE FROM 0000H TO 8000H +; + LD HL,0000H ; COPY MEMORY FROM 0000 + LD DE,8000H ; TO 8000H + LD BC,1000H ; COPY 1000H BYTES + LDIR +; + JP PHASE2 ; JUMP TO PHASE 2 BOOT IN UPPER MEMORY +; +;______________________________________________________________________________________________________________________ +; +; THIS IS THE PHASE 2 CODE THAT MUST EXECUTE IN UPPER MEMORY +; + .ORG $ + $8000 ; WE ARE NOW EXECUTING IN UPPER MEMORY +; +PHASE2: + LD SP,9000H ; INIT BOOT STACK +; +; COPY RAMPG0 TO RAMPG1 +; + LD HL,0000H ; HL = LOCATION IN LOMEM TO COPY FROM/TO +LOOP: + LD DE,09000H ; DE = BUFFER ADDRESS + LD BC,1000H ; BYTES TO COPY (4K CHUNKS) + PUSH BC ; SAVE COPY SIZE + PUSH DE ; SAVE COPY DEST + PUSH HL ; SAVE COPY SOURCE + LD A,0 ; SELECT PAGE 1 + CALL RAMPG ; OF ROM FOR COPY + LDIR ; COPY ROM -> BUFFER + POP DE ; RESTORE SOURCE AS NEW DESTINATION + POP HL ; RESTORE DESTINATION AS NEW SOURCE + POP BC ; RESTORE COPY SIZE + LD A,1 ; SELECT PAGE 1 + CALL RAMPG ; OF RAM FOR COPY + LDIR ; COPY BUFFER -> RAM + EX DE,HL ; GET LOMEM POINTER BACK TO HL + LD A,H ; HIGH BYTE OF POINTER TO A + CP 80H ; HIGH BYTE WILL BE 80H WHEN WE ARE DONE + JP NZ,LOOP ; IF NOT DONE, LOOP TO DO NEXT 4K CHUNK +; +; INITIALIZE HBIOS AND JUMP TO LOADER +; + LD A,1 ; SETUP TO SELECT PAGE 1 + CALL RAMPG ; SELECT RAM PAGE 1 (WHICH IS NOW LOADED WITH BNK1 CODE) + CALL 1000H ; CALL HBIOS INITIALIZATION + CALL RAMPGZ ; MAKE SURE RAM PAGE ZERO IS MAPPED TO LOWER 32K + CALL 0FF00H ; CALL HBIOS PROXY INITIALIZATION +; + JP 8400H ; JUMP TO LOADER +;______________________________________________________________________________________________________________________ +; +; NOTE THAT MEMORY MANAGER CODE IS IN UPPER MEMORY! +; +#INCLUDE "memmgr.asm" +;______________________________________________________________________________________________________________________ +; +; PAD OUT REMAINDER OF PAGE +; + .ORG $ - $8000 ; ORG BACK TO LOWER MEMORY + .FILL $0200 - $,$FF ; PAD OUT REMAINDER OF PAGE +; + .END diff --git a/trunk/Source/bootgen.asm b/trunk/Source/bootgen.asm new file mode 100644 index 00000000..973d476e --- /dev/null +++ b/trunk/Source/bootgen.asm @@ -0,0 +1,424 @@ +;___BOOTGEN___________________________________________________________________________________________________________ +; +; COPY THE SYSTEM TO THE BOOT SECTORS OF AN IDE HDD +; +; CREATED BY : DAN WERNER 09 12.2009 +; +; +; +; +;__CONSTANTS_________________________________________________________________________________________________________________________ +; +CR: .EQU 0DH ; ASCII CARRIAGE RETURN CHARACTER +LF: .EQU 0AH ; ASCII LINE FEED CHARACTER +ESC: .EQU 1BH ; ASCII ESCAPE CHARACTER +BS: .EQU 08H ; ASCII BACKSPACE CHARACTER + +; +; +; +;__MAIN_PROGRAM_____________________________________________________________________________________________________________________ +; + .ORG 00100h ; FOR DEBUG IN CP/M (AS .COM) + + + LD HL,(0001H) ; GET WBOOT ADDRESS + LD BC,1603H ; GET CP/M TOP + SBC HL,BC ; + LD (CPMSTART),HL ; SET IT + DEC HL ; + LD SP,HL ; SETUP STACK + + +; PARSE COMMAND LINE + LD HL,0081H ; SET INDEX POINTER + LD B,(0080H) ; NUMBER OF BYTES +PARSECMD: + LD A,(HL) ; GET DRIVE LETTER ON COMMAND LINE + INC HL + CP 20H ; IS SPACE? + JP NZ,PARSEGOT ; JUMP ON NON-BLANK + DJNZ PARSECMD ; LOOP +PARSEERR: + LD DE,MSG_VALID ; + LD C,09H ; CP/M WRITE START STRING TO CONSOLE CALL + CALL 0005H + JP EXIT ; EXIT +PARSEGOT: + SUB 'A' ; TURN IT INTO A NUMERIC + JP C,PARSEERR ; + CP 16 ; VALID CP/M DRIVE? + JP P,PARSEERR ; + LD (DEVICENUMBER),A ; DEVICE ID + ; GET NUMBER OF SECTORS PER TRACK + LD L,A ; L=DISK NUMBER 0,1,2,3,4 + LD H,0 ; HIGH ORDER ZERO + ADD HL,HL ; *2 + ADD HL,HL ; *4 + ADD HL,HL ; *8 + ADD HL,HL ; *16 (SIZE OF EACH HEADER) + PUSH HL ; + POP DE + LD HL,(0001H) ; + LD BC,0058 ; + ADD HL,BC ; + ADD HL,DE ; HL= DPBASE(DISKNO*16) + EX DE,HL ; + LD A,(DE) ; + LD L,A ; + INC DE ; + LD A,(DE) ; + LD H,A ; + EX DE,HL ; + LD A,(DE) ; + LD (SECTRACK),A ; + INC DE ; + LD A,(DE) ; + LD (SECTRACK+1),A ; + + LD DE,DRIVE_MSG ; + LD C,09H ; CP/M WRITE START STRING TO CONSOLE CALL + CALL 0005H + LD A,(DEVICENUMBER) ; + ADD A,'A' ; + CALL COUT ; + LD A,':' ; + CALL COUT ; + CALL CRLF ; + + + LD DE,BASE_MSG ; + LD C,09H ; CP/M WRITE START STRING TO CONSOLE CALL + CALL 0005H + LD HL,(CPMSTART) ; + CALL PHL ; + LD DE,END_MSG ; + LD C,09H ; CP/M WRITE START STRING TO CONSOLE CALL + CALL 0005H + LD HL,(CPMEND) ; + CALL PHL ; + CALL CRLF ; + + LD DE,SECTOR_MSG ; + LD C,09H ; CP/M WRITE START STRING TO CONSOLE CALL + CALL 0005H + LD HL,(SECTRACK) ; + CALL PHL ; + CALL CRLF ; + + +; RUN WITH GOOD OUTPUT + + LD A,(DEVICENUMBER) ; SET DEVICE NUMBER + LD C,A + CALL SELDSK ; SELECT DISK + + LD HL,000CH ; SET INITIAL SECTOR + LD (CURSECTOR),HL + + LD HL,0000H ; SET INITIAL TRACK + LD (CURTRACK),HL ; + + LD HL,(CPMSTART) ; SET BEGINNING OF CPM + LD (CURADDRESS),HL ; + + LD BC,(DMAAD) ; SETUP THE DMA AREA + CALL SETDMA ; + +LOOP: + LD BC,(CURSECTOR) ; SET SECTOR + CALL SETSEC ; + LD BC,(CURTRACK) ; + CALL SETTRK ; + CALL COPYTODMA ; COPY BYTES TO DMA + CALL WRITE ; WRITE SECTOR + + LD HL,(CURADDRESS) ; IF IX>CPMEND, EXIT PROGRAM + LD BC,(CPMEND) ; + LD A,H ; + CP B ; + JP NZ,CONTINUE ; + LD A,L ; + CP C ; + JP M,ENDLOOP ; +CONTINUE: + LD HL,(CURSECTOR) ; GET NEXT TRACK & SECTOR + INC HL ; + LD (CURSECTOR),HL ; + LD BC,(SECTRACK) ; + LD A,H ; + CP B ; + JP NZ,LOOP ; + LD A,L ; + CP C ; + JP NZ,LOOP ; + + LD HL,(CURTRACK) ; + INC HL ; + LD (CURTRACK),HL ; + LD HL,0000H ; + LD (CURSECTOR),HL ; + JP LOOP ; + +ENDLOOP: +; WRITE CP/M BOOT START AND END ADDRESSES IN LAST TWO WORDS OF MEDIA INFO SECTOR + LD BC,000BH ; SET SECTOR + CALL SETSEC ; + LD BC,0000H ; + CALL SETTRK ; + CALL READ ; + LD HL,(DMAAD) ; SET ADDRESS IN BUFFER TO LAST TWO WORDS + LD BC,122 ; + ADD HL,BC ; + LD A,(CPMSTART) ; + LD (HL),A ; + LD A,(CPMSTART+1) ; + INC HL + LD (HL),A ; + LD A,(CPMEND) ; + INC HL + LD (HL),A ; + LD A,(CPMEND+1) ; + INC HL + LD (HL),A ; + LD A,(0001H) ; + DEC A ; + DEC A ; + DEC A ; + INC HL + LD (HL),A ; + LD A,(0002H) ; + INC HL + LD (HL),A ; + CALL WRITE ; WRITE SECTOR + +EXIT: + + LD DE,MSG_END ; + LD C,09H ; CP/M WRITE END STRING TO CONSOLE CALL + CALL 0005H ; + ; + LD C,00H ; CP/M SYSTEM RESET CALL + CALL 0005H ; RETURN TO PROMPT + + + + + +;___COPYTODMA_____________________________________________________________________________________ +; +; COPY CURRENT ADDRESS BLOCK TO DMA +;_________________________________________________________________________________________________ +COPYTODMA: + LD HL,(DMAAD) ; LOAD HL WITH DMA ADDRESS + LD E,L ; + LD D,H ; GET IT INTO DE + LD HL,(CURADDRESS) ; GET RAM ADDRESS TO COPY + LD BC,128 ; BC IS COUNTER FOR FIXED SIZE TRANSFER (128 BYTES) + LDIR ; TRANSFER + LD HL,(CURADDRESS) ; INCREMENT ADDRESS POINTER BY COPY SIZE + LD BC,128 ; + ADD HL,BC ; + LD (CURADDRESS),HL ; + RET + + + + + + + +;__HXOUT_________________________________________________________________________________________________________________________ +; +; PRINT THE ACCUMULATOR CONTENTS AS HEX DATA ON THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +HXOUT: + PUSH BC ; SAVE BC + LD B,A ; + RLC A ; DO HIGH NIBBLE FIRST + RLC A ; + RLC A ; + RLC A ; + AND 0FH ; ONLY THIS NOW + ADD A,30H ; TRY A NUMBER + CP 3AH ; TEST IT + JR C,OUT1 ; IF CY SET PRINT 'NUMBER' + ADD A,07H ; MAKE IT AN ALPHA +OUT1: + CALL COUT ; SCREEN IT + LD A,B ; NEXT NIBBLE + AND 0FH ; JUST THIS + ADD A,30H ; TRY A NUMBER + CP 3AH ; TEST IT + JR C,OUT2 ; PRINT 'NUMBER' + ADD A,07H ; MAKE IT ALPHA +OUT2: + CALL COUT ; SCREEN IT + POP BC ; RESTORE BC + RET ; + + +;__SPACE_________________________________________________________________________________________________________________________ +; +; PRINT A SPACE CHARACTER ON THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +SPACE: + PUSH AF ; STORE AF + LD A,20H ; LOAD A "SPACE" + CALL COUT ; SCREEN IT + POP AF ; RESTORE AF + RET ; DONE + +;__CRLF_________________________________________________________________________________________________________________________ +; +; PRINT A CR/LF +;________________________________________________________________________________________________________________________________ +; +CRLF: + PUSH AF ; STORE AF + LD A,0DH ; LOAD A "SPACE" + CALL COUT ; SCREEN IT + LD A,0AH ; LOAD A "SPACE" + CALL COUT ; SCREEN IT + POP AF ; RESTORE AF + RET ; DONE + +;__COUT_________________________________________________________________________________________________________________________ +; +; PRINT CONTENTS OF A +;________________________________________________________________________________________________________________________________ +; +COUT: + PUSH BC ; + PUSH AF ; + PUSH HL ; + PUSH DE ; + + LD (COUT_BUFFER),A ; + LD DE,COUT_BUFFER ; + LD C,09H ; CP/M WRITE START STRING TO CONSOLE CALL + CALL 0005H + POP DE ; + POP HL ; + POP AF ; + POP BC ; + RET ; DONE + + + + +;__PHL_________________________________________________________________________________________________________________________ +; +; PRINT THE HL REG ON THE SERIAL PORT +;________________________________________________________________________________________________________________________________ +; +PHL: + LD A,H ; GET HI BYTE + CALL HXOUT ; DO HEX OUT ROUTINE + LD A,L ; GET LOW BYTE + CALL HXOUT ; HEX IT + CALL SPACE ; + RET ; DONE + +COUT_BUFFER: + .DB 00 + .DB "$" + +BASE_MSG: + .TEXT "CP/M IMAGE=" + .db "$" +END_MSG: + .TEXT "TO " + .db "$" +SECTOR_MSG: + .TEXT "SECTORS/TRACK=" + .db "$" + +DRIVE_MSG: + .TEXT "DRIVE=" + .db "$" + + +;__CBIOS_________________________________________________________________________________________________________________________ +; +; CBIOS JUMP TABLE +;________________________________________________________________________________________________________________________________ +; + +SELDSK: ;SELECT DISK + PUSH BC ; + LD HL,(0001H) ; + LD BC,0024 ; + ADD HL,BC ; + POP BC ; + JP (HL) ; +SETTRK: ;SET DISK TRACK ADDR + PUSH BC ; + LD HL,(0001H) ; + LD BC,0027 ; + ADD HL,BC ; + POP BC ; + JP (HL) ; +SETSEC: ;SET DISK SECTOR ADDR + PUSH BC ; + LD HL,(0001H) ; + LD BC,0030 ; + ADD HL,BC ; + POP BC ; + JP (HL) ; +SETDMA: ;SET DMA BUFFER ADDR + PUSH BC ; + LD HL,(0001H) ; + LD BC,0033 ; + ADD HL,BC ; + POP BC ; + JP (HL) ; +READ: ;READ SECTOR + PUSH BC ; + LD HL,(0001H) ; + LD BC,0036 ; + ADD HL,BC ; + POP BC ; + JP (HL) ; +WRITE: ;WRITE SECTOR + PUSH BC ; + LD HL,(0001H) ; + LD BC,0039 ; + ADD HL,BC ; + POP BC ; + JP (HL) ; + + + +CURTRACK: .DW 0 ; CURRENT TRACK +CURSECTOR: .DW 0 ; CURRENT SECTOR +CURADDRESS: .DW 0 ; CURRENT CP/M ADDRESS +DMAAD: .DW 5000H ; DIRECT MEMORY ADDRESS + +CPMEND: .DW 0FDFFH ; END OF CP/M +SECTRACK: .DW 0100H ; SECTORS PER TRACK +CPMSTART: .DW 0D000H ; START OF CP/M +DEVICENUMBER: .DB 2 ; DEVICE ID + + + +MSG_END: + .DB LF, CR ; LINE FEED AND CARRIAGE RETURN + .TEXT "BOOTGEN COMPLETED." + .DB LF, CR ; LINE FEED AND CARRIAGE RETURN + .DB "$" ; LINE TERMINATOR +MSG_VALID: + .DB LF, CR ; LINE FEED AND CARRIAGE RETURN + .TEXT "USAGE: BOOTGEN (DRIVE):" + .DB LF, CR ; LINE FEED AND CARRIAGE RETURN + .TEXT "(DRIVE) IS ANY VALID CP/M DRIVE:" + .DB LF, CR ; LINE FEED AND CARRIAGE RETURN + .DB "$" ; LINE TERMINATOR + + + .END + + + \ No newline at end of file diff --git a/trunk/Source/bootrom.asm b/trunk/Source/bootrom.asm new file mode 100644 index 00000000..60ced9f8 --- /dev/null +++ b/trunk/Source/bootrom.asm @@ -0,0 +1,109 @@ +;___BOOTROM____________________________________________________________________________________________________________ +; +; ROM BOOT MANAGER +; +; HARDWARE COLD START WILL JUMP HERE FOR INITIALIZATION +; REFER TO BANKEDBIOS.TXT FOR MORE INFORMATION. +;______________________________________________________________________________________________________________________ +; +; +#INCLUDE "std.asm" +; + .ORG 0100H +; + DI ; NO INTERRUPTS + IM 1 ; INTERRUPT MODE 1 + +; +; PERFORM MINIMAL Z180 SPECIFIC INITIALIZATION +; +#IF (PLATFORM == PLT_N8) + ; SET BASE FOR CPU IO REGISTERS + LD A,CPU_IOBASE + OUT0 (CPU_ICR),A + + ; SET CPU CLOCK DIV + LD A,Z180_CLKDIV << 7 + OUT0 (CPU_CCR),A + + ; SET WAIT STATES + LD A,0 + (Z180_MEMWAIT << 6) | (Z180_IOWAIT << 4) + OUT0 (CPU_DCNTL),A + + ; MMU SETUP + LD A,80H + OUT0 (CPU_CBAR),A ; SETUP FOR 32K/32K BANK CONFIG + XOR A + OUT0 (CPU_BBR),A ; BANK BASE = 0 + LD A,(RAMSIZE - 64) >> 2 + OUT0 (CPU_CBR),A ; COMMON BASE = LAST (TOP) BANK +#ENDIF + +; +; COPY ENTIRE CONTENTS OF ROM BANK 0 TO HI RAM +; THIS INCLUDES OURSELVES AND THE LOADER CODE +; - HBIOS PROXY AT $FF00 IS OVERLAID, BUT WE DON'T CARE +; BECAUSE IT WILL BE REFRESHED DURING HBIOS +; INIT LATER. +; + LD HL,0000H ; COPY MEMORY FROM LOMEM (0000H) + LD DE,8000H ; TO HIMEM (8000H) + LD BC,8000H ; COPY ENTIRE BANK, 8000H BYTES + LDIR +; + JP PHASE2 ; JUMP TO PHASE 2 BOOT IN UPPER MEMORY +; +;______________________________________________________________________________________________________________________ +; +; THIS IS THE PHASE 2 CODE THAT MUST EXECUTE IN UPPER MEMORY +; + .ORG $ + $8000 ; WE ARE NOW EXECUTING IN UPPER MEMORY +; +PHASE2: + LD SP,9000H ; INIT BOOT STACK +; +; COPY ROMPG1 TO RAMPG1 +; + LD HL,0000H ; HL = LOCATION IN LOMEM TO COPY FROM/TO +LOOP: + LD DE,09000H ; DE = BUFFER ADDRESS + LD BC,1000H ; BYTES TO COPY (4K CHUNKS) + PUSH BC ; SAVE COPY SIZE + PUSH DE ; SAVE COPY DEST + PUSH HL ; SAVE COPY SOURCE + LD A,1 ; SELECT PAGE 1 + CALL ROMPG ; OF ROM FOR COPY + LDIR ; COPY ROM -> BUFFER + POP DE ; RESTORE SOURCE AS NEW DESTINATION + POP HL ; RESTORE DESTINATION AS NEW SOURCE + POP BC ; RESTORE COPY SIZE + LD A,1 ; SELECT PAGE 1 + CALL RAMPG ; OF RAM FOR COPY + LDIR ; COPY BUFFER -> RAM + EX DE,HL ; GET LOMEM POINTER BACK TO HL + LD A,H ; HIGH BYTE OF POINTER TO A + CP 80H ; HIGH BYTE WILL BE 80H WHEN WE ARE DONE + JP NZ,LOOP ; IF NOT DONE, LOOP TO DO NEXT 4K CHUNK +; +; INITIALIZE HBIOS AND JUMP TO LOADER +; + LD A,1 ; SETUP TO SELECT PAGE 1 + CALL RAMPG ; SELECT RAM PAGE 1 (WHICH IS NOW LOADED WITH BNK1 CODE) + CALL 1000H ; CALL HBIOS INITIALIZATION + CALL RAMPGZ ; MAKE SURE RAM PAGE ZERO IS MAPPED TO LOWER 32K + CALL 0FF00H ; CALL HBIOS PROXY INITIALIZATION +; + JP 8400H ; JUMP TO LOADER +;______________________________________________________________________________________________________________________ +; +; NOTE THAT MEMORY MANAGER CODE IS IN UPPER MEMORY! +; +#INCLUDE "memmgr.asm" +;______________________________________________________________________________________________________________________ +; +; PAD OUT REMAINDER OF PAGE +; + .ORG $ - $8000 ; ORG BACK TO LOWER MEMORY + .FILL $0200 - $,$FF ; PAD OUT REMAINDER OF PAGE +; + .END diff --git a/trunk/Source/cbios.asm b/trunk/Source/cbios.asm new file mode 100644 index 00000000..dd087583 --- /dev/null +++ b/trunk/Source/cbios.asm @@ -0,0 +1,2123 @@ +;__________________________________________________________________________________________________ +; +; CBIOS FOR N8VEM +; +; BY ANDREW LYNCH, WITH INPUT FROM MANY SOURCES +;__________________________________________________________________________________________________ +; +; cbios.asm 6/04/2012 dwg - added BOOTLU +; cbios.asm 5/21/2012 dwg - added peek and poke for bank 1 frame 0 +; cbios.asm 5/16/2012 dwg - new architecture for 2.0.0.0 Beta 3 +; + +; The std.asm file contains the majority of the standard equates +; that describe data sructures, magic values and bit fields used +; by the CBIOS. + +#INCLUDE "std.asm" +; +#INCLUDE "syscfg.exp" +; + .ORG CBIOS_LOC ; DEFINED IN STD.ASM +; +;================================================================================================== +; CP/M JUMP VECTOR TABLE FOR INDIVIDUAL SUBROUTINES +;================================================================================================== +; These jumps are defined in the CP/M-80 v2.2 system guide and comprise +; the invariant part of the BIOS. + + JP BOOT ; #0 - COLD START +WBOOTE JP WBOOT ; #1 - WARM START + JP CONST ; #2 - CONSOLE STATUS + JP CONIN ; #3 - CONSOLE CHARACTER IN + JP CONOUT ; #4 - CONSOLE CHARACTER OUT + JP LIST ; #5 - LIST CHARACTER OUT + JP PUNCH ; #6 - PUNCH CHARACTER OUT + JP READER ; #7 - READER CHARACTER OUT + JP HOME ; #8 - MOVE HEAD TO HOME POSITION + JP SELDSK ; #9 - SELECT DISK + JP SETTRK ; #10 - SET TRACK NUMBER + JP SETSEC ; #11 - SET SECTOR NUMBER + JP SETDMA ; #12 - SET DMA ADDRESS + JP READ ; #13 - READ DISK + JP WRITE ; #14 - WRITE DISK + JP LISTST ; #15 - RETURN LIST STATUS + JP SECTRN ; #16 - SECTOR TRANSLATE +;------------------------------------------------------------------------ +; These jumps are enhancements, added for the benefit of the RomWBW BIOS +; and are located following the invariant jump table so they can be +; easily located by external programs. They transfger control to routines +; that are located somewhere within the main section of the CBIOS. + + JP BNKSEL ; #17 - SEL. RAM BANK FOR LOW32K (obsolete, use HBIOS) + JP GETDSK ; #18 - Get Disk Info (device/unit/lu) + JP SETDSK ; #19 - Set Disk Into (device/unit/lu) + JP GETINFO ; #20 - Get BIOS Info Base Ptr +; Expansion area for future enhancements - In order not to shift the +; subsequent data and break local and external code, space is set aside for +; four additional jumps. Until implemented, an invocation will result in +; a system panic. + CALL PANIC ; #21 - reserved for JP + CALL PANIC ; #22 - reserved for JP + CALL PANIC ; #23 - reserved for JP + CALL PANIC ; #24 - reserved for JP +; +;================================================================================================== +; CONFIGURATION DATA +;================================================================================================== +; +; The following RomWBW specific configuration data is located at this +; offset so they can be located by code in the CBIOS. The declarations +; are based on the selected configuration file used at build-time. The +; data is included from an external file so as to not clutter the main +; BIOS code. The size of the configuration data is available by virtue +; of the SIZ_CNFGDATA equate (see below). + +ORG_INFOLIST .EQU $ + + .DB RMJ + .DB RMN + .DB RUP + .DB RTP + +#INCLUDE "infolist.inc" + +SIZ_INFOLIST .EQU $ - ORG_INFOLIST ; + .ECHO "INFOLIST occupies " + .ECHO SIZ_INFOLIST + .ECHO " bytes.\n" +; +;================================================================================================== +; BIOS FUNCTIONS +;================================================================================================== +; +;__________________________________________________________________________________________________ +BOOT: + JP INIT ; GO TO COLD BOOT CODE +; +;__________________________________________________________________________________________________ +WBOOT: + DI + IM 1 + + LD SP,ISTACK ; STACK FOR INITIALIZATION + + ; RELOAD COMMAND PROCESSOR FROM CACHE + LD A,1 + CALL RAMPG + LD HL,0800H ; LOCATION IN RAM1 OF COMMAND PROCESSOR CACHE + LD DE,CPM_LOC ; LOCATION OF ACTIVE COMMAND PROCESSOR + LD BC,CCPSIZ ; SIZE OF COMMAND PROCESSOR + LDIR + CALL RAMPGZ + + ; FALL THRU TO INVOKE CP/M +; +;__________________________________________________________________________________________________ +GOCPM: + ; SETUP DISK XFR BUFFER LOCATION + LD HL,SECBUF + LD (BUFADR),HL + LD B,BF_DIOSBA + RST 08 + + LD A,0C3H ; LOAD A WITH 'JP' INSTRUCTION (USED BELOW) + + ; CPU RESET / RST 0 -> WARM START CP/M + LD (0000H),A + LD HL,WBOOTE + LD (0001H),HL + +; ; INT / RST 38 -> INVOKE MONITOR +; LD (0038H),A +; LD HL,GOMON +; LD (0039H),HL + +; ; INT / RST 38 -> PANIC +; LD (0038H),A +; LD HL,PANIC ; PANIC ROUTINE ADDRESS +; LD (0039H),HL ; POKE IT + + ; CALL 5 -> INVOKE BDOS + LD (0005H),A + LD HL,BDOS + LD (0006H),HL + + ; RESET (DE)BLOCKING ALGORITHM + CALL BLKRES + + ; DEFAULT DMA ADDRESS + LD BC,80H + CALL SETDMA + + ; ENSURE VALID DISK AND JUMP TO CCP + LD A,(CDISK) ; GET CURRENT USER/DISK + AND 0FH ; ISOLATE DISK PART + LD C,A ; SETUP C WITH CURRENT USER/DISK, ASSUME IT IS OK + CALL DSK_STATUS ; CHECK DISK STATUS + JR Z,CURDSK ; ZERO MEANS OK + LD A,(DEFDRIVE) ; CURRENT DRIVE NOT READY, USE DEFAULT + JR GOCCP +CURDSK: + LD A,(CDISK) ; GET CURRENT USER/DISK +GOCCP: + LD C,A ; SETUP C WITH CURRENT USER/DISK, ASSUME IT IS OK + JP CCP +; +;__________________________________________________________________________________________________ +GOMON: + CALL PANIC +; +; DI +; IM 1 +; +; LD SP,STACK +; +; ; RELOAD MONITOR INTO RAM (IN CASE IT HAS BEEN OVERWRITTEN) +; CALL ROMPGZ +; LD HL,MON_IMG +; LD DE,MON_LOC +; LD BC,MON_SIZ +; LDIR +; CALL RAMPGZ + +; ; JUMP TO MONITOR WARM ENTRY +; JP MON_UART +; +;__________________________________________________________________________________________________ +CONST: +; CONSOLE STATUS, RETURN 0FFH IF CHARACTER READY, 00H IF NOT +; + LD B,BF_CIOIST ; B = FUNCTION + LD HL,CIOST ; HL = ADDRESS OF COMPLETION ROUTINE + JR CONIO +; +;__________________________________________________________________________________________________ +CONIN: +; CONSOLE CHARACTER INTO REGISTER A +; + LD B,BF_CIOIN ; B = FUNCTION + LD HL,CIOIN ; HL = ADDRESS OF COMPLETION ROUTINE + JR CONIO + +;__________________________________________________________________________________________________ +CONOUT: +; CONSOLE CHARACTER OUTPUT FROM REGISTER C +; + LD B,BF_CIOOUT ; B = FUNCTION + LD HL,CIOOUT ; HL = ADDRESS OF COMPLETION ROUTINE + LD E,C ; E = CHARACTER TO SEND +; JR CONIO ; COMMENTED OUT, FALL THROUGH OK +; +;__________________________________________________________________________________________________ +CONIO: +; + LD A,(IOBYTE) ; GET IOBYTE + AND $03 ; ISOLATE RELEVANT IOBYTE BITS FOR CONSOLE + OR $00 ; PUT LOGICAL DEVICE IN BITS 2-3 (CON:=$00, RDR:=$04, PUN:=$08, LST:=$0B + JP CIO_DISP +; +;__________________________________________________________________________________________________ +LIST: +; LIST CHARACTER FROM REGISTER C +; + LD B,BF_CIOOUT ; B = FUNCTION + LD HL,CIOOUT ; HL = ADDRESS OF COMPLETION ROUTINE + LD E,C ; E = CHARACTER TO SEND + JR LISTIO +; +;__________________________________________________________________________________________________ +LISTST: +; RETURN LIST STATUS (0 IF NOT READY, 1 IF READY) +; + LD B,BF_CIOOST ; B = FUNCTION + LD HL,CIOST ; HL = ADDRESS OF COMPLETION ROUTINE +; JR LISTIO ; COMMENTED OUT, FALL THROUGH OK +; +;__________________________________________________________________________________________________ +LISTIO: +; + LD A,(IOBYTE) ; GET IOBYTE + RLCA ; SHIFT RELEVANT BITS TO BITS 0-1 + RLCA + AND $03 ; ISOLATE RELEVANT IOBYTE BITS FOR LST: + OR $0C ; PUT LOGICAL DEVICE IN BITS 2-3 (CON:=$00, RDR:=$04, PUN:=$08, LST:=$0C + JP CIO_DISP +; +;__________________________________________________________________________________________________ +PUNCH: +; PUNCH CHARACTER FROM REGISTER C +; + LD B,BF_CIOOUT ; B = FUNCTION + LD HL,CIOOUT ; HL = ADDRESS OF COMPLETION ROUTINE + LD E,C ; E = CHARACTER TO SEND +; JR PUNCHIO ; COMMENTED OUT, FALL THROUGH OK +; +;__________________________________________________________________________________________________ +PUNCHIO: +; + LD A,(IOBYTE) ; GET IOBYTE + RLCA ; SHIFT RELEVANT BITS TO BITS 0-1 + RLCA + RLCA + RLCA + AND $03 ; ISOLATE RELEVANT IOBYTE BITS FOR PUN: + OR $08 ; PUT LOGICAL DEVICE IN BITS 2-3 (CON:=$00, RDR:=$04, PUN:=$08, LST:=$0B + JP CIO_DISP +; +;__________________________________________________________________________________________________ +READER: +; READ CHARACTER INTO REGISTER A FROM READER DEVICE +; + LD B,BF_CIOIN ; B = FUNCTION + LD HL,CIOIN ; HL = ADDRESS OF COMPLETION ROUTINE + JR READERIO +; +;__________________________________________________________________________________________________ +READERST: +; RETURN READER STATUS (0 IF NOT READY, 1 IF READY) +; + LD B,BF_CIOIST ; B = FUNCTION + LD HL,CIOST ; HL = ADDRESS OF COMPLETION ROUTINE +; JR READERIO ; COMMENTED OUT, FALL THROUGH OK +; +;__________________________________________________________________________________________________ +READERIO: +; + LD A,(IOBYTE) ; GET IOBYTE + RRCA ; SHIFT RELEVANT BITS TO BITS 0-1 + RRCA + AND $03 ; ISOLATE RELEVANT IOBYTE BITS FOR RDR: + OR $04 ; PUT LOGICAL DEVICE IN BITS 2-3 (CON:=$00, RDR:=$04, PUN:=$08, LST:=$0B + JP CIO_DISP +; +;__________________________________________________________________________________________________ +CIOIN: +; COMPLETION ROUTINE FOR CHARACTER INPUT FUNCTIONS +; + LD A,E ; MOVE CHARACTER RETURNED TO A +; RET ; FALL THRU +; +;__________________________________________________________________________________________________ +CIOOUT: +; COMPLETION ROUTINE FOR CHARACTER OUTPUT FUNCTIONS +; + RET +; +;__________________________________________________________________________________________________ +CIOST: +; COMPLETION ROUTINE FOR CHARACTER STATUS FUNCTIONS (IST/OST) +; + OR A ; SET FLAGS + RET Z ; NO CHARACTERS WAITING (IST) OR OUTPUT BUF FULL (OST) + XOR A + DEC A ; $FF SIGNALS READY TO READ (IST) OR WRITE (OST) + RET +;__________________________________________________________________________________________________ +SELDSK: +; SELECT DISK NUMBER FOR SUBSEQUENT DISK OPS +#IF DSKTRACE + CALL PRTSELDSK ; *DEBUG* +#ENDIF + JP DSK_SELECT +; +;__________________________________________________________________________________________________ +HOME: +; SELECT TRACK 0 (BC = 0) AND FALL THRU TO SETTRK +#IF DSKTRACE + CALL PRTHOME ; *DEBUG* +#ENDIF + + LD A,(HSTWRT) ; CHECK FOR PENDING WRITE + OR A + JR NZ,HOMED + LD (HSTACT),A ; CLEAR HOST ACTIVE FLAG + +HOMED: + LD BC,0 +; +;__________________________________________________________________________________________________ +SETTRK: +; SET TRACK GIVEN BY REGISTER BC + LD (SEKTRK),BC + RET +; +;__________________________________________________________________________________________________ +SETSEC: +; SET SECTOR GIVEN BY REGISTER BC + LD (SEKSEC),BC + RET +; +;__________________________________________________________________________________________________ +SECTRN: +; SECTOR TRANSLATION FOR SKEW, HARD CODED 1:1, NO SKEW IMPLEMENTED + LD H,B + LD L,C + RET +; +;__________________________________________________________________________________________________ +SETDMA: + LD (DMAADR),BC + RET +; +;__________________________________________________________________________________________________ +READ: + LD A,DOP_READ + JR READWRITE +; +;__________________________________________________________________________________________________ +WRITE: + LD A,C + LD (WRTYPE),A ; SAVE WRITE TYPE + LD A,DOP_WRITE + JR READWRITE +; +;__________________________________________________________________________________________________ +BNKSEL: +; + LD A,C + JP RAMPG +; +;__________________________________________________________________________________________________ +GETDSK: +; +; INPUT: C=DRIVE # (0=A, 1=B, ... P=16) +; OUTPUT: A=RESULT (0=OK, 1=INVALID DRIVE #) +; B=DEVICE/UNIT +; DE=CURRENT LU +; HL=LU COUNT SUPPORTED ON DEVICE/UNIT (0 = NO SUPPORT) +; + ; C HAS CPM DRIVE, LOOKUP DPH (INCLUDES INVALID DRIVE CHECK) + CALL DSK_GETDPH ; HL = DPH (0 IF INVALID DRIVE) + RET NZ ; A=1 AND NZ SET IF INVALID DRIVE + + ; HL HAS DPH POINTER, LOOKUP LU INFO (ERROR IF NO LU SUPPORT) + CALL DSK_GETLU ; HL = ADDRESS OF START OF LU DATA + JR NZ,GETDSK1 ; NO LU SUPPORT, BAIL OUT + + ; HL POINTS TO START OF LU DATA, FILL IN LU VALUES + LD E,(HL) + INC HL + LD D,(HL) ; DE NOW HAS CURRENT SLICE NUMBER + INC HL + LD A,(HL) + INC HL + LD H,(HL) + LD L,A ; HL NOW HAS SLICE COUNT FOR DEVICE + +GETDSK1: + XOR A ; A=0 FOR SUCCESS (EVEN IF NO LU SUPPORT) + RET +; +;__________________________________________________________________________________________________ +SETDSK: +; +; INPUT: C=DRIVE # (0=A, 1=B, ... P=16) +; B=DEVICE/UNIT +; DE=CURRENT LU +; HL=LU COUNT SUPPORTED ON DEVICE/UNIT +; OUTPUT: A=RESULT (0=OK, 1=INVALID DRIVE #) +; B=DEVICE/UNIT +; DE=CURRENT LU +; HL=LU COUNT SUPPORTED ON DEVICE/UNIT (0 = NO SUPPORT) +; +; NOTES: +; PARMS ARE NOT VALUE CHECKED. A NON-EXISTENT DEVICE/UNIT/LU COULD +; BE SET AS A RESULT. CALLER IS RESPONSIBLE FOR THIS. +; + ; SAVE INCOMING LU VALUES FOR LATER + PUSH BC + PUSH HL + PUSH DE + + ; MAKE SURE NEW DEVICE/UNIT IS A MASS STORAGE DEVICE + LD A,B ; LOAD THE REQEUSTED DEVICE/UNIT + CP $20 ; MASS STORAGE DEVICES START AT DEV/UNIT $20 + JR C,SETDSK2 ; IF NOT, BAIL OUT + + ; C HAS CPM DRIVE, LOOKUP DPH (INCLUDES INVALID DRIVE CHECK) + PUSH BC + CALL DSK_GETDPH ; HL = DPH (0 IF INVALID DRIVE) + POP BC + JR NZ,SETDSK2 ; A=1 AND NZ SET IF INVALID DRIVE + + ; UPDATE DEVICE/UNIT (CHECK NEW DEVICE IS VALID) + DEC HL ; POINT TO DEVICE/UNIT BYTE + LD A,(HL) ; LOAD CURRENT DEVICE/UNIT + CP $20 ; MASS STORAGE DEVICES START AT DEV/UNIT $20 + JR C,SETDSK2 ; IF NOT, BAIL OUT + LD A,B ; LOAD NEW DEVICE/UNIT VALUE + LD (HL),A ; SAVE IT + INC HL ; POINT HL BACK TO START OF DPH + + ; HL HAS DPH POINTER, LOOKUP LU INFO (ERROR IF NO LU SUPPORT) + CALL DSK_GETLU ; HL = ADDRESS OF START OF LU DATA + + ; RECOVER THE NEW SLICE AND SLICE COUNT + POP DE ; DE = NEW SLICE + POP BC ; BC = NEW SLICE COUNT + + ; CHECK IF DRIVE IS LU CAPABLE, BYPASS LU SETTING IF NOT + JR NZ,SETDSK1 + + ; PLUG IN THE NEW VALUES + LD (HL),E + INC HL + LD (HL),D ; CURRENT SLICE NOW SET TO DE + INC HL ; POINT TO SLICE COUNT + LD (HL),C + INC HL + LD (HL),B ; SLICE COUNT NOW SET TO HL + +SETDSK1: + ; SUCCESS EXIT (USE GETDSK TO RETURN DATA) + CALL BLKRES ; RESET (DE)BLOCKING ALGORITHM FOR SAFETY + POP BC + JR GETDSK + +SETDSK2: + ; ERROR EXIT + POP DE + POP HL + POP BC + XOR A + INC A + RET +; +;__________________________________________________________________________________________________ +GETINFO: +; +; The purpose of the GETINFO BIOS entry point is to return a +; base pointer to a table of pointers. These pointers are used +; by utility programs to locate BIOS internals that are not able +; to be located by normal means specified in the system guide. +; +; The pointers are defined in an included file so as to not clutter +; the main code. The contents are used by external utilties and are +; not used in any manner by the CBIOS code specifically. +; + LD HL,INFOLIST + RET +; +;__________________________________________________________________________________________________ +READWRITE: + LD (DSKOP),A ; SET THE ACTIVE DISK OPERATION +#IF DSKTRACE + CALL PRTDSKOP ; *DEBUG* +#ENDIF + LD A,(SEKDU) ; GET DEVICE/UNIT + AND 0F0H ; ISOLATE DEVICE NIBBLE + JR Z,DIRRW ; DEVICE = 0 = MD, SO DIRECT R/W + JP BLKRW ; OTHERWISE, (DE)BLOCKING R/W + +; +;================================================================================================== +; DIRECT READ/WRITE (NO (DE)BLOCKING, NO BUFFERING, 128 BYTE SECTOR) +;================================================================================================== +; +DIRRW: + CALL BLKFLSH ; FLUSH ANY PENDING WRITES SO WE CAN USE SEC BUF + RET NZ ; RETURN ON ERROR + + CALL BLKRES ; RESET (DE)BLOCKING ALG, BUF IS NO LONGER VALID + + ; AT THIS POINT THE ACCESS IS HARDCODED TO POINT TO MEMORY DISK DRIVER + ; SINCE THERE IS NO OTHER DIRECT READ/WRITE DEVICE + + LD A,(DSKOP) + + CP DOP_READ + JP Z,MD_READ + + CP DOP_WRITE + JP Z,MD_WRITE + + CALL PANIC +; +;================================================================================================== +; BLOCKED READ/WRITE (BLOCK AND BUFFER FOR 512 BYTE SECTOR) +;================================================================================================== +; +;__________________________________________________________________________________________________ +; +; RESET (DE)BLOCKING ALGORITHM - JUST MARK BUFFER INVALID +; NOTE: BUFFER CONTENTS INVALIDATED, BUT RETAIN ANY PENDING WRITE +; +BLKRES: + XOR A + LD (HSTACT),A ; BUFFER NO LONGER VALID + LD (UNACNT),A ; CLEAR UNALLOC COUNT + + RET + +;__________________________________________________________________________________________________ +; +; FLUSH (DE)BLOCKING ALGORITHM - DO PENDING WRITES +; +BLKFLSH: + ; CHECK FOR BUFFER WRITTEN (DIRTY) + LD A,(HSTWRT) ; GET BUFFER WRITTEN FLAG + OR A + RET Z ; NOT DIRTY, RETURN WITH A=0 AND Z SET + + ; CLEAR THE BUFFER WRITTEN FLAG (EVEN IF A WRITE ERROR OCCURS) + XOR A ; Z = 0 + LD (HSTWRT),A ; SAVE IT + + ; DO THE WRITE AND RETURN RESULT + JP DSK_WRITE + +#IF WRTCACHE + +WRT_ALL .EQU 0 ; WRITE TO ALLOCATED +WRT_DIR .EQU 1 ; WRITE TO DIRECTORY +WRT_UAL .EQU 2 ; WRITE TO UNALLOCATED + +; +;__________________________________________________________________________________________________ +; +; (DE)BLOCKING READ/WRITE ROUTINE. MANAGES PHYSICAL DISK BUFFER AND CALLS +; PHYSICAL READ/WRITE ROUTINES APPROPRIATELY. +; +BLKRW: + ; FIX!!! WE ABORT ON FIRST ERROR, DRI SEEMS TO PASS ERROR STATUS TO THE END!!! + + ; IF WRITE OPERATION, GO TO SPECIAL WRITE PROCESSING + LD A,(DSKOP) ; GET REQUESTED OPERATION + CP DOP_WRITE ; WRITE + JR Z,BLKRW1 ; GO TO WRITE PROCESSING + + ; OTHERWISE, CLEAR OUT ANY SEQUENTIAL, UNALLOC WRITE PROCESSING + ; AND GO DIRECTLY TO MAIN I/O + XOR A ; ZERO TO A + LD (WRTYPE),A ; SET WRITE TYPE = 0 (WRT_ALL) TO ENSURE READ OCCURS + LD (UNACNT),A ; SET UNACNT TO ABORT SEQ WRITE PROCESSING + + JR BLKRW4 ; GO TO I/O + +BLKRW1: + ; WRITE PROCESSING + ; CHECK FOR FIRST WRITE TO UNALLOCATED BLOCK + LD A,(WRTYPE) ; GET WRITE TYPE + CP WRT_UAL ; IS IT WRITE TO UNALLOC? + JR NZ,BLKRW2 ; NOPE, BYPASS + + ; INITIALIZE START OF SEQUENTIAL WRITING TO UNALLOCATED BLOCK + ; AND THEN TREAT SUBSEQUENT PROCESSING AS A NORMAL WRITE + CALL UNA_INI ; INITIALIZE SEQUENTIAL WRITE TRACKING + XOR A ; A = 0 = WRT_ALL + LD (WRTYPE),A ; NOW TREAT LIKE WRITE TO ALLOCATED + +BLKRW2: + ; IF WRTYPE = WRT_ALL AND SEQ WRITE, GOTO BLKRW7 (SKIP READ) + OR A ; NOTE: A WILL ALREADY HAVE THE WRITE TYPE HERE + JR NZ,BLKRW3 ; NOT TYPE = 0 = WRT_ALL, SO MOVE ON + + CALL UNA_CHK ; CHECK FOR CONTINUATION OF SEQ WRITES TO UNALLOCATED BLOCK + JR NZ,BLKRW3 ; NOPE, ABORT + + ; WE MATCHED EVERYTHING, TREAT AS WRITE TO UNALLOCATED BLOCK + LD A,WRT_UAL ; WRITE TO UNALLOCATED + LD (WRTYPE),A ; SAVE WRITE TYPE + + CALL UNA_INC ; INCREMENT SEQUENTIAL WRITE TRACKING + JR BLKRW4 ; PROCEED TO I/O PROCESSING + +BLKRW3: + ; NON-SEQUENTIAL WRITE DETECTED, STOP ANY FURTHER CHECKING + XOR A ; ZERO + LD (UNACNT),A ; CLEAR UNALLOCATED WRITE COUNT + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ; IS A FLUSH NEEDED HERE??? + ; FLUSH CURRENT BUFFER CONTENTS IF NEEDED + ;CALL BLKFLSH ; FLUSH PENDING WRITES + ;RET NZ ; ABORT ON ERROR + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +BLKRW4: + ; START OF ACTUAL I/O PROCESSING + CALL BLK_XLT ; DO THE LOGICAL TO PHYSICAL MAPPING: SEK... -> XLT... + CALL BLK_CMP ; IS THE DESIRED PHYSICAL BLOCK IN BUFFER? + JR Z,BLKRW6 ; BLOCK ALREADY IN ACTIVE BUFFER, NO READ REQUIRED + + ; AT THIS POINT, WE KNOW WE NEED TO READ THE TARGET PHYSICAL SECTOR + ; IT MAY ACTUALLY BE A PREREAD FOR A SUBSEQUENT WRITE, BUT THAT IS OK + + ; FIRST, FLUSH CURRENT BUFFER CONTENTS + CALL BLKFLSH ; FLUSH PENDING WRITES + RET NZ ; ABORT ON ERROR + + ; IMPLEMENT THE TRANSLATED VALUES + CALL BLK_SAV ; SAVE XLAT VALUES: XLT... -> HST... + + ; IF WRITE TO UNALLOC BLOCK, BYPASS READ, LEAVES BUFFER UNDEFINED + LD A,(WRTYPE) + CP 2 + JR Z,BLKRW6 + + ; DO THE ACTUAL READ + CALL DSK_READ ; READ PHYSICAL SECTOR INTO BUFFER + JR Z,BLKRW6 ; GOOD READ, CONTINUE + + ; IF READ FAILED, RESET (DE)BLOCKING ALGORITHM AND RETURN ERROR + PUSH AF ; SAVE ERROR STATUS + CALL BLKRES ; INVALIDATE (DE)BLOCKING BUFFER + POP AF ; RECOVER ERROR STATUS + RET ; ERROR RETURN + +BLKRW6: + ; CHECK TYPE OF OPERATIONS, IF WRITE, THEN GO TO WRITE PROCESSING + LD A,(DSKOP) ; GET PENDING OPERATION + CP DOP_WRITE ; IS IT A WRITE? + JR Z,BLKRW7 ; YES, GO TO WRITE PROCESSING + + ; THIS IS A READ OPERATION, WE ALREADY DID THE I/O, NOW JUST DEBLOCK AND RETURN + CALL BLK_DEBLOCK ; EXTRACT DATA FROM BLOCK + XOR A ; NO ERROR + RET ; ALL DONE + +BLKRW7: + ; THIS IS A WRITE OPERATION, INSERT DATA INTO BLOCK + CALL BLK_BLOCK ; INSERT DATA INTO BLOCK + + ; MARK THE BUFFER AS WRITTEN + LD A,TRUE ; BUFFER DIRTY = TRUE + LD (HSTWRT),A ; SAVE IT + + ; CHECK WRITE TYPE, IF WRT_DIR, FORCE THE PHYSICAL WRITE + LD A,(WRTYPE) ; GET WRITE TYPE + CP WRT_DIR ; 1 = DIRECTORY WRITE + JP Z,BLKFLSH ; FLUSH PENDING WRITES AND RETURN STATUS + + XOR A ; ALL IS WELL, SET RETURN CODE 0 + RET ; RETURN +; +;__________________________________________________________________________________________________ +; +; INITIALIZE TRACKING OF SEQUENTIAL WRITES INTO UNALLOCATED BLOCK +; SETUP UNA... VARIABLES +; +UNA_INI: + ; COPY SEKDSK/TRK/SEC TO UNA... + LD HL,SEK + LD DE,UNA + LD BC,UNASIZ + LDIR + + ; SETUP UNACNT AND UNASPT + LD HL,(SEKDPH) ; HL POINTS TO DPH + LD DE,10 ; OFFSET OF DPB ADDRESS IN DPH + ADD HL,DE ; DPH POINTS TO DPB ADDRESS + LD A,(HL) + INC HL + LD H,(HL) + LD L,A ; HL POINTS TO DPB + LD C,(HL) + INC HL + LD B,(HL) ; BC HAS SPT + LD (UNASPT),BC ; SAVE SECTORS PER TRACK + DEC HL + DEC HL ; HL POINTS TO RECORDS PER BLOCK (BYTE IN FRONT OF DPB) + LD A,(HL) ; GET IT + LD (UNACNT),A ; SAVE IT + +; CALL NEWLINE ; *DEBUG* +; CALL PRTHEXBYTE ; *DEBUG* +; CALL PC_SPACE ; *DEBUG* +; CALL PRTHEXWORD ; *DEBUG* +; CALL PC_SPACE ; *DEBUG* +; LD BC,(UNASPT) ; *DEBUG* +; CALL PRTHEXWORD ; *DEBUG* + + RET +; +;__________________________________________________________________________________________________ +; +; CHECK FOR CONTINUATION OF SEQUENTIAL WRITES TO UNALLOCATED BLOCK +; SEE IF UNACNT > 0 AND UNA... VARIABLES MATCH SEK... VARIABLES +; +UNA_CHK: + LD A,(UNACNT) ; GET THE COUNTER + OR A + JR NZ,UNA_CHK1 ; IF NOT DONE WITH BLOCK, KEEP CHECKING + + ; CNT IS NOW ZERO, EXHAUSTED RECORDS IN ONE BLOCK! + DEC A ; HACK TO SET NZ + RET ; RETURN WITH NZ + +UNA_CHK1: + ; COMPARE UNA... VARIABLES WITH SEK... VARIABLES + LD HL,SEK + LD DE,UNA + LD B,UNASIZ + JR BLK_CMPLOOP +; +;__________________________________________________________________________________________________ +; +; INCREMENT THE SEQUENTIAL WRITE TRACKING VARIABLES +; TO REFLECT THE NEXT RECORD (TRK/SEC) WE EXPECT +; +UNA_INC: + ; DECREMENT THE BLOCK RECORD COUNT + LD HL,UNACNT + DEC (HL) + + ; INCREMENT THE SECTOR + LD DE,(UNASEC) + INC DE + LD (UNASEC),DE + + ; CHECK FOR END OF TRACK + LD HL,(UNASPT) + XOR A + SBC HL,DE + RET NZ + + ; HANDLE END OF TRACK + LD (UNASEC),HL ; SECTOR BACK TO 0 (NOTE: HL=0 AT THIS POINT) + LD HL,(UNATRK) ; GET CURRENT TRACK + INC HL ; BUMP IT + LD (UNATRK),HL ; SAVE IT + + RET +#ELSE +; +;__________________________________________________________________________________________________ +; +; (DE)BLOCKING READ/WRITE ROUTINE. MANAGES PHYSICAL DISK BUFFER AND CALLS +; PHYSICAL READ/WRITE ROUTINES APPROPRIATELY. +; +BLKRW: + CALL BLK_XLT ; SECTOR XLAT: SEK... -> XLT... + CALL BLK_CMP ; IN BUFFER? + JR Z,BLKRW1 ; YES, BYPASS READ + CALL BLK_SAV ; SAVE XLAT VALUES: XLT... -> HST... + LD A,FALSE ; ASSUME FAILURE, INVALIDATE BUFFER + LD (HSTACT),A ; SAVE IT + CALL DSK_READ ; READ PHYSICAL SECTOR INTO BUFFER + RET NZ ; BAIL OUT ON ERROR + +BLKRW1: + LD A,(DSKOP) ; GET PENDING OPERATION + CP DOP_WRITE ; IS IT A WRITE? + JR Z,BLKRW2 ; YES, GO TO WRITE ROUTINE + + CALL BLK_DEBLOCK ; EXTRACT DATA FROM BLOCK + XOR A ; NO ERROR + RET ; ALL DONE + +BLKRW2: + CALL BLK_BLOCK ; INSERT DATA INTO BLOCK + CALL DSK_WRITE ; WRITE PHYSICAL SECTOR FROM BUFFER + RET NZ ; BAIL OUT ON ERROR + + LD A,TRUE ; BUFFER IS NOW VALID + LD (HSTACT),A ; SAVE IT + + XOR A ; ALL IS WELL, SET RETURN CODE 0 + RET ; RETURN +#ENDIF +; +;__________________________________________________________________________________________________ +; +; TRANSLATE FROM CP/M DSK/TRK/SEC TO PHYSICAL +; SEK... -> XLT... +; +BLK_XLT: + ; FIRST, DO A BYTE COPY OF SEK... TO XLT... + LD HL,SEK + LD DE,XLT + LD BC,XLTSIZ + LDIR + + ; NOW UPDATE XLTSEC BASED ON (DE)BLOCKING FACTOR (ALWAYS 4:1) + LD BC,(SEKSEC) ; SECTOR IS FACTORED DOWN (4:1) DUE TO BLOCKING + SRL B ; 16 BIT RIGHT SHIFT TWICE TO DIVIDE BY 4 + RR C + SRL B + RR C + LD (XLTSEC),BC + + RET +; +;__________________________________________________________________________________________________ +; +; SAVE RESULTS OF TRANSLATION: XLT... -> HST... +; IMPLICITLY SETS HSTACT TO TRUE! +; +BLK_SAV: + LD HL,XLT + LD DE,HST + LD BC,XLTSIZ + LDIR + RET +; +;__________________________________________________________________________________________________ +; +; COMPARE RESULTS OF TRANSLATION TO CURRENT BUF (XLT... TO HST...) +; NOTE THAT HSTACT IS COMPARED TO XLTACT IMPLICITLY! XLTACT IS ALWAYS TRUE, SO +; HSTACT MUST BE TRUE FOR COMPARE TO SUCCEED. +; +BLK_CMP: + LD HL,XLT + LD DE,HST + LD B,XLTSIZ +BLK_CMPLOOP: + LD A,(DE) + CP (HL) + RET NZ ; BAD COMPARE, RETURN WITH NZ + INC HL + INC DE + DJNZ BLK_CMPLOOP + RET ; RETURN WITH Z +; +;__________________________________________________________________________________________________ +; +; BLOCK DATA - INSERT CPM DMA BUF INTO PROPER PART OF PHYSICAL SECTOR BUFFER +; +BLK_BLOCK: + CALL BLK_SETUP ; SETUP SOURCE AND DESTINATION + EX DE,HL ; SWAP HL/DE FOR BLOCK OPERATION + LD BC,128 ; DMA BUFFER SIZE + LDIR ; COPY THE DATA + RET +; +;__________________________________________________________________________________________________ +; +; DEBLOCK DATA - EXTRACT DESIRED CPM DMA BUF FROM PHYSICAL SECTOR BUFFER +; +BLK_DEBLOCK: + CALL BLK_SETUP ; SETUP SOURCE AND DESTINATION + LD BC,128 ; DMA BUFFER SIZE + LDIR ; COPY THE DATA + RET +; +;__________________________________________________________________________________________________ +; +; SETUP SOURCE AND DESTINATION POINTERS FOR BLOCK COPY OPERATION +; AT EXIT, HL = ADDRESS OF DESIRED BLOCK IN SECTOR BUFFER, DE = DMA +; +BLK_SETUP: + LD BC,(SEKSEC) + LD A,C + AND 3 ; A = INDEX OF CPM BUF IN SEC BUF + RRCA ; MULTIPLY BY 64 + RRCA + LD E,A ; INTO LOW ORDER BYTE OF DESTINATION + LD D,0 ; HIGH ORDER BYTE IS ZERO + LD HL,(BUFADR) ; HL = START OF SEC BUF + ADD HL,DE ; ADD IN COMPUTED OFFSET + ADD HL,DE ; HL NOW = INDEX * 128 (SOURCE) + LD DE,(DMAADR) ; DE = DESTINATION = DMA BUF + RET +; +;================================================================================================== +; CHARACTER DEVICE INTERFACE +;================================================================================================== +; +; ROUTING FOR CHARACTER DEVICE FUNCTIONS +; A = INDEX INTO CIO_MAP BASED ON IOBYTE BIOS REQUEST +; B = FUNCTION REQUESTED: BF_CIO(IN/OUT/IST/OST) +; E = CHARACTER (IF APPLICABLE TO FUNCTION) +; HL = ADDRESS OF COMPLETION ROUTINE +; +CIO_DISP: + PUSH HL ; PUT COMPLETION ROUTINE ON STACK + + ; LOOKUP IOBYTE MAPPED DEVICE CODE + ; WARNING: CIO_MAP MUST NOT CROSS PAGE BOUNDARY!!! + AND 0FH ; ISOLATE INDEX INTO CIO_MAP + + LD HL,CIO_MAP ; HL = ADDRESS OF CIO_MAP + ADD A,L ; ADD LOW BYTE TO OFFSET + LD L,A ; GET RESULT BACK TO L + + LD A,(HL) ; LOOKUP DEVICE CODE + LD C,A ; SAVE IN C FOR BIOS USAGE + + CP CIODEV_BAT ; CHECK FOR SPECIAL DEVICE (BAT, NUL) + JR NC,CIO_DISP1 ; HANDLE SPECIAL DEVICE + RST 08 ; OTHERWISE HANDLE VIA HBIOS + RET ; RETURN VIA COMPLETION ROUTINE SET AT START + +CIO_DISP1: + ; HANDLE SPECIAL DEVICES + AND 0F0H ; ISOLATE DEVICE + CP CIODEV_BAT ; BAT: ? + JR Z,CIO_BAT ; YES, GO TO BAT DEVICE HANDLER + CP CIODEV_NUL ; NUL: ? + JR Z,CIO_NUL ; YES, GO TO NUL DEVICE HANDLER + CALL PANIC ; SOMETHING BAD HAPPENED +; +; BAT: IS A PSEUDO DEVICE REDIRECTING INPUT TO READER AND OUTPUT TO LIST +; +CIO_BAT: + LD C,E ; PUT CHAR BACK IN C + LD A,B ; GET REQUESTED FUNCTION + CP BF_CIOIN ; INPUT? + JP Z,READER ; -> READER + CP BF_CIOIST ; INPUT STATUS? + JP Z,READERST ; -> READER + CP BF_CIOOUT ; OUTPUT? + JP Z,LIST ; -> LIST + CP BF_CIOOST ; OUTPUT STATUS? + JP Z,LISTST ; -> LIST + CALL PANIC +; +; NUL: IS A DUMMY DEVICE THAT DOES NOTHING +; +CIO_NUL: + LD A,B ; FUNCTION + CP BF_CIOIN + JR Z,NUL_IN + CP BF_CIOIST + JR Z,NUL_IST + CP BF_CIOOUT + JR Z,NUL_OUT + CP BF_CIOOST + JR Z,NUL_OST + CALL PANIC +; +NUL_IN: + LD E,$1B ; RETURN EOF +NUL_OUT: + RET +; +NUL_IST: +NUL_OST: +; LD A,$FF + XOR A ; A=0 + DEC A ; A=$FF & NZ SET + RET +; +;================================================================================================== +; PHYSICAL DISK INTERFACE +;================================================================================================== +; +DSK_DISP: + LD A,C ; GET DEVICE/UNIT TO A + AND 0F0H ; ISOLATE DEVICE + CP DIODEV_MD ; MEMORY DISK? (RAM/ROM) + JP Z,MD_DISPATCH ; YES, GO TO MEMORY DISK DISPATCH + + RST 08 ; OTHERWISE, HANDLE IN HBIOS + RET ; AND RETURN +; +; LOOKUP DPH BASED ON DPM DRIVE NUMBER +; ENTER WITH C=CPM DRIVE NUMBER +; RETURNS WITH HL = DPH ADDRESS (0 ON ERROR) +; A=0 ON SUCCESS, A=1 ON ERROR +; NOTE: DE IS NOT MODIFIED!!! +; +DSK_GETDPH: + ; CHECK FOR INVALID DRIVE NUMBER + LD A,C ; A = CPM DRIVE NUMBER + CP DPH_CNT ; COMPARE TO NUMBER OF DRIVES CONFIGURED + JR C,DSK_GETDPH1 ; IN RANGE, CONTINUE + XOR A ; ZERO ACCUMULATOR + LD H,A ; HL = 0 FOR FAILURE + LD L,A ; HL = 0 FOR FAILURE + INC A ; A = 1, NZ SET FOR INVALID DRIVE + RET ; FAILURE RETURN + + ; LOOKUP DPH FOR CPM DRIVE + ; WARNING: DPH_MAP MUST NOT CROSS PAGE BOUNDARY!!! +DSK_GETDPH1: + LD A,C ; GET CPM DRIVE NUMBER BACK + LD HL,DPH_MAP ; POINT TO START OF DPH_MAP + RLCA ; DOUBLE A TO USE AS OFFSET INTO DPH_MAP + ADD A,L ; ADD LOW BYTE TO OFFSET + LD L,A ; HL = ADDRESS OF DESIRED ENTRY IN DPH_MAP + LD A,(HL) ; DEREFERENCE + INC HL ; HL + LD H,(HL) ; TO GET + LD L,A ; DPHADR IN HL + + ; FILL IN DEVICE/UNIT + DEC HL ; POINT TO DEVICE CODE (BYTE IN FRONT OF DPH) + LD B,(HL) ; B = DEVICE/UNIT + INC HL ; HL = DPH AGAIN + + ; RETURN SUCCESS + XOR A ; A=0, Z SET + RET ; SUCCESS RETURN +; +; SET HL TO START OF LU DATA FOR DRIVE GIVEN DRIVE DPH POINTER IN HL +; ENTER WITH HL=POINTER TO DPH OF DRIVE +; RETURNS WITH HL = LU DATA ADDRESS (0 ON NO SUPPORT) +; Z SET IF LU SUPPORT, NZ IF NOT +; +DSK_GETLU: + ; CHECK FOR LU SUPPORT + LD DE,16 ; DPH + 16 IS "LU' MARKER LOCATION + ADD HL,DE ; HL POINTS TO MARKER LOCATION NOW + LD A,(HL) ; LOAD FIRST BYTE + INC HL ; POINT TO NEXT BYTE + CP 'L' ; IS IT 'L' + JR NZ,DSK_GETLU1 ; NOPE, BAIL OUT + LD A,(HL) ; LOAD SECOND BYTE + INC HL ; POINT TO NEXT BYTE + CP 'U' ; IS SECOND BYTE 'U'? + JR NZ,DSK_GETLU1 ; NOPE, BAIL OUT + RET ; SUCCESS, EXIT WITH Z SET + +DSK_GETLU1: + LD HL,0 ; OTHERWISE, HL=0 + RET ; AND RETURN WITH NZ SET +; +; +; +DSK_SELECT: + ; C HAS CPM DRIVE, SAVE IT + LD A,C + LD (SEKDSK),A + + ; LOOKUP DPH (INCLUDES INVALID DRIVE CHECK) + CALL DSK_GETDPH ; HL = DPH (0 IF INVALID DRIVE) + RET NZ ; A=1 AND NZ SET IF INVALID DRIVE + + ; FIX: WE COULD RETURN DUE TO INVALID DRIVE WITH ALL OF THE + ; REMAINING SEK... VARS SET TO PREVIOUS DRIVE? + + ; SAVE CURRENT DEVICE/UNIT AND DPH ADDRESS + LD A,B ; A = DEVIE/UNIT + LD (SEKDU),A ; SAVE DEVICE/UNIT + LD (SEKDPH),HL ; SAVE DPH POINTER + + ; SETUP IX AS INDEX INTO DPH + PUSH IX ; SAVE IX + LD IX,(SEKDPH) ; IX=DPH ADDRESS + + ; CHECK IF THIS IS LOGIN, IF NOT, BYPASS MEDIA DETECTION + ; FIX: WHAT IF PREVIOUS MEDIA DETECTION FAILED??? + BIT 0,E ; TEST DRIVE LOGIN BIT + JR NZ,DSK_SELECT2 ; BYPASS MEDIA DETECTION +; +DSK_SELECT1: + ; DETERMINE MEDIA IN DRIVE + LD A,(SEKDU) ; GET DEVICE/UNIT + LD C,A ; STORE IN C + LD B,BF_DIOMED ; DRIVER FUNCTION = DISK MEDIA + CALL DSK_DISP ; CALL DRIVER, RETURNS WITH A=MEDIA ID + + ; CHECK FOR NO MEDIA + LD HL,0 ; ASSUME NO MEDIA FAILURE, HL = 0 + OR A ; SET FLAGS + JR Z,DSK_SELECT4 ; IF Z, NO MEDIA, BAIL OUT WITH HL=0 + + ; A HAS MEDIA ID, SET HL TO CORRESPONDING DPB_MAP ENTRY + LD HL,DPB_MAP ; HL = DPB_MAP + RLCA ; DPB_MAP ENTRIES ARE 2 BYTES EACH + ADD A,L ; ADD LOW BYTE TO OFFSET + LD L,A ; GET RESULT BACK TO L + + ; LOOKUP THE ACTUAL DPB ADDRESS NOW + LD E,(HL) ; DEREFERENCE HL... + INC HL ; INTO DE... + LD D,(HL) ; DE = ADDRESS OF DESIRED DPB + + ; PLUG APPROPRIATE DPB INTO THE ACTIVE DPH + LD (IX+10),E ; DPH.DPB := DPB ADDRESS (LSB) + LD (IX+11),D ; DPH.DPB := DPB ADDRESS (MSB) + +DSK_SELECT2: + ; CHECK FOR SLICE SUPPORT, BYPASS LU OFFSET CALC IF NOT + LD HL,(SEKDPH) ; LOAD DPH + CALL DSK_GETLU ; CHECK FOR LU SUPPORT + JR NZ,DSK_SELECT3 ; IF NOT (NZ), BYPASS LU OFFSET CALC + + ; RECOMPUTE TRACK OFFSET BASED ON SLICE NUMBER + LD E,65 ; FIX: FIXME!!! HARDCODED!!! E = TRACKS PER SLICE + LD H,(IX+18) ; H = SLICE VALUE + CALL MULT8 ; HL = TOTAL OFFSET + +DSK_SELECT3: + LD (SEKOFF),HL ; SAVE LU TRACK OFFSET + LD HL,(SEKDPH) ; HL = DPH ADDRESS FOR CP/M + +DSK_SELECT4: + POP IX ; RESTORE IX + RET +; +; +; +DSK_STATUS: + ; C HAS CPM DRIVE, LOOKUP DEVICE/UNIT AND CHECK FOR INVLAID DRIVE + CALL DSK_GETDPH ; B = DEVICE/UNIT + RET NZ ; INVALID DRIVE ERROR + + ; VALID DRIVE, DISPATCH TO DRIVER + LD C,B ; C=DEVICE/UNIT + LD B,BF_DIOST ; SET B = FUNCTION: STATUS + JP DSK_DISP ; DISPATCH +; +; +; +DSK_READ: + ; SET B = FUNCTION: READ + LD B,BF_DIORD + JR DSK_IO +; +; +; +DSK_WRITE: + ; SET B = FUNCTION: WRITE + LD B,BF_DIOWR + JR DSK_IO +; +; +; +DSK_IO: + ; SET HL=TRACK (ADD IN TRACK OFFSET) + LD DE,(HSTOFF) ; DE = TRACK OFFSET FOR LU SUPPORT + LD HL,(HSTTRK) ; HL = TRACK # + ADD HL,DE ; HL = TRACK # TO READ TAKING LU SUPPORT INTO ACCOUNT + ; SET DE=SECTOR + LD DE,(HSTSEC) ; DE = SECTOR # + ; SET C = DEVICE/UNIT + LD A,(HSTDU) ; LOAD DEVICE/UNIT VALUE + LD C,A ; SAVE IN C + ; DISPATCH TO DRIVER + CALL DSK_DISP ; CALL DRIVER + OR A ; SET FLAGS BASED ON RESULT + RET +; +;================================================================================================== +; IN MEMORY DISK DRIVERS (ROM/RAM) +;================================================================================================== +; +; USES ROM/RAM STORAGE NOT USED BY SYSTEM/OS FOR DISK STORAGE +; ROM DRIVE: +; FIRST 32KB OF ROM RESERVED FOR SYSTEM BOOT AREA. REMAINDER IS ALLOCATED +; AS READ-ONLY DISK STORAGE. +; RAM DRIVE: +; FIRST AND LAST 32KB OF RAM IS RESERVED AND MAPPED TO FIRST AND LAST 32KB +; OF CPU MEMORY SPACE (FOR 64KB TOTAL). EVERYTHING ELSE IS ALLOCATED AS +; READ/WRITE DISK STORAGE. +; ROUTINES BELOW TRANSLATE REQUESTS FOR RAM/ROM STORAGE ACCESS BY CP/M BY +; TEMPORARILY MAPPING RAM/ROM INTO LOWER 32KB OF CPU MEMORY SPACE AND COPYING +; THE REQUESTED 128 BYTE BLOCK INTO THE CP/M DMA BUFFER. +; +MD_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F + JR Z,MD_READ + DEC A + JR Z,MD_WRITE + DEC A + JR Z,MD_READY + DEC A + JR Z,MD_SELECT + CALL PANIC +; +;__________________________________________________________________________________________________ +MD_INIT: +; +; INITIALIZE RAM DISK BY FILLING DIRECTORY WITH 'E5' BYTES +; FILL FIRST 8K OF RAM DISK TRACK 1 WITH 'E5' +; +#IF (CLRRAMDISK != CLR_NEVER) + LD A,2 ; START OF RAM DISK (SECOND 32KB) + CALL RAMPG ; SELECT RAM DISK + +#IF (CLRRAMDISK == CLR_AUTO) + ; CHECK FIRST 32 DIRECTORY ENTRIES. IF ANY START WITH AN INVALID + ; VALUE, INIT THE RAM DISK. VALID ENTRIES ARE E5 (EMPTY ENTRY) OR + ; 0-15 (USER NUMBER). + LD HL,0 + LD DE,32 + LD B,32 +CLRRAM0: + LD A,(HL) + CP 0E5H + JR Z,CLRRAM1 ; E5 IS VALID + CP 16 + JR C,CLRRAM1 ; 0-15 IS ALSO VALID + JR CLRRAM2 ; INVALID ENTRY! JUMP TO INIT +CLRRAM1: + ADD HL,DE ; LOOP FOR 32 ENTRIES + DJNZ CLRRAM0 +; JR CLRRAM2 ; *DEBUG* + JR CLRRAM3 ; ALL ENTRIES VALID, BYPASS INIT +CLRRAM2: +#ENDIF + CALL RAMPGZ + LD DE,STR_INITRAMDISK + CALL WRITESTR + LD A,2 + CALL RAMPG + + LD HL,0 ; SOURCE OF FILL IN HL + LD BC,2000H - 1 ; LENGTH OF FILL - 1 + LD A,0E5H ; FILL VALUE IN A + LD E,L ; DE = HL + LD D,H ; " + INC DE ; THEN OFFSET BY ONE + LD (HL),A ; FILL INITIAL BYTE + LDIR ; COMPLETE THE FILL +CLRRAM3: + CALL RAMPGZ +#ENDIF + RET +; +;__________________________________________________________________________________________________ +MD_READY: + LD A,TRUE + RET +; +;__________________________________________________________________________________________________ +MD_SELECT: + LD A,C + AND 0FH + ADD A,MID_MDROM + RET +; +;__________________________________________________________________________________________________ +MD_READ: + CALL MD_PGSEL ; SET PAGER BASED ON DRIVE AND TRACK + LD DE,(BUFADR) ; SETUP SECTOR BUF AS DESTINATION + CALL MD_SECADR ; SETUP RAM/ROM PAGE ADDRESS IN HL + CALL MD_DMACPY ; MOVE SECTOR TO SECBUF + CALL RAMPGZ ; RESTORE NORMAL 32K LOWER CPU RAM + LD DE,(DMAADR) ; SETUP FOR COPY TO DMA ADDRESS + LD HL,(BUFADR) ; FROM BUFFER + CALL MD_DMACPY ; COPY FROM BUF TO DMA + LD A,00H ; SIGNAL SUCCESS + RET +; +;__________________________________________________________________________________________________ +MD_WRITE: + ; CHECK FOR WRITE ACCESS TO ROM + LD A,(SEKDU) ; GET DRIVE + OR A ; DEVICE = 0, UNIT = 0 MEANS ROM DISK (READ ONLY!) + JR Z,MD_RDONLY + + LD DE,(BUFADR) ; GET SECTOR BUF ADDRESS + LD HL,(DMAADR) ; GET DMA BUF ADDRESS + CALL MD_DMACPY ; MOVE FROM DMA BUF TO SECTOR BUF + CALL MD_PGSEL ; SET PAGER BASED ON DRIVE AND TRACK + CALL MD_SECADR ; SETUP PAGE ADDRESS IN HL + LD DE,(BUFADR) ; SECTOR BUF ADDRESS IN DE + EX DE,HL ; REVERSE THEM TO... + CALL MD_DMACPY ; COPY FROM SECTOR BUF TO RAM PAGE + CALL RAMPGZ ; RESTORE NORMAL 32K LOWER CPU RAM + LD A,00H ; SIGNAL SUCCESS + RET + +MD_RDONLY: + LD DE,STR_READONLY ; SET DE TO START OF ERROR MESSAGE + CALL WRITESTR ; PRINT ERROR MESSAGE + LD A,1 ; SEND BAD SECTOR ERROR BACK + RET ; BDOS WILL ALSO PRINT ITS OWN ERROR MESSAGE +; +;__________________________________________________________________________________________________ +MD_SECADR: +; DETERMINE MEMORY ADDRESS CORRESPONDING TO CURRENT SECTOR +; SECTOR SIZE = 128, SO JUST MULTIPLY BY 128 +; RETURNS ADDRESS IN HL + LD HL,(SEKSEC) ; GET SECTOR INTO HL + LD B,7 +MD_SECADR1: + ADD HL,HL + DJNZ MD_SECADR1 + RET +;__________________________________________________________________________________________________ +MD_PGSEL: +; SELECT MEMORY PAGE BASED ON DRIVE AND TRACK +; DRIVE UNIT 0 = ROM, OTHERWISE RAM + + LD A,(SEKTRK) + INC A ; OFFSET PAST RESERVED 32KB SYSTEM AREA OF RAM/ROM! + INC A ; OFFSET ANOTHER 32K PAST DRIVER BANK + LD C,A + LD A,(SEKDU) + OR A + LD A,C + JP Z,ROMPG ; DEVICE/UNIT = 0? YES, ROM PAGE + JP RAMPG ; ELSE RAM PAGE +; +;__________________________________________________________________________________________________ +MD_DMACPY: +; COPIES ONE CPM SECTOR FROM ONE MEMORY ADDRESS TO ANOTHER +; INPUT DE=SOURCE ADDRESS, HL=TARGET ADDRESS, USES BC + LD BC,128 ; BC IS COUNTER FOR FIXED SIZE TRANSFER (128 BYTES) + LDIR ; TRANSFER + RET +; +#INCLUDE "memmgr.asm" +; +;================================================================================================== +; UTILITY FUNCTIONS +;================================================================================================== +; +#DEFINE CIOMODE_CBIOS +ORG_UTIL .EQU $ +#INCLUDE "util.asm" +SIZ_UTIL .EQU $ - ORG_UTIL + .ECHO "UTIL occupies " + .ECHO SIZ_UTIL + .ECHO " bytes.\n" +; +;================================================================================================== +; DIAGNOSTICS +;================================================================================================== +; +#IF DSKTRACE +;__________________________________________________________________________________________________ +PRTSELDSK: + CALL NEWLINE + PUSH BC + PUSH DE + LD B,E + LD DE,STR_SELDSK + CALL WRITESTR + CALL PC_SPACE + LD DE,STR_DSK + LD A,C + CALL PRTHEXBYTE + CALL PC_SPACE + CALL PC_LBKT + LD A,B + CALL PRTHEXBYTE + CALL PC_RBKT + POP DE + POP BC + RET +; +;__________________________________________________________________________________________________ +PRTHOME: + CALL NEWLINE + LD DE,STR_HOME + CALL WRITESTR + RET +; +;__________________________________________________________________________________________________ +PRTDSKOP: + + LD (XSTKSAV),SP + LD SP,XSTK + + CALL NEWLINE + LD A,(DSKOP) + LD DE,STR_READ + CP DOP_READ + CALL Z,WRITESTR + LD DE,STR_WRITE + CP DOP_WRITE + CALL Z,WRITESTR + LD A,C + CALL Z,PRTHEXBYTE + LD DE,STR_DSK + CALL WRITESTR + LD A,(SEKDSK) + CALL PRTHEXBYTE + LD DE,STR_TRK + CALL WRITESTR + LD BC,(SEKTRK) + CALL PRTHEXWORD + LD DE,STR_SEC + CALL WRITESTR + LD BC,(SEKSEC) + CALL PRTHEXWORD + + LD SP,(XSTKSAV) + + RET + + RET + +XSTKSAV .DW 0 + .FILL $20 +XSTK .EQU $ +; +STR_SELDSK .DB "SELDSK$" +STR_HOME .DB "HOME$" +STR_READ .DB "READ$" +STR_WRITE .DB "WRITE$" +STR_DSK .DB " DSK=$" +STR_TRK .DB " TRK=$" +STR_SEC .DB " SEC=$" +; +#ENDIF +; +;================================================================================================== +; DATA +;================================================================================================== +; +STR_BANNER .DB "\r\n", OSLBL, " for ", PLATFORM_NAME, "\r\n" + .DB "CBIOS v", BIOSVER, " (" +VAR_LOC .DB VARIANT + .DB "-" +TST_LOC .DB TIMESTAMP, ")", DSKYLBL, VDULBL, FDLBL, IDELBL, PPIDELBL, SDLBL, PRPLBL, PPPLBL, "\r\n$" +STR_INITRAMDISK .DB "\r\nFormatting RAMDISK...$" +STR_READONLY .DB "\r\nCBIOS Error: Read Only Drive$" +STR_STALE .DB "\r\nCBIOS Error: Stale Drive$" +; +SECADR: .DW 0 ; ADDRESS OF SECTOR IN ROM/RAM PAGE +DEFDRIVE .DB 0 ; DEFAULT DRIVE +; +; DOS DISK VARIABLES +; +DSKOP: .DB 0 ; DISK OPERATION (DOP_READ/DOP_WRITE) +WRTYPE: .DB 0 ; WRITE TYPE (0=NORMAL, 1=DIR (FORCE), 2=FIRST RECORD OF BLOCK) +DMAADR: .DW 0 ; DIRECT MEMORY ADDRESS +HSTWRT: .DB 0 ; TRUE = BUFFER IS DIRTY +BUFADR: .DW $8000 ; ADDRESS OF PHYSICAL SECTOR BUFFER (DEFAULT MATCHES HBIOS) +; +; DISK I/O REQUEST PENDING +; +SEK: +SEKDSK: .DB 0 ; DISK NUMBER 0-15 +SEKTRK: .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL) +SEKSEC: .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL) +SEKDU: .DB 0 ; DEVICE/UNIT +SEKDPH: .DW 0 ; ADDRESS OF ACTIVE (SELECTED) DPH +SEKOFF: .DW 0 ; TRACK OFFSET IN EFFECT FOR LU +SEKACT: .DB TRUE ; ALWAYS TRUE! +; +; RESULT OF TRANSLATION CPM TO PHYSICAL TRANSLATION +; +XLT: +XLTDSK .DB 0 +XLTTRK .DW 0 +XLTSEC .DW 0 +XLTDU .DB 0 +XLTDPH .DW 0 +XLTOFF: .DW 0 +XLTACT .DB TRUE ; ALWAYS TRUE! +; +XLTSIZ .EQU $ - XLT +; +; DSK/TRK/SEC IN BUFFER (VALID WHEN HSTACT=TRUE) +; +HST: +HSTDSK .DB 0 ; DISK IN BUFFER +HSTTRK .DW 0 ; TRACK IN BUFFER +HSTSEC .DW 0 ; SECTOR IN BUFFER +HSTDU .DB 0 ; DEVICE/UNIT IN BUFFER +HSTDPH .DW 0 ; CURRENT DPH ADDRESS +HSTOFF .DW 0 ; TRACK OFFSET IN EFFECT FOR LU +HSTACT .DB 0 ; TRUE = BUFFER HAS VALID DATA +; +; SEQUENTIAL WRITE TRACKING FOR UNALLOCATED BLOCK +; +UNA: +UNADSK: .DB 0 ; DISK NUMBER 0-15 +UNATRK: .DW 0 ; TWO BYTES FOR TRACK # (LOGICAL) +UNASEC: .DW 0 ; TWO BYTES FOR SECTOR # (LOGICAL) +; +UNASIZ .EQU $ - UNA +; +UNACNT: .DB 0 ; COUNT DOWN UNALLOCATED RECORDS IN BLOCK +UNASPT: .DW 0 ; SECTORS PER TRACK +; +DIRBF: .FILL 128,00H ; SCRATCH DIRECTORY AREA +; +; DRIVER STORAGE +; +; MEMORY DISK 00: ROM DISK +; +ROMBLKS .EQU ((ROMSIZE - 64) / 2) +; + .DB DIODEV_MD + 0 +MDDPH0 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_ROM + .DW MDCSV0,MDALV0 +; +CKS_ROM .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA +ALS_ROM .EQU ((ROMBLKS + 7) / 8) ; ALS: BLKS / 8 (ROUNDED UP) +; +; MEMORY DISK 01: RAM DISK +; +RAMBLKS .EQU ((RAMSIZE - 96) / 2) +; + .DB DIODEV_MD + 1 +MDDPH1 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_RAM + .DW MDCSV1,MDALV1 +; +CKS_RAM .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA +ALS_RAM .EQU ((RAMBLKS + 7) / 8) ; ALS: BLKS / 8 (ROUNDED UP) +; +MDCSV0: .FILL 0 ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +MDALV0: .FILL ALS_ROM,00H ; MAX OF 512 DATA BLOCKS +MDCSV1: .FILL 0 ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +MDALV1: .FILL ALS_RAM,00H ; MAX OF 256 DATA BLOCKS +; +#IF (FDENABLE) +ORG_FD_DATA .EQU $ + #INCLUDE "fd_data.asm" +SIZ_FD_DATA .EQU $ - ORG_FD_DATA + .ECHO "FD_DATA occupies " + .ECHO SIZ_FD_DATA + .ECHO " bytes.\n" +#ENDIF + +#IF (IDEENABLE) +ORG_IDE_DATA .EQU $ + #INCLUDE "ide_data.asm" +SIZ_IDE_DATA .EQU $ - ORG_IDE_DATA + .ECHO "IDE_DATA occupies " + .ECHO SIZ_IDE_DATA + .ECHO " bytes.\n" +#ENDIF + +#IF (PPIDEENABLE) +ORG_PPIDE_DATA .EQU $ + #INCLUDE "ppide_data.asm" +SIZ_PPIDE_DATA .EQU $ - ORG_PPIDE_DATA + .ECHO "PPIDE_DATA occupies " + .ECHO SIZ_PPIDE_DATA + .ECHO " bytes.\n" +#ENDIF + +#IF (SDENABLE) +ORG_SD_DATA .EQU $ + #INCLUDE "sd_data.asm" +SIZ_SD_DATA .EQU $ - ORG_SD_DATA + .ECHO "SD_DATA occupies " + .ECHO SIZ_SD_DATA + .ECHO " bytes.\n" +#ENDIF + +#IF (PRPENABLE & PRPSDENABLE) +ORG_PRPSD_DATA .EQU $ + #INCLUDE "prp_data.asm" +SIZ_PRPSD_DATA .EQU $ - ORG_PRPSD_DATA + .ECHO "PRPSD_DATA occupies " + .ECHO SIZ_PRPSD_DATA + .ECHO " bytes.\n" +#ENDIF +#IF (PPPENABLE & PPPSDENABLE) +ORG_PPPSD_DATA .EQU $ + #INCLUDE "ppp_data.asm" +SIZ_PPPSD_DATA .EQU $ - ORG_PPPSD_DATA + .ECHO "PPPSD_DATA occupies " + .ECHO SIZ_PPPSD_DATA + .ECHO " bytes.\n" +#ENDIF +#IF (HDSKENABLE) +ORG_HDSK_DATA .EQU $ + #INCLUDE "hdsk_data.asm" +SIZ_HDSK_DATA .EQU $ - ORG_HDSK_DATA + .ECHO "HDSK_DATA occupies " + .ECHO SIZ_HDSK_DATA + .ECHO " bytes.\n" +#ENDIF +; +; DISK PARAMETER BLOCKS +; +; BLS BSH BLM EXM (DSM<256) EXM (DSM>255) +; ---------- --- --- ------------- ------------- +; 1,024 3 7 0 N/A +; 2,048 4 15 1 0 +; 4,096 5 31 3 1 +; 8,192 6 63 7 3 +; 16,384 7 127 15 7 +; +; AL0/1: EACH BIT SET ALLOCATES A BLOCK OF DIR ENTRIES. EACH DIR ENTRY +; IS 32 BYTES. BIT COUNT = (((DRM + 1) * 32) / BLS) +; +; CKS = (DIR ENT / 4), ZERO FOR NON-REMOVABLE MEDIA +; +; ALS = TOTAL BLKS (DSM + 1) / 8 +;__________________________________________________________________________________________________ +; +; ROM DISK: 256 SECS/TRK, 128 BYTES/SEC +; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 +; ROM DISK SIZE = TOTAL ROM - 32K RESERVED FOR SYSTEM USE +; + .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) +DPB_ROM: + .DW 256 ; SPT: SECTORS PER TRACK + .DB 4 ; BSH: BLOCK SHIFT FACTOR + .DB 15 ; BLM: BLOCK MASK +#IF (ROMBLKS < 256) + .DB 1 ; EXM: EXTENT MASK +#ELSE + .DB 0 ; EXM: EXTENT MASK +#ENDIF + .DW ROMBLKS - 1 ; DSM: TOTAL STORAGE IN BLOCKS - 1 + .DW 255 ; DRM: DIR ENTRIES - 1 = 255 + .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE + .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE + .DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA + .DW 0 ; OFF: ROM DISK HAS NO SYSTEM AREA +;__________________________________________________________________________________________________ +; +; RAM DISK: 256 SECS/TRK, 128 BYTES/SEC +; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 +; RAM DISK SIZE = TOTAL RAM - 64K RESERVED FOR SYSTEM USE +; + .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) +DPB_RAM: + .DW 256 ; SPT: SECTORS PER TRACK + .DB 4 ; BSH: BLOCK SHIFT FACTOR + .DB 15 ; BLM: BLOCK MASK +#IF (RAMBLKS < 256) + .DB 1 ; EXM: EXTENT MASK +#ELSE + .DB 0 ; EXM: EXTENT MASK +#ENDIF + .DW RAMBLKS - 1 ; DSM: TOTAL STORAGE IN BLOCKS - 1 + .DW 255 ; DRM: DIR ENTRIES - 1 = 255 + .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE + .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE + .DW 0 ; CKS: ZERO FOR NON-REMOVABLE MEDIA + .DW 0 ; OFF: RESERVED TRACKS = 0 TRK +;__________________________________________________________________________________________________ +; +; 8MB HARD DISK DRIVE, 65 TRKS, 1024 SECS/TRK, 128 BYTES/SEC +; BLOCKSIZE (BLS) = 4K, DIRECTORY ENTRIES = 128 +; SEC/TRK ENGINEERED SO THAT AFTER DEBLOCKING, SECTOR NUMBER OCCUPIES 1 BYTE (0-255) +; + .DB (4096 / 128) ; RECORDS PER BLOCK (BLS / 128) +DPB_HD: + .DW 1024 ; SPT: SECTORS PER TRACK + .DB 5 ; BSH: BLOCK SHIFT FACTOR + .DB 31 ; BLM: BLOCK MASK + .DB 1 ; EXM: EXTENT MASK + .DW 2047 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((8MB - 128K OFF) / 4K BLS) - 1 = 2047 + .DW 511 ; DRM: DIR ENTRIES - 1 = 512 - 1 = 511 + .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE + .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE + .DW 0 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 + .DW 1 ; OFF: RESERVED TRACKS = 1 TRKS * (512 B/SEC * 1024 SEC/TRK) = 128K +;__________________________________________________________________________________________________ +; +; IBM 720KB 3.5" FLOPPY DRIVE, 80 TRKS, 36 SECS/TRK, 512 BYTES/SEC +; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 128 +; + .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) +DPB_FD720: + .DW 36 ; SPT: SECTORS PER TRACK + .DB 4 ; BSH: BLOCK SHIFT FACTOR + .DB 15 ; BLM: BLOCK MASK + .DB 0 ; EXM: EXTENT MASK + .DW 350 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((720K - 18K OFF) / 2K BLS) - 1 = 350 + .DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127 + .DB 11000000B ; AL0: DIR BLK BIT MAP, FIRST BYTE + .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE + .DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4 + .DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K +;__________________________________________________________________________________________________ +; +; IBM 1.44MB 3.5" FLOPPY DRIVE, 80 TRKS, 72 SECS/TRK, 512 BYTES/SEC +; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 +; + .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) +DPB_FD144: + .DW 72 ; SPT: SECTORS PER TRACK + .DB 4 ; BSH: BLOCK SHIFT FACTOR + .DB 15 ; BLM: BLOCK MASK + .DB 0 ; EXM: EXTENT MASK + .DW 710 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,440K - 18K OFF) / 2K BLS) - 1 = 710 + .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 + .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE + .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE + .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 + .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 72 SEC/TRK) = 18K +;__________________________________________________________________________________________________ +; +; IBM 360KB 5.25" FLOPPY DRIVE, 40 TRKS, 9 SECS/TRK, 512 BYTES/SEC +; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 128 +; + .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) +DPB_FD360: + .DW 36 ; SPT: SECTORS PER TRACK + .DB 4 ; BSH: BLOCK SHIFT FACTOR + .DB 15 ; BLM: BLOCK MASK + .DB 0 ; EXM: EXTENT MASK + .DW 170 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((360K - 18K OFF) / 2K BLS) - 1 = 170 + .DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127 + .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE + .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE + .DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4 + .DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K +;__________________________________________________________________________________________________ +; +; IBM 1.20MB 5.25" FLOPPY DRIVE, 80 TRKS, 60 SECS/TRK, 512 BYTES/SEC +; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 +; + .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) +DPB_FD120: + .DW 60 ; SPT: SECTORS PER TRACK + .DB 4 ; BSH: BLOCK SHIFT FACTOR + .DB 15 ; BLM: BLOCK MASK + .DB 0 ; EXM: EXTENT MASK + .DW 591 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,200K - 15K OFF) / 2K BLS) - 1 = 591 + .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 + .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE + .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE + .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 + .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K +;__________________________________________________________________________________________________ +; +; IBM 1.11MB 8" FLOPPY DRIVE, 74 TRKS, 60 SECS/TRK, 512 BYTES/SEC +; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 +; + .DB (2048 / 128) ; RECORDS PER BLOCK (BLS / 128) +DPB_FD111: + .DW 60 ; SPT: SECTORS PER TRACK + .DB 4 ; BSH: BLOCK SHIFT FACTOR + .DB 15 ; BLM: BLOCK MASK + .DB 0 ; EXM: EXTENT MASK + .DW 546 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,110K - 15K OFF) / 2K BLS) - 1 = 546 + .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 + .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE + .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE + .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 + .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K +; +;================================================================================================== +; START OF HIMEM AREA +;================================================================================================== +; +; THE FOLLOWING DATA STRUCTURES MUST NOT CROSS A PAGE BOUNDARY DUE TO OPTIMIZATION OF +; LOOKUP CODE. SO, HERE WE ORG SO THAT THERE IS JUST ENOUGH SPACE AT THE TOP OF THE +; CBIOS FOR THE DATA STRUCTURES. OBVIOUSLY, FOR THIS TO WORK, CBIOS MUST BE SET TO +; END AT A PAGE BOUNDARY, WHICH IS INTENDED +; +SLACK .EQU (CBIOS_END - $ - 32 - 32 - 16 - 512) + .FILL SLACK,00H +; + .ECHO "CBIOS space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" +; +;================================================================================================== +; DPB MAPPING TABLE +;================================================================================================== +; +; MAP MEDIA ID'S TO APPROPRIATE DPB ADDRESSEES +; THE ENTRIES IN THIS TABLE MUST CONCIDE WITH THE VALUES +; OF THE MEDIA ID'S (SAME SEQUENCE, NO GAPS) +; +DPB_MAP: + .DW 0 ; MID_NONE (NO MEDIA) + .DW DPB_ROM ; MID_MDROM + .DW DPB_RAM ; MID_MDRAM + .DW DPB_HD ; MID_HD + .DW DPB_FD720 ; MID_FD720 + .DW DPB_FD144 ; MID_FD144 + .DW DPB_FD360 ; MID_FD360 + .DW DPB_FD120 ; MID_FD120 + .DW DPB_FD111 ; MID_FD111 +; +DPB_CNT .EQU ($ - DPB_MAP) / 2 +; +;================================================================================================== +; DRIVE LETTER MAPPING TABLE +;================================================================================================== +; +; THE DISK MAP TABLE BELOW MAPS DRIVE LETTERS TO PHYSICAL STORAGE DEVICES. +; CP/M DRIVE LETTERS ARE ASSIGNED BASED ON THE ORDER OF ENTRIES IN THE TABLE, +; SO THE FIRST ENTRY IS A:, THE SECOND ENTRY IS B:, ETC. +; EACH ENTRY IS A COMBINATION (OR) OF THE DEVICE AND THE UNIT. +; DIODEV_MD = MEMORY DISKS (ROM/RAM) (UNIT 0 = ROM, UNIT 1 = RAM) +; DIODEV_FD = FLOPPY DISKS (TWO UNITS (0/1) SUPPORTED) +; DIODEV_IDE = IDE DISKS (TWO UNITS (0/1) MASTER/SLAVE SUPPORTED) +; DIODEV_PPIDE = PPIDE DISKS (TWO UNITS (0/1) MASTER/SLAVE SUPPORTED) +; DIODEV_SD = SD CARD (ONE UNIT SUPPORTED) +; DIODEV_PRPSD = PROPIO SD CARD (ONE UNIT SUPPORTED) +; DIODEV_PPPSD = PROPIO SD CARD (ONE UNIT SUPPORTED) +; DIODEV_HDDSK = SIMH HARD DISK (TWO UNITS SUPPORTED) +; +; DRIVE LETTERS ARE ASSIGNED SEQUENTIALLY. +; +; ALTERNATIVELY, YOU CAN DEFINE A MACRO CALLED CUSTOM_DPHMAP THAT +; DEFINES AN ENTIRELY CUSTOM MAPPING +; +DPH_MAP: +#IFDEF CUSTOM_DPHMAP + CUSTOM_DPHMAP +#ELSE + #IF (DSKMAP == DM_ROM) + .DW MDDPH0 + #ENDIF + #IF (DSKMAP == DM_RAM) + .DW MDDPH1 + #ENDIF + #IF (DSKMAP == DM_FD) + .DW FDDPH0 + .DW FDDPH1 + #ENDIF + #IF (DSKMAP == DM_IDE) + .DW IDEDPH0 + .DW IDEDPH1 + .DW IDEDPH2 + .DW IDEDPH3 + #ENDIF + #IF (DSKMAP == DM_PPIDE) + .DW PPIDEDPH0 + .DW PPIDEDPH1 + .DW PPIDEDPH2 + .DW PPIDEDPH3 + #ENDIF + #IF (DSKMAP == DM_SD) + .DW SDDPH0 + .DW SDDPH1 + .DW SDDPH2 + .DW SDDPH3 + #ENDIF + #IF (DSKMAP == DM_PRPSD) + .DW PRPSDDPH0 + .DW PRPSDDPH1 + .DW PRPSDDPH2 + .DW PRPSDDPH3 + #ENDIF + #IF (DSKMAP == DM_PPPSD) + .DW PPPSDDPH0 + .DW PPPSDDPH1 + .DW PPPSDDPH2 + .DW PPPSDDPH3 + #ENDIF + #IF (DSKMAP == DM_HDSK) + .DW HDSKDPH0 + .DW HDSKDPH1 + .DW HDSKDPH2 + .DW HDSKDPH3 + #ENDIF + #IF (DSKMAP != DM_ROM) + .DW MDDPH0 + #ENDIF + #IF (DSKMAP != DM_RAM) + .DW MDDPH1 ; was MDDHP1 + #ENDIF + #IF ((DSKMAP != DM_FD) & FDENABLE) + .DW FDDPH0 + .DW FDDPH1 + #ENDIF + #IF ((DSKMAP != DM_IDE) & IDEENABLE) + .DW IDEDPH0 + .DW IDEDPH1 + .DW IDEDPH2 + .DW IDEDPH3 + #ENDIF + #IF ((DSKMAP != DM_PPIDE) & PPIDEENABLE) + .DW PPIDEDPH0 + .DW PPIDEDPH1 + .DW PPIDEDPH2 + .DW PPIDEDPH3 + #ENDIF + #IF ((DSKMAP != DM_SD) & SDENABLE) + .DW SDDPH0 + .DW SDDPH1 + .DW SDDPH2 + .DW SDDPH3 + #ENDIF + #IF ((DSKMAP != DM_PRPSD) & PRPENABLE & PRPSDENABLE) + .DW PRPSDDPH0 + .DW PRPSDDPH1 + .DW PRPSDDPH2 + .DW PRPSDDPH3 + #ENDIF + #IF ((DSKMAP != DM_PPPSD) & PPPENABLE & PPPSDENABLE) + .DW PPPSDDPH0 + .DW PPPSDDPH1 + .DW PPPSDDPH2 + .DW PPPSDDPH3 + #ENDIF + #IF ((DSKMAP != DM_HDSK) & HDSKENABLE) + .DW HDSKDPH0 + .DW HDSKDPH1 + .DW HDSKDPH2 + .DW HDSKDPH3 + #ENDIF +#ENDIF ; CUSTOM_DPHMAP +; +DPH_CNT .EQU ($ - DPH_MAP) / 2 + .FILL (16 - DPH_CNT) * 2,0FFH +DSK_CNT .EQU DPH_CNT +; +;================================================================================================== +; CHARACTER DEVICE MAPPING +;================================================================================================== +; +; MAP LOGICAL TO PHYSICAL DEVICES +; +LD_TTY .EQU CIODEV_UART +LD_CRT .EQU CIODEV_VDU +LD_BAT .EQU CIODEV_BAT +LD_UC1 .EQU CIODEV_UART +LD_PTR .EQU CIODEV_UART +LD_UR1 .EQU CIODEV_UART +LD_UR2 .EQU CIODEV_UART +LD_PTP .EQU CIODEV_UART +LD_UP1 .EQU CIODEV_UART +LD_UP2 .EQU CIODEV_UART +LD_LPT .EQU CIODEV_UART +LD_UL1 .EQU CIODEV_UART +; +#IF (PLATFORM == PLT_N8) +LD_UC1 .SET CIODEV_UART + 1 +#ENDIF +; +#IF (VDUENABLE) +LD_CRT .SET CIODEV_VDU +#ENDIF +#IF (PRPENABLE & PRPCONENABLE) +LD_CRT .SET CIODEV_PRPCON +#ENDIF +#IF (PPPENABLE & PPPCONENABLE) +LD_CRT .SET CIODEV_PPPCON +#ENDIF +; +CIO_MAP: +; + ; CONSOLE + .DB LD_TTY ; CON:=TTY: (IOBYTE XXXXXX00) + .DB LD_CRT ; CON:=CRT: (IOBYTE XXXXXX01) + .DB LD_BAT ; CON:=BAT: (IOBYTE XXXXXX10) + .DB LD_UC1 ; CON:=UC1: (IOBYTE XXXXXX11) + ; READER + .DB LD_TTY ; RDR:=TTY: (IOBYTE XXXX00XX) + .DB LD_PTR ; RDR:=PTR: (IOBYTE XXXX01XX) + .DB LD_UR1 ; RDR:=UR1: (IOBYTE XXXX10XX) + .DB LD_UR2 ; RDR:=UR2: (IOBYTE XXXX11XX) + ; PUNCH + .DB LD_TTY ; PUN:=TTY: (IOBYTE XX00XXXX) + .DB LD_PTP ; PUN:=PTP: (IOBYTE XX01XXXX) + .DB LD_UP1 ; PUN:=UP1: (IOBYTE XX10XXXX) + .DB LD_UP2 ; PUN:=UP2: (IOBYTE XX11XXXX) + ; LIST + .DB LD_TTY ; LST:=TTY: (IOBYTE 00XXXXXX) + .DB LD_CRT ; LST:=CRT: (IOBYTE 01XXXXXX) + .DB LD_LPT ; LST:=LPT: (IOBYTE 10XXXXXX) + .DB LD_UL1 ; LST:=UL1: (IOBYTE 11XXXXXX) +; +;================================================================================================== +; SECTOR AND CONFIG BUFFER; +;================================================================================================== +; +; A 512 AREA IS ALLOCATED AT FD00 AND IS USED FOR TWO PURPOSES: +; 1) AS THE DISK SECTOR BUFFER AFTER CBIOS COLD INIT IS DONE +; 2) FOR CBIOS INIT CODE THAT CAN BE DISCARDED AFTER INITIALIZTION: +; A) SYSTEM CONFIGURATION DATA BUFFER +; B) CBIOS INIT CODE THAT CAN BE DISCARDED AFTER INIT +; + .FILL 0FD00H - $,00H ; MAKE SURE SEC/CFGBUF STARTS AT FD00 +; +SECBUF: ; START OF 512 BYTE DISK SECTOR +CFGBUF: ; START OF 256 BYTE CONFIG BUFFER + .FILL 256,0 +; +INIT: + DI + IM 1 + + ; SETUP A TEMP STACK IN UPPER 32K + LD SP,ISTACK ; STACK FOR INITIALIZATION + + ; ENSURE RAM PAGE ZERO ACTIVE + CALL RAMPGZ + + ; THIS INIT CODE WILL BE OVERLAID, SO WE ARE GOING + ; TO MODIFY THE BOOT ENTRY POINT TO CAUSE A PANIC + ; TO EASILY IDENTIFY IF SOMETHING TRIES TO INVOKE + ; THE BOOT ENTRY POINT AFTER INIT IS DONE. + LD A,0CDH ; "CALL" INSTRUCTION + LD (BOOT),A ; STORE IT BOOT ENTRY POINT + LD HL,PANIC ; ADDRESS OF PANIC ROUTINE + LD (BOOT+1),HL ; STORE IT AT BOOT ENTRY + 1 + + ; PARAMETER INITIALIZATION + LD A,DEFIOBYTE ; LOAD DEFAULT IOBYTE + LD (IOBYTE),A ; STORE IT + +#IF (PLATFORM != PLT_N8) + IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER +; LD A,40H ; *DEBUG* SIMULATE JUMPER OPEN +; LD A,00H ; *DEBUG* SIMULATE JUMPER SHORTED + AND 40H ; ISOLATE BIT 6 + JR Z,INIT1 ; IF BIT6=0, SHORTED, USE ALT IOBYTE + LD A,DEFIOBYTE ; LOAD DEF IOBYTE VALUE + JR INIT2 ; CONTINUE +INIT1: + LD A,ALTIOBYTE ; LOAD ALT IOBYTE VALUE +INIT2: + LD (IOBYTE),A ; SET THE ACTIVE IOBYTE +#ENDIF + + ; DEFAULT DRIVE + CALL DEFDRV ; DETERMINE DEFAULT DRIVE + LD A,(DEFDRIVE) ; GET DEFAULT DRIVE + LD (CDISK),A ; SETUP CDISK + + ; STARTUP MESSAGE + LD DE,STR_BANNER + CALL WRITESTR + + ; SAVE COMMAND PROCESSOR TO CACHE IN RAM1 + LD A,1 + CALL RAMPG + LD HL,CPM_LOC ; LOCATION OF ACTIVE COMMAND PROCESSOR + LD DE,0800H ; LOCATION IN RAM 1 OF COMMAND PROCESSOR CACHE + LD BC,CCPSIZ ; SIZE OF COMMAND PROCESSOR + LDIR + CALL RAMPGZ + + ; SYSTEM INITIALIZATION + CALL BLKRES ; RESET DISK (DE)BLOCKING ALGORITHM + CALL MD_INIT ; INITIALIZE MEMORY DISK DRIVER (RAM/ROM) + + ; STARTUP CPM + JP GOCPM +; +DEFDRV: + ; START BY ASSUMING DRIVE 0 IS DEFAULT + XOR A ; ZERO + LD (DEFDRIVE),A ; STORE IT + + ; GET CONFIG INFO (STORE IN CFGBUF) + LD BC,$F000 + LD DE,CFGBUF + RST 08 + + ; IF NOT A DISK DEVICE BOOT, BAIL OUT, NOTHING MORE TO DO + LD A,(CFGBUF+DISKBOOT) ; DID WE BOOT FROM A DISK DEVICE? + OR A ; SET FLAGS + RET Z + + ; SCAN DRIVES TO MATCH BOOTDEVICE/LU AND STORE DEFDRIVE + LD C,-1 ; INIT CURRENT DRIVE FOR LOOP +DEFDRV1: + INC C ; NEXT DRIVE + LD A,C ; A = C + CP 16 ; MAX DRIVE IS 15, PAST IT? + RET Z ; NO MATCHES, BAIL OUT + CALL DSK_GETDPH ; GET POINTER TO DPH INTO HL + OR A ; SET FLAGS + JR NZ,DEFDRV1 ; INVALID DRIVE, BYPASS IT + DEC HL ; POINT TO DEVICE/UNIT + LD E,(HL) ; E = DEVICE/UNIT BYTE + LD A,(CFGBUF+BOOTDEVICE) ; A = BOOTDEVICE + CP E ; MATCH BOOTDEVICE? + JR NZ,DEFDRV1 ; NOPE, NEXT DRIVE + INC HL ; POINT HL BACK TO START OF DPH + CALL DSK_GETLU ; GET POINTER TO LU DATA IN HL + JR NZ,DEFDRV2 ; NO LU SUPPORT, DEVICE ALREADY MATCHED, WE ARE DONE + LD E,(HL) ; E = LU LSB + LD A,(CFGBUF+BOOTLU) ; A = BOOT LU LSB + CP E ; MATCH LSB? + JR NZ,DEFDRV1 ; NOPE, NEXT DRIVE + INC HL ; POINT TO LU MSB + LD E,(HL) ; E = LU MSB + LD A,(CFGBUF+BOOTLU+1) ; A = BOOT LU MSB + CP E ; MATCH MSB? + JR NZ,DEFDRV1 ; NOPE, NEXT DRIVE + +DEFDRV2: + ; WE HAVE A MATCH MATCHED, RECORD NEW DEFAULT DRIVE + LD A,C ; C HAS MATCHING DRIVE, MOVE TO A + LD (DEFDRIVE),A ; SAVE IT + RET +; + .FILL (256 - ($ - INIT)),0 ; FILL REMAINDER OF PAGE +; +ISTACK .EQU $ ; TEMP STACK SPACE +; + .END diff --git a/trunk/Source/ccpb03.asm b/trunk/Source/ccpb03.asm new file mode 100644 index 00000000..dd3c8462 --- /dev/null +++ b/trunk/Source/ccpb03.asm @@ -0,0 +1,1264 @@ + .title "Digital Research CCP, Version 2.2" + .page 49 + +MON .EQU 1 ;ADD THE CCP MON COMMAND +USRDSP .EQU 1 ;SHOW THE USER NUMBER +CHKU0B .EQU 0 ;CHECK FOR TRANSIENTS ON USER 0 TOO +ENDFIL .EQU 1 ;FILE FULL CCP SIZE +; +;************************************************************** +;* +;* C C P - C O N S O L E C O M M A N D P R O C E S S O R +;* +;************************************************************** +;* +IOBYTE: .EQU 3 ; I/O DEFINITION BYTE. +TDRIVE: .EQU 4 ; CURRENT DRIVE NAME AND USER NUMBER. +ENTRY: .EQU 5 ; ENTRY POINT FOR THE CP/M BDOS. +TFCB: .EQU 5CH ; DEFAULT FILE CONTROL BLOCK. +TBUFF: .EQU 80H ; I/O BUFFER AND COMMAND LINE STORAGE. +TBASE: .EQU 100H ; TRANSIANT PROGRAM STORAGE AREA. +; +; SET CONTROL CHARACTER .EQUATES. +; +CNTRLC: .EQU 03H ; CONTROL-C +CNTRLE: .EQU 05H ; CONTROL-E +BS: .EQU 08H ; BACKSPACE +TAB: .EQU 09H ; TAB +LF: .EQU 0AH ; LINE FEED +FF: .EQU 0CH ; FORM FEED +CR: .EQU 0DH ; CARRIAGE RETURN +CNTRLP: .EQU 10H ; CONTROL-P +CNTRLR: .EQU 12H ; CONTROL-R +CNTRLS: .EQU 13H ; CONTROL-S +CNTRLU: .EQU 15H ; CONTROL-U +CNTRLX: .EQU 18H ; CONTROL-X +CNTRLZ: .EQU 1AH ; CONTROL-Z (END-OF-FILE MARK) +DEL: .EQU 7FH ; RUBOUT +; +; SET ORIGIN FOR CP/M +; + +NK .EQU 59 ;SYSTEM SIZE +BASE .EQU (NK*1024)-5000H +CCPO .EQU BASE+3400H ;CCP ORIGIN +BDOSO .EQU BASE+3C00H ;BDOS ORIGIN +BIOSO .EQU BASE+4A00H ;BIOS ORIGIN + + .ORG CCPO +; +CBASE: JP COMMAND ; EXECUTE COMMAND PROCESSOR (CCP). + JP CLEARBUF ; ENTRY TO EMPTY INPUT BUFFER BEFORE STARTING CCP. + +; +; STANDARD CP/M CCP INPUT BUFFER. FORMAT IS (MAX LENGTH), +; (ACTUAL LENGTH), (CHAR #1), (CHAR #2), (CHAR #3), ETC. +; +INBUFF: .DB 127 ; LENGTH OF INPUT BUFFER. +; N8VEM - if add any text after this point, change .DB 0 below to length +; and put a 0 after the text, and delete the same number of zeros after the dig +; so that inpoint ends up at the same spot +; INBUFF+1 is cleared on the next warm boot, so only runs once. + .DB 0 ;CURRENT LENGTH OF CONTENTS. + + +; .DB 17 ; Autoboot length of string +; .DB "SUPERSUB AUTOEXEC" +; .DB 0 ; zero at end + + + .DB "COPYRIGHT" + .DB " 1979 (C) BY " + .DB "DIGITAL RESEARCH " + .FILL ((INBUFF + 128) - $),055H + + +INPOINT:.DW INBUFF+2 ; INPUT LINE POINTER +NAMEPNT:.DW 0 ; INPUT LINE POINTER USED FOR ERROR MESSAGE. POINTS TO +; ;START OF NAME IN ERROR. +; +; ROUTINE TO PRINT (A) ON THE CONSOLE. ALL REGISTERS USED. +; +PRINT: LD E,A ; SETUP BDOS CALL. + LD C,2 + JP ENTRY +; +; ROUTINE TO PRINT (A) ON THE CONSOLE AND TO SAVE (BC). +; +PRINTB: PUSH BC + CALL PRINT + POP BC + RET +; +; ROUTINE TO SEND A CARRIAGE RETURN, LINE FEED COMBINATION +; TO THE CONSOLE. +; +CRLF: LD A,CR + CALL PRINTB + LD A,LF + JP PRINTB +; +; ROUTINE TO SEND ONE SPACE TO THE CONSOLE AND SAVE (BC). +; +SPACE: LD A,' ' + JP PRINTB +; +; ROUTINE TO PRINT CHARACTER STRING POINTED TO BE (BC) ON THE +; CONSOLE. IT MUST TERMINATE WITH A NULL BYTE. +; +PLINE: PUSH BC + CALL CRLF + POP HL +PLINE2: LD A,(HL) + OR A + RET Z + INC HL + PUSH HL + CALL PRINT + POP HL + JP PLINE2 +; +; ROUTINE TO RESET THE DISK SYSTEM. +; +RESDSK: LD C,13 + JP ENTRY +; +; ROUTINE TO SELECT DISK (A). +; +DSKSEL: LD E,A + LD C,14 + JP ENTRY +; +; ROUTINE TO CALL BDOS AND SAVE THE RETURN CODE. THE ZERO +; FLAG IS SET ON A RETURN OF 0FFH. +; +ENTRY1: CALL ENTRY + LD (RTNCODE),A ; SAVE RETURN CODE. + INC A ; SET ZERO IF 0FFH RETURNED. + RET +; +; ROUTINE TO OPEN A FILE. (DE) MUST POINT TO THE FCB. +; +OPEN: LD C,15 + JP ENTRY1 +; +; ROUTINE TO OPEN FILE AT (FCB). +; +OPENFCB:XOR A ; CLEAR THE RECORD NUMBER BYTE AT FCB+32 + LD (FCB+32),A + LD DE,FCB + JP OPEN +; +; ROUTINE TO CLOSE A FILE. (DE) POINTS TO FCB. +; +CLOSE: LD C,16 + JP ENTRY1 +; +; ROUTINE TO SEARCH FOR THE FIRST FILE WITH AMBIGUEOUS NAME +; (DE). +; +SRCHFST:LD C,17 + JP ENTRY1 +; +; SEARCH FOR THE NEXT AMBIGEOUS FILE NAME. +; +SRCHNXT:LD C,18 + JP ENTRY1 +; +; SEARCH FOR FILE AT (FCB). +; +SRCHFCB:LD DE,FCB + JP SRCHFST +; +; ROUTINE TO DELETE A FILE POINTED TO BY (DE). +; +DELETE: LD C,19 + JP ENTRY +; +; ROUTINE TO CALL THE BDOS AND SET THE ZERO FLAG IF A ZERO +; STATUS IS RETURNED. +; +ENTRY2: CALL ENTRY + OR A ; SET ZERO FLAG IF APPROPRIATE. + RET +; +; ROUTINE TO READ THE NEXT RECORD FROM A S.EQUENTIAL FILE. +; (DE) POINTS TO THE FCB. +; +RDREC: LD C,20 + JP ENTRY2 +; +; ROUTINE TO READ FILE AT (FCB). +; +READFCB:LD DE,FCB + JP RDREC +; +; ROUTINE TO WRITE THE NEXT RECORD OF A S.EQUENTIAL FILE. +; (DE) POINTS TO THE FCB. +; +WRTREC: LD C,21 + JP ENTRY2 +; +; ROUTINE TO CREATE THE FILE POINTED TO BY (DE). +; +CREATE: LD C,22 + JP ENTRY1 +; +; ROUTINE TO RENAME THE FILE POINTED TO BY (DE). NOTE THAT +; THE NEW NAME STARTS AT (DE+16). +; +RENAM: LD C,23 + JP ENTRY +; +; GET THE CURRENT USER CODE. +; +GETUSR: LD E,0FFH +; +; ROUTNE TO GET OR SET THE CURRENT USER CODE. +; IF (E) IS FF THEN THIS IS A GET, ELSE IT IS A SET. +; +GETSETUC: + LD C,32 + JP ENTRY +; +; ROUTINE TO SET THE CURRENT DRIVE BYTE AT (TDRIVE). +; +SETCDRV:CALL GETUSR ; GET USER NUMBER + ADD A,A ; AND SHIFT INTO THE UPPER 4 BITS. + ADD A,A + ADD A,A + ADD A,A + LD HL,CDRIVE ; NOW ADD IN THE CURRENT DRIVE NUMBER. + OR (HL) + LD (TDRIVE),A ; AND SAVE. + RET +; +; MOVE CURRENTLY ACTIVE DRIVE DOWN TO (TDRIVE). +; +MOVECD: LD A,(CDRIVE) + LD (TDRIVE),A + RET +; +; ROUTINE TO CONVERT (A) INTO UPPER CASE ASCII. ONLY LETTERS +; ARE AFFECTED. +; +UPPER: CP 'A' ; CHECK FOR LETTERS IN THE RANGE OF 'A' TO 'Z'. + RET C + CP '{' + RET NC + AND 5FH ; CONVERT IT IF FOUND. + RET +; +; ROUTINE TO GET A LINE OF INPUT. WE MUST CHECK TO SEE IF THE +; USER IS IN (BATCH) MODE. IF SO, THEN READ THE INPUT FROM FILE +; ($$$.SUB). AT THE END, RESET TO CONSOLE INPUT. +; +GETINP: LD A,(BATCH) ; IF =0, THEN USE CONSOLE INPUT. + OR A + JP Z,GETINP1 +; +; USE THE SUBMIT FILE ($$$.SUB) WHICH IS PREPARED BY A +; SUBMIT RUN. IT MUST BE ON DRIVE (A) AND IT WILL BE DELETED +; IF AND ERROR OCCURES (LIKE EOF). +; + LD A,(CDRIVE) ; SELECT DRIVE 0 IF NEED BE. + OR A + LD A,0 ; ALWAYS USE DRIVE A FOR SUBMIT. + CALL NZ,DSKSEL ; SELECT IT IF REQUIRED. + LD DE,BATCHFCB + CALL OPEN ; LOOK FOR IT. + JP Z,GETINP1 ; IF NOT THERE, USE NORMAL INPUT. + LD A,(BATCHFCB+15) ; GET LAST RECORD NUMBER+1. + DEC A + LD (BATCHFCB+32),A + LD DE,BATCHFCB + CALL RDREC ; READ LAST RECORD. + JP NZ,GETINP1 ; QUIT ON END OF FILE. +; +; MOVE THIS RECORD INTO INPUT BUFFER. +; + LD DE,INBUFF+1 + LD HL,TBUFF ; DATA WAS READ INTO BUFFER HERE. + LD B,128 ; ALL 128 CHARACTERS MAY BE USED. + CALL HL2DE ; (HL) TO (DE), (B) BYTES. + LD HL,BATCHFCB+14 + LD (HL),0 ; ZERO OUT THE 'S2' BYTE. + INC HL ; AND DECREMENT THE RECORD COUNT. + DEC (HL) + LD DE,BATCHFCB ; CLOSE THE BATCH FILE NOW. + CALL CLOSE + JP Z,GETINP1 ; QUIT ON AN ERROR. + LD A,(CDRIVE) ; RE-SELECT PREVIOUS DRIVE IF NEED BE. + OR A + CALL NZ,DSKSEL ; DON'T DO NEEDLESS SELECTS. +; +; PRINT LINE JUST READ ON CONSOLE. +; + LD HL,INBUFF+2 + CALL PLINE2 + CALL CHKCON ; CHECK CONSOLE, QUIT ON A KEY. + JP Z,GETINP2 ; JUMP IF NO KEY IS PRESSED. +; +; TERMINATE THE SUBMIT JOB ON ANY KEYBOARD INPUT. DELETE THIS +; FILE SUCH THAT IT IS NOT RE-STARTED AND JUMP TO NORMAL KEYBOARD +; INPUT SECTION. +; + CALL DELBATCH ; DELETE THE BATCH FILE. + JP CMMND1 ; AND RESTART COMMAND INPUT. +; +; GET HERE FOR NORMAL KEYBOARD INPUT. DELETE THE SUBMIT FILE +; INCASE THERE WAS ONE. +; +GETINP1:CALL DELBATCH ; DELETE FILE ($$$.SUB). + CALL SETCDRV ; RESET ACTIVE DISK. + LD C,10 ; GET LINE FROM CONSOLE DEVICE. + LD DE,INBUFF + CALL ENTRY + CALL MOVECD ; RESET CURRENT DRIVE (AGAIN). +; +; CONVERT INPUT LINE TO UPPER CASE. +; +GETINP2:LD HL,INBUFF+1 + LD B,(HL) ; (B)=CHARACTER COUNTER. +GETINP3:INC HL + LD A,B ; END OF THE LINE? + OR A + JP Z,GETINP4 + LD A,(HL) ; CONVERT TO UPPER CASE. + CALL UPPER + LD (HL),A + DEC B ; ADJUST CHARACTER COUNT. + JP GETINP3 +GETINP4:LD (HL),A ; ADD TRAILING NULL. + LD HL,INBUFF+2 + LD (INPOINT),HL ; RESET INPUT LINE POINTER. + RET +; +; ROUTINE TO CHECK THE CONSOLE FOR A KEY PRESSED. THE ZERO +; FLAG IS SET IS NONE, ELSE THE CHARACTER IS RETURNED IN (A). +; +CHKCON: LD C,11 ; CHECK CONSOLE. + CALL ENTRY + OR A + RET Z ; RETURN IF NOTHING. + LD C,1 ; ELSE GET CHARACTER. + CALL ENTRY + OR A ; CLEAR ZERO FLAG AND RETURN. + RET +; +; ROUTINE TO GET THE CURRENTLY ACTIVE DRIVE NUMBER. +; +GETDSK: LD C,25 + JP ENTRY +; +; SET THE STABDARD DMA ADDRESS. +; +STDDMA: LD DE,TBUFF +; +; ROUTINE TO SET THE DMA ADDRESS TO (DE). +; +DMASET: LD C,26 + JP ENTRY +; +; DELETE THE BATCH FILE CREATED BY SUBMIT. +; +DELBATCH: + LD HL,BATCH ; IS BATCH ACTIVE? + LD A,(HL) + OR A + RET Z + LD (HL),0 ; YES, DE-ACTIVATE IT. + XOR A + CALL DSKSEL ; SELECT DRIVE 0 FOR SURE. + LD DE,BATCHFCB ; AND DELETE THIS FILE. + CALL DELETE + LD A,(CDRIVE) ; RESET CURRENT DRIVE. + JP DSKSEL +; +; PRINT BACK FILE NAME WITH A '?' TO INDICATE A SYNTAX ERROR. +; +SYNERR: CALL CRLF ; END CURRENT LINE. + LD HL,(NAMEPNT) ; THIS POINTS TO NAME IN ERROR. +SYNERR1:LD A,(HL) ; PRINT IT UNTIL A SPACE OR NULL IS FOUND. + CP ' ' + JP Z,SYNERR2 + OR A + JP Z,SYNERR2 + PUSH HL + CALL PRINT + POP HL + INC HL + JP SYNERR1 +SYNERR2:LD A,'?' ; ADD TRAILING '?'. + CALL PRINT + CALL CRLF + CALL DELBATCH ; DELETE ANY BATCH FILE. + JP CMMND1 ; AND RESTART FROM CONSOLE INPUT. +; +; CHECK CHARACTER AT (DE) FOR LEGAL COMMAND INPUT. NOTE THAT THE +; ZERO FLAG IS SET IF THE CHARACTER IS A DELIMITER. +; +CHECK: LD A,(DE) + OR A + RET Z + CP ' ' ; CONTROL CHARACTERS ARE NOT LEGAL HERE. + JP C,SYNERR + RET Z ; CHECK FOR VALID DELIMITER. + CP '=' + RET Z + CP '_' + RET Z + CP '.' + RET Z + CP ':' + RET Z + CP $3B + RET Z + CP '<' + RET Z + CP '>' + RET Z + RET +; +; GET THE NEXT NON-BLANK CHARACTER FROM (DE). +; +NONBLANK: + LD A,(DE) + OR A ; STRING ENDS WITH A NULL. + RET Z + CP ' ' + RET NZ + INC DE + JP NONBLANK +; +; ADD (HL)=(HL)+(A) +; +ADDHL: ADD A,L + LD L,A + RET NC ; TAKE CARE OF ANY CARRY. + INC H + RET +; +; CONVERT THE FIRST NAME IN (FCB). +; +CONVFST:LD A,0 +; +; FORMAT A FILE NAME (CONVERT * TO '?', ETC.). ON RETURN, +; (A)=0 IS AN UNAMBIGEOUS NAME WAS SPECIFIED. ENTER WITH (A) .EQUAL TO +; THE POSITION WITHIN THE FCB FOR THE NAME (EITHER 0 OR 16). +; +CONVERT:LD HL,FCB + CALL ADDHL + PUSH HL + PUSH HL + XOR A + LD (CHGDRV),A ; INITIALIZE DRIVE CHANGE FLAG. + LD HL,(INPOINT) ; SET (HL) AS POINTER INTO INPUT LINE. + EX DE,HL + CALL NONBLANK ; GET NEXT NON-BLANK CHARACTER. + EX DE,HL + LD (NAMEPNT),HL ; SAVE POINTER HERE FOR ANY ERROR MESSAGE. + EX DE,HL + POP HL + LD A,(DE) ; GET FIRST CHARACTER. + OR A + JP Z,CONVRT1 + SBC A,'A'-1 ; MIGHT BE A DRIVE NAME, CONVERT TO BINARY. + LD B,A ; AND SAVE. + INC DE ; CHECK NEXT CHARACTER FOR A ':'. + LD A,(DE) + CP ':' + JP Z,CONVRT2 + DEC DE ; NOPE, MOVE POINTER BACK TO THE START OF THE LINE. +CONVRT1:LD A,(CDRIVE) + LD (HL),A + JP CONVRT3 +CONVRT2:LD A,B + LD (CHGDRV),A ; SET CHANGE IN DRIVES FLAG. + LD (HL),B + INC DE +; +; CONVERT THE BASIC FILE NAME. +; +CONVRT3:LD B,08H +CONVRT4:CALL CHECK + JP Z,CONVRT8 + INC HL + CP '*' ; NOTE THAT AN '*' WILL FILL THE REMAINING + JP NZ,CONVRT5 ; FIELD WITH '?'. + LD (HL),'?' + JP CONVRT6 +CONVRT5:LD (HL),A + INC DE +CONVRT6:DEC B + JP NZ,CONVRT4 +CONVRT7:CALL CHECK ; GET NEXT DELIMITER. + JP Z,GETEXT + INC DE + JP CONVRT7 +CONVRT8:INC HL ; BLANK FILL THE FILE NAME. + LD (HL),' ' + DEC B + JP NZ,CONVRT8 +; +; GET THE EXTENSION AND CONVERT IT. +; +GETEXT: LD B,03H + CP '.' + JP NZ,GETEXT5 + INC DE +GETEXT1:CALL CHECK + JP Z,GETEXT5 + INC HL + CP '*' + JP NZ,GETEXT2 + LD (HL),'?' + JP GETEXT3 +GETEXT2:LD (HL),A + INC DE +GETEXT3:DEC B + JP NZ,GETEXT1 +GETEXT4:CALL CHECK + JP Z,GETEXT6 + INC DE + JP GETEXT4 +GETEXT5:INC HL + LD (HL),' ' + DEC B + JP NZ,GETEXT5 +GETEXT6:LD B,3 +GETEXT7:INC HL + LD (HL),0 + DEC B + JP NZ,GETEXT7 + EX DE,HL + LD (INPOINT),HL ; SAVE INPUT LINE POINTER. + POP HL +; +; CHECK TO SEE IF THIS IS AN AMBIGEOUS FILE NAME SPECIFICATION. +; SET THE (A) REGISTER TO NON ZERO IF IT IS. +; + LD BC,11 ; SET NAME LENGTH. +GETEXT8:INC HL + LD A,(HL) + CP '?' ; ANY QUESTION MARKS? + JP NZ,GETEXT9 + INC B ; COUNT THEM. +GETEXT9:DEC C + JP NZ,GETEXT8 + LD A,B + OR A + RET +; +; CP/M COMMAND TABLE. NOTE COMMANDS CAN BE EITHER 3 OR 4 CHARACTERS LONG. +; + .IF MON +NUMCMDS:.EQU 7 ; NUMBER OF COMMANDS + .ELSE +NUMCMDS:.EQU 6 ; NUMBER OF COMMANDS + .ENDIF + +CMDTBL: .DB "DIR " + .DB "ERA " + .DB "TYPE" + .DB "SAVE" + .DB "REN " + .DB "USER" + .IF MON + .DB "MON " + .ENDIF + +CMDADR: .DW DIRECT + .DW ERASE + .DW TYPE + .DW SAVE + .DW RENAME + .DW USER + .IF MON + .DW MONITOR + .ENDIF + .DW UNKNOWN +; +; SEARCH THE COMMAND TABLE FOR A MATCH WITH WHAT HAS JUST +; BEEN ENTERED. IF A MATCH IS FOUND, THEN WE JUMP TO THE +; PROPER SECTION. ELSE JUMP TO (UNKNOWN). +; ON RETURN, THE (C) REGISTER IS SET TO THE COMMAND NUMBER +; THAT MATCHED (OR NUMCMDS+1 IF NO MATCH). +; +SEARCH: LD HL,CMDTBL + LD C,0 +SEARCH1:LD A,C + CP NUMCMDS ; THIS COMMANDS EXISTS. + RET NC + LD DE,FCB+1 ; CHECK THIS ONE. + LD B,4 ; MAX COMMAND LENGTH. +SEARCH2:LD A,(DE) + CP (HL) + JP NZ,SEARCH3 ; NOT A MATCH. + INC DE + INC HL + DEC B + JP NZ,SEARCH2 + LD A,(DE) ; ALLOW A 3 CHARACTER COMMAND TO MATCH. + CP ' ' + JP NZ,SEARCH4 + LD A,C ; SET RETURN REGISTER FOR THIS COMMAND. + RET +SEARCH3:INC HL + DEC B + JP NZ,SEARCH3 +SEARCH4:INC C + JP SEARCH1 +; +; SET THE INPUT BUFFER TO EMPTY AND THEN START THE COMMAND +; PROCESSOR (CCP). +; +CLEARBUF: + XOR A + LD (INBUFF+1),A ; SECOND BYTE IS ACTUAL LENGTH. +COMMAND:LD SP,CCPSTACK ; SETUP STACK AREA. + PUSH BC ; NOTE THAT (C) SHOULD BE .EQUAL TO: + LD A,C ; (UUUUDDDD) WHERE 'UUUU' IS THE USER NUMBER + RRA ; AND 'DDDD' IS THE DRIVE NUMBER. + RRA + RRA + RRA + AND 0FH ; ISOLATE THE USER NUMBER. + LD E,A + CALL GETSETUC ; AND SET IT. + CALL RESDSK ; RESET THE DISK SYSTEM. + LD (BATCH),A ; CLEAR BATCH MODE FLAG. + POP BC + LD A,C + AND 0FH ; ISOLATE THE DRIVE NUMBER. + LD (CDRIVE),A ; AND SAVE. + CALL DSKSEL ; ...AND SELECT. + LD A,(INBUFF+1) + OR A ; ANYTHING IN INPUT BUFFER ALREADY? + JP NZ,CMMND2 ; YES, WE JUST PROCESS IT. +; +; ENTRY POINT TO GET A COMMAND LINE FROM THE CONSOLE. +; +CMMND1: LD SP,CCPSTACK ; SET STACK STRAIGHT. + CALL CRLF ; START A NEW LINE ON THE SCREEN. + CALL GETDSK ; GET CURRENT DRIVE. + ADD A,'A' + CALL PRINT ; PRINT CURRENT DRIVE. + .IF USRDSP + CALL GETUSR ;GET CURRENT USER NUMBER + CP 10 ;TWO DIGITS? + JR C,CMMND3 ;NO + LD A,'1' ;PRINT LEADING '1' + CALL PRINT + CALL GETUSR ;GET CURRENT USER NUMBER + SUB 10 ;SUBTRACT 10 +CMMND3: ADD A,'0' + CALL PRINT + .ENDIF + LD A,'>' + CALL PRINT ; AND ADD PROMPT. + CALL GETINP ; GET LINE FROM USER. +; +; PROCESS COMMAND LINE HERE. +; +CMMND2: LD DE,TBUFF + CALL DMASET ; SET STANDARD DMA ADDRESS. + CALL GETDSK + LD (CDRIVE),A ; SET CURRENT DRIVE. + CALL CONVFST ; CONVERT NAME TYPED IN. + CALL NZ,SYNERR ; WILD CARDS ARE NOT ALLOWED. + LD A,(CHGDRV) ; IF A CHANGE IN DRIVES WAS INDICATED, + OR A ; THEN TREAT THIS AS AN UNKNOWN COMMAND + JP NZ,UNKNOWN ; WHICH GETS EXECUTED. + CALL SEARCH ; ELSE SEARCH COMMAND TABLE FOR A MATCH. +; +; NOTE THAT AN UNKNOWN COMMAND RETURNS +; WITH (A) POINTING TO THE LAST ADDRESS +; IN OUR TABLE WHICH IS (UNKNOWN). +; + LD HL,CMDADR ; NOW, LOOK THRU OUR ADDRESS TABLE FOR COMMAND (A). + LD E,A ; SET (DE) TO COMMAND NUMBER. + LD D,0 + ADD HL,DE + ADD HL,DE ; (HL)=(CMDADR)+2*(COMMAND NUMBER). + LD A,(HL) ; NOW PICK OUT THIS ADDRESS. + INC HL + LD H,(HL) + LD L,A + JP (HL) ; NOW EXECUTE IT. +; +; READ ERROR WHILE TYPEING A FILE. +; +RDERROR:LD BC,RDERR + JP PLINE +RDERR: .DB "Read Error",0 +; +; REQUIRED FILE WAS NOT LOCATED. +; +NONE: LD BC,NOFILE + JP PLINE +NOFILE: .DB "No File",0 +; +; DECODE A COMMAND OF THE FORM 'A>FILENAME NUMBER{ FILENAME}. +; NOTE THAT A DRIVE SPECIFIER IS NOT ALLOWED ON THE FIRST FILE +; NAME. ON RETURN, THE NUMBER IS IN REGISTER (A). ANY ERROR +; CAUSES 'FILENAME?' TO BE PRINTED AND THE COMMAND IS ABORTED. +; +DECODE: CALL CONVFST ; CONVERT FILENAME. + LD A,(CHGDRV) ; DO NOT ALLOW A DRIVE TO BE SPECIFIED. + OR A + JP NZ,SYNERR + LD HL,FCB+1 ; CONVERT NUMBER NOW. + LD BC,11 ; (B)=SUM REGISTER, (C)=MAX DIGIT COUNT. +DECODE1:LD A,(HL) + CP ' ' ; A SPACE TERMINATES THE NUMERAL. + JP Z,DECODE3 + INC HL + SUB '0' ; MAKE BINARY FROM ASCII. + CP 10 ; LEGAL DIGIT? + JP NC,SYNERR + LD D,A ; YES, SAVE IT IN (D). + LD A,B ; COMPUTE (B)=(B)*10 AND CHECK FOR OVERFLOW. + AND 0E0H + JP NZ,SYNERR + LD A,B + RLCA + RLCA + RLCA ; (A)=(B)*8 + ADD A,B ; .......*9 + JP C,SYNERR + ADD A,B ; .......*10 + JP C,SYNERR + ADD A,D ; ADD IN NEW DIGIT NOW. +DECODE2:JP C,SYNERR + LD B,A ; AND SAVE RESULT. + DEC C ; ONLY LOOK AT 11 DIGITS. + JP NZ,DECODE1 + RET +DECODE3:LD A,(HL) ; SPACES MUST FOLLOW (WHY?). + CP ' ' + JP NZ,SYNERR + INC HL +DECODE4:DEC C + JP NZ,DECODE3 + LD A,B ; SET (A)=THE NUMERIC VALUE ENTERED. + RET +; +; MOVE 3 BYTES FROM (HL) TO (DE). NOTE THAT THERE IS ONLY +; ONE REFERENCE TO THIS AT (A2D5H). +; +MOVE3: LD B,3 +; +; MOVE (B) BYTES FROM (HL) TO (DE). +; +HL2DE: LD A,(HL) + LD (DE),A + INC HL + INC DE + DEC B + JP NZ,HL2DE + RET +; +; COMPUTE (HL)=(TBUFF)+(A)+(C) AND GET THE BYTE THAT'S HERE. +; +EXTRACT:LD HL,TBUFF + ADD A,C + CALL ADDHL + LD A,(HL) + RET +; +; CHECK DRIVE SPECIFIED. IF IT MEANS A CHANGE, THEN THE NEW +; DRIVE WILL BE SELECTED. IN ANY CASE, THE DRIVE BYTE OF THE +; FCB WILL BE SET TO NULL (MEANS USE CURRENT DRIVE). +; +DSELECT:XOR A ; NULL OUT FIRST BYTE OF FCB. + LD (FCB),A + LD A,(CHGDRV) ; A DRIVE CHANGE INDICATED? + OR A + RET Z + DEC A ; YES, IS IT THE SAME AS THE CURRENT DRIVE? + LD HL,CDRIVE + CP (HL) + RET Z + JP DSKSEL ; NO. SELECT IT THEN. +; +; CHECK THE DRIVE SELECTION AND RESET IT TO THE PREVIOUS +; DRIVE IF IT WAS CHANGED FOR THE PRECEEDING COMMAND. +; +RESETDR:LD A,(CHGDRV) ; DRIVE CHANGE INDICATED? + OR A + RET Z + DEC A ; YES, WAS IT A DIFFERENT DRIVE? + LD HL,CDRIVE + CP (HL) + RET Z + LD A,(CDRIVE) ; YES, RE-SELECT OUR OLD DRIVE. + JP DSKSEL + +; +;************************************************************** +;* +;* M O N I T O R C O M M A N D +;* +;************************************************************** +; + .IF MON +MONITOR:RST 38 + .ENDIF + +; +;************************************************************** +;* +;* D I R E C T O R Y C O M M A N D +;* +;************************************************************** +; +DIRECT: CALL CONVFST ; CONVERT FILE NAME. + CALL DSELECT ; SELECT INDICATED DRIVE. + LD HL,FCB+1 ; WAS ANY FILE INDICATED? + LD A,(HL) + CP ' ' + JP NZ,DIRECT2 + LD B,11 ; NO. FILL FIELD WITH '?' - SAME AS *.*. +DIRECT1:LD (HL),'?' + INC HL + DEC B + JP NZ,DIRECT1 +DIRECT2:LD E,0 ; SET INITIAL CURSOR POSITION. + PUSH DE + CALL SRCHFCB ; GET FIRST FILE NAME. + CALL Z,NONE ; NONE FOUND AT ALL? +DIRECT3:JP Z,DIRECT9 ; TERMINATE IF NO MORE NAMES. + LD A,(RTNCODE) ; GET FILE'S POSITION IN SEGMENT (0-3). + RRCA + RRCA + RRCA + AND 60H ; (A)=POSITION*32 + LD C,A + LD A,10 + CALL EXTRACT ; EXTRACT THE TENTH ENTRY IN FCB. + RLA ; CHECK SYSTEM FILE STATUS BIT. + JP C,DIRECT8 ; WE DON'T LIST THEM. + POP DE + LD A,E ; BUMP NAME COUNT. + INC E + PUSH DE + AND 03H ; AT END OF LINE? + PUSH AF + JP NZ,DIRECT4 + CALL CRLF ; YES, END THIS LINE AND START ANOTHER. + PUSH BC + CALL GETDSK ; START LINE WITH ('A:'). + POP BC + ADD A,'A' + CALL PRINTB + LD A,':' + CALL PRINTB + JP DIRECT5 +DIRECT4:CALL SPACE ; ADD SEPERATOR BETWEEN FILE NAMES. + LD A,':' + CALL PRINTB +DIRECT5:CALL SPACE + LD B,1 ; 'EXTRACT' EACH FILE NAME CHARACTER AT A TIME. +DIRECT6:LD A,B + CALL EXTRACT + AND 7FH ; STRIP BIT 7 (STATUS BIT). + CP ' ' ; ARE WE AT THE END OF THE NAME? + JP NZ,DRECT65 + POP AF ; YES, DON'T PRINT SPACES AT THE END OF A LINE. + PUSH AF + CP 3 + JP NZ,DRECT63 + LD A,9 ; FIRST CHECK FOR NO EXTENSION. + CALL EXTRACT + AND 7FH + CP ' ' + JP Z,DIRECT7 ; DON'T PRINT SPACES. +DRECT63:LD A,' ' ; ELSE PRINT THEM. +DRECT65:CALL PRINTB + INC B ; BUMP TO NEXT CHARACTER PSOITION. + LD A,B + CP 12 ; END OF THE NAME? + JP NC,DIRECT7 + CP 9 ; NOPE, STARTING EXTENSION? + JP NZ,DIRECT6 + CALL SPACE ; YES, ADD SEPERATING SPACE. + JP DIRECT6 +DIRECT7:POP AF ; GET THE NEXT FILE NAME. +DIRECT8:CALL CHKCON ; FIRST CHECK CONSOLE, QUIT ON ANYTHING. + JP NZ,DIRECT9 + CALL SRCHNXT ; GET NEXT NAME. + JP DIRECT3 ; AND CONTINUE WITH OUR LIST. +DIRECT9:POP DE ; RESTORE THE STACK AND RETURN TO COMMAND LEVEL. + JP GETBACK +; +;************************************************************** +;* +;* E R A S E C O M M A N D +;* +;************************************************************** +; +ERASE: CALL CONVFST ; CONVERT FILE NAME. + CP 11 ; WAS '*.*' ENTERED? + JP NZ,ERASE1 + LD BC,YESNO ; YES, ASK FOR CONFIRMATION. + CALL PLINE + CALL GETINP + LD HL,INBUFF+1 + DEC (HL) ; MUST BE EXACTLY 'Y'. + JP NZ,CMMND1 + INC HL + LD A,(HL) + CP 'Y' + JP NZ,CMMND1 + INC HL + LD (INPOINT),HL ; SAVE INPUT LINE POINTER. +ERASE1: CALL DSELECT ; SELECT DESIRED DISK. + LD DE,FCB + CALL DELETE ; DELETE THE FILE. + INC A + CALL Z,NONE ; NOT THERE? + JP GETBACK ; RETURN TO COMMAND LEVEL NOW. +YESNO: .DB "All (Y/N)?",0 +; +;************************************************************** +;* +;* T Y P E C O M M A N D +;* +;************************************************************** +; +TYPE: CALL CONVFST ; CONVERT FILE NAME. + JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + CALL DSELECT ; SELECT INDICATED DRIVE. + CALL OPENFCB ; OPEN THE FILE. + JP Z,TYPE5 ; NOT THERE? + CALL CRLF ; OK, START A NEW LINE ON THE SCREEN. + LD HL,NBYTES ; INITIALIZE BYTE COUNTER. + LD (HL),0FFH ; SET TO READ FIRST SECTOR. +TYPE1: LD HL,NBYTES +TYPE2: LD A,(HL) ; HAVE WE WRITTEN THE ENTIRE SECTOR? + CP 128 + JP C,TYPE3 + PUSH HL ; YES, READ IN THE NEXT ONE. + CALL READFCB + POP HL + JP NZ,TYPE4 ; END OR ERROR? + XOR A ; OK, CLEAR BYTE COUNTER. + LD (HL),A +TYPE3: INC (HL) ; COUNT THIS BYTE. + LD HL,TBUFF ; AND GET THE (A)TH ONE FROM THE BUFFER (TBUFF). + CALL ADDHL + LD A,(HL) + CP CNTRLZ ; END OF FILE MARK? + JP Z,GETBACK + CALL PRINT ; NO, PRINT IT. + CALL CHKCON ; CHECK CONSOLE, QUIT IF ANYTHING READY. + JP NZ,GETBACK + JP TYPE1 +; +; GET HERE ON AN END OF FILE OR READ ERROR. +; +TYPE4: DEC A ; READ ERROR? + JP Z,GETBACK + CALL RDERROR ; YES, PRINT MESSAGE. +TYPE5: CALL RESETDR ; AND RESET PROPER DRIVE + JP SYNERR ; NOW PRINT FILE NAME WITH PROBLEM. +; +;************************************************************** +;* +;* S A V E C O M M A N D +;* +;************************************************************** +; +SAVE: CALL DECODE ; GET NUMERIC NUMBER THAT FOLLOWS SAVE. + PUSH AF ; SAVE NUMBER OF PAGES TO WRITE. + CALL CONVFST ; CONVERT FILE NAME. + JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + CALL DSELECT ; SELECT SPECIFIED DRIVE. + LD DE,FCB ; NOW DELETE THIS FILE. + PUSH DE + CALL DELETE + POP DE + CALL CREATE ; AND CREATE IT AGAIN. + JP Z,SAVE3 ; CAN'T CREATE? + XOR A ; CLEAR RECORD NUMBER BYTE. + LD (FCB+32),A + POP AF ; CONVERT PAGES TO SECTORS. + LD L,A + LD H,0 + ADD HL,HL ; (HL)=NUMBER OF SECTORS TO WRITE. + LD DE,TBASE ; AND WE START FROM HERE. +SAVE1: LD A,H ; DONE YET? + OR L + JP Z,SAVE2 + DEC HL ; NOPE, COUNT THIS AND COMPUTE THE START + PUSH HL ; OF THE NEXT 128 BYTE SECTOR. + LD HL,128 + ADD HL,DE + PUSH HL ; SAVE IT AND SET THE TRANSFER ADDRESS. + CALL DMASET + LD DE,FCB ; WRITE OUT THIS SECTOR NOW. + CALL WRTREC + POP DE ; RESET (DE) TO THE START OF THE LAST SECTOR. + POP HL ; RESTORE SECTOR COUNT. + JP NZ,SAVE3 ; WRITE ERROR? + JP SAVE1 +; +; GET HERE AFTER WRITING ALL OF THE FILE. +; +SAVE2: LD DE,FCB ; NOW CLOSE THE FILE. + CALL CLOSE + INC A ; DID IT CLOSE OK? + JP NZ,SAVE4 +; +; PRINT OUT ERROR MESSAGE (NO SPACE). +; +SAVE3: LD BC,NOSPACE + CALL PLINE +SAVE4: CALL STDDMA ; RESET THE STANDARD DMA ADDRESS. + JP GETBACK +NOSPACE:.DB "No Space",0 +; +;************************************************************** +;* +;* R E N A M E C O M M A N D +;* +;************************************************************** +; +RENAME: CALL CONVFST ; CONVERT FIRST FILE NAME. + JP NZ,SYNERR ; WILD CARDS NOT ALLOWED. + LD A,(CHGDRV) ; REMEMBER ANY CHANGE IN DRIVES SPECIFIED. + PUSH AF + CALL DSELECT ; AND SELECT THIS DRIVE. + CALL SRCHFCB ; IS THIS FILE PRESENT? + JP NZ,RENAME6 ; YES, PRINT ERROR MESSAGE. + LD HL,FCB ; YES, MOVE THIS NAME INTO SECOND SLOT. + LD DE,FCB+16 + LD B,16 + CALL HL2DE + LD HL,(INPOINT) ; GET INPUT POINTER. + EX DE,HL + CALL NONBLANK ; GET NEXT NON BLANK CHARACTER. + CP '=' ; ONLY ALLOW AN '=' OR '_' SEPERATOR. + JP Z,RENAME1 + CP '_' + JP NZ,RENAME5 +RENAME1:EX DE,HL + INC HL ; OK, SKIP SEPERATOR. + LD (INPOINT),HL ; SAVE INPUT LINE POINTER. + CALL CONVFST ; CONVERT THIS SECOND FILE NAME NOW. + JP NZ,RENAME5 ; AGAIN, NO WILD CARDS. + POP AF ; IF A DRIVE WAS SPECIFIED, THEN IT + LD B,A ; MUST BE THE SAME AS BEFORE. + LD HL,CHGDRV + LD A,(HL) + OR A + JP Z,RENAME2 + CP B + LD (HL),B + JP NZ,RENAME5 ; THEY WERE DIFFERENT, ERROR. +RENAME2:LD (HL),B ; RESET AS PER THE FIRST FILE SPECIFICATION. + XOR A + LD (FCB),A ; CLEAR THE DRIVE BYTE OF THE FCB. +RENAME3:CALL SRCHFCB ; AND GO LOOK FOR SECOND FILE. + JP Z,RENAME4 ; DOESN'T EXIST? + LD DE,FCB + CALL RENAM ; OK, RENAME THE FILE. + JP GETBACK +; +; PROCESS RENAME ERRORS HERE. +; +RENAME4:CALL NONE ; FILE NOT THERE. + JP GETBACK +RENAME5:CALL RESETDR ; BAD COMMAND FORMAT. + JP SYNERR +RENAME6:LD BC,EXISTS ; DESTINATION FILE ALREADY EXISTS. + CALL PLINE + JP GETBACK +EXISTS: .DB "File Exists",0 +; +;************************************************************** +;* +;* U S E R C O M M A N D +;* +;************************************************************** +; +USER: CALL DECODE ; GET NUMERIC VALUE FOLLOWING COMMAND. + CP 16 ; LEGAL USER NUMBER? + JP NC,SYNERR + LD E,A ; YES BUT IS THERE ANYTHING ELSE? + LD A,(FCB+1) + CP ' ' + JP Z,SYNERR ; YES, THAT IS NOT ALLOWED. + CALL GETSETUC ; OK, SET USER CODE. + JP GETBACK1 +; +;************************************************************** +;* +;* T R A N S I A N T P R O G R A M C O M M A N D +;* +;************************************************************** +; +UNKNOWN:LD A,(FCB+1) ; ANYTHING TO EXECUTE? + CP ' ' + JP NZ,UNKWN1 + LD A,(CHGDRV) ; NOPE, ONLY A DRIVE CHANGE? + OR A + JP Z,GETBACK1 ; NEITHER??? + DEC A + LD (CDRIVE),A ; OK, STORE NEW DRIVE. + CALL MOVECD ; SET (TDRIVE) ALSO. + CALL DSKSEL ; AND SELECT THIS DRIVE. + JP GETBACK1 ; THEN RETURN. +; +; HERE A FILE NAME WAS TYPED. PREPARE TO EXECUTE IT. +; +UNKWN1: LD DE,FCB+9 ; AN EXTENSION SPECIFIED? + LD A,(DE) + CP ' ' + JP NZ,SYNERR ; YES, NOT ALLOWED. +UNKWN2: PUSH DE + CALL DSELECT ; SELECT SPECIFIED DRIVE. + POP DE + LD HL,COMFILE ; SET THE EXTENSION TO 'COM'. LD HL,COMFILE + CALL MOVE3 ; MOVE 3 BYTES FROM (HL) TO (DE) TO ADD .COM + CALL OPENFCB ; AND OPEN THIS FILE. + .IF CHKU0B + JP NZ,UNKWNA ; GOT IT + LD E,0 ; TRY USER 0, THIS DRIVE + CALL GETSETUC ; OK, SET USER CODE. + CALL OPENFCB + JP NZ,UNKWNA ; GOT IT + LD HL,FCB ; SEE IF ON DRIVE B, USER 0 + LD (HL),2 + CALL OPENFCB + .ENDIF + JP Z,UNKWN9 ; NOPE +; +; LOAD IN THE PROGRAM. +; +UNKWNA: LD HL,TBASE ; STORE THE PROGRAM STARTING HERE. +UNKWN3: PUSH HL + EX DE,HL + CALL DMASET ; SET TRANSFER ADDRESS. + LD DE,FCB ; AND READ THE NEXT RECORD. + CALL RDREC + JP NZ,UNKWN4 ; END OF FILE OR READ ERROR? + POP HL ; NOPE, BUMP POINTER FOR NEXT SECTOR. + LD DE,128 + ADD HL,DE + LD DE,CBASE ; ENOUGH ROOM FOR THE WHOLE FILE? + LD A,L + SUB E + LD A,H + SBC A,D + JP NC,UNKWN0 ; NO, IT CAN'T FIT. + JP UNKWN3 +; +; GET HERE AFTER FINISHED READING. +; +UNKWN4: POP HL + DEC A ; NORMAL END OF FILE? + JP NZ,UNKWN0 + CALL RESETDR ; YES, RESET PREVIOUS DRIVE. + CALL CONVFST ; CONVERT THE FIRST FILE NAME THAT FOLLOWS + LD HL,CHGDRV ; COMMAND NAME. + PUSH HL + LD A,(HL) ; SET DRIVE CODE IN DEFAULT FCB. + LD (FCB),A + LD A,16 ; PUT SECOND NAME 16 BYTES LATER. + CALL CONVERT ; CONVERT SECOND FILE NAME. + POP HL + LD A,(HL) ; AND SET THE DRIVE FOR THIS SECOND FILE. + LD (FCB+16),A + XOR A ; CLEAR RECORD BYTE IN FCB. + LD (FCB+32),A + LD DE,TFCB ; MOVE IT INTO PLACE AT(005CH). + LD HL,FCB + LD B,33 + CALL HL2DE + LD HL,INBUFF+2 ; NOW MOVE THE REMAINDER OF THE INPUT +UNKWN5: LD A,(HL) ; LINE DOWN TO (0080H). LOOK FOR A NON BLANK. + OR A ; OR A NULL. + JP Z,UNKWN6 + CP ' ' + JP Z,UNKWN6 + INC HL + JP UNKWN5 +; +; DO THE LINE MOVE NOW. IT ENDS IN A NULL BYTE. +; +UNKWN6: LD B,0 ; KEEP A CHARACTER COUNT. + LD DE,TBUFF+1 ; DATA GETS PUT HERE. +UNKWN7: LD A,(HL) ; MOVE IT NOW. + LD (DE),A + OR A + JP Z,UNKWN8 + INC B + INC HL + INC DE + JP UNKWN7 +UNKWN8: LD A,B ; NOW STORE THE CHARACTER COUNT. + LD (TBUFF),A + CALL CRLF ; CLEAN UP THE SCREEN. + CALL STDDMA ; SET STANDARD TRANSFER ADDRESS. + CALL SETCDRV ; RESET CURRENT DRIVE. + CALL TBASE ; AND EXECUTE THE PROGRAM. +; +; TRANSIANT PROGRAMS RETURN HERE (OR REBOOT). +; + LD SP,BATCH ; SET STACK FIRST OFF. + CALL MOVECD ; MOVE CURRENT DRIVE INTO PLACE (TDRIVE). + CALL DSKSEL ; AND RESELECT IT. + JP CMMND1 ; BACK TO COMAND MODE. +; +; GET HERE IF SOME ERROR OCCURED. +; +UNKWN9: CALL RESETDR ; INPROPER FORMAT. + JP SYNERR +UNKWN0: LD BC,BADLOAD ; READ ERROR OR WON'T FIT. + CALL PLINE + JP GETBACK +BADLOAD:.DB "Bad Load",0 +COMFILE:.DB "COM" ; COMMAND FILE EXTENSION. +; +; GET HERE TO RETURN TO COMMAND LEVEL. WE WILL RESET THE +; PREVIOUS ACTIVE DRIVE AND THEN EITHER RETURN TO COMMAND +; LEVEL DIRECTLY OR PRINT ERROR MESSAGE AND THEN RETURN. +; +GETBACK:CALL RESETDR ; RESET PREVIOUS DRIVE. +GETBACK1: + CALL CONVFST ; CONVERT FIRST NAME IN (FCB). + LD A,(FCB+1) ; IF THIS WAS JUST A DRIVE CHANGE REQUEST, + SUB ' ' ; MAKE SURE IT WAS VALID. + LD HL,CHGDRV + OR (HL) + JP NZ,SYNERR + JP CMMND1 ; OK, RETURN TO COMMAND LEVEL. +; +; CCP STACK AREA. +; + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +CCPSTACK: .EQU $ ;END OF CCP STACK AREA. + +; +; BATCH (OR SUBMIT) PROCESSING INFORMATION STORAGE. +; +BATCH: .DB 0 ; BATCH MODE FLAG (0=NOT ACTIVE). +BATCHFCB:.DB 0,"$$$ SUB" + .DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +; +; FILE CONTROL BLOCK SETUP BY THE CCP. +; +FCB: .DB 0," ",0,0,0,0,0 + .DB " ",0,0,0,0,0 +RTNCODE:.DB 0 ; STATUS RETURNED FROM BDOS CALL. +CDRIVE: .DB 0 ; CURRENTLY ACTIVE DRIVE. +CHGDRV: .DB 0 ; CHANGE IN DRIVES FLAG (0=NO CHANGE). +NBYTES: .DW 0 ; BYTE COUNTER USED BY TYPE. + + .IF ENDFIL + .FILL ((CCPO + 0800H) - $),055H + .ENDIF + + .END diff --git a/trunk/Source/cnfgdata.inc b/trunk/Source/cnfgdata.inc new file mode 100644 index 00000000..c6657b92 --- /dev/null +++ b/trunk/Source/cnfgdata.inc @@ -0,0 +1,202 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; cnfgdata.inc 6/02/2012 dwg - for 2.0 B8 ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; 6/04/2012 dwg - add BOOTLU per Wayne email ; +; 6/02/2012 dwg - change BOOTDISK to DEVUNIT ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; 5/10/2012 dwg - cleanup for 2.0 architecture ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; cnfgdata.inc 3/14/2012 dwg - for 2.0 X5 ; +; 3/14/2012 dwg - retire LDRCON & DBGCON ; +; cnfgdata.inc 3/04/2012 dwg - for 2.0.0.0 ; +; 3/04/2012 dwg - added ptrs VAR_LOC & TST_LOC ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + .DB RMJ,RMN,RUP,RTP ; config data version + +; Loader data +; +; This area is for notes left by the loader from when the ccp/bdos/bios were +; placed in memory and kicked off, this allows logging onto the boot drive on startup +; +DISKBOOT .DB FALSE ; FALSE if ROM BOOT, otherwise TRUE +BOOTDEVICE .DB 0 ; if not ROM boot, has DEV/UNIT of boot device +BOOTLU .DW 0 ; logical unit on dev/unit for boot + .DB 0,0,0, 0,0,0 ; system startup time to be filled in by loader (from rtc) + +;================================================================================================== +; CONFIGURATION +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; + +;CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS + .DB CPUFREQ + +;PLATFORM .EQU PLT_ZETA ; PLT_N8VEM, PLT_ZETA + .DB PLATFORM + +;DIOPLT .EQU DIOPLT_ZETA ; DIOPLT_NONE, DIOPLT_DISKIO, DIOPLT_ZETA, DIOPLT_DIDE, DIOPLT_N8, DIOPLT_DISKIO3 + .DB DIOPLT + +;VDUMODE .EQU VDUPLT_NONE ; VDUPLT_NONE, VDUPLT_VDUV1, VDUPLT_PROPIO, VDUPLT_N8, VDUPLT_V2 (ONLY V1 IMPLEMENTED!) + .DB VDUMODE + +;ROMSIZE .EQU 512 ; SIZE OF ROM IN KB, MUST MATCH YOUR HARDWARE!!! + .DW ROMSIZE + +;RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! + .DW RAMSIZE + +;CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) + .DB CLRRAMDISK + + +;DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) + .DB DSKYENABLE + +;UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) + .DB UARTENABLE + +;VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) + .DB VDUENABLE + + +;FDENABLE .EQU TRUE ; TRUE FOR FLOPPY SUPPORT + .DB FDENABLE + +;FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) + .DB FDTRACE + +;FDMEDIA .EQU FDM720 ; FDM720 OR FDM144 (ONLY RELEVANT IF FDENABLE = TRUE) + .DB FDMEDIA + +;FDMEDIAALT .EQU FDM144 ; ALTERNATIVE MEDIA TO TRY + .DB FDMEDIAALT + +;FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY + .DB FDMAUTO + + +;IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT + .DB IDEENABLE + +;IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) + .DB IDETRACE + +;IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) + .DB IDE8BIT + +;IDECAPACITY .EQU 64 ; SIZE OF DEVICE IN MEGABYTES + .DW IDECAPACITY + +;PPIDEENABLE .EQU TRUE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) + .DB PPIDEENABLE + +;PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) + .DB PPIDETRACE + +;PPIDE8BIT .EQU TRUE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) + .DB PPIDE8BIT + +;PPIDECAPACITY .EQU 64 + .DW PPIDECAPACITY ; SIZE OF DEVICE IN MEGABYTES + +; PPIDESLOW .EQU FALSE + .DB PPIDESLOW ; Add NOPs to PPIDE driver for recovery time + +;BOOTTYPE: .EQU BT_JP2 ; BT_UART, BT_DSKY, BT_JP2 + .DB BOOTTYPE + +;BOOT_TIMEOUT .EQU 10 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE + .DB BOOT_TIMEOUT + +;BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT + .DB BOOT_DEFAULT + +;BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 + .DW BAUDRATE + +#IF (PLATFORM == PLT_N8) +;Z180_CLKDIV .EQU 1 ; 0=XTAL/2, 1=XTAL/1 + .DB Z180_CLKDIV + +;Z180_MEMWAIT .EQU 0 ; MEMORY WAIT STATES TO INSERT (0-3) + .DB Z180_MEMWAIT + +;Z180_IOWAIT .EQU 3 ; IO WAIT STATES TO INSERT (0-3) + .DB Z180_IOWAIT + +;Z180_CNTLB0 .EQU 20H ; SERIAL PORT 0 DIV, SEE Z180 CLOCKING DOCUMENT + .DB Z180_CNTLB0 + +;Z180_CNTLB1 .EQU 20H ; SERIAL PORT 1 DIV, SEE Z180 CLOCKING DOCUMENT + .DB Z180_CNTLB1 + + .DB SDENABLE ; SD support boolean + .DB SDTRACE ; SD trace type + +;SDCAPACITY .EQU 64 ; DEVICE SIZE IN MEGABYTES + .DW SDCAPACITY + + .DB SDCSIO ; USE CSI/O PORT (boolean) + .DB SDCSIOFAST ; USE FAST CSI/O ALGORITHM (boolean) +#ELSE + .DB 0E5h ; placeholder for Z180_CLKDIV + .DB 0E5h ; placeholder for Z180_MEMWAIT + .DB 0E5h ; placeholder for Z180_IOWAIT + .DB 0E5h ; placeholder for Z180_CNTLB0 + .DB 0E5h ; placeholder for Z180_CNTLB1 + .DB 0e5h ; placeholder for SDENABLE + .DB 0e5h ; placeholder for SDTARCE + .DW 0e5e5h ; placeholder for SDCAPACITY + .DB 0e5h ; placeholder for SDCSIO + .DB 0e5h ; placeholder for SDCSIOFAST +#ENDIF + +; DEFIOBYTE .EQU $00 ; INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE); + .DB DEFIOBYTE + +; TERMTYPE .EQU TERM_TTY + .DB TERMTYPE + +; REVISION .EQU 500 ; approximate svn revision of source tree + .DW REVISION + +#IF (PRPSDENABLE) + .DB PRPSDENABLE + .DB PRPSDTRACE + .DW PRPSDCAPACITY + .DB PRPCONENABLE +#ELSE + .DB 0E5h ; placeholder for PRPSDENABLE + .DB 0E5h ; placeholder for PRPSDTARCE + .DW 0E5E5h ; placeholder for PRPSDCAPACITY + .DB 0E5h ; placeholder for PRPCONENABLE +#ENDIF + +; DATASIZE .EQU 0700h ; + .DW BIOSSIZE + +;PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT + .DB PPPENABLE + +;PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) + .DB PPPSDENABLE + +;PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) + .DB PPPSDTRACE + +;PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) + .DW PPPSDCAPACITY + +;PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) + .DB PPPCONENABLE + +; PRPENABLE .EQU FALSE + .DB PRPENABLE + +;;;;;;;;;;;;;;;;;;;;;; +; eof - cnfgdata.inc ; +;;;;;;;;;;;;;;;;;;;;;; diff --git a/trunk/Source/config_n8_2312.asm b/trunk/Source/config_n8_2312.asm new file mode 100644 index 00000000..07140955 --- /dev/null +++ b/trunk/Source/config_n8_2312.asm @@ -0,0 +1,92 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 20 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8 ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU TRUE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_N8 ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU TRUE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU TRUE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 +; +Z180_CLKDIV .EQU 1 ; 0=XTAL/2, 1=XTAL/1 +Z180_MEMWAIT .EQU 0 ; MEMORY WAIT STATES TO INSERT (0-3) +Z180_IOWAIT .EQU 3 ; IO WAIT STATES TO INSERT (0-3) +Z180_CNTLB0 .EQU 20H ; SERIAL PORT 0 DIV, SEE Z180 CLOCKING DOCUMENT +Z180_CNTLB1 .EQU 20H ; SERIAL PORT 1 DIV, SEE Z180 CLOCKING DOCUMENT diff --git a/trunk/Source/config_n8_2511.asm b/trunk/Source/config_n8_2511.asm new file mode 100644 index 00000000..26f909b5 --- /dev/null +++ b/trunk/Source/config_n8_2511.asm @@ -0,0 +1,92 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 20 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8 ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU TRUE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_N8 ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU TRUE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 +; +Z180_CLKDIV .EQU 1 ; 0=XTAL/2, 1=XTAL/1 +Z180_MEMWAIT .EQU 0 ; MEMORY WAIT STATES TO INSERT (0-3) +Z180_IOWAIT .EQU 3 ; IO WAIT STATES TO INSERT (0-3) +Z180_CNTLB0 .EQU 20H ; SERIAL PORT 0 DIV, SEE Z180 CLOCKING DOCUMENT +Z180_CNTLB1 .EQU 20H ; SERIAL PORT 1 DIV, SEE Z180 CLOCKING DOCUMENT diff --git a/trunk/Source/config_n8vem.asm b/trunk/Source/config_n8vem.asm new file mode 100644 index 00000000..e97bafc7 --- /dev/null +++ b/trunk/Source/config_n8vem.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8VEM SBC 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU FALSE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_n8vem_dide.asm b/trunk/Source/config_n8vem_dide.asm new file mode 100644 index 00000000..1e7d50d4 --- /dev/null +++ b/trunk/Source/config_n8vem_dide.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8VEM SBC 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU TRUE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIDE ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU TRUE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIDE ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_n8vem_diskio.asm b/trunk/Source/config_n8vem_diskio.asm new file mode 100644 index 00000000..ef7ecf3b --- /dev/null +++ b/trunk/Source/config_n8vem_diskio.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8VEM SBC 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU TRUE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU TRUE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_n8vem_diskio3.asm b/trunk/Source/config_n8vem_diskio3.asm new file mode 100644 index 00000000..f56e1e98 --- /dev/null +++ b/trunk/Source/config_n8vem_diskio3.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8VEM SBC W/ DISKIO V3 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU TRUE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO3 ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU TRUE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_DIO3 ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_n8vem_ppide.asm b/trunk/Source/config_n8vem_ppide.asm new file mode 100644 index 00000000..0b446223 --- /dev/null +++ b/trunk/Source/config_n8vem_ppide.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8VEM SBC W/ PPIDE 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU FALSE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU TRUE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_n8vem_ppisd.asm b/trunk/Source/config_n8vem_ppisd.asm new file mode 100644 index 00000000..4dff875f --- /dev/null +++ b/trunk/Source/config_n8vem_ppisd.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8VEM SBC 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU FALSE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU TRUE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU TRUE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_n8vem_propio.asm b/trunk/Source/config_n8vem_propio.asm new file mode 100644 index 00000000..be2262e0 --- /dev/null +++ b/trunk/Source/config_n8vem_propio.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8VEM SBC 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_PRPCON ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU CIODEV_UART ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $01 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU $00 ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU FALSE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_n8vem_vdu.asm b/trunk/Source/config_n8vem_vdu.asm new file mode 100644 index 00000000..5f1bb97a --- /dev/null +++ b/trunk/Source/config_n8vem_vdu.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR N8VEM SBC W/ VDU 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU TRUE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU FALSE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_simh.asm b/trunk/Source/config_simh.asm new file mode 100644 index 00000000..ff1ccfe0 --- /dev/null +++ b/trunk/Source/config_simh.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR SIMH EMULATOR 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 8 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_N8VEM ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_ALWAYS ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU FALSE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU FALSE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_DIO ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU TRUE ; TRUE FOR HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_zeta.asm b/trunk/Source/config_zeta.asm new file mode 100644 index 00000000..c1af54d8 --- /dev/null +++ b/trunk/Source/config_zeta.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR ZETA 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 20 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_ZETA ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_UART ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU DEFCON ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $00 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU DEFIOBYTE ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU TRUE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_ZETA ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU TRUE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU TRUE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU FALSE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/config_zeta_ppp.asm b/trunk/Source/config_zeta_ppp.asm new file mode 100644 index 00000000..f782a170 --- /dev/null +++ b/trunk/Source/config_zeta_ppp.asm @@ -0,0 +1,86 @@ +; +;================================================================================================== +; ROMWBW 2.X CONFIGURATION FOR ZETA W/ PPP 5/8/2012 +;================================================================================================== +; +; BUILD CONFIGURATION OPTIONS +; +CPUFREQ .EQU 20 ; IN MHZ, USED TO COMPUTE DELAY FACTORS +; +PLATFORM .EQU PLT_ZETA ; PLT_N8VEM, PLT_ZETA, PLT_N8 +; +DIOPLT .EQU 0 ; DEPRECATED +; +DEFCON .EQU CIODEV_PPPCON ; DEFAULT CONSOLE DEVICE (LOADER AND MONITOR): CIODEV_UART, CIODEV_VDU, DIODEV_PRPCON +ALTCON .EQU CIODEV_UART ; ALT CONSOLE DEVICE (USED WHEN CONFIG JUMPER SHORTED) +; +RAMSIZE .EQU 512 ; SIZE OF RAM IN KB, MUST MATCH YOUR HARDWARE!!! +CLRRAMDISK .EQU CLR_AUTO ; CLR_ALWAYS, CLR_NEVER, CLR_AUTO (CLEAR IF INVALID DIR AREA) +; +DSKMAP .EQU DM_RAM ; DM_ROM, DM_RAM, DM_FD, DM_IDE, DM_PPIDE, DM_SD, DM_PRPSD, DM_PPPSD +; +DSKYENABLE .EQU FALSE ; TRUE FOR DSKY SUPPORT (DO NOT COMBINE WITH PPIDE) +; +UARTENABLE .EQU TRUE ; TRUE FOR UART SUPPORT (ALMOST ALWAYS WANT THIS TO BE TRUE) +UARTFIFO .EQU TRUE ; TRUE ENABLES UART FIFO (16550 ASSUMED, N8VEM AND ZETA ONLY) +UARTAFC .EQU FALSE ; TRUE ENABLES AUTO FLOW CONTROL (YOUR TERMINAL/UART MUST SUPPORT RTS/CTS FLOW CONTROL!!!) +; +VDUENABLE .EQU FALSE ; TRUE FOR VDU SERVICES (YOU MUST HAVE THE HARDWARE!) +VDUMODE .EQU VDUMODE_VDU ; VDUMODE_NONE, VDUMODE_VDU, VDUMODE_N8, VDUMODE_CVDU (ONLY VDUPLT_VDU IMPLEMENTED!) +; +BIOSSIZE .EQU 0100H ; AMOUNT OF SPACE WITHIN BIOS AREA TO RESERVE FOR DATA +; +DEFIOBYTE .EQU $01 ; DEFAULT INITIAL VALUE FOR CP/M IOBYTE, $00=TTY, $01=CRT (MUST HAVE CRT HARDWARE) +ALTIOBYTE .EQU $00 ; ALT INITIAL VALUE (USED WHEN CONFIG JUMPER SHORTED) +WRTCACHE .EQU TRUE ; ENABLE WRITE CACHING IN CBIOS (DE)BLOCKING ALGORITHM +DSKTRACE .EQU FALSE ; ENABLE TRACING OF CBIOS DISK FUNCTION CALLS +; +FDENABLE .EQU TRUE ; TRUE FOR FLOPPY SUPPORT +FDMODE .EQU FDMODE_ZETA ; FDMODE_DIO, FDMODE_ZETA, FDMODE_DIDE, FDMODE_N8, FDMODE_DIO3 +FDTRACE .EQU 1 ; 0=SILENT, 1=FATAL ERRORS, 2=ALL ERRORS, 3=EVERYTHING (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIA .EQU FDM144 ; FDM720, FDM144, FDM360, FDM120 (ONLY RELEVANT IF FDENABLE = TRUE) +FDMEDIAALT .EQU FDM720 ; ALTERNATE MEDIA TO TRY, SAME CHOICES AS ABOVE (ONLY RELEVANT IF FDMAUTO = TRUE) +FDMAUTO .EQU TRUE ; SELECT BETWEEN MEDIA OPTS ABOVE AUTOMATICALLY +; +IDEENABLE .EQU FALSE ; TRUE FOR IDE SUPPORT +IDEMODE .EQU IDEMODE_DIO ; IDEMODE_DIO, IDEMODE_DIDE +IDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +IDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +IDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +PPIDEENABLE .EQU FALSE ; TRUE FOR PPIDE SUPPORT (DO NOT COMBINE WITH DSKYENABLE) +PPIDEMODE .EQU PPIDEMODE_STD ; PPIDEMODE_STD, PPIDEMODE_DIO3 +PPIDETRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPIDEENABLE = TRUE) +PPIDE8BIT .EQU FALSE ; USE IDE 8BIT TRANSFERS (PROBABLY ONLY WORKS FOR CF CARDS!) +PPIDECAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PPIDESLOW .EQU FALSE ; ADD DELAYS TO HELP PROBLEMATIC HARDWARE (TRY THIS IF PPIDE IS UNRELIABLE) +; +SDENABLE .EQU FALSE ; TRUE FOR SD SUPPORT +SDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +SDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +SDCSIO .EQU FALSE ; TRUE IF USING THE CSIO PORT (N8 ONLY) +SDCSIOFAST .EQU FALSE ; TRUE IF USING THE LOOKUP TABLE RATHER THAN SHIFTS AND ROTATES (N8 ONLY) +PPISD .EQU FALSE ; TRUE IF USING PPISD MINI-BOARD (DO NOT COMBINE WITH PPIDE) +; +PRPENABLE .EQU FALSE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PRPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PRPSDENABLE = TRUE) +PRPSDCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +PRPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +PPPENABLE .EQU TRUE ; TRUE FOR PARPORTPROP SUPPORT +PPPSDENABLE .EQU TRUE ; TRUE FOR PROPIO SD SUPPORT (FOR N8VEM PROPIO ONLY!) +PPPSDTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF PPPENABLE = TRUE) +PPPSDCAPACITY .EQU 64 ; CAPACITY OF PPP SD DEVICE (IN MB) +PPPCONENABLE .EQU TRUE ; TRUE FOR PROPIO CONSOLE SUPPORT (PS/2 KBD & VGA VIDEO) +; +HDSKENABLE .EQU FALSE ; TRUE FOR SIMH HDSK SUPPORT +HDSKTRACE .EQU 1 ; 0=SILENT, 1=ERRORS, 2=EVERYTHING (ONLY RELEVANT IF IDEENABLE = TRUE) +HDSKCAPACITY .EQU 64 ; CAPACITY OF DEVICE (IN MB) +; +BOOTTYPE: .EQU BT_MENU ; BT_MENU (WAIT FOR KEYPRESS), BT_AUTO (BOOT_DEFAULT AFTER BOOT_TIMEOUT SECS) +BOOT_TIMEOUT .EQU 20 ; APPROX TIMEOUT IN SECONDS FOR AUTOBOOT, 0 FOR IMMEDIATE +BOOT_DEFAULT .EQU 'R' ; SELECTION TO INVOKE AT TIMEOUT +; +BAUDRATE .EQU 38400 ; IN BPS: 1200, 9600, 38400, ..., 115200 +TERMTYPE .EQU TERM_ANSI ; TERM_TTY=0, TERM_ANSI=1, TERM_WYSE=2 diff --git a/trunk/Source/dbgmon.asm b/trunk/Source/dbgmon.asm new file mode 100644 index 00000000..5150fa04 --- /dev/null +++ b/trunk/Source/dbgmon.asm @@ -0,0 +1,1590 @@ +;___ROM_MONITOR_PROGRAM_______________________________________________________ +; +; ORIGINAL CODE BY: ANDREW LYNCH (LYNCHAJ@YAHOO COM) 13 FEB 2007 +; +; MODIFIED BY : DAN WERNER 03 09.2009 +; +;__REFERENCES_________________________________________________________________ +; THOMAS SCHERRER BASIC HAR.DWARE TEST ASSEMBLER SOURCES FROM THE Z80 INFO PAGE +; INCLUDING ORIGINAL SCHEMATIC CONCEPT +; HTTP://Z80 INFO/Z80SOURC.TXT +; CODE SAMPLES FROM BRUCE JONES PUBLIC DOMAIN ROM MONITOR FOR THE SBC-200C +; HTTP://WWW RETROTECHNOLOGY.COM/HERBS_STUFF/SD_BRUCE_CODE.ZIP +; INSPIRATION FROM JOEL OWENS "Z-80 SPACE-TIME PRODUCTIONS SINGLE BOARD COMPUTER" +; HTTP://WWW JOELOWENS.ORG/Z80/Z80INDEX.HTML +; GREAT HELP AND TECHNICAL ADVICE FROM ALLISON AT ALPACA_DESIGNERS +; HTTP://GROUPS YAHOO.COM/GROUP/ALPACA_DESIGNERS +; INTEL SDK-85 ROM DEBUG MONITOR +;_____________________________________________________________________________ +; +#INCLUDE "std.asm" +; +;__CONSTANTS__________________________________________________________________ +; +ENDT: .EQU 0FFh ; MARK END OF TEXT +CR: .EQU 0DH ; ASCII CARRIAGE RETURN CHARACTER +LF: .EQU 0AH ; ASCII LINE FEED CHARACTER +ESC: .EQU 1BH ; ASCII ESCAPE CHARACTER +BS: .EQU 08H ; ASCII BACKSPACE CHARACTER +; +;__MAIN_PROGRAM_______________________________________________________________ +; +; ORG 00100h ; FOR DEBUG IN CP/M (AS .COM) + .ORG MON_LOC +; +;__ENTRY JUMP TABLE___________________________________________________________ +; + JP DSKY_ENTRY + JP UART_ENTRY +; +#DEFINE CIOMODE_CBIOS +#INCLUDE "util.asm" +; +#INCLUDE "memmgr.asm" +; +;__DSKY_ENTRY_________________________________________________________________ +; +DSKY_ENTRY: + LD SP,MON_STACK ; SET THE STACK POINTER + CALL INITIALIZE ; INITIALIZE SYSTEM + +;__FRONT_PANEL_STARTUP________________________________________________________ +; +; START UP THE SYSTEM WITH THE FRONT PANEL INTERFACE +; +;_____________________________________________________________________________ +; + CALL MTERM_INIT ; INIT 8255 FOR MTERM + LD HL,CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + + + +FRONTPANELLOOP: + CALL KB_GET ; GET KEY FROM KB + + CP 10H ; IS PORT READ? + JP Z,DOPORTREAD ; YES, JUMP + CP 11H ; IS PORT WRITE? + JP Z,DOPORTWRITE ; YES, JUMP + CP 14H ; IS DEPOSIT? + JP Z,DODEPOSIT ; YES, JUMP + CP 15H ; IS EXAMINE? + JP Z,DOEXAMINE ; YES, JUMP + CP 16H ; IS GO? + JP Z,DOGO ; YES, JUMP + CP 17H ; IS BO? + JP Z,DOBOOT ; YES, JUMP + + JR FRONTPANELLOOP ; LOOP +EXIT: + RET + + +;__DOBOOT_____________________________________________________________________ +; +; PERFORM BOOT FRONT PANEL ACTION +;_____________________________________________________________________________ +; +DOBOOT: + ; ENSURE DEFAULT MEMORY PAGE CONFIGURATION +;#IF (PLATFORM == PLT_N8) +; LD A,DEFACR +; OUT0 (ACR),A +; XOR A +; OUT0 (RMAP),A +;#ELSE +; XOR A +; OUT (MPCL_ROM),A +; OUT (MPCL_RAM),A +;#ENDIF + CALL ROMPGZ + ; JUMP TO RESTART ADDRESS + JP 0000H +; +;__DOPORTREAD_________________________________________________________________ +; +; PERFORM PORT READ FRONT PANEL ACTION +;_____________________________________________________________________________ +; +DOPORTREAD: + CALL GETPORT ; GET PORT INTO A +PORTREADLOOP: + LD C,A ; STORE PORT IN "C" + SRL A ; ROTATE HIGH NIB TO LOW + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; SHOW HIGH NIB IN DISP 5 + LD A,C ; RESTORE PORT VALUE INTO "A" + AND 0FH ; CLEAR HIGH NIB, LEAVING LOW + LD (DISPLAYBUF+4),A ; SHOW LOW NIB IN DISP 4 + IN A,(C) ; GET PORT VALUE FROM PORT IN "C" + LD C,A ; STORE VALUE IN "C" + SRL A ; ROTATE HIGH NIB TO LOW + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+1),A ; SHOW HIGH NIB IN DISP 1 + LD A,C ; RESTORE VALUE TO "A" + AND 0FH ; CLEAR HIGH NIB, LEAVING LOW + LD (DISPLAYBUF),A ; DISPLAY LOW NIB IN DISP 0 + LD A,10H ; CLEAR OTHER DISPLAYS + LD (DISPLAYBUF+2),A ; + LD (DISPLAYBUF+3),A ; + LD A,13H ; "P" + LD (DISPLAYBUF+7),A ; STORE IN DISP 7 + LD A,14H ; "O" + LD (DISPLAYBUF+6),A ; STORE IN DISP 6 + LD HL,DISPLAYBUF ; SET POINTER TO DISPLAY BUFFER + CALL HEXDISPLAY ; DISPLAY BUFFER CONTENTS +PORTREADGETKEY: + CALL KB_GET ; GET KEY FROM KB + CP 12H ; [CL] PRESSED, EXIT + JP Z,PORTREADEXIT ; + CP 10H ; [PR] PRESSED, PROMPT FOR NEW PORT + JR Z,DOPORTREAD ; + JR PORTREADGETKEY ; NO VALID KEY, LOOP +PORTREADEXIT: + LD HL,CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + JP FRONTPANELLOOP ; + +;__DOPORTWRITE________________________________________________________________ +; +; PERFORM PORT WRITE FRONT PANEL ACTION +;_____________________________________________________________________________ +; +DOPORTWRITE: + CALL GETPORT ; GET PORT INTO A +PORTWRITELOOP: + LD C,A ; STORE PORT IN "C" + SRL A ; ROTATE HIGH NIB INTO LOW + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; DISPLAY HIGH NIB IN DISPLAY 5 + LD A,C ; RESTORE PORT VALUE INTO "A" + AND 0FH ; CLEAR OUT HIGH NIB + LD (DISPLAYBUF+4),A ; DISPLAY LOW NIB IN DISPLAY 4 + LD A,10H ; CLEAR OUT DISPLAYS 2 AND 3 + LD (DISPLAYBUF+2),A ; + LD (DISPLAYBUF+3),A ; + LD A,13H ; DISPLAY "P" IN DISP 7 + LD (DISPLAYBUF+7),A ; + LD A,14H ; DISPLAY "O" IN DISP 6 + LD (DISPLAYBUF+6),A ; + LD HL,DISPLAYBUF ; POINT TO DISPLAY BUFFER + CALL GETVALUE ; INPUT A BYTE VALUE, RETURN IN "A" + OUT (C),A ; OUTPUT VALUE TO PORT STORED IN "C" + LD HL,CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + JP FRONTPANELLOOP ; + + +;__DOGO_______________________________________________________________________ +; +; PERFORM GO FRONT PANEL ACTION +;_____________________________________________________________________________ +; +DOGO: + CALL GETADDR ; GET ADDRESS INTO HL + JP (HL) ; GO THERE! + + + +;__DODEPOSIT__________________________________________________________________ +; +; PERFORM DEPOSIT FRONT PANEL ACTION +;_____________________________________________________________________________ +; +DODEPOSIT: + CALL GETADDR ; GET ADDRESS INTO HL + PUSH HL +DEPOSITLOOP: + LD A,H ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+7),A ; + LD A,H ; + AND 0FH ; + LD (DISPLAYBUF+6),A ; + LD A,L ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; + LD A,L ; + AND 0FH ; + LD (DISPLAYBUF+4),A ; + LD A,10H ; + LD (DISPLAYBUF+3),A ; + LD HL,DISPLAYBUF ; + CALL GETVALUE ; + POP HL ; + LD (HL),A ; +DEPOSITGETKEY: + CALL KB_GET ; GET KEY FROM KB + CP 12H ; [CL] PRESSED, EXIT + JP Z,DEPOSITEXIT ; + CP 13H ; [EN] PRESSED, INC ADDRESS AND LOOP + JR Z,DEPOSITFW ; + CP 14H ; [DE] PRESSED, PROMPT FOR NEW ADDRESS + JR Z,DODEPOSIT ; + JR DEPOSITGETKEY ; NO VALID KEY, LOOP +DEPOSITFW: + INC HL ; + PUSH HL ; STORE HL + JR DEPOSITLOOP ; +DEPOSITEXIT: + LD HL,CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + JP FRONTPANELLOOP ; + + + + +;__DOEXAMINE__________________________________________________________________ +; +; PERFORM EXAMINE FRONT PANEL ACTION +;_____________________________________________________________________________ +; +DOEXAMINE: + CALL GETADDR ; GET ADDRESS INTO HL + PUSH HL ; STORE HL +EXAMINELOOP: + LD A,H ; MOVE HIGH BYTE IN "A" + SRL A ; SHOW HIGH NIBBLE IN DISP 7 + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+7),A ; + LD A,H ; RESTORE HIGH BYTE + AND 0FH ; CLEAR HIGH NIBBLE + LD (DISPLAYBUF+6),A ; DISPLAY LOW NIBBLE IN DISP 6 + LD A,L ; PUT LOW BYTE IN "A" + SRL A ; SHOW HIGH NIBBLE IN DISP 5 + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+5),A ; + LD A,L ; RESTORE LOW BYTE IN "A" + AND 0FH ; CLEAR OUT HIGH NIBBLE + LD (DISPLAYBUF+4),A ; DISPLAY LOW NIBBLE IN DISP 4 + LD A,10H ; CLEAR OUT DISP 3 + LD (DISPLAYBUF+3),A ; + LD A,(HL) ; GET VALUE FROM ADDRESS IN HL + SRL A ; DISPLAY HIGH NIB IN DISPLAY 1 + SRL A ; + SRL A ; + SRL A ; + LD (DISPLAYBUF+1),A ; + LD A,(HL) ; GET VALUE FROM ADDRESS IN HL + AND 0FH ; CLEAR OUT HIGH NIBBLE + LD (DISPLAYBUF),A ; DISPLAY LOW NIBBLE IN DISPLAY 0 + LD HL,DISPLAYBUF ; POINT TO DISPLAY BUFFER + CALL HEXDISPLAY ; DISPLAY BUFFER ON DISPLAYS + POP HL ; RESTORE HL +EXAMINEGETKEY: + CALL KB_GET ; GET KEY FROM KB + CP 12H ; [CL] PRESSED, EXIT + JP Z,EXAMINEEXIT ; + CP 13H ; [EN] PRESSED, INC ADDRESS AND LOOP + JR Z,EXAMINEFW ; + CP 15H ; [DE] PRESSED, PROMPT FOR NEW ADDRESS + JR Z,DOEXAMINE ; + JR EXAMINEGETKEY ; NO VALID KEY, LOOP +EXAMINEFW: + INC HL ; HL++ + PUSH HL ; STORE HL + JR EXAMINELOOP ; +EXAMINEEXIT: + LD HL,CPUUP ; SET POINTER TO DATA BUFFER + CALL SEGDISPLAY ; DISPLAY + JP FRONTPANELLOOP ; + + +;__GETADDR____________________________________________________________________ +; +; GET ADDRESS FROM FRONT PANEL +;_____________________________________________________________________________ +; +GETADDR: + PUSH BC ; STORE BC + JR GETADDRCLEAR ; +GETADDR1: + LD HL,ADDR ; DISPLAY PROMPT + CALL SEGDISPLAY ; +GETADDRLOOP: + CALL KB_GET ; + CP 10H ; + JP M,GETADDRNUM ; NUMBER PRESSED, STORE IT + CP 13H ; EN PRESSED, DONE + JR Z,GETADDRDONE ; + CP 12H ; CLEAR PRESSED, CLEAR + JR Z,GETADDRCLEAR ; + JR GETADDRLOOP ; INVALID KEY, LOOP +GETADDRDONE: + LD HL,00H ; HL=0 + LD A,(DISPLAYBUF+1) ; GET DIGIT IN DISPLAY 1 + SLA A ; ROTATE IT TO HIGH NIBBLE + SLA A ; + SLA A ; + SLA A ; + LD C,A ; STORE IT IN "C" + LD A,(DISPLAYBUF) ; GET DIGIT IN DISPLAY 0 + AND 0FH ; CLEAR HIGH NIBBLE + OR C ; ADD IN NIBBLE STORED IN C + LD L,A ; STORE IT IN LOW BYTE OF ADDRESS POINTER + LD A,(DISPLAYBUF+3) ; GET DIGIT IN DISPLAY 3 + SLA A ; ROTATE IT TO HIGH NIBBLE + SLA A ; + SLA A ; + SLA A ; + LD C,A ; STORE IT IN "C" + LD A,(DISPLAYBUF+2) ; GET DIGIT IN DISPLAY 2 + AND 0FH ; CLEAR HIGH NIBBLE + OR C ; ADD IN NIBBLE STORED IN "C" + LD H,A ; STORE BYTE IN HIGH BYTE OF ADDRESS POINTER + LD A,10H ; CLEAR OUT DISPLAYS 0,1,2 & 3 + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + LD (DISPLAYBUF+2),A ; + LD (DISPLAYBUF+3),A ; + POP BC ; RESTORE BC + RET +GETADDRNUM: + LD C,A ; + LD A,(DISPLAYBUF+2) ; SHIFT BYTES IN DISPLAY BUF TO THE LEFT + LD (DISPLAYBUF+3),A ; + LD A,(DISPLAYBUF+1) ; + LD (DISPLAYBUF+2),A ; + LD A,(DISPLAYBUF) ; + LD (DISPLAYBUF+1),A ; + LD A,C ; DISPLAY KEYSTROKE IN RIGHT MOST DISPLAY (0) + LD (DISPLAYBUF+0),A ; + JR GETADDRDISP ; +GETADDRCLEAR: + LD A,12H ; CLEAR OUT DISPLAYS 0,1,2 & 3 + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + LD (DISPLAYBUF+2),A ; + LD (DISPLAYBUF+3),A ; +GETADDRDISP: + LD A,(DISPLAYBUF) ; ENCODE DIGITS IN DISPLAY BUFFER TO DISPLAY + CALL DECODEDISPLAY ; + LD (ADDR),A ; + LD A,(DISPLAYBUF+1) ; + CALL DECODEDISPLAY ; + LD (ADDR+1),A ; + LD A,(DISPLAYBUF+2) ; + CALL DECODEDISPLAY ; + LD (ADDR+2),A ; + LD A,(DISPLAYBUF+3) ; + CALL DECODEDISPLAY ; + LD (ADDR+3),A ; + JP GETADDR1 ; + + + +;__DSPSECTOR__________________________________________________________________ +; +; DISPLAY SECTOR IN HL ON FRONT PANEL +;_____________________________________________________________________________ +; +DSPSECTOR: + PUSH BC ; STORE BC + PUSH HL ; STORE HL + LD A,H ; DISPLAY HIGH BYTE, HIGH NIBBLE + SRL A ; + SRL A ; + SRL A ; + SRL A ; + AND 0FH ; + CALL DECODEDISPLAY ; + LD (SEC+3),A ; + LD A,H ; DISPLAY HIGH BYTE, LOW NIBBLE + AND 0FH ; + CALL DECODEDISPLAY ; + LD (SEC+2),A ; + LD A,L ; DISPLAY LOW BYTE, HIGH NIBBLE + AND 0F0H ; + SRL A ; + SRL A ; + SRL A ; + SRL A ; + AND 0FH ; + CALL DECODEDISPLAY ; + LD (SEC+1),A ; DISPLAY LOW BYTE, LOW NIBBLE + LD A,L ; + AND 0FH ; + CALL DECODEDISPLAY ; + LD (SEC),A ; + LD HL,SEC ; DISPLAY PROMPT + CALL SEGDISPLAY ; + POP HL ; RESTORE HL + POP BC ; RESTORE BC + RET + + + +;__GETPORT____________________________________________________________________ +; +; GET PORT FROM FRONT PANEL +;_____________________________________________________________________________ +; +GETPORT: + PUSH BC ; STORE BC + JR GETPORTCLEAR ; +GETPORT1: + LD HL,PORT ; DISPLAY PROMPT + CALL SEGDISPLAY ; +GETPORTLOOP: + CALL KB_GET ; + CP 10H ; + JP M,GETPORTNUM ; NUMBER PRESSED, STORE IT + CP 13H ; EN PRESSED, DONE + JR Z,GETPORTDONE ; + CP 12H ; CLEAR PRESSED, CLEAR + JR Z,GETPORTCLEAR ; + JR GETPORTLOOP ; INVALID KEY, LOOP +GETPORTDONE: + LD A,(DISPLAYBUF+1) ; + SLA A ; + SLA A ; + SLA A ; + SLA A ; + LD C,A ; + LD A,(DISPLAYBUF) ; + AND 0FH ; + OR C ; + LD C,A ; + LD A,10H ; + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + LD A,C ; + POP BC ; RESTORE BC + RET +GETPORTNUM: + LD C,A ; + LD A,(DISPLAYBUF) ; + LD (DISPLAYBUF+1),A ; + LD A,C ; + LD (DISPLAYBUF+0),A ; + JR GETPORTDISP ; +GETPORTCLEAR: + LD A,12H ; + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; +GETPORTDISP: + LD A,(DISPLAYBUF) ; + CALL DECODEDISPLAY ; + LD (PORT),A ; + LD A,(DISPLAYBUF+1) ; + CALL DECODEDISPLAY ; + LD (PORT+1),A ; + JP GETPORT1 ; + + +;__GETVALUE___________________________________________________________________ +; +; GET VALUE FROM FRONT PANEL +;_____________________________________________________________________________ +; +GETVALUE: + PUSH BC ; STORE BC + JR GETVALUECLEAR ; +GETVALUE1: + CALL HEXDISPLAY ; + +GETVALUELOOP: + CALL KB_GET ; + CP 10H ; + JP M,GETVALUENUM ; NUMBER PRESSED, STORE IT + CP 13H ; EN PRESSED, DONE + JR Z,GETVALUEDONE ; + CP 12H ; CLEAR PRESSED, CLEAR + JR Z,GETVALUECLEAR ; + JR GETVALUELOOP ; INVALID KEY, LOOP +GETVALUEDONE: + LD A,(DISPLAYBUF+1) ; + SLA A ; + SLA A ; + SLA A ; + SLA A ; + LD C,A ; + LD A,(DISPLAYBUF) ; + AND 0FH ; + OR C ; + LD C,A ; + LD A,10H ; + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + LD A,C ; + POP BC ; RESTORE BC + RET +GETVALUENUM: + LD C,A ; + LD A,(DISPLAYBUF) ; + LD (DISPLAYBUF+1),A ; + LD A,C ; + LD (DISPLAYBUF+0),A ; + JR GETVALUE1 ; +GETVALUECLEAR: + LD A,12H ; + LD (DISPLAYBUF),A ; + LD (DISPLAYBUF+1),A ; + JP GETVALUE1 ; + + +;__UART_ENTRY_________________________________________________________________ +; +; SERIAL MONITOR STARTUP +;_____________________________________________________________________________ +; +UART_ENTRY: + LD SP,MON_STACK ; SET THE STACK POINTER + CALL INITIALIZE ; INITIALIZE SYSTEM + + XOR A ;ZERO OUT ACCUMULATOR (ADDED) + PUSH HL ;PROTECT HL FROM OVERWRITE + LD HL,TXT_READY ;POINT AT TEXT + CALL MSG ;SHOW WE'RE HERE + POP HL ;PROTECT HL FROM OVERWRITE + +; +;__SERIAL_MONITOR_COMMANDS____________________________________________________ +; +; B XX BOOT CPM FROM DRIVE XX +; D XXXXH YYYYH DUMP MEMORY FROM XXXX TO YYYY +; F XXXXH YYYYH ZZH FILL MEMORY FROM XXXX TO YYYY WITH ZZ +; H LOAD INTEL HEX FORMAT DATA +; I INPUT FROM PORT AND SHOW HEX DATA +; K ECHO KEYBOARD INPUT +; M XXXXH YYYYH ZZZZH MOVE MEMORY BLOCK XXXX TO YYYY TO ZZZZ +; O OUTPUT TO PORT HEX DATA +; P XXXXH YYH PROGRAM RAM FROM XXXXH WITH VALUE IN YYH, WILL PROMPT FOR NEXT LINES FOLLOWING UNTIL CR +; R RUN A PROGRAM FROM CURRENT LOCATION +; +;__COMMAND_PARSE______________________________________________________________ +; +; PROMPT USER FOR COMMANDS, THEN PARSE THEM +;_____________________________________________________________________________ +; + +SERIALCMDLOOP: + CALL CRLFA ; CR,LF,> + LD HL,KEYBUF ; SET POINTER TO KEYBUF AREA + CALL GETLN ; GET A LINE OF INPUT FROM THE USER + LD HL,KEYBUF ; RESET POINTER TO START OF KEYBUF + LD A,(HL) ; LOAD FIRST CHAR INTO A (THIS SHOULD BE THE COMMAND) + INC HL ; INC POINTER + + CP 'B' ; IS IT "B" (Y/N) + JP Z,DOBOOT ; IF YES DO BOOT + CP 'R' ; IS IT "R" (Y/N) + JP Z,RUN ; IF YES GO RUN ROUTINE + CP 'P' ; IS IT "P" (Y/N) + JP Z,PROGRM ; IF YES GO PROGRAM ROUTINE + CP 'O' ; IS IT AN "O" (Y/N) + JP Z,POUT ; PORT OUTPUT + CP 'H' ; IS IT A "H" (Y/N) + JP Z,HXLOAD ; INTEL HEX FORMAT LOAD DATA + CP 'I' ; IS IT AN "I" (Y/N) + JP Z,PIN ; PORT INPUT + CP 'D' ; IS IT A "D" (Y/N) + JP Z,DUMP ; DUMP MEMORY + CP 'K' + JP Z,KLOP ; LOOP ON KEYBOARD + CP 'M' ; IS IT A "M" (Y/N) + JP Z,MOVE ; MOVE MEMORY COMMAND + CP 'F' ; IS IT A "F" (Y/N) + JP Z,FILL ; FILL MEMORY COMMAND + LD HL,TXT_COMMAND ; POINT AT ERROR TEXT + CALL MSG ; PRINT COMMAND LABEL + + JR SERIALCMDLOOP + + + + + +;__KLOP_______________________________________________________________________ +; +; READ FROM THE SERIAL PORT AND ECHO, MONITOR COMMAND "K" +;_____________________________________________________________________________ +; +KLOP: + CALL KIN ; GET A KEY + CALL COUT ; OUTPUT KEY TO SCREEN + CP ESC ; IS ? + JR NZ,KLOP ; NO, LOOP + JP SERIALCMDLOOP ; + +;__GETLN______________________________________________________________________ +; +; READ A LINE(80) OF TEXT FROM THE SERIAL PORT, HANDLE , TERM ON +; EXIT IF TOO MANY CHARS STORE RESULT IN HL. CHAR COUNT IN C. +;_____________________________________________________________________________ +; +GETLN: + LD C,00H ; ZERO CHAR COUNTER + PUSH DE ; STORE DE +GETLNLOP: + CALL KIN ; GET A KEY + CALL COUT ; OUTPUT KEY TO SCREEN + CP CR ; IS ? + JR Z,GETLNDONE ; YES, EXIT + CP BS ; IS ? + JR NZ,GETLNSTORE ; NO, STORE CHAR + LD A,C ; A=C + CP 0 ; + JR Z,GETLNLOP ; NOTHING TO BACKSPACE, IGNORE & GET NEXT KEY + DEC HL ; PERFORM BACKSPACE + DEC C ; LOWER CHAR COUNTER + LD A,0 ; + LD (HL),A ; STORE NULL IN BUFFER + LD A,20H ; BLANK OUT CHAR ON TERM + CALL COUT ; + LD A,BS ; + CALL COUT ; + JR GETLNLOP ; GET NEXT KEY +GETLNSTORE: + LD (HL),A ; STORE CHAR IN BUFFER + INC HL ; INC POINTER + INC C ; INC CHAR COUNTER + LD A,C ; A=C + CP 4DH ; OUT OF BUFFER SPACE? + JR NZ,GETLNLOP ; NOPE, GET NEXT CHAR +GETLNDONE: + LD (HL),00H ; STORE NULL IN BUFFER + POP DE ; RESTORE DE + RET ; +; +;__KIN________________________________________________________________________ +; +; READ FROM THE SERIAL PORT AND ECHO & CONVERT INPUT TO UCASE +;_____________________________________________________________________________ +; +KIN: + CALL CIN + AND 7FH ; STRIP HI BIT + CP 'A' ; KEEP NUMBERS, CONTROLS + RET C ; AND UPPER CASE + CP 7BH ; SEE IF NOT LOWER CASE + RET NC + AND 5FH ; MAKE UPPER CASE + RET +; +;__CRLF_______________________________________________________________________ +; +; SEND CR & LF TO THE SERIAL PORT +;_____________________________________________________________________________ +; +CRLF: + PUSH HL ; PROTECT HL FROM OVERWRITE + LD HL,TCRLF ; LOAD MESSAGE POINTER + CALL MSG ; SEBD MESSAGE TO SERIAL PORT + POP HL ; PROTECT HL FROM OVERWRITE + RET ; + + +;__LDHL_______________________________________________________________________ +; +; GET ONE WORD OF HEX DATA FROM BUFFER POINTED TO BY HL SERIAL PORT, RETURN IN HL +;_____________________________________________________________________________ +; +LDHL: + PUSH DE ; STORE DE + CALL HEXIN ; GET K B. AND MAKE HEX + LD D,A ; THATS THE HI BYTE + CALL HEXIN ; DO HEX AGAIN + LD L,A ; THATS THE LOW BYTE + LD H,D ; MOVE TO HL + POP DE ; RESTORE BC + RET ; GO BACK WITH ADDRESS + + +;__HEXIN______________________________________________________________________ +; +; GET ONE BYTE OF HEX DATA FROM BUFFER IN HL, RETURN IN A +;_____________________________________________________________________________ +; +HEXIN: + PUSH BC ;SAVE BC REGS + CALL NIBL ;DO A NIBBLE + RLC A ;MOVE FIRST BYTE UPPER NIBBLE + RLC A ; + RLC A ; + RLC A ; + LD B,A ; SAVE ROTATED BYTE + CALL NIBL ; DO NEXT NIBBLE + ADD A,B ; COMBINE NIBBLES IN ACC + POP BC ; RESTORE BC + RET ; DONE +NIBL: + LD A,(HL) ; GET K B. DATA + INC HL ; INC KB POINTER + CP 40H ; TEST FOR ALPHA + JR NC,ALPH ; + AND 0FH ; GET THE BITS + RET ; +ALPH: + AND 0FH ; GET THE BITS + ADD A,09H ; MAKE IT HEX A-F + RET ; + + +;__HEXINS_____________________________________________________________________ +; +; GET ONE BYTE OF HEX DATA FROM SERIAL PORT, RETURN IN A +;_____________________________________________________________________________ +; +HEXINS: + PUSH BC ;SAVE BC REGS + CALL NIBLS ;DO A NIBBLE + RLC A ;MOVE FIRST BYTE UPPER NIBBLE + RLC A ; + RLC A ; + RLC A ; + LD B,A ; SAVE ROTATED BYTE + CALL NIBLS ; DO NEXT NIBBLE + ADD A,B ; COMBINE NIBBLES IN ACC + POP BC ; RESTORE BC + RET ; DONE +NIBLS: + CALL KIN ; GET K B. DATA + INC HL ; INC KB POINTER + CP 40H ; TEST FOR ALPHA + JR NC,ALPH ; + AND 0FH ; GET THE BITS + RET ; + + +;__HXOUT______________________________________________________________________ +; +; PRINT THE ACCUMULATOR CONTENTS AS HEX DATA ON THE SERIAL PORT +;_____________________________________________________________________________ +; +HXOUT: + PUSH BC ; SAVE BC + LD B,A ; + RLC A ; DO HIGH NIBBLE FIRST + RLC A ; + RLC A ; + RLC A ; + AND 0FH ; ONLY THIS NOW + ADD A,30H ; TRY A NUMBER + CP 3AH ; TEST IT + JR C,OUT1 ; IF CY SET PRINT 'NUMBER' + ADD A,07H ; MAKE IT AN ALPHA +OUT1: + CALL COUT ; SCREEN IT + LD A,B ; NEXT NIBBLE + AND 0FH ; JUST THIS + ADD A,30H ; TRY A NUMBER + CP 3AH ; TEST IT + JR C,OUT2 ; PRINT 'NUMBER' + ADD A,07H ; MAKE IT ALPHA +OUT2: + CALL COUT ; SCREEN IT + POP BC ; RESTORE BC + RET ; + + +;__SPACE______________________________________________________________________ +; +; PRINT A SPACE CHARACTER ON THE SERIAL PORT +;_____________________________________________________________________________ +; +SPACE: + PUSH AF ; STORE AF + LD A,20H ; LOAD A "SPACE" + CALL COUT ; SCREEN IT + POP AF ; RESTORE AF + RET ; DONE + +;__PHL________________________________________________________________________ +; +; PRINT THE HL REG ON THE SERIAL PORT +;_____________________________________________________________________________ +; +PHL: + LD A,H ; GET HI BYTE + CALL HXOUT ; DO HEX OUT ROUTINE + LD A,L ; GET LOW BYTE + CALL HXOUT ; HEX IT + CALL SPACE ; + RET ; DONE + +;__POUT_______________________________________________________________________ +; +; OUTPUT TO AN I/O PORT, MONITOR COMMAND "O" +;_____________________________________________________________________________ +; +POUT: +POUT1: + INC HL ; + CALL HEXIN ; GET PORT + LD C,A ; SAVE PORT POINTER + INC HL ; + CALL HEXIN ; GET DATA +OUTIT: + OUT (C),A ; + JP SERIALCMDLOOP ; + + +;__PIN________________________________________________________________________ +; +; INPUT FROM AN I/O PORT, MONITOR COMMAND "I" +;_____________________________________________________________________________ +; +PIN: + INC HL ; + CALL HEXIN ; GET PORT + LD C,A ; SAVE PORT POINTER + CALL CRLF ; + IN A,(C) ; GET DATA + CALL HXOUT ; SHOW IT + JP SERIALCMDLOOP ; + + + + + +;__CRLFA______________________________________________________________________ +; +; PRINT COMMAND PROMPT TO THE SERIAL PORT +;_____________________________________________________________________________ +; +CRLFA: + PUSH HL ; PROTECT HL FROM OVERWRITE + LD HL,PROMPT ; + CALL MSG ; + POP HL ; PROTECT HL FROM OVERWRITE + RET ; DONE + + +;__MSG________________________________________________________________________ +; +; PRINT A STRING TO THE SERIAL PORT +;_____________________________________________________________________________ +; +MSG: + +TX_SERLP: + LD A,(HL) ; GET CHARACTER TO A + CP ENDT ; TEST FOR END BYTE + JP Z,TX_END ; JUMP IF END BYTE IS FOUND + CALL COUT ; + INC HL ; INC POINTER, TO NEXT CHAR + JP TX_SERLP ; TRANSMIT LOOP +TX_END: + RET ;ELSE DONE + +;__RUN________________________________________________________________________ +; +; TRANSFER OUT OF MONITOR, USER OPTION "R" +;_____________________________________________________________________________ +; +RUN: + INC HL ; SHOW READY + CALL LDHL ; GET START ADDRESS + JP (HL) ; + + +;__PROGRM_____________________________________________________________________ +; +; PROGRAM RAM LOCATIONS, USER OPTION "P" +;_____________________________________________________________________________ +; +PROGRM: + INC HL ; SHOW READY + PUSH HL ; STORE HL + CALL LDHL ; GET START ADDRESS + LD D,H ; + LD E,L ; DE POINTS TO ADDRESS TO PROGRAM + POP HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; +PROGRMLP: + CALL HEXIN ; GET NEXT HEX NUMBER + LD (DE),A ; STORE IT + INC DE ; NEXT ADDRESS; + CALL CRLFA ; CR,LF,> + LD A,'P' ; + CALL COUT ; + CALL SPACE ; + LD H,D ; + LD L,E ; + CALL PHL ; + LD HL,KEYBUF ; SET POINTER TO KEYBUF AREA + CALL GETLN ; GET A LINE OF INPUT FROM THE USER + LD HL,KEYBUF ; RESET POINTER TO START OF KEYBUF + LD A,(HL) ; LOAD FIRST CHAR INTO A + CP 00H ; END OF LINE? + JP Z,PROGRMEXIT ; YES, EXIT + JP PROGRMLP ; NO, LOOP +PROGRMEXIT: + JP SERIALCMDLOOP + + + + + + + +;__DUMP_______________________________________________________________________ +; +; PRINT A MEMORY DUMP, USER OPTION "D" +;_____________________________________________________________________________ +; +DUMP: + INC HL ; SHOW READY + PUSH HL ; STORE HL + CALL LDHL ; GET START ADDRESS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; SAVE START + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; + CALL LDHL ; GET END ADDRESS + INC HL ; ADD ONE MORE FOR LATER COMPARE + EX DE,HL ; PUT END ADDRESS IN DE + POP HL ; GET BACK START +GDATA: + CALL CRLF ; +BLKRD: + CALL PHL ; PRINT START LOCATION + LD C,16 ; SET FOR 16 LOCS + PUSH HL ; SAVE STARTING HL +NXTONE: + EXX ; + LD C,E ; + IN A,(C) ; + EXX ; + AND 7FH ; + CP ESC ; + JP Z,SERIALCMDLOOP ; + CP 19 ; + JR Z,NXTONE ; + LD A,(HL) ; GET BYTE + CALL HXOUT ; PRINT IT + CALL SPACE ; +UPDH: + INC HL ; POINT NEXT + DEC C ; DEC LOC COUNT + JR NZ,NXTONE ; IF LINE NOT DONE + ; NOW PRINT 'DECODED' DATA TO RIGHT OF DUMP +PCRLF: + CALL SPACE ; SPACE IT + LD C,16 ; SET FOR 16 CHARS + POP HL ; GET BACK START +PCRLF0: + LD A,(HL) ; GET BYTE + AND 060H ; SEE IF A 'DOT' + LD A,(HL) ; O K. TO GET + JR NZ,PDOT ; +DOT: + LD A,2EH ; LOAD A DOT +PDOT: + CALL COUT ; PRINT IT + INC HL ; + LD A,D ; + CP H ; + JR NZ,UPDH1 ; + LD A,E ; + CP L ; + JP Z,SERIALCMDLOOP ; +; +;IF BLOCK NOT DUMPED, DO NEXT CHARACTER OR LINE +UPDH1: + DEC C ; DEC CHAR COUNT + JR NZ,PCRLF0 ; DO NEXT +CONTD: + CALL CRLF ; + JP BLKRD ; + + +;__HXLOAD_____________________________________________________________________ +; +; LOAD INTEL HEX FORMAT FILE FROM THE SERIAL PORT, USER OPTION "H" +; +; [INTEL HEX FORMAT IS: +; 1) COLON (FRAME 0) +; 2) RECORD LENGTH FIELD (FRAMES 1 AND 2) +; 3) LOAD ADDRESS FIELD (FRAMES 3,4,5,6) +; 4) RECORD TYPE FIELD (FRAMES 7 AND 8) +; 5) DATA FIELD (FRAMES 9 TO 9+2*(RECORD LENGTH)-1 +; 6) CHECKSUM FIELD - SUM OF ALL BYTE VALUES FROM RECORD LENGTH TO AND +; INCLUDING CHECKSUM FIELD = 0 ] +; +; EXAMPLE OF INTEL HEX FORMAT FILE +; EACH LINE CONTAINS A CARRIAGE RETURN AS THE LAST CHARACTER +; :18F900002048454C4C4F20574F524C4420FF0D0AFF0D0A3EFF0D0A54BF +; :18F918006573742050726F746F7479706520524F4D204D6F6E69746FF1 +; :18F9300072205265616479200D0AFF0D0A434F4D4D414E4420524543F2 +; :18F948004549564544203AFF0D0A434845434B53554D204552524F52CD +; :16F96000FF0A0D20202D454E442D4F462D46494C452D20200A0DA4 +; :00000001FF +;_____________________________________________________________________________ +HXLOAD: + CALL CRLF ; SHOW READY +HXLOAD0: + CALL KIN ; GET THE FIRST CHARACTER, EXPECTING A ':' +HXLOAD1: + CP 03Ah ; IS IT COLON ':'? START OF LINE OF INTEL HEX FILE + JR NZ,HXLOADERR ; IF NOT, MUST BE ERROR, ABORT ROUTINE + LD E,0 ; FIRST TWO CHARACTERS IS THE RECORD LENGTH FIELD + CALL HEXINS ; GET US TWO CHARACTERS INTO BC, CONVERT IT TO A BYTE + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD D,A ; LOAD RECORD LENGTH COUNT INTO D + CALL HEXINS ; GET NEXT TWO CHARACTERS, MEMORY LOAD ADDRESS + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD H,A ; PUT VALUE IN H REGISTER + CALL HEXINS ; GET NEXT TWO CHARACTERS, MEMORY LOAD ADDRESS + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD L,A ; PUT VALUE IN L REGISTER + CALL HEXINS ; GET NEXT TWO CHARACTERS, RECORD FIELD TYPE + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + CP 001h ; RECORD FIELD TYPE 00 IS DATA, 01 IS END OF FILE + JR NZ,HXLOAD2 ; MUST BE THE END OF THAT FILE + CALL HEXINS ; GET NEXT TWO CHARACTERS, ASSEMBLE INTO BYTE + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD A,E ; RECALL THE CHECKSUM BYTE + AND A ; IS IT ZERO? + JP Z,HXLOADEXIT ; MUST BE O K., GO BACK FOR SOME MORE, ELSE + JR HXLOADERR ; CHECKSUMS DON'T ADD UP, ERROR OUT +HXLOAD2: + LD A,D ; RETRIEVE LINE CHARACTER COUNTER + AND A ; ARE WE DONE WITH THIS LINE? + JR Z,HXLOAD3 ; GET TWO MORE ASCII CHARACTERS, BUILD A BYTE AND CHECKSUM + CALL HEXINS ; GET NEXT TWO CHARS, CONVERT TO BYTE IN A, CHECKSUM IT + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD (HL),A ; CHECKSUM OK, MOVE CONVERTED BYTE IN A TO MEMORY LOCATION + INC HL ; INCREMENT POINTER TO NEXT MEMORY LOCATION + DEC D ; DECREMENT LINE CHARACTER COUNTER + JR HXLOAD2 ; AND KEEP LOADING INTO MEMORY UNTIL LINE IS COMPLETE +HXLOAD3: + CALL HEXINS ; GET TWO CHARS, BUILD BYTE AND CHECKSUM + CALL HXCHKSUM ; UPDATE HEX CHECK SUM + LD A,E ; CHECK THE CHECKSUM VALUE + AND A ; IS IT ZERO? + JR Z,HXLOADAGAIN ; IF THE CHECKSUM IS STILL OK, CONTINUE ON, ELSE +HXLOADERR: + LD HL,TXT_CKSUMERR ; GET "CHECKSUM ERROR" MESSAGE + CALL MSG ; PRINT MESSAGE FROM (HL) AND TERMINATE THE LOAD + JP HXLOADEXIT ; RETURN TO PROMPT +HXCHKSUM: + LD C,A ; BUILD THE CHECKSUM + LD A,E ; + SUB C ; THE CHECKSUM SHOULD ALWAYS .EQUAL ZERO WHEN CHECKED + LD E,A ; SAVE THE CHECKSUM BACK WHERE IT CAME FROM + LD A,C ; RETRIEVE THE BYTE AND GO BACK + RET ; BACK TO CALLER +HXLOADAGAIN: + CALL KIN ; CATCH THE TRAILING CARRIAGE RETURN + JP HXLOAD0 ; LOAD ANOTHER LINE OF DATA +HXLOADEXIT: + CALL KIN ; CATCH ANY STRAY TRAILING CHARACTERS + JP SERIALCMDLOOP ; RETURN TO PROMPT + + +;__MOVE_______________________________________________________________________ +; +; MOVE MEMORY, USER OPTION "M" +;_____________________________________________________________________________ +; +MOVE: + LD C,03 + ; START GETNM REPLACEMENT + ; GET SOURCE STARTING MEMORY LOCATION + INC HL ; SHOW EXAMINE READY + PUSH HL ; + CALL LDHL ; LOAD IN HL REGS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; PUSH MEMORY ADDRESS ON STACK + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; PRINT SPACE SEPARATOR + PUSH HL ; + CALL LDHL ; LOAD IN HL REGS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; PUSH MEMORY ADDRESS ON STACK + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; PRINT SPACE SEPARATOR + CALL LDHL ; LOAD IN HL REGS + PUSH HL ; PUSH MEMORY ADDRESS ON STACK + ; END GETNM REPLACEMENT + POP DE ; DEST + POP BC ; SOURCE END + POP HL ; SOURCE + PUSH HL ; + LD A,L ; + CPL ; + LD L,A ; + LD A,H ; + CPL ; + LD H,A ; + INC HL ; + ADD HL,BC ; + LD C,L ; + LD B,H ; + POP HL ; + CALL MOVE_LOOP ; + JP SERIALCMDLOOP ; EXIT MOVE COMMAND ROUTINE +MOVE_LOOP: + LD A,(HL) ; FETCH + LD (DE),A ; DEPOSIT + INC HL ; BUMP SOURCE + INC DE ; BUMP DEST + DEC BC ; DEC COUNT + LD A,C ; + OR B ; + JP NZ,MOVE_LOOP ; TIL COUNT=0 + RET ; + +;__FILL_______________________________________________________________________ +; +; FILL MEMORY, USER OPTION "M" +;_____________________________________________________________________________ +; +FILL: + LD C,03 ; + ; START GETNM REPLACEMENT + ; GET FILL STARTING MEMORY LOCATION + INC HL ; SHOW EXAMINE READY + PUSH HL ; + CALL LDHL ; LOAD IN HL REGS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; PUSH MEMORY ADDRESS ON STACK + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; PRINT SPACE SEPARATOR + ; GET FILL ENDING MEMORY LOCATION + PUSH HL ; + CALL LDHL ; LOAD IN HL REGS + LD D,H ; + LD E,L ; + POP HL ; + PUSH DE ; PUSH MEMORY ADDRESS ON STACK + INC HL ; + INC HL ; + INC HL ; + INC HL ; + INC HL ; PRINT SPACE SEPARATOR + ; GET TARGET STARTING MEMORY LOCATION + CALL HEXIN ; GET K B. AND MAKE HEX + LD C,A ; PUT FILL VALUE IN F SO IT IS SAVED FOR LATER + PUSH BC ; PUSH FILL VALUE BYTE ON STACK + ; END GETNM REPLACEMENT + POP BC ; BYTE + POP DE ; END + POP HL ; START + LD (HL),C ; +FILL_LOOP: + LD (HL),C ; + INC HL ; + LD A,E ; + SUB L ; + LD B,A ; + LD A,D ; + SUB H ; + OR B ; + JP NZ,FILL_LOOP ; + JP SERIALCMDLOOP ; + +;__GOCPM______________________________________________________________________ +; +; BOOT CP/M FROM ROM DRIVE, USER OPTION "C" +;_____________________________________________________________________________ +; +GOCPM: +;___________________________ +; REMOVE COMMENTS WHEN BURNED IN ROM +;___________________________ + +; LD A,000000000b ; RESET MPCL LATCH TO DEFAULT ROM +; OUT (MPCL),A ; +; LD HL,ROMSTART_CPM ; WHERE IN ROM CP/M IS STORED (FIRST BYTE) +; LD DE,RAMTARG_CPM ; WHERE IN RAM TO MOVE MONITOR TO (FIRST BYTE) +; LD BC,MOVSIZ_CPM ; NUMBER OF BYTES TO MOVE FROM ROM TO RAM +; LDIR ; PERFORM BLOCK COPY OF CP/M TO UPPER RAM PAGE +; LD A,010000000b ; RESET MPCL LATCH TO DEFAULT CP/M WITH 64K SETTING +; OUT (MPCL),A ; + + JP CPM_ENT +; +;__FILL_MEM___________________________________________________________________ +; +; FUNCTION : FILL MEMORY WITH A VALUE +; INPUT : HL = START ADDRESS BLOCK +; : BC = LENGTH OF BLOCK +; : A = VALUE TO FILL WITH +; USES : DE, BC +; OUTPUT : +; CALLS : +; TESTED : 13 FEB 2007 +;_____________________________________________________________________________ +; +FILL_MEM: + LD E,L ; + LD D,H ; + INC DE ; + LD (HL),A ; INITIALISE FIRST BYTE OF BLOCK WITH DATA BYTE IN A + DEC BC ; + LDIR ; FILL MEMORY + RET ; RETURN TO CALLER + +; +;__INITIALIZE_________________________________________________________________ +; +; INITIALIZE SYSTEM +;_____________________________________________________________________________ +; +INITIALIZE: +; CALL CIOCON_DISP + (CF_INIT * 3) + RET +; + +;__MTERM_INIT_________________________________________________________________ +; +; SETUP 8255, MODE 0, PORT A=OUT, PORT B=IN, PORT C=OUT/OUT +; +;_____________________________________________________________________________ +MTERM_INIT: + LD A, 82H + OUT (PIOX),A + LD A, 30H ;set PC4,5 to disable PPISD (if used) + OUT (PIOC),A ;won't affect DSKY + RET + +;__KB_GET_____________________________________________________________________ +; +; GET A SINGLE KEY AND DECODE +; +;_____________________________________________________________________________ +KB_GET: + PUSH HL ; STORE HL +KB_GET_LOOP: ; WAIT FOR KEY + CALL KB_SCAN ; SCAN KB ONCE + CP 00H ; NULL? + JR Z,KB_GET_LOOP ; LOOP WHILE NOT ZERO + LD D,A ; STORE A + LD A,4FH+30H ; SCAN ALL COL LINES + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE +KB_CLEAR_LOOP: ; WAIT FOR KEY TO CLEAR + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KB_CLEAR_LOOP ; YES, EXIT + LD A,D ; RESTORE A + LD D,00H ; + LD HL,KB_DECODE ; POINT TO BEGINNING OF TABLE +KB_GET_LLOOP: + CP (HL) ; MATCH? + JR Z,KB_GET_DONE ; FOUND, DONE + INC HL + INC D ; D + 1 + JP NZ,KB_GET_LLOOP ; NOT FOUND, LOOP UNTIL EOT +KB_GET_DONE: + LD A,D ; RESULT INTO A + POP HL ; RESTORE HL + RET +; +;__KB_SCAN____________________________________________________________________ +; +; SCAN KEYBOARD MATRIX FOR AN INPUT +; +;_____________________________________________________________________________ +; +KB_SCAN: + LD C,0000H + LD A,41H+30H ; SCAN COL ONE + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KB_SCAN_FOUND ; YES, EXIT + + LD C,0040H + LD A,42H+30H ; SCAN COL TWO + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KB_SCAN_FOUND ; YES, EXIT + + LD C,0080H + LD A,44H+30H ; SCAN COL THREE + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KB_SCAN_FOUND ; YES, EXIT + + LD C,00C0H ; + LD A,48H+30H ; SCAN COL FOUR + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL KB_SCAN_DELAY ; DELAY TO ALLOW LINES TO STABILIZE + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KB_SCAN_FOUND ; YES, EXIT + + LD A, 40H+30H ; TURN OFF ALL COLUMNS + OUT (PIOC),A ; SEND TO COLUMN LINES + LD A, 00H ; RETURN NULL + RET ; EXIT + +KB_SCAN_FOUND: + AND 3FH ; CLEAR TOP TWO BITS + OR C ; ADD IN ROW BITS + LD C,A ; STORE VALUE + LD A, 00H+30H ; TURN OFF ALL COLUMNS + OUT (PIOC),A ; SEND TO COLUMN LINES + LD A,C ; RESTORE VALUE + RET + +PAUSE: +KB_SCAN_DELAY: + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + NOP + RET + + + +;__HEXDISPLAY_________________________________________________________________ +; +; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP +; +;_____________________________________________________________________________ +HEXDISPLAY: + PUSH HL ; STORE HL + PUSH AF ; STORE AF + PUSH BC ; STORE BC + LD BC,0007H + ADD HL,BC + LD B,08H ; SET DIGIT COUNT + LD A,40H+30H ; SET CONTROL PORT 7218 TO OFF + OUT (PIOC),A ; OUTPUT + CALL PAUSE ; WAIT + LD A,0F0H ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) + OUT (PIOA),A ; OUTPUT TO PORT + LD A,80H+30H ; STROBE WRITE PULSE WITH CONTROL=1 + OUT (PIOC),A ; OUTPUT TO PORT + CALL PAUSE ; WAIT + LD A,40H+30H ; SET CONTROL PORT 7218 TO OFF + OUT (PIOC),A ; OUTPUT +HEXDISPLAY_LP: + LD A,(HL) ; GET DISPLAY DIGIT + CALL DECODEDISPLAY ; DECODE DISPLAY + OUT (PIOA),A ; OUT TO PIOA + LD A,00H+30H ; SET WRITE STROBE + OUT (PIOC),A ; OUT TO PIOC + CALL PAUSE ; DELAY + LD A,40H+30H ; SET CONTROL PORT OFF + OUT (PIOC),A ; OUT TO PIOC + CALL PAUSE ; WAIT + DEC HL ; INC POINTER + DJNZ HEXDISPLAY_LP ; LOOP FOR NEXT DIGIT + POP BC ; RESTORE BC + POP AF ; RESTORE AF + POP HL ; RESTORE HL + RET + +;__DECODEDISPLAY______________________________________________________________ +; +; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP +; +;_____________________________________________________________________________ +DECODEDISPLAY: + PUSH BC ; STORE BC + PUSH HL ; STORE HL + LD HL,SEGDECODE ; POINT HL TO DECODE TABLE + LD B,00H ; RESET HIGH BYTE + LD C,A ; CHAR INTO LOW BYTE + ADD HL,BC ; SET TABLE POINTER + LD A,(HL) ; GET VALUE + POP HL ; RESTORE HL + POP BC ; RESTORE BC + RET + + +;__SEGDISPLAY_________________________________________________________________ +; +; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP +; +;_____________________________________________________________________________ +SEGDISPLAY: + PUSH AF ; STORE AF + PUSH BC ; STORE BC + LD BC,0007H + ADD HL,BC + LD B,08H ; SET DIGIT COUNT + LD A,40H+30H ; SET CONTROL PORT 7218 TO OFF + OUT (PIOC),A ; OUTPUT + CALL PAUSE ; WAIT + LD A,0F0H ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) + OUT (PIOA),A ; OUTPUT TO PORT + LD A,80H+30H ; STROBE WRITE PULSE WITH CONTROL=1 + OUT (PIOC),A ; OUTPUT TO PORT + CALL PAUSE ; WAIT + LD A,40H+30H ; SET CONTROL PORT 7218 TO OFF + OUT (PIOC),A ; OUTPUT +SEGDISPLAY_LP: + LD A,(HL) ; GET DISPLAY DIGIT + OUT (PIOA),A ; OUT TO PIOA + LD A,00H+30H ; SET WRITE STROBE + OUT (PIOC),A ; OUT TO PIOC + CALL PAUSE ; DELAY + LD A,40H+30H ; SET CONTROL PORT OFF + OUT (PIOC),A ; OUT TO PIOC + CALL PAUSE ; WAIT + DEC HL ; INC POINTER + DJNZ SEGDISPLAY_LP ; LOOP FOR NEXT DIGIT + POP BC ; RESTORE BC + POP AF ; RESTORE AF + RET + +; +;__WORK_AREA__________________________________________________________________ +; +; RESERVED RAM FOR MONITOR WORKING AREA +;_____________________________________________________________________________ +; +KEYBUF: .FILL 80,' ' +DISPLAYBUF: .FILL 8,0 +; +;__TEXT_STRINGS_______________________________________________________________ +; +; SYSTEM TEXT STRINGS +;_____________________________________________________________________________ +; +TCRLF: + .DB CR,LF,ENDT + +PROMPT: + .DB CR,LF,'>',ENDT + +TXT_READY: + .DB CR,LF + .TEXT " NN NN 8888 VV VV EEEEEEEEEE MM MM" + .DB CR,LF + .TEXT " NNNN NN 88 88 VV VV EE MMMM MMMM" + .DB CR,LF + .TEXT " NN NN NN 88 88 VV VV EE MM MM MM MM" + .DB CR,LF + .TEXT " NN NNNN 88 88 VV VV EE MM MM MM" + .DB CR,LF + .TEXT " NN NN 8888 VV VV EEEEEEE MM MM" + .DB CR,LF + .TEXT " NN NN 88 88 VV VV EE MM MM" + .DB CR,LF + .TEXT " NN NN 88 88 VV VV EE MM MM" + .DB CR,LF + .TEXT " NN NN 88 88 VVV EE MM MM" + .DB CR,LF + .TEXT " NN NN 8888 V EEEEEEEEEE MM MM S B C" + .DB CR,LF + .DB CR,LF + .TEXT " ****************************************************************************" + .DB CR,LF + .TEXT "MONITOR READY " + .DB CR,LF,ENDT + +TXT_COMMAND: + .DB CR,LF + .TEXT "UNKNOWN COMMAND." + .DB ENDT + +TXT_CKSUMERR: + .DB CR,LF + .TEXT "CHECKSUM ERROR." + .DB ENDT +CPUUP: + .DB 084H,0EEH,0BBH,080H,0BBH,0EEH,0CBH,084H +ADDR: + .DB 00H,00H,00H,00H,08CH,0BDH,0BDH,0FEH + + +PORT: + .DB 00H,00H,80H,80H,094H,08CH,09DH,0EEH +SEC: + .DB 80H,80H,80H,80H,80H,0CBH,0CFH,0D7H + + +;_KB DECODE TABLE_____________________________________________________________ +; +; +KB_DECODE: +; 0 1 2 3 4 5 6 7 8 9 A B C D E F + .DB 41H,02H,42H,82H,04H,44H,84H,08H,48H,88H,10H,50H,90H,20H,60H,0A0H +; FW BK CL EN DP EX GO BO + .DB 01H,81H,0C1H,0C2H,0C4H,0C8H,0D0H,0E0H +; +; F-KEYS, +; FW = FORWARD +; BK = BACKWARD +; CL = CLEAR +; EN = ENTER +; DP = DEPOSIT (INTO MEM) +; EX = EXAMINE (MEM) +; GO = GO +; BO = BOOT +;_____________________________________________________________________________ +;_HEX 7_SEG_DECODE_TABLE______________________________________________________ +; +; 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, ,- +; AND WITH 7FH TO TURN ON DP +;_____________________________________________________________________________ +SEGDECODE: + .DB 0FBH,0B0H,0EDH,0F5H,0B6H,0D7H,0DFH,0F0H,0FFH,0F7H,0FEH,09FH + .DB 0CBH,0BDH,0CFH,0CEH,080H,084H,00H,0EEH,09DH + +;********************* END OF PROGRAM *********************************** +; +SLACK .EQU (MON_END - $) + .FILL SLACK,00H +; +MON_STACK .EQU $ +; + .ECHO "DBGMON space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" + + .END diff --git a/trunk/Source/diskdefs b/trunk/Source/diskdefs new file mode 100644 index 00000000..2e1f5725 --- /dev/null +++ b/trunk/Source/diskdefs @@ -0,0 +1,341 @@ +diskdef ibm-3740 + seclen 128 + tracks 77 + sectrk 26 + blocksize 1024 + maxdir 64 + skew 6 + boottrk 2 + os p2dos +end + +diskdef 4mb-hd + seclen 128 + tracks 1024 + sectrk 32 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 0 + os p2dos +end + +diskdef pcw + seclen 512 + tracks 40 + sectrk 9 + blocksize 1024 + maxdir 64 + skew 1 + boottrk 1 + os 3 +end + +diskdef pc1.2m + seclen 512 + tracks 80 + # this format uses 15 sectors per track, but 30 per cylinder + sectrk 30 + blocksize 4096 + maxdir 256 + skew 1 + boottrk 0 + os 3 +end + +# CP/M 86 on 1.44MB floppies +diskdef cpm86-144feat + seclen 512 + tracks 160 + sectrk 18 + blocksize 4096 + maxdir 256 + skew 1 + boottrk 2 + os 3 +end + +diskdef cf2dd + seclen 512 + tracks 160 + sectrk 9 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 1 + os 3 +end + +#amstrad: values are read from super block (special name hardcoded) + +# Royal alphatronic +# setfdprm /dev/fd1 dd ssize=256 cyl=40 sect=16 head=2 +diskdef alpha + seclen 256 + tracks 40 + sectrk 32 + blocksize 2048 + maxdir 128 + skew 1 + boottrk 2 + os 2.2 +end + +# Apple II CP/M skew o Apple II DOS 3.3 skew +diskdef apple-do + seclen 256 + tracks 35 + sectrk 16 + blocksize 1024 + maxdir 64 + skew 0 + boottrk 3 + os 2.2 +end + +# Apple II CP/M skew o Apple II PRODOS skew +diskdef apple-po + seclen 256 + tracks 35 + sectrk 16 + blocksize 1024 + maxdir 64 + skew 0 + boottrk 3 + os 2.2 +end + +# MYZ80 hard drive (only works with libdsk, because it has a 256-byte header) +diskdef myz80 + seclen 1024 + tracks 64 + sectrk 128 + blocksize 4096 + maxdir 1024 + skew 1 + boottrk 0 + os 3 +end + +# Despite being Amstrad formats, CPC System and CPC Data don't have an Amstrad +# superblock. You'll need to use libdsk to access them because the Linux +# and Windows kernel drivers won't touch them. +diskdef cpcsys + seclen 512 + tracks 40 + sectrk 9 + blocksize 1024 + maxdir 64 + skew 1 + boottrk 2 + os 3 +end +diskdef cpcdata + seclen 512 + tracks 40 + sectrk 9 + blocksize 1024 + maxdir 64 + skew 1 + boottrk 0 + os 3 +end + +# after being read in with no sector skew. +diskdef nigdos + seclen 512 + # NigDos double sided disk format, 42 tracks * 2 sides + tracks 84 + sectrk 10 + blocksize 2048 + maxdir 128 + skew 1 + boottrk 0 + # this format wastes half of the directory entry + logicalextents 1 + os 3 +end + +diskdef epsqx10 + seclen 512 + tracks 40 + sectrk 20 + blocksize 2048 + maxdir 128 + skew 0 + boottrk 2 + os 2.2 +end + +diskdef ibm-8ss + seclen 512 + tracks 40 + sectrk 8 + blocksize 1024 + maxdir 64 + skew 0 + boottrk 1 + os 2.2 +end + +diskdef ibm-8ds + seclen 512 + tracks 40 + sectrk 8 + blocksize 1024 + maxdir 64 + skew 0 + boottrk 1 + os 2.2 +end + +diskdef electroglas + seclen 512 + tracks 80 + sectrk 10 + blocksize 2048 + maxdir 256 + skew 0 + boottrk 1 + os 3 +end + +# IBM CP/M-86 +# setfdprm /dev/fd1 sect=8 dtr=1 hd ssize=512 tpi=48 head=1 +diskdef ibmpc-514ss + seclen 512 + tracks 40 + sectrk 8 + blocksize 1024 + maxdir 64 + skew 1 + boottrk 1 + os 2.2 +end + +# IBM CP/M-86 +# setfdprm /dev/fd1 sect=8 dtr=1 hd ssize=512 tpi=48 +diskdef ibmpc-514ds + seclen 512 + tracks 80 + sectrk 8 + blocksize 2048 + maxdir 64 + skew 0 + boottrk 2 + os 2.2 +end + +diskdef p112 + seclen 512 + tracks 160 + sectrk 18 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 2 + os 3 +end + +diskdef p112-old + seclen 512 + tracks 160 + sectrk 18 + blocksize 2048 + maxdir 128 + skew 1 + boottrk 1 + os 3 +end + +diskdef kpii + seclen 512 + tracks 40 + sectrk 10 + blocksize 1024 + maxdir 32 + skew 0 + boottrk 1 + os 2.2 +end + +# setfdprm /dev/fd0 dd sect=10 +diskdef interak + seclen 512 + tracks 80 + sectrk 20 + blocksize 4096 + maxdir 256 + skew 1 + boottrk 2 + os 2.2 +end + +# For 512KB ROM, less 32K for system image +diskdef rom512KB + seclen 128 + tracks 14 + sectrk 256 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 0 + os 2.2 +end + +# For 1024KB ROM, less 32K for system image +diskdef rom1024KB + seclen 128 + tracks 30 + sectrk 256 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 0 + os 2.2 +end + +# For N8VEM mass storage (4 raw partitions) +diskdef hd0 + seclen 512 + tracks 65 + sectrk 256 + blocksize 4096 + maxdir 512 + skew 1 + boottrk 1 + os 2.2 +end + +diskdef hd1 + seclen 512 + tracks 130 + sectrk 256 + blocksize 4096 + maxdir 512 + skew 1 + boottrk 66 + os 2.2 +end + +diskdef hd2 + seclen 512 + tracks 195 + sectrk 256 + blocksize 4096 + maxdir 512 + skew 1 + boottrk 131 + os 2.2 +end + +diskdef hd3 + seclen 512 + tracks 260 + sectrk 256 + blocksize 4096 + maxdir 512 + skew 1 + boottrk 196 + os 2.2 +end diff --git a/trunk/Source/fd.asm b/trunk/Source/fd.asm new file mode 100644 index 00000000..95648af7 --- /dev/null +++ b/trunk/Source/fd.asm @@ -0,0 +1,1635 @@ +; +;================================================================================================== +; FLOPPY DISK DRIVER +;================================================================================================== +; +; TODO: +; +; +; PORTS +; +#IF ((FDMODE == FDMODE_DIO) | (FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) +FDC_MSR: .EQU 036H ; 8272 MAIN STATUS REGISTER +FDC_DATA: .EQU 037H ; 8272 DATA PORT +FDC_DIR: .EQU 038H ; DATA INPUT REGISTER +FDC_DOR: .EQU 03AH ; DIGITAL OUTPUT REGISTER (LATCH) +FDC_DMA: .EQU 03CH ; PSEUDO DMA DATA PORT +#ENDIF +#IF (FDMODE == FDMODE_DIDE) +FDC_BID: .EQU 00100000B ; IO RANGE 20H-3FH +FDC_MSR: .EQU FDC_BID | 01010B ; 8272 MAIN STATUS REGISTER +FDC_DATA: .EQU FDC_BID | 01011B ; 8272 DATA PORT +FDC_DOR: .EQU FDC_BID | 01100B ; DOR +FDC_DCR: .EQU FDC_BID | 01101B ; DCR +FDC_DACK: .EQU FDC_BID | 11100B ; DACK +FDC_TC .EQU FDC_BID | 11101B ; TERMINAL COUNT (W/ DACK) +FDC_DMA: .EQU 03CH ; NOT USED BY DIDE +#ENDIF +#IF (FDMODE == FDMODE_N8) +FDC_MSR: .EQU 08CH ; 8272 MAIN STATUS REGISTER +FDC_DATA: .EQU 08DH ; 8272 DATA PORT +FDC_DOR: .EQU 092H ; DOR +FDC_DCR: .EQU 091H ; DCR +FDC_DACK: .EQU 090H ; DACK +FDC_TC .EQU 093H ; TERMINAL COUNT (W/ DACK) +FDC_DMA: .EQU 03CH ; NOT USED BY N8 +#ENDIF +; +; FDC RESULT CODES +; +FRC_OK .EQU 0 ; 00 +FRC_NOTIMPL .EQU -01H ; FF +FRC_CMDERR .EQU -02H ; FE +FRC_ERROR .EQU -03H ; FD +FRC_ABORT .EQU -04H ; FC +FRC_BUFMAX .EQU -05H ; FB +FRC_ABTERM .EQU -08H ; F8 +FRC_INVCMD .EQU -09H ; F7 +FRC_DSKCHG .EQU -0AH ; F6 +FRC_ENDCYL .EQU -0BH ; F5 +FRC_DATAERR .EQU -0CH ; F4 +FRC_OVERRUN .EQU -0DH ; F3 +FRC_NODATA .EQU -0EH ; F2 +FRC_NOTWRIT .EQU -0FH ; F1 +FRC_MISADR .EQU -10H ; F0 +FRC_TOFDCRDY .EQU -11H ; EF +FRC_TOSNDCMD .EQU -12H ; EE +FRC_TOGETRES .EQU -13H ; ED +FRC_TOEXEC .EQU -14H ; EC +FRC_TOSEEKWT .EQU -15H ; EB +; +#IF (FDTRACE > 0) +; +; FDC STATUS CODE STRINGS +; +FSS_OK .TEXT "OK$" +FSS_NOTIMPL .TEXT "NOT IMPLEMENTED$" +FSS_CMDERR .TEXT "COMMAND ERROR$" +FSS_ERROR .TEXT "ERROR$" +FSS_ABORT .TEXT "ABORT$" +FSS_BUFMAX .TEXT "BUFFER EXCEEDED$" +FSS_ABTERM .TEXT "ABNORMAL TERMINATION$" +FSS_INVCMD .TEXT "INVALID COMMAND$" +FSS_DSKCHG .TEXT "DISK CHANGE$" +FSS_ENDCYL .TEXT "END OF CYLINDER$" +FSS_DATAERR .TEXT "DATA ERROR$" +FSS_OVERRUN .TEXT "OVERRUN$" +FSS_NODATA .TEXT "NO DATA$" +FSS_NOTWRIT .TEXT "NOT WRITABLE$" +FSS_MISADR .TEXT "MISSING ADDRESS MARK$" +FSS_TOFDCRDY .TEXT "FDC READY TIMEOUT$" +FSS_TOSNDCMD .TEXT "SENDCMD TIMEOUT$" +FSS_TOGETRES .TEXT "GET RESULTS TIMEOUT$" +FSS_TOEXEC .TEXT "EXEC TIMEOUT$" +FSS_TOSEEKWT .TEXT "SEEK WAIT TIMEOUT$" +; +; FDC STATUS STRING TABLE +; +FSST: .DB FRC_OK \ .DW FSS_OK +FSST_ENTSIZ .EQU $ - FSST + .DB FRC_NOTIMPL \ .DW FSS_NOTIMPL + .DB FRC_CMDERR \ .DW FSS_CMDERR + .DB FRC_ERROR \ .DW FSS_ERROR + .DB FRC_ABORT \ .DW FSS_ABORT + .DB FRC_BUFMAX \ .DW FSS_BUFMAX + .DB FRC_ABTERM \ .DW FSS_ABTERM + .DB FRC_INVCMD \ .DW FSS_INVCMD + .DB FRC_DSKCHG \ .DW FSS_DSKCHG + .DB FRC_ENDCYL \ .DW FSS_ENDCYL + .DB FRC_DATAERR \ .DW FSS_DATAERR + .DB FRC_OVERRUN \ .DW FSS_OVERRUN + .DB FRC_NODATA \ .DW FSS_NODATA + .DB FRC_NOTWRIT \ .DW FSS_NOTWRIT + .DB FRC_MISADR \ .DW FSS_MISADR + .DB FRC_TOFDCRDY \ .DW FSS_TOFDCRDY + .DB FRC_TOSNDCMD \ .DW FSS_TOSNDCMD + .DB FRC_TOGETRES \ .DW FSS_TOGETRES + .DB FRC_TOEXEC \ .DW FSS_TOEXEC + .DB FRC_TOSEEKWT \ .DW FSS_TOSEEKWT +FSST_COUNT .EQU (($ - FSST) / FSST_ENTSIZ) ; # ENTRIES IN TABLE +#ENDIF +; +; FDC COMMANDS +; +CMD_READ .EQU 00000110B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N +CMD_READDEL .EQU 00001100B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N +CMD_WRITE .EQU 00000101B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N +CMD_WRITEDEL .EQU 00001001B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N +CMD_READTRK .EQU 00000010B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,DTL --> ST0,ST1,ST2,C,H,R,N +CMD_READID .EQU 00001010B ; CMD,HDS/DS --> ST0,ST1,ST2,C,H,R,N +CMD_FMTTRK .EQU 00001101B ; CMD,HDS/DS,N,SC,GPL,D --> ST0,ST1,ST2,C,H,R,N +CMD_SCANEQ .EQU 00010001B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,STP --> ST0,ST1,ST2,C,H,R,N +CMD_SCANLOEQ .EQU 00011001B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,STP --> ST0,ST1,ST2,C,H,R,N +CMD_SCANHIEQ .EQU 00011101B ; CMD,HDS/DS,C,H,R,N,EOT,GPL,STP --> ST0,ST1,ST2,C,H,R,N +CMD_RECAL .EQU 00000111B ; CMD,DS --> +CMD_SENSEINT .EQU 00001000B ; CMD --> ST0,PCN +CMD_SPECIFY .EQU 00000011B ; CMD,SRT/HUT,HLT/ND --> +CMD_DRVSTAT .EQU 00000100B ; CMD,HDS/DS --> ST3 +CMD_SEEK .EQU 00001111B ; CMD,HDS/DS --> +CMD_VERSION .EQU 00010000B ; CMD --> ST0 +; +; STATIC CONFIGURATION, NEVER CHANGES (PRIVATE) +; +FCD_MT .EQU 000H ; MULTI-TRACK, WE DON'T USE, SET TO 0 +FCD_MFM .EQU 001H ; MFM, 0=FM, 1=MFM, WE USE MFM ALWAYS +FCD_SK .EQU 000H ; SKIP MODE, WE DON'T USE, SET TO 0 +FCD_N .EQU 002H ; SECTOR SIZE, N=2 FOR 512 BYTES +FCD_DTL .EQU 0FFH ; DATA LENGTH (WHEN N=0, SET TO FF OTHERWISE) +FCD_STP .EQU 001H ; SECTOR SCAN TYPE, 1=CONTIG, 2=ALTERNATING +; +FCD_PC720 .DB 050H ; NUMBER OF CYLINDERS + .DB 002H ; NUMBER OF HEADS + .DB 009H ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) + .DB 009H ; SECTOR COUNT + .DW 200H ; SECTOR SIZE IN BYTES + .DB 02AH ; GAP LENGTH (R/W) + .DB 050H ; GAP LENGTH (FORMAT) + .DB 0DFH ; SRT/HUT: STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME + .DB 005H ; HLT/ND: HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT + .DB DOR_BR250 ; DOR + .DB DCR_BR250 ; DCR + .IF (($ - FCD_PC720) != FCD_LEN) + .ECHO "*** FCD_PC720 SIZE ERROR!!! ***\n" + .ENDIF +; +FCD_PC144 .DB 050H ; NUMBER OF CYLINDERS + .DB 002H ; NUMBER OF HEADS + .DB 012H ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) + .DB 012H ; SECTOR COUNT + .DW 200H ; SECTOR SIZE IN BYTES + .DB 01BH ; GAP LENGTH (R/W) + .DB 06CH ; GAP LENGTH (FORMAT) + .DB 0DFH ; SRT/HUT: STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME + .DB 009H ; HLT/ND: HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT + .DB DOR_BR500 ; DOR + .DB DCR_BR500 ; DCR + .IF (($ - FCD_PC144) != FCD_LEN) + .ECHO "*** FCD_PC144 SIZE ERROR!!! ***\n" + .ENDIF +; +FCD_PC360 .DB 028H ; NUMBER OF CYLINDERS + .DB 002H ; NUMBER OF HEADS + .DB 009H ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) + .DB 009H ; SECTOR COUNT + .DW 200H ; SECTOR SIZE IN BYTES + .DB 02AH ; GAP LENGTH (R/W) + .DB 050H ; GAP LENGTH (FORMAT) + .DB 0DFH ; SRT/HUT: STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME + .DB 005H ; HLT/ND: HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT + .DB DOR_BR250 ; DOR + .DB DCR_BR250 ; DCR + .IF (($ - FCD_PC360) != FCD_LEN) + .ECHO "*** FCD_PC360 SIZE ERROR!!! ***\n" + .ENDIF +; +FCD_PC120 .DB 050H ; NUMBER OF CYLINDERS + .DB 002H ; NUMBER OF HEADS + .DB 00FH ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) + .DB 00FH ; SECTOR COUNT + .DW 200H ; SECTOR SIZE IN BYTES + .DB 01BH ; GAP LENGTH (R/W) + .DB 054H ; GAP LENGTH (FORMAT) + .DB 0DFH ; SRT/HUT: STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME + .DB 009H ; HLT/ND: HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT + .DB DOR_BR500 ; DOR + .DB DCR_BR500 ; DCR + .IF (($ - FCD_PC120) != FCD_LEN) + .ECHO "*** FCD_PC120 SIZE ERROR!!! ***\n" + .ENDIF +; +FCD_PC111 .DB 04AH ; NUMBER OF CYLINDERS + .DB 002H ; NUMBER OF HEADS + .DB 00FH ; NUMBER OF SECTORS + .DB 001H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) + .DB 00FH ; SECTOR COUNT + .DW 200H ; SECTOR SIZE IN BYTES + .DB 01BH ; GAP LENGTH (R/W) + .DB 054H ; GAP LENGTH (FORMAT) + .DB 0DFH ; SRT/HUT: STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME + .DB 009H ; HLT/ND: HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT + .DB DOR_BR500 ; DOR + .DB DCR_BR500 ; DCR + .IF (($ - FCD_PC111) != FCD_LEN) + .ECHO "*** FCD_PC111 SIZE ERROR!!! ***\n" + .ENDIF +; +; FCD LOOKUP TABLE (CALLED TO SET HL TO ADDRESS OF MEDIA DATA ABOVE) +; ENTRIES BELOW MUST MATCH COUNT AND VALUES OF FDMXXX IN STD.ASM +; +FCD_TBL: + LD HL,FCD_PC720 \ RET ; FDM720 = 0 + LD HL,FCD_PC144 \ RET ; FDM144 = 1 + LD HL,FCD_PC360 \ RET ; FDM360 = 2 + LD HL,FCD_PC120 \ RET ; FDM120 = 3 + LD HL,FCD_PC111 \ RET ; FDM111 = 4 +; +; DOR BITS (3AH) +; +; DISKIO 250KBPS 500KBPS +; ------- ------- ------- +;D7 /DC/RDY 1 (N/A) 1 (N/A) +;D6 /REDWC (DENSITY) 0 (DD) 1 (HD) +;D5 P0* (PRECOMP BIT 0) 1 \ 0 \ +;D4 P1* (PRECOMP BIT 1) 0 (125NS) 1 (125NS) +;D3 P2* (PRECOMP BIT 2) 0 / 0 / +;D2 MINI (BITRATE) 1 (250KBPS) 0 (500KBPS) +;D1 /MOTOR (ACTIVE LO) 1 (OFF) 1 (OFF) +;D0 TC (TERMINAL COUNT) 0 (OFF) 0 (OFF) +; +; *NOTE: FOR 9229 DATA SEPARATOR USED IN DISKIO, VALUE OF PRECOMP BITS CHANGES WITH MINI +; IF MINI=1 (250KBPS), USE 001 FOR 125NS PRECOMP, IF MINI=0, USE 010 FOR 125NS PRECOMP +; +#IF (FDMODE == FDMODE_DIO) +DOR_BR250 .EQU 10100100B ; 250KBPS W/ MOTOR ON +DOR_BR500 .EQU 11010000B ; 500KBPS W/ MOTOR ON +DOR_INIT .EQU 11010010B ; INITIAL DEFAULT LATCH VALUE +#ENDIF +; +; ZETA/DISKIO3 250KBPS 500KBPS +; ------------ ------- ------- +;D7 /FDC_RST 1 (RUN) 1 (RUN) +;D6 DENSEL 1 (DD) 0 (HD) +;D5 P0 (PRECOMP BIT 0) 1 \ 1 \ +;D4 P1 (PRECOMP BIT 1) 0 (125NS) 0 (125NS) +;D3 P2 (PRECOMP BIT 2) 0 / 0 / +;D2 MINI (BITRATE) 1 (250KBPS) 0 (500KBPS) +;D1 MOTOR 0 (OFF) 0 (OFF) +;D0 TC 0 (OFF) 0 (OFF) +; +; MOTOR AND DENSITY SELECT ARE INVERTED ON ZETA/DISKIO3 +; +#IF ((FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) +DOR_BR250 .EQU 11100110B ; 250KBPS W/ MOTOR ON +DOR_BR500 .EQU 10100010B ; 500KBPS W/ MOTOR ON +DOR_INIT .EQU 10100000B ; INITIAL DEFAULT LATCH VALUE +#ENDIF +; +; *** DIDE/N8 *** +; +#IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8)) +DOR_INIT .EQU 00001100B ; SOFT RESET INACTIVE, DMA ENABLED +DOR_BR250 .EQU DOR_INIT +DOR_BR500 .EQU DOR_INIT +#ENDIF +; +; DCR (ONLY APPLIES TO DIDE AND N8) +; +DCR_BR250 .EQU 01H ; 250KBPS +DCR_BR500 .EQU 00H ; 500KBPS +; +#IF (FDTRACE > 0) +; +; FDC COMMAND STRINGS +; +FCS_NOP: .TEXT "NOP$" +FCS_READ: .TEXT "READ$" +FCS_READDEL: .TEXT "READDEL$" +FCS_WRITE: .TEXT "WRITE$" +FCS_WRITEDEL: .TEXT "WRITEDEL$" +FCS_READTRK: .TEXT "READTRK$" +FCS_READID: .TEXT "READID$" +FCS_FMTTRK: .TEXT "FMTTRK$" +FCS_SCANEQ: .TEXT "SCANEQ$" +FCS_SCANLOEQ: .TEXT "SCANLOEQ$" +FCS_SCANHIEQ: .TEXT "SCANHIEQ$" +FCS_RECAL: .TEXT "RECAL$" +FCS_SENSEINT: .TEXT "SENSEINT$" +FCS_SPECIFY: .TEXT "SPECIFY$" +FCS_DRVSTAT: .TEXT "DRVSTAT$" +FCS_SEEK: .TEXT "SEEK$" +FCS_VERSION: .TEXT "VER$" +; +; FDC COMMAND TABLE +; +FCT .DB CMD_READ \ .DW FCS_READ +FCT_ENTSIZ .EQU $ - FCT + .DB CMD_READDEL \ .DW FCS_READDEL + .DB CMD_WRITE \ .DW FCS_WRITE + .DB CMD_WRITEDEL \ .DW FCS_WRITEDEL + .DB CMD_READTRK \ .DW FCS_READTRK + .DB CMD_READID \ .DW FCS_READID + .DB CMD_FMTTRK \ .DW FCS_FMTTRK + .DB CMD_SCANEQ \ .DW FCS_SCANEQ + .DB CMD_SCANLOEQ \ .DW FCS_SCANLOEQ + .DB CMD_SCANHIEQ \ .DW FCS_SCANHIEQ + .DB CMD_RECAL \ .DW FCS_RECAL + .DB CMD_SENSEINT \ .DW FCS_SENSEINT + .DB CMD_SPECIFY \ .DW FCS_SPECIFY + .DB CMD_DRVSTAT \ .DW FCS_DRVSTAT + .DB CMD_SEEK \ .DW FCS_SEEK + .DB CMD_VERSION \ .DW FCS_VERSION +FCT_COUNT .EQU (($ - FCT) / FCT_ENTSIZ) ; # ENTRIES IN TABLE +#ENDIF +; +; +; +FD_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F + JR Z,FD_RD + DEC A + JR Z,FD_WR + DEC A + JR Z,FD_ST + DEC A + JR Z,FD_MED + CALL PANIC +; +FD_RD: + JP FD_READ +FD_WR: + JP FD_WRITE +FD_ST: + JP FD_STATUS +FD_MED: + JP FD_MEDIA +; +; FD_MEDIA +; +FD_MEDIA: + CALL FD_SELECTUNIT + +#IF (FDMAUTO) + ; SETUP TO READ TRK 0, HD 0, SEC 0 + LD A,C ; C STILL HAS REQUESTED DRIVE + AND 0FH + LD (FCD_DS),A + LD A,0 + LD (FCD_C),A + LD (FCD_H),A + INC A + LD (FCD_R),A + LD A,DOP_READID + LD (FCD_DOP),A + +#IF (FDTRACE < 3) + ; SUPPRESS TRACING FOR MEDIA TESTS + LD A,0 + LD (FCD_TRACE),A +#ENDIF + + LD B,5 + +FD_MEDIARETRY: + ; TRY PRIMARY MEDIA CHOICE FIRST + LD A,FDMEDIA + CALL FD_TESTMEDIA + JR Z,FD_MEDIA3 ; IF SUCCESS, WE ARE DONE + + ; TRY ALTERNATE MEDIA CHOICE + LD A,FDMEDIAALT + CALL FD_TESTMEDIA + JR Z,FD_MEDIA3 ; IF SUCCESS, WE ARE DONE + + DJNZ FD_MEDIARETRY + + ; NO JOY, RETURN WITH A=0 (NO MEDIA) + XOR A + RET + +FD_TESTMEDIA: + LD HL,(FDDS_MEDIAADR) + LD (HL),A + PUSH BC + CALL FD_START + POP BC + RET + +FD_MEDIA3: + +#IF (FDTRACE < 3) + ; RESTORE TRACING FOR MEDIA TESTS + LD A,FDTRACE + LD (FCD_TRACE),A +#ENDIF +#ENDIF + +#IF (FDTRACE >= 3) + LD DE,FDSTR_SELECT + CALL WRITESTR + LD BC,(FDDS_MEDIAADR) + CALL PRTHEXWORD +#ENDIF + + ; LOAD THE MEDIA BYTE + LD HL,(FDDS_MEDIAADR) + LD A,(HL) + ADD A,MID_FD720 ; ASSUMES MID_ VALUES ARE IN SAME ORDER AS FDM VALUES + +#IF (FDTRACE >= 3) + CALL PC_SPACE + CALL PRTHEXBYTE +#ENDIF + RET +; +; FD_INIT +; +FD_INIT: + LD A,FDMEDIA + LD (FCD_U0MEDIA),A + LD (FCD_U1MEDIA),A + LD A,0FEH + LD (FCD_U0TRK),A + LD (FCD_U1TRK),A + + LD A,FDTRACE + LD (FCD_TRACE),A + + LD BC,0 + LD (FCD_IDLECNT),BC + + LD A,DOR_INIT + LD (FST_DOR),A + + CALL FC_RESETFDC + CALL FD_CLRDSKCHG + + LD A,TRUE + LD (FCD_FDCRDY),A + + RET +; +; FD_IDLE QUIESCES THE FLOPPY SUBSYSTEM (MOTOR OFF) +; AFTER BEING CALLED ENOUGH TIMES... +; SHOULD IT INVALIDATE THE BUFFER??? +; +FD_IDLE: + LD BC,(FCD_IDLECNT) + LD A,B + OR C + RET Z ; COUNTER ALREADY FIRED + + DEC BC ; DECREMENT COUNTER + LD (FCD_IDLECNT),BC ; SAVE IT + LD A,B + OR C + RET NZ ; STILL COUNTING DOWN, RETURN + + CALL FC_MOTOROFF ; COUNTER JUST EXPIRED, SHUTDOWN MOTOR! + RET +; +; FD_STATUS +; +FD_STATUS: + CALL FD_SELECTUNIT + LD HL,(FDDS_TRKADR) + LD A,(HL) ; A = CURRENT TRACK + + CP 0FFH ; IS CURRENT TRACK = $FF? + JR Z,FD_STATUS1 ; IF SO, NOT READY + + XOR A ; A = 0 = OK + RET ; RETURN + +FD_STATUS1: + OR A ; A ALREADY = $FF, JUST SET FLAGS + RET +; +; FD_CLRDSKCHG +; +FD_CLRDSKCHG: + ; PROCESS ANY PENDING DISK CHANGE NOTIFICATIONS + LD B,5 +FD_CLRDSKCHG1: + PUSH BC + CALL FC_SENSEINT + POP BC + LD A,(FST_RC) + CP FRC_DSKCHG + RET NZ ; NO MORE DISK CHANGE NOTIFICATIONS + DJNZ FD_CLRDSKCHG1 +; +; FD_WTSEEK +; +; WAIT FOR PENDING SEEK OPERATION TO COMPLETE BY POLLING SENSEINT +; AND WAITING FOR ABTERM OR OK. +; +FD_WTSEEK: + LD BC,1000H + +FD_WTSEEKLOOP: + PUSH BC + CALL FC_SENSEINT + POP BC + + LD A,(FST_RC) ; CHECK RC + CP FRC_ABTERM ; ABTERM = DONE/FAILED + JR Z,FD_RETRC + CP FRC_OK ; OK = DONE/SUCCESS + JR Z,FD_RETRC + + DEC BC ; CHECK LOOP COUNTER IN BC + LD A,B ; " + OR C ; " + JR NZ,FD_WTSEEKLOOP ; LOOP UNTIL COUNTER EXHAUSTED + +FD_RETRC: + LD A,(FST_RC) + OR A + RET ; TIMEOUT/FAILED +; +; FD_FDCRESET +; +FD_FDCRESET: + CALL FC_RESETFDC + + CALL FD_CLRDSKCHG + + LD A,TRUE + LD (FCD_FDCRDY),A + + ; MARK ALL DRIVES AS NEEDING RECALIBRATION + ; NOTE THAT IF THE VALUE IS CURRENT $FF, + ; WE NEED TO LEAVE IT ALONE, SO WE 'OR' IN THE + ; $FE TO AVOID THIS SCENARIO. + LD A,(FCD_U0TRK) + OR 0FEH + LD (FCD_U0TRK),A + + LD A,(FCD_U1TRK) + OR 0FEH + LD (FCD_U1TRK),A + + RET +; +; FD_DRIVERESET +; +; ATTEMPT TO FULLY RESET FLOPPY DRIVE, PRIMARILY RECALIBRATE +; +FD_DRIVERESET: + CALL FC_SPECIFY + RET NZ ; ERROR, BAIL OUT + + CALL FC_RECAL + RET NZ ; ERROR, BAIL OUT + + ; FIRST RECAL MAY FAIL TO REACH TRACK 0 + ; SO WE TRY ONCE MORE IN CASE OF A FAILURE + CALL FD_WTSEEK + RET Z + + ; SECOND TRY, ONLY IF NEEDED + CALL FC_RECAL + RET NZ ; ERROR, BAIL OUT + + CALL FD_WTSEEK + RET +; +; +; +FD_SELECTUNIT: + LD A,C + AND 0FH ; ISOLATE THE UNIT NIBBLE + + ; GOOD PLACE FOR AN INTEGRITY CHECK + CP 2 + CALL NC,PANIC + + LD HL,FCD_UNITS + LD D,0 + AND 0FH + RLCA + LD E,A + ADD HL,DE + + LD (FDDS_TRKADR),HL ; LOAD TRKADR + INC HL ; SKIP TRK + LD (FDDS_MEDIAADR),HL ; LOAD MEDIAADR + + RET + +FD_READ: + LD A,DOP_READ + JR FD_RUN +; +FD_WRITE: + LD A,DOP_WRITE + JR FD_RUN +; +FD_RUN: + LD (FCD_DOP),A + + ; UPDATE DRIVE SELECTION + LD A,(HSTDSK) ; GET THE NEW DRIVE SELECTION + AND 0FH + LD (FCD_DS),A ; UPDATE FCD_DS TO NEW VALUE + LD C,A + CALL FD_SELECTUNIT + + ; MAP HSTTRK TO FCD_H, FCD_C + LD BC,(HSTTRK) + LD A,C ; HEAD IS LOW ORDER BIT + AND 1 ; ISOLATE IT + LD (FCD_H),A ; SAVE IT + LD A,C ; LOAD TRACK IN A + SRL A ; DIVIDE BY 2 FOR PHYSICAL TRACK + LD (FCD_C),A ; SAVE IT + + ; MAP HSTSEC TO FCD_R + LD BC,(HSTSEC) + LD A,C + INC A ; SWITCH FROM ZERO BASED TO ONE BASED + LD (FCD_R),A + + ; SET RETRY COUNTER + LD B,5 +FD_RETRY: + PUSH BC + CALL FD_START + POP BC + + LD A,(FST_RC) ; CHECK RESULT + OR A + RET Z ; SUCCESS + + DJNZ FD_RETRY ; RETRY TILL COUNTER EXHAUSTED + +#IF (FDTRACE == 1) + CALL FC_PRTRESULTS +#ENDIF + + LD A,(FST_RC) + OR A ; OTHERWISE SET FLAGS BASED ON RC (IN A) + RET ; AND GIVE UP +; +; +; +FD_START: + LD A,(FCD_FDCRDY) + CP TRUE + CALL NZ,FD_FDCRESET + + ; COPY MEDIA CONFIG INTO FCD + ; THIS IS HERE TO ACCOMMODATE DIFFERENT MEDIA + ; IN DIFFERENT FLOPPY UNITS. + LD HL,(FDDS_MEDIAADR) + LD A,(HL) ; A = MEDIA BYTE + RLCA ; TABLE IS 4 BYTE ENTRIES + RLCA ; A = A * 4 + LD HL,FCD_TBL ; HL = START OF TABLE + LD D,0 ; SET DE TO TABLE OFFSET + LD E,A + ADD HL,DE ; OFFSET BASED ON DESIRED MEDIA + CALL JPHL ; CALL THE TABLE ENTRY (SEE FCD_TBL) + LD DE,FCD ; DE = DESTINATION + LD BC,FCD_LEN ; BC = BYTES TO COPY + LDIR ; BYTES COPY FROM MDB TO FCD + + CALL FC_MOTORON ; INCLUDES LATCH SETUP + + LD HL,(FDDS_TRKADR) + LD A,(HL) + CP 0FEH ; FF = DRIVE NEEDS TO BE RESET + JR C,FD_RUN0 ; NO RESET NEEDED, BYPASS + + CALL FD_DRIVERESET + JR NZ,FD_RUNERR + + ; RECORD CURRENT TRACK POSITION + LD A,0 + LD HL,(FDDS_TRKADR) + LD (HL),A + +FD_RUN0: + ; COMPARE CURRENT TRACK WITH REQUESTED TRACK TO SEE IF SEEK NEEDED + LD HL,(FDDS_TRKADR) + LD A,(HL) + LD B,A + LD A,(FCD_C) + CP B + JR Z,FD_RUN1 ; FDDS_TRKADR == FCD_C, SKIP SEEK + + ; INITIATE SEEK TO NEW TRACK + CALL FC_SEEK + JR NZ,FD_RUNERR + + ; WAIT FOR SEEK TO COMPLETE + CALL FD_WTSEEK + JR NZ,FD_RUNERR + + ; RECORD NEW CURRENT TRACK + LD A,(FCD_C) + LD HL,(FDDS_TRKADR) + LD (HL),A + +FD_RUN1: + ; GET THE REQUESTED OPERATION + LD A,(FCD_DOP) + + ; SETUP RETURN ADDRESS + LD HL,FD_RUNCHK + PUSH HL + + ; DISPATCH TO FUNCTION + CP DOP_READ + JR Z,FC_READ + CP DOP_WRITE + JR Z,FC_WRITE + CP DOP_READID + JR Z,FC_READID + CALL PANIC + +FD_RUNCHK: +#IF (DSKYENABLE) + CALL FD_DSKY +#ENDIF + +FD_RUNEXIT: + LD A,(FST_RC) + OR A + RET Z + +FD_RUNERR: + ; INDICATE THAT A CONTROLLER RESET IS DESIRED + LD A,FALSE + LD (FCD_FDCRDY),A + + ; FLAG DRIVE IN ERROR STATUS BY SETTING TRKADR == FF + LD A,0FFH + LD HL,(FDDS_TRKADR) + LD (HL),A + + JP FD_RETRC + +#IF (DSKYENABLE) +FD_DSKY: + LD HL,DSKY_HEXBUF + LD A,(FCD_C) + LD (HL),A + INC HL + LD A,(FCD_R) + LD (HL),A + INC HL + LD A,(FRB_ST0) + LD (HL),A + INC HL + LD A,(FRB_ST1) + LD (HL),A + CALL DSKY_HEXOUT + RET +#ENDIF +; +;=============================================================================== +; FLOPPY DISK CONTROL SERVICES (PHYSICAL DEVICE CONTROL FOR FDC HARDWARE) +;=============================================================================== +; +; ENTRY POINTS FOR FDC COMMANDS +; +FC_READ: + LD A,CMD_READ | 11100000B + CALL FC_SETUPIO + JP FOP + +FC_WRITE: + LD A,CMD_WRITE | 11000000B + CALL FC_SETUPIO + JP FOP + +FC_READID: + LD A,CMD_READID | 01000000B + CALL FC_SETUPCMD + JP FOP + +FC_RECAL: + LD A,CMD_RECAL | 00000000B + CALL FC_SETUPCMD + JP FOP ; FIX: DO WE NEED TO REMOVE HDS BITS FROM SECOND BYTE? + +FC_SENSEINT: + LD A,CMD_SENSEINT | 00000000B + CALL FC_SETUPCMD + LD A,1 ; GENERIC COMMAND, BUT JUST FIRST COMMAND CODE + LD (FCP_LEN),A + JP FOP + +FC_SPECIFY: + LD A,CMD_SPECIFY | 00000000B + CALL FC_SETUPSPECIFY + JP FOP + +FC_DRVSTAT: + LD A,CMD_DRVSTAT | 00000000B + CALL FC_SETUPCMD + JP FOP + +FC_SEEK: + LD A,CMD_SEEK | 00000000B + CALL FC_SETUPSEEK + JP FOP +; +; HELPER FUNCTIONS TO SETUP CMDBUF +; +FC_SETUPCMD: + ; TRICKY... THE INCOMING BYTE IN A MUST CONTAIN THE COMMAND CODE ITSELF + ; IN THE LOW 5 BITS PLUS IT MUST SET WHICH OF THE DESIRED BITS IT WANTS + ; IN THE HIGH 3 BITS. WE 'AND' THIS WITH THE TEMPATE BITS TO PRODUCE + ; THE CORRECT FINAL COMMAND BYTE + LD DE,FCP_BUF + AND 5FH ; MT=0, MFM=1, SK=0, CMD=11111 + LD (DE),A ; SAVE THE BYTE + AND 00011111B ; ISOLATE JUST THE COMMAND BITS + LD (FCP_CMD),A ; SAVE IT FOR LATER + INC DE + + LD A,(FCD_H) ; START WITH HDS + AND 01H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY + RLCA ; MAKE ROOM FOR DS BITS + RLCA ; + LD B,A ; SAVE WHAT WE HAVE SO FAR IN B + LD A,(FCD_DS) ; GET DS VALUE + AND 03H ; MASK TO REMOVE IRRELEVANT BITS FOR SAFETY + OR B ; COMBINE WITH SAVED + LD (DE),A ; SAVE THE BYTE + INC DE + + LD A,2 ; LENGTH IS 2 BYTES AT THIS POINT + LD (FCP_LEN),A + + RET + +FC_SETUPIO: + CALL FC_SETUPCMD + + LD A,(FCD_C) + LD (DE),A + INC DE + + LD A,(FCD_H) + LD (DE),A + INC DE + + LD A,(FCD_R) + LD (DE),A + INC DE + + LD A,FCD_N + LD (DE),A + INC DE + + LD A,(FCD_EOT) + LD (DE),A + INC DE + + LD A,(FCD_GPL) + LD (DE),A + INC DE + + LD A,FCD_DTL + LD (DE),A + INC DE + + LD A,9 + LD (FCP_LEN),A + + RET + +FC_SETUPSEEK: + CALL FC_SETUPCMD ; START WITH GENERIC IO CMD + + LD A,(FCD_C) + LD (DE),A + INC DE + + LD A,3 + LD (FCP_LEN),A + + RET + +FC_SETUPSPECIFY: + CALL FC_SETUPCMD + DEC DE ; BACKUP 1 BYTE, WE ONLY WANT FIRST BYTE + + LD A,(FCD_SRTHUT) + LD (DE),A ; SAVE THE BYTE + INC DE + + LD A,(FCD_HLTND) + LD (DE),A ; SAVE THE BYTE + INC DE + + LD A,3 + LD (FCP_LEN),A + + RET +; +; SET FST_DOR +; +FC_SETDOR + LD (FST_DOR),A + OUT (FDC_DOR),A +#IF (FDTRACE >= 3) + CALL NEWLINE + LD DE,FDSTR_DOR + CALL WRITESTR + LD DE,FDSTR_ARROW + CALL WRITESTR + CALL PC_SPACE + LD A,(FST_DOR) + CALL PRTHEXBYTE +#ENDIF + RET +; +; RESET FDC BY PULSING BIT 7 OF LATCH LOW +; +FC_RESETFDC: +#IF (FDTRACE >= 3) + LD DE,FDSTR_RESETFDC + CALL WRITESTR +#ENDIF + LD A,(FST_DOR) + PUSH AF + +#IF ((FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) + RES 7,A +#ENDIF +#IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8)) + LD A,0 +#ENDIF + CALL FC_SETDOR + CALL DELAY + POP AF + CALL FC_SETDOR + + LD DE,100 ; DELAY: 25us * 100 = 2.5ms + CALL VDELAY + RET +; +; PULSE TERMCT TO TERMINATE ANY ACTIVE EXECUTION PHASE +; +FC_PULSETC: +#IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8)) + IN A,(FDC_TC) +#ELSE + LD A,(FST_DOR) + SET 0,A + OUT (FDC_DOR),A + RES 0,A + OUT (FDC_DOR),A +#ENDIF + RET +; +; SET FST_DOR FOR MOTOR CONTROL ON +; +FC_MOTORON: +; LD BC,300H + LD BC,10H + LD (FCD_IDLECNT),BC + +#IF (FDTRACE >= 3) + LD DE,FDSTR_MOTON + CALL WRITESTR +#ENDIF +#IF ((FDMODE == FDMODE_DIO) | (FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) + LD A,(FST_DOR) + PUSH AF + + LD A,(FCD_DOR) ; GET NEW LATCH VALUE (W/ MOTOR ON) + CALL FC_SETDOR ; AND IMPLEMENT IT + + POP AF +#IF ((FDMODE == FDMODE_ZETA) | (FDMODE == FDMODE_DIO3)) + XOR 00000010B ; MOTOR BIT INVERTED ON ZETA +#ENDIF + BIT 1,A ; SET FLAGS SET BASED ON CURRENT MOTOR BIT + RET Z ; MOTOR WAS PREVIOUSLY ON, WE ARE DONE +#ENDIF +#IF ((FDMODE == FDMODE_DIDE) | (FDMODE == FDMODE_N8)) + ; SETUP DCR FOR DIDE HARDWARE + LD A,(FCD_DCR) + OUT (FDC_DCR),A + + LD HL,FST_DOR ; POINT TO FDC_DOR + LD A,(HL) ; START WITH CURRENT DOR + PUSH AF + AND 11111100B ; GET RID OF ANY ACTIVE DS BITS + LD C,A ; SAVE IT FOR NOW + LD A,(FCD_DS) ; NOW GET CURRENT DS + LD B,A ; PUT IN B FOR LATER + OR C ; COMBINE WITH SAVED DOR + LD C,A ; RE-SAVE IT + INC B ; SET UP B AS LOOP COUNTER (DS + 1) + LD A,00001000B ; STARTING BIT PATTERN FOR MOTOR +FC_MOTORON1: + RLA ; SHIFT LEFT + DJNZ FC_MOTORON1 ; DS TIMES + OR C ; COMBINE WITH SAVED + LD (HL),A ; COMMIT THE NEW VALUE TO FST_DOR + CALL FC_SETDOR ; OUTPUT TO CONTROLLER + + LD C,A + POP AF + CP C + RET Z ; MOTOR WAS PREVIOUSLY ON +#ENDIF + +#IF (FDTRACE >= 3) + LD DE,FDSTR_MOTDELAY + CALL WRITESTR +#ENDIF + CALL LDELAY ; DELAY FOR MOTOR SPINUP IF NOT PREVIOUSLY ON + RET +; +; SET FST_DOR FOR MOTOR CONTROL OFF +; +FC_MOTOROFF: + LD A,(FCD_FDCRDY) + CP TRUE + CALL NZ,FD_FDCRESET + + LD A,DOR_INIT + CALL FC_SETDOR ; OUTPUT TO CONTROLLER + +#IF (FDTRACE >= 3) + LD DE,FDSTR_MOTOFF + CALL WRITESTR +#ENDIF + RET +; +;=============================================================================== +; FDC OPERATIONS +;=============================================================================== +; +FOP: +; +; INITIALIZATION +; + LD A,0 + LD (FRB_LEN),A + + LD A,FRC_OK + LD (FST_RC),A +; +; CLEAR FDC, DISCARD ANY PENDING BYTES (GARBAGE?) +; + LD B,0 ; B IS LOOP COUNTER +FOP_CLR1: + CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR + IN A,(FDC_MSR) ; GET STATUS + AND 0C0H ; ISOLATE HIGH NIBBLE, RQM/DIO/NDM/CB + CP 0C0H ; LOOKING FOR RQM=1, DIO=1, BYTES PENDING + JR NZ,FOP_CMD1 ; NO BYTES PENDING, GO TO NEXT PHASE + IN A,(FDC_DATA) ; GET THE PENDING BYTE AND DISCARD + DJNZ FOP_CLR1 + JP FOP_TOFDCRDY ; OTHERWISE, TIMEOUT +; +; SEND COMMAND +; +FOP_CMD1: + LD HL,FCP_BUF + LD A,(FCP_LEN) + LD D,A ; D = CMD BYTES TO SEND + +FOP_CMD2: ; START OF LOOP TO SEND NEXT BYTE + LD B,0 ; B IS LOOP COUNTER + +FOP_CMD4: ; START OF STATUS LOOP, WAIT FOR FDC TO BE READY FOR BYTE + CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR + IN A,(FDC_MSR) ; READ MAIN STATUS REGISTER + AND 0C0H ; ISOLATE RQM/DIO + CP 080H ; LOOKING FOR RQM=1, DIO=0 (FDC READY FOR A BYTE) + JR Z,FOP_CMD6 ; GOOD, GO TO SEND BYTE + CP 0C0H ; HMMMM... RQM=1 & DIO=1, FDC WANTS TO SEND US DATA, UNEXPECTED + JR Z,FOP_RES ; GO IMMEDIATELY TO RESULTS??? + DJNZ FOP_CMD4 ; LOOP TILL COUNTER EXHAUSTED + JR FOP_TOSNDCMD ; COUNTER EXHAUSTED, TIMEOUT / EXIT + +FOP_CMD6: ; SEND NEXT BYTE + LD A,(HL) ; POINT TO NEXT BYTE TO SEND + OUT (FDC_DATA),A ; PUSH IT TO FDC + INC HL ; INCREMENT POINTER FOR NEXT TIME + DEC D ; DECREMENT NUM BYTES LEFT TO SEND + JR NZ,FOP_CMD2 ; DO NEXT BYTE +; +; EXECUTION PHASE +; +FOP_X1: + LD A,(FCP_CMD) + + LD HL,FOP_RES + PUSH HL + + CP CMD_READ + JP Z,FXR_READ + CP CMD_WRITE + JP Z,FXR_WRITE + CP CMD_READID + JP Z,FXR_NULL + RET ; RET ACTUALLY JUST JUMPS RIGHT TO FOP_RES +; +; RESULTS PHASE +; +FOP_RES: + LD HL,FRB ; POINT TO RECEIVE BUFFER + +FOP_RES0: + LD B,0 ; B IS LOOP COUNTER + +FOP_RES1: + CALL DELAY ; FDC MAY TAKE UP TO 12us TO UPDATE MSR + IN A,(FDC_MSR) ; READ MAIN STATUS REGISTER + AND 0F0H ; ISOLATE RQM/DIO/EXEC/BUSY + CP 0D0H ; LOOKING FOR RQM/DIO/BUSY + JR Z,FOP_RES2 ; GOOD, GO TO RECEIVE BYTE + CP 080H ; CHECK FOR RQM=1, DIO=0 (NOTHING LEFT) + JR Z,FOP_EVAL ; IF NOTHING LEFT, ALL DONE, GO TO EOD/EXIT + DJNZ FOP_RES1 ; LOOP TILL COUNTER EXHAUSTED + JR FOP_TOGETRES ; OTHERWISE TIMEOUT ERROR + +FOP_RES2: ; PROCESS NEXT PENDING BYTE + LD A,FRB_SIZ ; GET BUF SIZE + CP D ; REACHED MAX? + JR Z,FOP_BUFMAX ; HANDLE BUF MAX/EXIT + IN A,(FDC_DATA) ; GET THE BYTE + LD (HL),A ; SAVE VALUE + INC HL ; INCREMENT BUF POS + INC D ; INCREMENT BYTES RECEIVED + PUSH HL + LD HL,FRB_LEN ; POINT TO BUFFER LENGTH + LD (HL),D ; UPDATE NUMBER OF BYTES RECEIVED + POP HL + JR FOP_RES0 ; CONTINUE READ LOOP +; +; EXIT POINTS +; +FOP_NOTIMPL: + LD A,FRC_NOTIMPL + JR FOP_ERR + +FOP_CMDERR: + LD A,FRC_CMDERR + JR FOP_ERR + +FOP_ERROR: + LD A,FRC_ERROR + JR FOP_ERR + +FOP_ABORT: + LD A,FRC_ABORT + JR FOP_ERR + +FOP_BUFMAX: + LD A,FRC_BUFMAX + JR FOP_ERR + +FOP_TOFDCRDY: + LD A,FRC_TOFDCRDY + JR FOP_ERR + +FOP_TOSNDCMD: + LD A,FRC_TOSNDCMD + JR FOP_ERR + +FOP_TOGETRES: + LD A,FRC_TOGETRES + JR FOP_ERR + +FOP_TOEXEC: + LD A,FRC_TOEXEC + JR FOP_ERR + +FOP_ERR: + LD (FST_RC),A + +FOP_EVAL: + LD A,(FCP_CMD) + ; DRVSTAT IS WEIRD, HAS ONLY ST3, NOTHING TO EVAL + CP CMD_DRVSTAT + JR Z,FOP_EXIT + ; DO WE HAVE ST0? + LD A,(FRB_LEN) + CP 1 + JP M,FOP_EXIT + +FOP_EVALST0: + LD A,(FRB_ST0) + AND 11000000B + CP 01000000B ; ABTERM + JR Z,FOP_ABTERM + CP 10000000B ; INVCMD + JR Z,FOP_INVCMD + CP 11000000B ; DSKCHG + JR Z,FOP_DSKCHG + JR FOP_EXIT + +FOP_ABTERM: + ; SENSEINT DOES NOT USE ST1 + LD A,(FCP_CMD) + CP CMD_SENSEINT + JR Z,FOP_ABTERM1 + ; DO WE HAVE ST1? + LD A,(FRB_LEN) + CP 2 + JP M,FOP_ABTERM1 + JR FOP_EVALST1 +FOP_ABTERM1: ; NO FURTHER DATA, SET FST TO ABTERM + LD C,FRC_ABTERM + JR FOP_SETFST + +FOP_INVCMD: + LD C,FRC_INVCMD + JR FOP_SETFST + +FOP_DSKCHG: + LD C,FRC_DSKCHG + JR FOP_SETFST + +FOP_EVALST1: + LD A,(FRB_ST1) + + LD C,FRC_ENDCYL + BIT 7,A + JR NZ,FOP_SETFST + + LD C,FRC_DATAERR + BIT 5,A + JR NZ,FOP_SETFST + + LD C,FRC_OVERRUN + BIT 4,A + JR NZ,FOP_SETFST + + LD C,FRC_NODATA + BIT 2,A + JR NZ,FOP_SETFST + + LD C,FRC_NOTWRIT + BIT 1,A + JR NZ,FOP_SETFST + + LD C,FRC_MISADR + BIT 0,A + JR NZ,FOP_SETFST + + JR FOP_EXIT + +FOP_SETFST: + LD A,C + LD (FST_RC),A + +FOP_EXIT: +#IF (FDTRACE >= 2) + CALL FC_PRTRESULTS +#ENDIF + JP FD_RETRC +; +; EXECUTION ROUTINES +; +FXR_NOP: + RET +; +; NULL EXECUTION, NO DATA TO READ/WRITE (USED BY READID) +; +FXR_NULL: + LD BC,1000H ; BC IS LOOP COUNTER, 4096 ITERATIONS +FXR_NULL1: + CALL DELAY + IN A,(FDC_MSR) ; GET MSR + AND 0E0H ; ISOLATE RQM/DIO/NDM + CP 0C0H ; WE WANT RQM=1,DIO=1,NDM=0 (READY TO READ A BYTE W/ EXEC INACTIVE) + RET Z ; GOT IT, EXIT CLEAN W/O PULSING TC + DEC BC ; DECREMENT COUNTER (16 BIT) + LD A,B ; CHECK FOR ZERO + OR C ; " + JR NZ,FXR_NULL1 ; NOT ZERO YET, KEEP CHECKING + JP FXR_TO ; OTHERWISE, TIMEOUT ERROR + RET +; +; READ DATA +; +FXR_READ: + LD HL,(DIOBUF) ; POINT TO SECTOR BUFFER START + LD DE,(FCD_SECSZ) + LD A,(CPUFREQ + 3) / 4 + LD (FCD_TO),A +FXRR1 LD C,0 ; OUTER LOOP TIMEOUT COUNTER +FXRR2: LD B,0 ; SETUP FOR 256 ITERATIONS +FXRR3: IN A,(FDC_MSR) ; GET MSR + CP 0F0H ; WE WANT RQM=1,DIO=1,NDM=1,BUSY=1 (READY TO RECEIVE A BYTE W/ EXEC ACTIVE) + JR Z,FXRR4 ; GOT IT, DO BYTE READ + DJNZ FXRR3 ; NOT READY, LOOP IF COUNTER NOT ZERO + JR FXRR5 ; COUNTER ZERO, GO TO OUTER LOOP LOGIC + +FXRR4: IN A,(FDC_DATA) ; GET PENDING BYTE + LD (HL),A ; STORE IT IN BUFFER + INC HL ; INCREMENT THE BUFFER POINTER + DEC DE ; DECREMENT BYTE COUNT + LD A,D + OR E + JR NZ,FXRR2 ; IF NOT ZERO, REPEAT LOOP + JR FXR_END ; CLEAN EXIT + +FXRR5: ; OUTER LOOP, REALLY ONLY HAPPENS WHEN WAITING FOR FIRST BYTE OR ABORTED + CP 0C0H ; IF RQM=1, DIO=1, NDM=0 (EXECUTION ABORTED) + JR Z,FXR_ABORT ; BAIL OUT TO ERR ROUTINE, FIX: GO TO SPECIFIC ROUTINE FOR THIS??? + DEC C + JR NZ,FXRR2 ; IF NOT ZERO, LOOP SOME MORE + LD A,(FCD_TO) + DEC A + LD (FCD_TO),A + JR NZ,FXRR1 + JR FXR_TO ; OTHERWISE, TIMEOUT ERROR +; +; WRITE DATA +; +FXR_WRITE: + LD HL,(DIOBUF) ; POINT TO SECTOR BUFFER START + LD DE,(FCD_SECSZ) + LD A,(CPUFREQ + 3) / 4 + LD (FCD_TO),A +FXRW1 LD C,0 ; OUTER LOOP TIMEOUT COUNTER +FXRW2: LD B,0 ; SETUP FOR 256 ITERATIONS +FXRW3: IN A,(FDC_MSR) ; GET MSR + CP 0B0H ; WE WANT RQM=1,DIO=0,NDM=1,BUSY=1 (READY TO SEND A BYTE W/ EXEC ACTIVE) + JR Z,FXRW4 ; GOT IT, DO BYTE WRITE + DJNZ FXRW3 ; NOT READY, LOOP IF COUNTER NOT ZERO + JR FXRW5 ; COUNTER ZERO, GO TO OUTER LOOP LOGIC +FXRW4: LD A,(HL) ; GET NEXT BYTE TO WRITE + OUT (FDC_DATA),A ; WRITE IT + INC HL ; INCREMENT THE BUFFER POINTER + DEC DE ; DECREMENT LOOP COUNTER + LD A,D + OR E + JR NZ,FXRW2 ; IF NOT ZERO, REPEAT LOOP + JR FXR_END ; CLEAN EXIT +FXRW5: ; OUTER LOOP, REALLY ONLY HAPPENS WHEN WAITING FOR FIRST BYTE OR ABORTED + CP 0C0H ; IF RQM=1, DIO=1, NDM=0 (EXECUTION ABORTED) + JR Z,FXR_ABORT ; BAIL OUT TO ERR ROUTINE + DEC C + JR NZ,FXRW2 ; IF NOT ZERO, LOOP SOME MORE + LD A,(FCD_TO) + DEC A + LD (FCD_TO),A + JR NZ,FXRW1 + JR FXR_TO ; OTHERWISE, TIMEOUT ERROR +; +FXR_TO: + LD A,FRC_TOEXEC + JR FXR_ERR + +FXR_ABORT: + LD A,FRC_ABORT + JR FXR_ERR +; +; COMMON COMPLETION CODE FOR ALL EXECUTION ROUTINES +; +FXR_ERR: + LD (FST_RC),A + RET + +FXR_END: + CALL FC_PULSETC + RET + +#IF (FDTRACE > 0) +; +;=============================================================================== +; COMMAND PROCESSING STATUS DISPLAY +;=============================================================================== +; +; PRINT STATUS +; +FC_PRTFST: + PUSH AF + PUSH BC + PUSH DE + PUSH HL + LD A,(FST_RC) ; A GETS FST_RC + LD B,FSST_COUNT ; B GETS TABLE ENTRY COUNT + LD HL,FSST + LD DE,FSST_ENTSIZ ; TABLE ENTRY LENGTH + +FC_PRTFST0: ; START OF LOOP + LD C,(HL) + CP C + JR Z,FC_PRTFST1 ; FOUND CODE + + ADD HL,DE ; POINT TO NEXT ENTRY + DJNZ FC_PRTFST0 ; CHECK NEXT ENTRY TILL COUNT IS ZERO + + ; NO MATCHING ENTRY, PRINT THE HEX VALUE + CALL PC_SPACE + CALL PC_LBKT + CALL PRTHEXBYTE + CALL PC_RBKT + JR FC_PRTFSTX + +FC_PRTFST1: ; ENTRY FOUND, PRINT IT + CALL PC_SPACE + INC HL + LD E,(HL) + INC HL + LD D,(HL) + CALL PC_LBKT + CALL WRITESTR + CALL PC_RBKT + + +FC_PRTFSTX: + POP HL + POP DE + POP BC + POP AF + RET +; +; PRINT COMMAND +; +FC_PRTCMD: + PUSH AF + PUSH BC + PUSH DE + PUSH HL + LD A,(FCP_CMD) ; A GETS THE COMMAND CODE + LD B,FCT_COUNT ; B GETS TABLE ENTRY COUNT + LD HL,FCT + LD DE,FCT_ENTSIZ ; TABLE ENTRY LENGTH + +FCPC_LOOP: ; START OF LOOP + LD C,(HL) + CP C + JR Z,FCPC_MATCH ; FOUND CODE + + ADD HL,DE ; POINT TO NEXT ENTRY + DJNZ FCPC_LOOP ; CHECK NEXT ENTRY TILL COUNT IS ZERO + + ; NO MATCHING ENTRY, PRINT THE HEX VALUE + CALL PC_SPACE + CALL PC_LBKT + CALL PRTHEXBYTE + CALL PC_RBKT + JR FCPC_EXIT + +FCPC_MATCH: ; ENTRY FOUND, PRINT IT + INC HL + LD E,(HL) + INC HL + LD D,(HL) + CALL WRITESTR + +FCPC_EXIT: + POP HL + POP DE + POP BC + POP AF + RET +; +; PRINT RESULTS +; +FC_PRTRESULTS: + ; IF TRACE IS SET, FORCE PRINT RESULTS + LD A,(FCD_TRACE) + OR A + RET Z ; IF TRACE = 0, BE SILENT! + + CP 3 ; IS TRACE >= 3 ? + JR NC,FCPR2 ; YES, SO FORCE PRINT EVERYTHING! + + ; IF RC=OK, GET OUT, NOTHING TO PRINT + LD A,(FST_RC) + CP FRC_OK + RET Z + + ; SPECIAL CASE, DON'T PRINT IF SENSEINT & INVCMD/DSK CHG/ABTERM + LD A,(FCP_CMD) + CP CMD_SENSEINT + JR NZ,FCPR2 + + LD A,(FST_RC) + CP FRC_INVCMD + JR Z,FCPR_EXIT + CP FRC_DSKCHG + JR Z,FCPR_EXIT + CP FRC_ABTERM + JR Z,FCPR_EXIT + JR FCPR_EXIT + +FCPR2: + CALL NEWLINE + + LD DE,FDSTR_FD + CALL WRITESTR + CALL PC_COLON + CALL PC_SPACE + + CALL FC_PRTCMD + + LD A,(FCP_LEN) + LD DE,FCP_BUF + CALL PRTHEXBUF + + LD DE,FDSTR_ARROW + CALL WRITESTR + + LD A,(FRB_LEN) + LD DE,FRB + CALL PRTHEXBUF + + LD A,(FST_RC) + CALL FC_PRTFST + +FCPR_EXIT: + RET +; +; STRING CONSTANTS +; +FDSTR_ARROW .TEXT " -->$" +FDSTR_NORESP .TEXT "DRIVE NOT RESPONDING$" +FDSTR_FD .TEXT "FD$" +#IF (FDTRACE >= 3) +FDSTR_MOTON .TEXT "\r\nMOTOR ON$" +FDSTR_MOTOFF .TEXT "\r\nMOTOR OFF$" +FDSTR_MOTDELAY .TEXT "\r\nMOTOR DELAY$" +FDSTR_DOR .TEXT "DOR$" +FDSTR_RESETFDC .TEXT "\r\nRESET FDC$" +FDSTR_SELECT .TEXT "\r\nSELECT: $" +#ENDIF ; (FDTRACE >= 3) +#ENDIF ; (FDTRACE > 0) +; +; +;================================================================================================== +; FLOPPY DISK DRIVER - DATA +;================================================================================================== +; +; FDC COMMAND PHASE +; +FCP_CMD .DB 000H +FCP_LEN .DB 00H +FCP_BUF: +FCP_CMDX .DB 0 +FCP_HDSDS .DB 0 +FCP_C .DB 0 +FCP_H .DB 0 +FCP_R .DB 0 +FCP_N .DB 0 +FCP_EOT .DB 0 +FCP_GPL .DB 0 +FCP_DTL .DB 0 +FCP_BUFSIZ .EQU $-FCP_BUF +; +; FDC STATUS +; +FST_RC .DB 00H +FST_DOR .DB 00H +; +; FDC RESULTS BUFFER +; +FRB_LEN .DB 00H +FRB +FRB_ST0 +FRB_ST3 .DB 0 +FRB_ST1 +FRB_PCN .DB 0 +FRB_ST2 .DB 0 +FRB_C .DB 0 +FRB_H .DB 0 +FRB_R .DB 0 +FRB_N .DB 0 +FRB_SIZ .EQU $-FRB +; +; FDC COMMAND DATA +; +FCD: ; FLOPPY CONFIGURATION DATA (PUBLIC) MANAGED AS A "BLOCK" +FCD_NUMCYL .DB 000H ; NUMBER OF CYLINDERS +FCD_NUMHD .DB 000H ; NUMBER OF HEADS +FCD_NUMSEC .DB 000H ; NUMBER OF SECTORS +FCD_SOT .DB 000H ; START OF TRACK (ID OF FIRST SECTOR, USUALLY 1) +FCD_EOT ; END OF TRACK SECTOR (SAME AS SC SINCE SOT ALWAYS 1) +FCD_SC .DB 000H ; SECTOR COUNT +FCD_SECSZ .DW 000H ; SECTOR SIZE IN BYTES +FCD_GPL .DB 000H ; GAP LENGTH (R/W) +FCD_GPLF .DB 000H ; GAP LENGTH (FORMAT) +FCD_SRTHUT .DB 000H ; STEP RATE, IBM PS/2 CALLS FOR 3ms, 0DH = 3ms SRT, HEAD UNLOAD TIME +FCD_HLTND .DB 000H ; HEAD LOAD TIME, IBM PS/2 CALLS FOR 15ms 08H = 16ms HUT +FCD_DOR .DB 000H ; DOR VALUE +FCD_DCR .DB 000H ; DCR VALUE +FCD_LEN .EQU $ - FCD + ; DYNAMICALLY MANAGED (PUBLIC) +FCD_DS .DB 001H ; DRIVE SELECT (UNIT NUMBER 0-3) +FCD_C .DB 000H ; CYLINDER +FCD_H .DB 000H ; HEAD +FCD_R .DB 001H ; RECORD +FCD_D .DB 0E5H ; DATA FILL BYTE + ; STATUS MANAGEMENT +FCD_DOP .DB 0FFH ; CURRENT OPERATION (SEE DOP_...) +FCD_IDLECNT .DW 0 ; IDLE COUNT +FCD_TRACE .DB 0 ; TRACE LEVEL +FCD_TO .DB 0 ; TIMEOUT COUNTDOWN TIMER +FCD_FDCRDY .DB 0 ; FALSE MEANS FDC RESET NEEDED +; +; FLOPPY UNIT DATA +; +FCD_UNITS: +FCD_U0TRK .DB 0FFH ; CURRENT TRACK +FCD_U0MEDIA .DB FDMEDIA ; MEDIA BYTE +; .DW FDDPH0 ; ADDRESS OF DPH +; +FCD_U1TRK .DB 0FFH ; CURRENT TRACK +FCD_U1MEDIA .DB FDMEDIA ; MEDIA BYTE +; +; WORKING STORAGE (DERIVED FROM ABOVE FOR ACTIVE DRIVE UNIT) +; +FDDS_TRKADR .DW 0 ; POINTER TO FDCUXTRK ABOVE +FDDS_MEDIAADR .DW 0 ; POINTER TO FDCUXMEDIA ABOVE diff --git a/trunk/Source/fd_data.asm b/trunk/Source/fd_data.asm new file mode 100644 index 00000000..f1ddff25 --- /dev/null +++ b/trunk/Source/fd_data.asm @@ -0,0 +1,173 @@ +; +;================================================================================================== +; FLOPPY DISK DRIVER - DATA +;================================================================================================== +; +#IF (FDMEDIA == FDM720) + #DEFINE FDDPB DPB_FD720 ; DPB_FD720 OR DPB_FD144 + #DEFINE FDCKS CKS_FD720 + #DEFINE FDALS ALS_FD720 +#ENDIF +#IF (FDMEDIA == FDM144) + #DEFINE FDDPB DPB_FD144 ; DPB_FD720 OR DPB_FD144 + #DEFINE FDCKS CKS_FD144 + #DEFINE FDALS ALS_FD144 +#ENDIF +#IF (FDMEDIA == FDM360) + #DEFINE FDDPB DPB_FD360 ; DPB_FD720 OR DPB_FD144 + #DEFINE FDCKS CKS_FD360 + #DEFINE FDALS ALS_FD360 +#ENDIF +#IF (FDMEDIA == FDM120) + #DEFINE FDDPB DPB_FD120 ; DPB_FD720 OR DPB_FD144 + #DEFINE FDCKS CKS_FD120 + #DEFINE FDALS ALS_FD120 +#ENDIF +#IF (FDMEDIA == FDM111) + #DEFINE FDDPB DPB_FD111 ; DPB_FD720 OR DPB_FD144 + #DEFINE FDCKS CKS_FD111 + #DEFINE FDALS ALS_FD111 +#ENDIF +; +; +; + .DB DIODEV_FD + 0 +FDDPH0: .DW 0000, 0000 + .DW 0000, 0000 + .DW DIRBF, FDDPB + .DW FDCSV0, FDALV0 + .DB DIODEV_FD + 1 +FDDPH1: .DW 0000, 0000 + .DW 0000, 0000 + .DW DIRBF, FDDPB + .DW FDCSV1, FDALV1 +; .EXPORT FDDPH0, FDDPH1 +;; +;; DISK PARAMETER BLOCKS USED FOR FLOPPY DRIVER +;; +;; IBM 720KB 3.5" FLOPPY DRIVE, 80 TRKS, 36 SECS/TRK, 512 BYTES/SEC +;; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 128 +;; +;#IF ((FDMEDIA == FDM720) | (FDMEDIAALT == FDM720)) +;DPB_FD720: +; .DW 36 ; SPT: SECTORS PER TRACK +; .DB 4 ; BSH: BLOCK SHIFT FACTOR +; .DB 15 ; BLM: BLOCK MASK +; .DB 0 ; EXM: EXTENT MASK +; .DW 350 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((720K - 18K OFF) / 2K BLS) - 1 = 350 +; .DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127 +; .DB 11000000B ; AL0: DIR BLK BIT MAP, FIRST BYTE +; .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE +; .DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4 +; .DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K +;#ELSE +;DPB_FD720 .EQU 0 +;#ENDIF +CKS_FD720 .EQU 32 ; CKS: DIR ENT / 4 = 128 / 4 = 32 +ALS_FD720 .EQU 44 ; ALS: BLKS / 8 = 351 / 8 = 44 (ROUNDED UP) +; .EXPORT DPB_FD720 +;#ENDIF +;; +;; IBM 1.44MB 3.5" FLOPPY DRIVE, 80 TRKS, 72 SECS/TRK, 512 BYTES/SEC +;; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 +;; +;#IF ((FDMEDIA == FDM144) | (FDMEDIAALT == FDM144)) +;DPB_FD144: +; .DW 72 ; SPT: SECTORS PER TRACK +; .DB 4 ; BSH: BLOCK SHIFT FACTOR +; .DB 15 ; BLM: BLOCK MASK +; .DB 0 ; EXM: EXTENT MASK +; .DW 710 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,440K - 18K OFF) / 2K BLS) - 1 = 710 +; .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 +; .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE +; .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE +; .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 +; .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 72 SEC/TRK) = 18K +;#ELSE +;DPB_FD144 .EQU 0 +;#ENDIF +CKS_FD144 .EQU 64 ; CKS: DIR ENT / 4 = 256 / 4 = 64 +ALS_FD144 .EQU 89 ; ALS: BLKS / 8 = 711 / 8 = 89 (ROUNDED UP) +; .EXPORT DPB_FD144 +;#ENDIF +;; +;; IBM 360KB 5.25" FLOPPY DRIVE, 40 TRKS, 9 SECS/TRK, 512 BYTES/SEC +;; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 128 +;; +;#IF ((FDMEDIA == FDM360) | (FDMEDIAALT == FDM360)) +;DPB_FD360: +; .DW 36 ; SPT: SECTORS PER TRACK +; .DB 4 ; BSH: BLOCK SHIFT FACTOR +; .DB 15 ; BLM: BLOCK MASK +; .DB 0 ; EXM: EXTENT MASK +; .DW 170 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((360K - 18K OFF) / 2K BLS) - 1 = 170 +; .DW 127 ; DRM: DIR ENTRIES - 1 = 128 - 1 = 127 +; .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE +; .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE +; .DW 32 ; CKS: DIRECTORY CHECK VECTOR SIZE = 128 / 4 +; .DW 4 ; OFF: RESERVED TRACKS = 4 TRKS * (512 B/SEC * 36 SEC/TRK) = 18K +;#ELSE +;DPB_FD360 .EQU 0 +;#ENDIF +CKS_FD360 .EQU 32 ; CKS: DIR ENT / 4 = 128 / 4 = 32 +ALS_FD360 .EQU 89 ; ALS: BLKS / 8 = 171 / 8 = 22 (ROUNDED UP) +; .EXPORT DPB_FD360 +;#ENDIF +;; +;; IBM 1.20MB 5.25" FLOPPY DRIVE, 80 TRKS, 60 SECS/TRK, 512 BYTES/SEC +;; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 +;; +;#IF ((FDMEDIA == FDM120) | (FDMEDIAALT == FDM120)) +;DPB_FD120: +; .DW 60 ; SPT: SECTORS PER TRACK +; .DB 4 ; BSH: BLOCK SHIFT FACTOR +; .DB 15 ; BLM: BLOCK MASK +; .DB 0 ; EXM: EXTENT MASK +; .DW 591 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,200K - 15K OFF) / 2K BLS) - 1 = 591 +; .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 +; .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE +; .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE +; .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 +; .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K +;#ELSE +;DPB_FD120 .EQU 0 +;#ENDIF +CKS_FD120 .EQU 64 ; CKS: DIR ENT / 4 = 256 / 4 = 64 +ALS_FD120 .EQU 74 ; ALS: BLKS / 8 = 592 / 8 = 74 (ROUNDED UP) +; .EXPORT DPB_FD120 +;#ENDIF +;; +;; IBM 1.11MB 8" FLOPPY DRIVE, 74 TRKS, 60 SECS/TRK, 512 BYTES/SEC +;; BLOCKSIZE (BLS) = 2K, DIRECTORY ENTRIES = 256 +;; +;#IF ((FDMEDIA == FDM111) | (FDMEDIAALT == FDM111)) +;DPB_FD111: +; .DW 60 ; SPT: SECTORS PER TRACK +; .DB 4 ; BSH: BLOCK SHIFT FACTOR +; .DB 15 ; BLM: BLOCK MASK +; .DB 0 ; EXM: EXTENT MASK +; .DW 546 ; DSM: TOTAL STORAGE IN BLOCKS - 1 BLK = ((1,110K - 15K OFF) / 2K BLS) - 1 = 546 +; .DW 255 ; DRM: DIR ENTRIES - 1 = 256 - 1 = 255 +; .DB 11110000B ; AL0: DIR BLK BIT MAP, FIRST BYTE +; .DB 00000000B ; AL1: DIR BLK BIT MAP, SECOND BYTE +; .DW 64 ; CKS: DIRECTORY CHECK VECTOR SIZE = 256 / 4 +; .DW 2 ; OFF: RESERVED TRACKS = 2 TRKS * (512 B/SEC * 60 SEC/TRK) = 15K +CKS_FD111 .EQU 64 ; CKS: DIR ENT / 4 = 256 / 4 = 64 +ALS_FD111 .EQU 69 ; ALS: BLKS / 8 = 592 / 8 = 74 (ROUNDED UP) +; .EXPORT DPB_FD111 +;#ENDIF +; +; +; +#IF (FDMAUTO) +; ASSUME WORST CASE SIZES +FDCSV0: .FILL CKS_FD144 +FDALV0: .FILL ALS_FD144 +FDCSV1: .FILL CKS_FD144 +FDALV1: .FILL ALS_FD144 +#ELSE +FDCSV0: .FILL FDCKS +FDALV0: .FILL FDALS +FDCSV1: .FILL FDCKS +FDALV1: .FILL FDALS +#ENDIF diff --git a/trunk/Source/hbfill.asm b/trunk/Source/hbfill.asm new file mode 100644 index 00000000..a0abddb5 --- /dev/null +++ b/trunk/Source/hbfill.asm @@ -0,0 +1,10 @@ +; +;================================================================================================== +; FILLER FOR HBIOS PROXY, JUST A 256 BYTE FILLER +;================================================================================================== +; +#INCLUDE "std.asm" +; + .FILL HB_SIZ,0FFH +; + .END diff --git a/trunk/Source/hdsk.asm b/trunk/Source/hdsk.asm new file mode 100644 index 00000000..ba01af57 --- /dev/null +++ b/trunk/Source/hdsk.asm @@ -0,0 +1,278 @@ +; +;================================================================================================== +; HDSK DISK DRIVER +;================================================================================================== +; +; IO PORT ADDRESSES +; +HDSK_IO .EQU $FD +; +HDSK_CMDNONE .EQU 0 +HDSK_CMDRESET .EQU 1 +HDSK_CMDREAD .EQU 2 +HDSK_CMDWRITE .EQU 3 +HDSK_CMDPARAM .EQU 4 +; +; STATUS +; +HDSKRC_OK .EQU 0 +; +; UNIT CONFIGURATION +; +HDSK0_DEVICE .DB 11100000B ; LBA, MASTER DEVICE +HDSK1_DEVICE .DB 11110000B ; LBA, SLAVE DEVICE +; +; +; +HDSK_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F + JR Z,HDSK_RD + DEC A + JR Z,HDSK_WR + DEC A + JR Z,HDSK_ST + DEC A + JR Z,HDSK_MED + CALL PANIC +; +HDSK_RD: + JP HDSK_READ +HDSK_WR: + JP HDSK_WRITE +HDSK_ST: + JP HDSK_STATUS +HDSK_MED: + JP HDSK_MEDIA +; +; HDSK_MEDIA +; +HDSK_MEDIA: + LD A,MID_HD + RET +; +; +; +HDSK_INIT: + XOR A + DEC A ; INITIAL STATUS IS NOT READY $FF + LD (HDSK_STAT),A ; SAVE IT + XOR A ; INIT SUCCEEDED + RET ; RETURN +; +; +; +HDSK_STATUS: + LD A,(HDSK_STAT) ; LOAD STATUS + OR A ; SET FLAGS + RET +; +; +; +HDSK_READ: + LD A,HDSK_CMDREAD + JR HDSK_RW +; +; +; +HDSK_WRITE: + LD A,HDSK_CMDWRITE + JR HDSK_RW +; +; +; +HDSK_RW: + LD (HDSK_CMD),A + + ; CLEAR RESULTS + XOR A ; A = 0 + LD (HDSK_RC),A ; CLEAR RETURN CODE + + ; INIT IF NEEDED + LD A,(HDSK_STAT) ; GET CURRENT STATUS + OR A ; SET FLAGS + CALL NZ,HDSK_RESET ; RESET IF NOT READY + + ; SET DEVICE + LD A,(HSTDSK) + AND 0FH + LD (HDSK_DEVICE),A + + ; SET SECTOR (IGNORES MSB) + LD A,(HSTSEC) + LD (HDSK_SEC),A + + ; SET TRACK + LD BC,(HSTTRK) + LD (HDSK_TRK),BC + + ; SET TRANSFER ADDRESS + LD BC,(DIOBUF) + LD (HDSK_DMA),BC + + ; EXECUTE COMMAND + LD B,7 ; SIZE OF PARAMETER BLOCK + LD HL,HDSK_PARMBLK ; START ADDRESS OF PARAMETER BLOCK +HDSK_RW1: + LD A,(HL) ; GET BYTE OF PARAMETER BLOCK + OUT (0FDH),A ; SEND IT TO PORT + INC HL ; POINT TO NEXT BYTE + DJNZ HDSK_RW1 + + IN A,(0FDH) ; GET RESULT CODE + LD (HDSK_RC),A + OR A + JR Z,HDSK_OK + JR HDSK_ERR + +HDSK_ERR: + XOR A + DEC A ; A=$FF TO SIGNAL ERROR + LD (HDSK_STAT),A ; SAVE IT +#IF (HDSKTRACE >= 1) + PUSH AF + CALL HDSK_PRT + POP AF +#ENDIF + RET + +HDSK_OK: +#IF (HDSKTRACE >= 2) + CALL HDSK_PRT +#ENDIF + XOR A + RET +; +; +; +HDSK_RESET: + LD B,32 + LD A,HDSK_CMDRESET +HDSK_RESET1: + OUT (0FDH),A + DJNZ HDSK_RESET1 + + XOR A ; STATUS = OK + LD (HDSK_STAT),A ; SAVE IT + +#IF (HDSKTRACE >= 2) + CALL NEWLINE + LD DE,HDSKSTR_PREFIX + CALL WRITESTR + CALL PC_SPACE + LD DE,HDSKSTR_RESET + CALL WRITESTR +#ENDIF + + RET +; +; +; +HDSK_PRT: + CALL NEWLINE + + LD DE,HDSKSTR_PREFIX + CALL WRITESTR + + CALL PC_SPACE + LD DE,HDSKSTR_CMD + CALL WRITESTR + LD A,(HDSK_CMD) + CALL PRTHEXBYTE + + CALL PC_SPACE + CALL PC_LBKT + LD A,(HDSK_CMD) + LD DE,HDSKSTR_NONE + CP HDSK_CMDNONE + JP Z,HDSK_PRTCMD + LD DE,HDSKSTR_RESET + CP HDSK_CMDRESET + JP Z,HDSK_PRTCMD + LD DE,HDSKSTR_READ + CP HDSK_CMDREAD + JP Z,HDSK_PRTCMD + LD DE,HDSKSTR_WRITE + CP HDSK_CMDWRITE + JP Z,HDSK_PRTCMD + LD DE,HDSKSTR_PARAM + CP HDSK_CMDPARAM + JP Z,HDSK_PRTCMD + LD DE,HDSKSTR_UNKCMD +HDSK_PRTCMD: + CALL WRITESTR + CALL PC_RBKT + + LD A,(HDSK_CMD) + CP HDSK_CMDREAD + JR Z,HDSK_PRTRW + CP HDSK_CMDWRITE + JR Z,HDSK_PRTRW + RET + +HDSK_PRTRW: + CALL PC_SPACE + LD A,(HDSK_DEVICE) + CALL PRTHEXBYTE + CALL PC_SPACE + LD BC,(HDSK_TRK) + CALL PRTHEXWORD + CALL PC_SPACE + LD A,(HDSK_SEC) + CALL PRTHEXBYTE + CALL PC_SPACE + LD BC,(HDSK_DMA) + CALL PRTHEXWORD + + CALL PC_SPACE + LD DE,HDSKSTR_ARROW + CALL WRITESTR + + CALL PC_SPACE + LD DE,HDSKSTR_RC + CALL WRITESTR + LD A,(HDSK_RC) + CALL PRTHEXBYTE + + CALL PC_SPACE + CALL PC_LBKT + LD A,(HDSK_RC) + LD DE,HDSKSTR_RCOK + CP HDSKRC_OK + JP Z,HDSK_PRTRC + LD DE,HDSKSTR_RCUNK + +HDSK_PRTRC: + CALL WRITESTR + CALL PC_RBKT + + RET +; +; +; +HDSKSTR_PREFIX .TEXT "HDSK:$" +HDSKSTR_CMD .TEXT "CMD=$" +HDSKSTR_RC .TEXT "RC=$" +HDSKSTR_ARROW .TEXT "-->$" +HDSKSTR_NONE .TEXT "NONE$" +HDSKSTR_RESET .TEXT "RESET$" +HDSKSTR_READ .TEXT "READ$" +HDSKSTR_WRITE .TEXT "WRITE$" +HDSKSTR_PARAM .TEXT "PARAM$" +HDSKSTR_UNKCMD .TEXT "UNKCMD$" +HDSKSTR_RCOK .TEXT "OK$" +HDSKSTR_RCUNK .TEXT "UNKNOWN ERROR$" +; +;================================================================================================== +; HDSK DISK DRIVER - DATA +;================================================================================================== +; +HDSK_STAT .DB 0 +HDSK_RC .DB 0 +; +HDSK_PARMBLK: +HDSK_CMD .DB 0 ; HDSK_READ OR HDSK_WRITE +HDSK_DEVICE .DB 0 ; 0 .. 7, DEFINES HARD DISK TO BE USED +HDSK_SEC .DB 0 ; 0 .. 31, DEFINES SECTOR +HDSK_TRK .DW 0 ; 0 .. 2047, DEFINES TRACK +HDSK_DMA .DW 0 ; DEFINES WHERE RESULT IS PLACED IN MEMORY \ No newline at end of file diff --git a/trunk/Source/hdsk_data.asm b/trunk/Source/hdsk_data.asm new file mode 100644 index 00000000..2e52e51c --- /dev/null +++ b/trunk/Source/hdsk_data.asm @@ -0,0 +1,61 @@ +; +;================================================================================================== +; HDSK DISK DRIVER - DATA +;================================================================================================== +; +HDSK_SLICETRKS .EQU 65 ; TRACKS PER SLICE +HDSK_TRKSIZE .EQU 128 ; SIZE OF TRACK (IN KB) +HDSK_SLICESIZE .EQU ((HDSK_SLICETRKS * HDSK_TRKSIZE) + 1023) / 1024 ; SIZE OF EACH SLICE (IN MB) +HDSK_NUMSLICES .EQU HDSKCAPACITY / HDSK_SLICESIZE ; TOTAL SLICES IN DEVICE +HDSK0_SLICEDEF .EQU 0 ; DEFAULT SLICE FOR UNIT 0 +HDSK1_SLICEDEF .EQU 1 ; DEFAULT SLICE FOR UNIT 1 +HDSK2_SLICEDEF .EQU 2 ; DEFAULT SLICE FOR UNIT 0 +HDSK3_SLICEDEF .EQU 3 ; DEFAULT SLICE FOR UNIT 1 +; + .DB DIODEV_HDSK + 0 +HDSKDPH0 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW HDSKCSV0,HDSKALV0 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +HDSK0_SLICE .DW HDSK0_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW HDSK_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_HDSK + 0 +HDSKDPH1 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW HDSKCSV1,HDSKALV1 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +HDSK1_SLICE .DW HDSK1_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW HDSK_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_HDSK + 0 +HDSKDPH2 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW HDSKCSV2,HDSKALV2 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +HDSK2_SLICE .DW HDSK2_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW HDSK_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_HDSK + 0 +HDSKDPH3 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW HDSKCSV3,HDSKALV3 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +HDSK3_SLICE .DW HDSK3_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW HDSK_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; +HDSKCKS .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA +HDSKALS .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP) +; +HDSKCSV0: .FILL HDSKCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +HDSKALV0: .FILL HDSKALS ; MAX OF 2048 DATA BLOCKS +HDSKCSV1: .FILL HDSKCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +HDSKALV1: .FILL HDSKALS ; MAX OF 2048 DATA BLOCKS +HDSKCSV2: .FILL HDSKCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +HDSKALV2: .FILL HDSKALS ; MAX OF 2048 DATA BLOCKS +HDSKCSV3: .FILL HDSKCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +HDSKALV3: .FILL HDSKALS ; MAX OF 2048 DATA BLOCKS diff --git a/trunk/Source/ide.asm b/trunk/Source/ide.asm new file mode 100644 index 00000000..feb7b7b5 --- /dev/null +++ b/trunk/Source/ide.asm @@ -0,0 +1,509 @@ +; +;================================================================================================== +; IDE DISK DRIVER +;================================================================================================== +; +; IO PORT ADDRESSES +; +#IF (IDEMODE == IDEMODE_DIO) +#IF (IDE8BIT) +IDEDATA: .EQU 20H ; DATA PORT (8 BIT) +#ELSE +IDEDATALO: .EQU 20H ; DATA PORT (16 BIT LO BYTE) +IDEDATAHI: .EQU 28H ; DATA PORT (16 BIT HI BYTE) +#ENDIF +#ENDIF +; +#IF (IDEMODE == IDEMODE_DIDE) +#IF (IDE8BIT) +IDEDATA: .EQU 20H ; DATA PORT (8 BIT OR 16 BIT PIO LO/HI BYTES) +#ELSE +IDEDATA: .EQU 28H ; DATA PORT (16 BIT PIO LO/HI BYTES) +IDEDMA: .EQU 29H ; DATA PORT (16 BIT DMA LO/HI BYTES) +#ENDIF +#ENDIF +; +IDEERR: .EQU 21H ; READ: ERROR REGISTER; WRITE: PRECOMP +IDESECTC: .EQU 22H ; SECTOR COUNT +IDESECTN: .EQU 23H ; SECTOR NUMBER +IDECYLLO: .EQU 24H ; CYLINDER LOW +IDECYLHI: .EQU 25H ; CYLINDER HIGH +IDEDEVICE: .EQU 26H ; DRIVE/HEAD +IDESTTS: .EQU 27H ; READ: STATUS; WRITE: COMMAND +IDECTRL: .EQU 2EH ; READ: ALTERNATIVE STATUS; WRITE; DEVICE CONTROL +IDEADDR: .EQU 2FH ; DRIVE ADDRESS (READ ONLY) +; +; +; +IDECMD_READ .EQU 020H +IDECMD_WRITE .EQU 030H +IDECMD_SETFEAT .EQU 0EFH +; +IDERC_OK .EQU 0 +IDERC_CMDERR .EQU 1 +IDERC_RDYTO .EQU 2 +IDERC_BUFTO .EQU 3 +; +; UNIT CONFIGURATION +; +IDE0_DEVICE .DB 11100000B ; LBA, MASTER DEVICE +IDE1_DEVICE .DB 11110000B ; LBA, SLAVE DEVICE +; +; +; +IDE_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F + JR Z,IDE_RD + DEC A + JR Z,IDE_WR + DEC A + JR Z,IDE_ST + DEC A + JR Z,IDE_MED + CALL PANIC +; +IDE_RD: + JP IDE_READ +IDE_WR: + JP IDE_WRITE +IDE_ST: + JP IDE_STATUS +IDE_MED: + JP IDE_MEDIA +; +; IDE_MEDIA +; +IDE_MEDIA: + LD A,MID_HD + RET +; +; +; +IDE_INIT: + CALL IDE_RESET + XOR A + DEC A ; INITIAL STATUS IS NOT READY $FF + LD (IDE_STAT),A ; SAVE IT + RET +; +; +; +IDE_STATUS: + LD A,(IDE_STAT) ; LOAD STATUS + OR A ; SET FLAGS + RET +; +; +; +IDE_READ: + LD A,IDECMD_READ + LD (IDE_CMD),A + JP IDE_RW +; +; +; +IDE_WRITE: + LD A,IDECMD_WRITE + LD (IDE_CMD),A + JP IDE_RW +; +; +; +IDE_RW: + ; CLEAR RESULTS + XOR A ; A = 0 + LD (IDE_RC),A ; CLEAR RETURN CODE + LD (IDE_STTS),A ; CLEAR SAVED STTS + LD (IDE_ERRS),A ; CLEAR SAVED ERR + + ; INIT REQUIRED? + LD A,(IDE_STAT) ; GET CURRENT STATUS + OR A ; SET FLAGS + JR Z,IDE_RW0 ; IF STATUS OK, BYPASS RESET + + CALL IDE_RESET ; DO THE RESET + +#IF (IDE8BIT) + CALL IDE_WAITRDY + + LD A,01H + OUT (IDEERR),A + LD A,IDECMD_SETFEAT + OUT (IDESTTS),A + CALL IDE_WAITRDY + JP NC,IDE_ERR + CALL IDE_CHKERR ; CHECK FOR ERRORS + JP NC,IDE_ERR +#IF (IDETRACE >= 2) + CALL IDE_PRT +#ENDIF +#ENDIF + +IDE_RW0: + CALL IDE_WAITRDY ; WAIT FOR DRIVE READY + JP NC,IDE_ERR + CALL IDE_SETUP ; SETUP CYL, TRK, HEAD + LD A,(IDE_CMD) + OUT (IDESTTS),A + CALL IDE_WAITRDY ; WAIT FOR DRIVE READY + JP NC,IDE_ERR + CALL IDE_CHKERR ; CHECK FOR ERRORS + JP NC,IDE_ERR + CALL IDE_WAITBUF ; WAIT FOR BUFFER READY + JP NC,IDE_ERR + + LD A,(IDE_CMD) ; DISPATCH TO READ OR WRITE SPECIFIC LOGIC + CP IDECMD_WRITE + JP Z,IDE_RW1 + + CALL IDE_BUFRD ; READ BUFFER + CALL IDE_WAITRDY ; WAIT FOR DRIVE READY + JP NC,IDE_ERR + CALL IDE_CHKERR ; CHECK FOR ERRORS + JP NC,IDE_ERR + JP IDE_OK + +IDE_RW1: + CALL IDE_BUFWR ; WRITE BUFFER + CALL IDE_WAITRDY ; WAIT FOR DRIVE READY + JP NC,IDE_ERR + CALL IDE_CHKERR ; CHECK FOR ERRORS + JP NC,IDE_ERR + JP IDE_OK + +IDE_ERR: + XOR A + DEC A ; A = $FF TO SIGNAL ERROR + LD (IDE_STAT),A ; SAVE IT +#IF (IDETRACE >= 1) + PUSH AF + CALL IDE_PRT + POP AF +#ENDIF + RET + +IDE_OK: +#IF (IDETRACE >= 2) + CALL IDE_PRT +#ENDIF + XOR A + RET +; +; +; +IDE_RESET: + LD A,000001110B ; NO INTERRUPTS, ASSERT RESET BOTH DRIVES + OUT (IDECTRL),A + LD DE,8 ; DELAY ABOUT 200ms + CALL VDELAY + LD A,000001010B ; NO INTERRUPTS, DEASSERT RESET + OUT (IDECTRL),A + XOR A + LD (IDE_STAT),A ; STATUS OK + RET ; SAVE IT +; +; +; +IDE_WAITRDY: + LD DE,0 ; TIMEOUT IS 250us * 65536 = 15 SECONDS +IDE_WBSY: + PUSH DE + LD DE,10 ; INNER LOOP DELAY IS 250us (25us * 10) + CALL VDELAY + POP DE + DEC DE + LD A,D + OR E + JP Z,IDE_TO + IN A,(IDESTTS) ; READ STATUS + LD (IDE_STTS),A ; SAVE IT + AND 011000000b ; ISOLATE BUSY AND RDY BITS + XOR 001000000b ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1 + JP NZ,IDE_WBSY + SCF ; CARRY 1 = OK + RET +IDE_TO: + LD A,IDERC_RDYTO + LD (IDE_RC),A + XOR A ; CARRY 0 = TIMEOUT + RET +; +; +; +IDE_CHKERR: + IN A,(IDESTTS) ; GET STATUS + LD (IDE_STTS),A ; SAVE IT + AND 000000001B ; ERROR BIT SET? + SCF ; ASSUME NO ERR + RET Z ; NO ERR, RETURN WITH CF SET + + IN A,(IDEERR) ; READ ERROR FLAGS + LD (IDE_ERRS),A ; SAVE IT + + LD A,IDERC_CMDERR ; COMMAND ERROR + LD (IDE_RC),A ; SAVE IT + + OR A ; CLEAR CF TO SIGNAL ERROR + RET +; +; +; +IDE_WAITBUF: + LD DE,0 +IDE_WDRQ: + CALL DELAY + INC DE + LD A,D + OR E + JP Z,IDE_TO2 + IN A,(IDESTTS) ; WAIT FOR DRIVE'S 512 BYTE READ BUFFER + LD (IDE_STTS),A ; SAVE IT + AND 000001000B ; TO FILL (OR READY TO FILL) + JP Z,IDE_WDRQ + SCF ; CARRY 1 = OK + RET +IDE_TO2: + LD A,IDERC_BUFTO + LD (IDE_RC),A + XOR A ; CARRY 0 = TIMED OUT + RET +; +; +; +IDE_BUFRD: + LD HL,(DIOBUF) + LD B,0 + +#IF (IDE8BIT | (IDEMODE == IDEMODE_DIDE)) + LD C,IDEDATA + INIR + INIR +#ELSE + LD C,IDEDATAHI +IDE_BUFRD1: + IN A,(IDEDATALO) ; READ THE LO BYTE + LD (HL),A ; SAVE IN BUFFER + INC HL ; INC BUFFER POINTER + INI ; READ AND SAVE HI BYTE, INC HL, DEC B + JP NZ,IDE_BUFRD1 ; LOOP AS NEEDED +#ENDIF + RET +; +; +; +IDE_BUFWR: + LD HL,(DIOBUF) + LD B,0 + +#IF (IDE8BIT | (IDEMODE == IDEMODE_DIDE)) + LD C,IDEDATA + OTIR + OTIR +#ELSE + LD C,IDEDATAHI +IDE_BUFWR1: + LD A,(HL) ; GET THE LO BYTE AND KEEP IT IN A FOR LATER + INC HL ; BUMP TO NEXT BYTE IN BUFFER + OUTI ; WRITE HI BYTE, INC HL, DEC B + OUT (IDEDATALO),A ; NOW WRITE THE SAVED LO BYTE TO LO BYTE + JP NZ,IDE_BUFWR1 ; LOOP AS NEEDED +#ENDIF + RET +; +; +; +IDE_SETUP: + LD A,1 + OUT (IDESECTC),A + + LD A,(HSTDSK) ; HSTDSK -> HEAD BIT 4 TO SELECT UNIT + AND 0FH + CP 0 + JP Z,IDE_SETUP_UNIT0 + CP 1 + JP Z,IDE_SETUP_UNIT1 + CALL NC,PANIC +IDE_SETUP_UNIT0: + LD A,(IDE0_DEVICE) +; LD DE,(IDE0_OFFSET) + JP IDE_SETUP1 +IDE_SETUP_UNIT1: + LD A,(IDE1_DEVICE) +; LD DE,(IDE1_OFFSET) + JP IDE_SETUP1 +IDE_SETUP1: + LD (IDE_DEVICE),A + OUT (IDEDEVICE),A + + LD HL,(HSTTRK) ; HSTTRK -> IDECYLHI/LO + LD A,H + LD (IDE_CYLHI),A + OUT (IDECYLHI),A + LD A,L + LD (IDE_CYLLO),A + OUT (IDECYLLO),A + + LD BC,(HSTSEC) ; HSTSEC -> IDESECTN + LD A,C + LD (IDE_SEC),A + OUT (IDESECTN),A + +#IF (DSKYENABLE) + CALL IDE_DSKY +#ENDIF + + RET +; +; +; +#IF (DSKYENABLE) +IDE_DSKY: + LD HL,DSKY_HEXBUF + LD A,(IDE_DEVICE) + LD (HL),A + INC HL + LD A,(IDE_CYLHI) + LD (HL),A + INC HL + LD A,(IDE_CYLLO) + LD (HL),A + INC HL + LD A,(IDE_SEC) + LD (HL),A + CALL DSKY_HEXOUT + RET +#ENDIF +; +; +; +IDE_PRT: + CALL NEWLINE + + LD DE,IDESTR_PREFIX + CALL WRITESTR + + CALL PC_SPACE + LD DE,IDESTR_CMD + CALL WRITESTR + LD A,(IDE_CMD) + CALL PRTHEXBYTE + + CALL PC_SPACE + CALL PC_LBKT + LD A,(IDE_CMD) + LD DE,IDESTR_READ + CP IDECMD_READ + JP Z,IDE_PRTCMD + LD DE,IDESTR_WRITE + CP IDECMD_WRITE + JP Z,IDE_PRTCMD + LD DE,IDESTR_UNKCMD +IDE_PRTCMD: + CALL WRITESTR + CALL PC_RBKT + + CALL PC_SPACE + LD A,(IDE_DEVICE) + CALL PRTHEXBYTE + LD A,(IDE_CYLHI) + CALL PRTHEXBYTE + LD A,(IDE_CYLLO) + CALL PRTHEXBYTE + LD A,(IDE_SEC) + CALL PRTHEXBYTE + + CALL PC_SPACE + LD DE,IDESTR_ARROW + CALL WRITESTR + + CALL PC_SPACE + IN A,(IDESTTS) + CALL PRTHEXBYTE + + CALL PC_SPACE + IN A,(IDEERR) + CALL PRTHEXBYTE + + CALL PC_SPACE + LD DE,IDESTR_RC + CALL WRITESTR + LD A,(IDE_RC) + CALL PRTHEXBYTE + + CALL PC_SPACE + CALL PC_LBKT + LD A,(IDE_RC) + LD DE,IDESTR_RCOK + CP IDERC_OK + JP Z,IDE_PRTRC + LD DE,IDESTR_RCCMDERR + CP IDERC_CMDERR + JP Z,IDE_PRTRC + LD DE,IDESTR_RCRDYTO + CP IDERC_RDYTO + JP Z,IDE_PRTRC + LD DE,IDESTR_RCBUFTO + CP IDERC_BUFTO + JP Z,IDE_PRTRC + LD DE,IDESTR_RCUNK +IDE_PRTRC: + CALL WRITESTR + CALL PC_RBKT + + RET +; +; +; +IDESTR_PREFIX .TEXT "IDE:$" +IDESTR_CMD .TEXT "CMD=$" +IDESTR_RC .TEXT "RC=$" +IDESTR_ARROW .TEXT "-->$" +IDESTR_READ .TEXT "READ$" +IDESTR_WRITE .TEXT "WRITE$" +IDESTR_UNKCMD .TEXT "UNKCMD$" +IDESTR_RCOK .TEXT "OK$" +IDESTR_RCCMDERR .TEXT "COMMAND ERROR$" +IDESTR_RCRDYTO .TEXT "READY TIMEOUT$" +IDESTR_RCBUFTO .TEXT "BUFFER TIMEOUT$" +IDESTR_RCUNK .TEXT "UNKNOWN ERROR$" +; +;================================================================================================== +; IDE DISK DRIVER - DATA +;================================================================================================== +; +IDE_STAT .DB 0 +IDE_RC .DB 0 +; +IDE_CMD: .DB 0 +IDE_DEVICE .DB 0 +IDE_CYLHI: .DB 0 +IDE_CYLLO: .DB 0 +IDE_SEC: .DB 0 +IDE_STTS: .DB 0 +IDE_ERRS .DB 0 +; +; +; +; +; Error Register (ERR bit being set in the Status Register) +; +; Bit 7: BBK (Bad Block Detected) Set when a Bad Block is detected. +; Bit 6: UNC (Uncorrectable Data Error) Set when Uncorrectable Error is encountered. +; Bit 5: MC (Media Changed) Set to 0. +; Bit 4: IDNF (ID Not Found) Set when Sector ID not found. +; Bit 3: MCR (Media Change Request) Set to 0. +; Bit 2: ABRT (Aborted Command) Set when Command Aborted due to drive error. +; Bit 1: TKONF (Track 0 Not Found) Set when Executive Drive Diagnostic Command. +; Bit 0: AMNF (Address mark Not Found) Set in case of a general error. +; +; Status Register (When the contents of this register are read by the host, the IREQ# bit is cleared) +; +; Bit 7: BSY (Busy) Set when the drive is busy and unable to process any new ATA commands. +; Bit 6: DRDY (Data Ready) Set when the device is ready to accept ATA commands from the host. +; Bit 5: DWF (Drive Write Fault) Always set to 0. +; Bit 4: DSC (Drive Seek Complete) Set when the drive heads have been positioned over a specific track. +; Bit 3: DRQ (Data Request) Set when device is ready to transfer a word or byte of data to or from the host and the device. +; Bit 2: CORR (Corrected Data) Always set to 0. +; Bit 1: IDX (Index) Always set to 0. +; Bit 0: ERR (Error) Set when an error occurred during the previous ATA command. \ No newline at end of file diff --git a/trunk/Source/ide_data.asm b/trunk/Source/ide_data.asm new file mode 100644 index 00000000..d4c20c90 --- /dev/null +++ b/trunk/Source/ide_data.asm @@ -0,0 +1,61 @@ +; +;================================================================================================== +; IDE DISK DRIVER - DATA +;================================================================================================== +; +IDE_SLICETRKS .EQU 65 ; TRACKS PER SLICE +IDE_TRKSIZE .EQU 128 ; SIZE OF TRACK (IN KB) +IDE_SLICESIZE .EQU ((IDE_SLICETRKS * IDE_TRKSIZE) + 1023) / 1024 ; SIZE OF EACH SLICE (IN MB) +IDE_NUMSLICES .EQU IDECAPACITY / IDE_SLICESIZE ; TOTAL SLICES IN DEVICE +IDE0_SLICEDEF .EQU 0 ; DEFAULT SLICE FOR UNIT 0 +IDE1_SLICEDEF .EQU 1 ; DEFAULT SLICE FOR UNIT 1 +IDE2_SLICEDEF .EQU 2 ; DEFAULT SLICE FOR UNIT 0 +IDE3_SLICEDEF .EQU 3 ; DEFAULT SLICE FOR UNIT 1 +; + .DB DIODEV_IDE + 0 +IDEDPH0 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW IDECSV0,IDEALV0 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +IDE0_SLICE .DW IDE0_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW IDE_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_IDE + 0 +IDEDPH1 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW IDECSV1,IDEALV1 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +IDE1_SLICE .DW IDE1_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW IDE_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_IDE + 0 +IDEDPH2 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW IDECSV2,IDEALV2 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +IDE2_SLICE .DW IDE2_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW IDE_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_IDE + 0 +IDEDPH3 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW IDECSV3,IDEALV3 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +IDE3_SLICE .DW IDE3_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW IDE_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; +IDECKS .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA +IDEALS .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP) +; +IDECSV0: .FILL IDECKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +IDEALV0: .FILL IDEALS ; MAX OF 2048 DATA BLOCKS +IDECSV1: .FILL IDECKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +IDEALV1: .FILL IDEALS ; MAX OF 2048 DATA BLOCKS +IDECSV2: .FILL IDECKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +IDEALV2: .FILL IDEALS ; MAX OF 2048 DATA BLOCKS +IDECSV3: .FILL IDECKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +IDEALV3: .FILL IDEALS ; MAX OF 2048 DATA BLOCKS diff --git a/trunk/Source/infolist.inc b/trunk/Source/infolist.inc new file mode 100644 index 00000000..1a062407 --- /dev/null +++ b/trunk/Source/infolist.inc @@ -0,0 +1,24 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; infolist.inc 6/ 7/2012 dwg - removed DSK_MAP pointer ; +; infolist.inc 5/16/2012 dwg - BIOS information pointers ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; The putpose of this table is to provide pointers that can +; be used by utility programs to access BIOS internals for +; debugging and informative purposes. Any time the format +; changes, the first word should be incremented to the Apps +; can determine the lineage of a specific BIOS. This table +; was created in support of the 2.0.0.0 banked BIOS. + +INFOLIST: + .DW 2 ; INFOLIST version 2 6/7/2012 + .DW STR_BANNER + .DW VAR_LOC + .DW TST_LOC + .DW DPB_MAP + .DW DPH_MAP + .DW CIO_MAP + +;;;;;;;;;;;;;;;;;;;;;; +; eof - infolist.inc ; +;;;;;;;;;;;;;;;;;;;;;; \ No newline at end of file diff --git a/trunk/Source/loader.asm b/trunk/Source/loader.asm new file mode 100644 index 00000000..036742b7 --- /dev/null +++ b/trunk/Source/loader.asm @@ -0,0 +1,795 @@ +; +;================================================================================================== +; LOADER +;================================================================================================== +; +; FIX!!! NEED TO SWITCH FROM CBIOS CALLS TO HBIOS CALLS!!! +; +; INCLUDE GENERIC STUFF +; +#INCLUDE "std.asm" +; +; 12/1/2011 dwg - +DRIVES .EQU 1 ; control diskmap display function +; + .ORG 8400H +; + ; SETUP OUR STACK + LD SP,BL_STACK ; SET UP LOADER STACK + + ; SETUP CBIOS IOBYTE + LD A,DEFIOBYTE ; LOAD DEFAULT IOBYTE + LD (IOBYTE),A ; STORE IT + +#IF (PLATFORM != PLT_N8) + IN A,(RTC) ; RTC PORT, BIT 6 HAS STATE OF CONFIG JUMPER +; LD A,40H ; *DEBUG* SIMULATE JUMPER OPEN +; LD A,00H ; *DEBUG* SIMULATE JUMPER SHORTED + AND 40H ; ISOLATE BIT 6 + JR Z,INIT1 ; IF BIT6=0, SHORTED, USE ALT IOBYTE + LD A,DEFIOBYTE ; LOAD DEF IOBYTE VALUE + JR INIT2 ; CONTINUE +INIT1: + LD A,ALTIOBYTE ; LOAD ALT IOBYTE VALUE +INIT2: + LD (IOBYTE),A ; SET THE ACTIVE IOBYTE +#ENDIF + + ; RUN THE BOOT LOADER MENU + JP DOBOOTMENU +; +;__DOBOOT________________________________________________________________________________________________________________________ +; +; PERFORM BOOT FRONT PANEL ACTION +;________________________________________________________________________________________________________________________________ +; + +DOBOOTMENU: + LD DE,STR_BANNER + CALL WRITESTR + + CALL LISTDRIVES + LD DE,STR_BOOTMENU + CALL WRITESTR + +#IF (DSKYENABLE) + LD HL,BOOT ; POINT TO BOOT MESSAGE + CALL SEGDISPLAY ; DISPLAY MESSAGE +#ENDIF + +#IF (BOOTTYPE == BT_AUTO) + LD BC,1000 * BOOT_TIMEOUT + LD (BL_TIMEOUT),BC +#ENDIF + +DB_BOOTLOOP: +; +; CHECK FOR CONSOLE BOOT KEYPRESS +; +#IF (UARTENABLE | VDUENABLE | (PRPENABLE & PRPCONENABLE) | (PPPENABLE & PPPCONENABLE)) + CALL CST + OR A + JR Z,DB_CONEND + CALL CINUC + CP 'S' ; SETUP + JR Z,GOSETUP + CP 'M' ; MONITOR + JR Z,GOMONUART + CP 'R' ; ROM BOOT + JR Z,GOROM + CP 'A' ; A-P, DISK BOOT + JR C,DB_INVALID + CP 'P' + 1 ; HMMM... 'M' DRIVE CONFLICTS WITH MONITOR SELECTION + JR NC,DB_INVALID + SUB 'A' + JR GOBOOTDISK +DB_CONEND: +#ENDIF +; +; CHECK FOR DSKY BOOT KEYPRESS +; +#IF (DSKYENABLE) + CALL KY_STAT ; GET KEY FROM KB INTO A + OR A + JR Z,DB_DSKYEND + CALL KY_GET + CP KY_GO ; GO = MONITOR + JR Z,GOMONDSKY + CP KY_BO ; BO = BOOT ROM + JR Z,GOROM + CP 0AH ; A-F, DISK BOOT + JR C,DB_INVALID + CP 0FH + 1 + JR NC,DB_INVALID + SUB 0AH + JR GOBOOTDISK +; LD HL,BOOT ; POINT TO BOOT MESSAGE +; LD A,00H ; BLANK OUT SELECTION,IT WAS INVALID +; LD (HL),A ; STORE IT IN DISPLAY BUFFER +; CALL SEGDISPLAY ; DISPLAY THE BUFFER +DB_DSKYEND: +#ENDIF +; +; IF CONFIGURED, CHECK FOR AUTOBOOT TIMEOUT +; +#IF (BOOTTYPE == BT_AUTO) + + ; DELAY FOR 1MS TO MAKE TIMEOUT CALC EASY + LD DE,40 + CALL VDELAY + + ; CHECK/INCREMENT TIMEOUT + LD BC,(BL_TIMEOUT) + DEC BC + LD (BL_TIMEOUT),BC + LD A,B + OR C + JR NZ,DB_BOOTLOOP + + ; TIMEOUT EXPIRED, PERFORM DEFAULT BOOT ACTION + LD A,BOOT_DEFAULT + CP 'M' ; MONITOR + JR Z,GOMONUART + CP 'R' ; ROM BOOT + JR Z,GOROM + CP 'A' ; A-P, DISK BOOT + JR C,DB_INVALID + CP 'P' + 1 ; HMMM... DRIVE M CONFLICTS WITH "MONITOR" SELECTION + JR NC,DB_INVALID + SUB 'A' + JR GOBOOTDISK +#ENDIF + + JP DB_BOOTLOOP +; +; BOOT OPTION PROCESSING +; +DB_INVALID: + LD DE,STR_INVALID + CALL WRITESTR + JP DOBOOTMENU +; +GOSETUP: + LD DE,STR_SETUP + CALL WRITESTR + JP DOSETUPMENU +; +GOMONUART: + LD DE,STR_BOOTMON + CALL WRITESTR + JP MON_UART +; +GOMONDSKY: + LD DE,STR_BOOTMON + CALL WRITESTR + JP MON_DSKY +; +GOROM: + LD DE,STR_BOOTROM + CALL WRITESTR + JP CPM_ENT +; +GOBOOTDISK: + LD C,A + LD DE,STR_BOOTDISK + CALL WRITESTR + JP BOOTDISK +; +; BOOT FROM DISK DRIVE +; +BOOTDISK: + LD DE,STR_BOOTDISK1 + CALL WRITESTR + + ; SAVE BOOT DRIVE + LD A,C + LD (BL_BOOTDRIVE),A + + ; SAVE BOOT DEVICE/SLICE + CALL CBIOS_GETDSK + LD A,B + LD (BL_BOOTDEVICE),A + LD (BL_BOOTLU),DE + + ; SELECT THE REQUESTED DRIVE + LD A,(BL_BOOTDRIVE) ; GET CBIOS BOOT DRIVE BACK + LD C,A ; MOVE TO C + LD E,0 ; BIT0=0 IN E MEANS FIRST SELECT + CALL CBIOS_SELDSK ; CALL CBIOS DSKSEL TO GET DPH ADDRESS + + ; IF HL=0, SELDSK FAILED! SELECTED DRIVE IS NOT AVAILABLE + LD A,H + OR L + JP Z,DB_NODISK + +; ; *DEBUG* PRINT DPH ADDRESS +; CALL NEWLINE +; PUSH HL +; POP BC +; CALL PRTHEXWORD + + ; BUMP HL TO POINT TO DPB AND LOAD IT + LD DE,10 + ADD HL,DE ; HL = ADDRESS OF ADDRESS OF DPB + LD A,(HL) ; DEREFERENCE + INC HL + LD H,(HL) + LD L,A ; NOW HL = ADDRESS OF DPB + +; ; *DEBUG* PRINT DPB ADDRESS +; CALL PC_SPACE +; PUSH HL +; POP BC +; CALL PRTHEXWORD + + ; FIRST WORD OF DPB IS SECTORS PER TRACK, SAVE IT + LD C,(HL) + INC HL + LD B,(HL) ; NOW BC = SECTORS PER TRACK +; LD BC,36 ; *DEBUG* + LD (BL_LDSPT),BC ; SAVE IT + + LD DE,12 ; POINT TO DPB OFFSET FIELD + ADD HL,DE + LD A,(HL) + INC HL + OR (HL) + JP Z,DB_NOBOOT ; IF OFFSET = ZERO, THERE IS NO BOOT AREA!!! + +; ; *DEBUG* PRINT SECTORS PER TRACK +; CALL PC_SPACE +; CALL PRTHEXWORD + + ; SETUP TO LOAD METADATA + LD BC,BL_METABUF + CALL CBIOS_SETDMA + LD BC,0 + CALL CBIOS_SETTRK + LD BC,11 + CALL CBIOS_SETSEC + + ; READ META DATA + CALL CBIOS_READ + OR A + JP NZ,DB_ERR + +; ; PRINT SIGNATURE +; CALL NEWLINE +; LD DE,STR_SIG +; CALL WRITESTR +; LD BC,(BL_SIG) +; CALL PRTHEXWORD + + ; CHECK SIGNATURE + LD BC,(BL_SIG) + LD A,$A5 + CP B + JP NZ,DB_NOBOOT + LD A,$5A + CP C + JP NZ,DB_NOBOOT + + ; PRINT CPMLOC VALUE + CALL NEWLINE + LD DE,STR_CPMLOC + CALL WRITESTR + LD BC,(BL_CPMLOC) + CALL PRTHEXWORD + + ; PRINT CPMEND VALUE + CALL PC_SPACE + LD DE,STR_CPMEND + CALL WRITESTR + LD BC,(BL_CPMEND) + CALL PRTHEXWORD + + ; PRINT CPMENT VALUE + CALL PC_SPACE + LD DE,STR_CPMENT + CALL WRITESTR + LD BC,(BL_CPMENT) + CALL PRTHEXWORD + CALL PC_SPACE + + LD DE,STR_LABEL + CALL WRITESTR + LD A,(BL_TERM) ; Display Disk Label if Present + CP '$' ; (dwg 2/7/2012) + JP NZ,NO_LABEL ; pick up string terminator for label + LD DE,BL_LABEL ; if it is there, then a printable + CALL WRITESTR ; label is there as wellm even if spaces. +NO_LABEL: ; + +; +; SETUP BL_CPM... STUFF +; + ; COMPUTE BL_SIZ + LD HL,(BL_CPMEND) + LD DE,(BL_CPMLOC) + SCF + CCF + SBC HL,DE + LD (BL_LDSIZ),HL + + ; SETUP FOR DATA LOAD + LD HL,BL_LDLOC + LD (BL_LDCLOC),HL + LD DE,(BL_LDSIZ) + ADD HL,DE + LD (BL_LDEND),HL + LD BC,0 + LD (BL_LDCTRK),BC + LD BC,12 + LD (BL_LDCSEC),BC + +; ; *DEBUG* PRINT SPT, SEC, TRK, SIZ, END +; CALL NEWLINE +; LD BC,(BL_LDSPT) +; CALL PRTHEXWORD +; CALL PC_SPACE +; LD BC,(BL_LDCSEC) +; CALL PRTHEXWORD +; CALL PC_SPACE +; LD BC,(BL_LDCTRK) +; CALL PRTHEXWORD +; CALL PC_SPACE +; LD BC,(BL_LDSIZ) +; CALL PRTHEXWORD +; CALL PC_SPACE +; LD BC,(BL_LDEND) +; CALL PRTHEXWORD + + ; LOADING MESSAGE + CALL NEWLINE + LD DE,STR_LOADING + CALL WRITESTR +; +; LOADING LOOP +; +DB_LOOP: + ; SETUP TO READ SECTOR + LD BC,(BL_LDCTRK) +; CALL NEWLINE ; *DEBUG* +; CALL PRTHEXWORD ; *DEBUG* + CALL CBIOS_SETTRK + + LD BC,(BL_LDCSEC) +; CALL PC_SPACE ; *DEBUG* +; CALL PRTHEXWORD ; *DEBUG* + CALL CBIOS_SETSEC + LD BC,(BL_LDCLOC) +; CALL PC_SPACE ; *DEBUG* +; CALL PRTHEXWORD ; *DEBUG* + CALL CBIOS_SETDMA + + ; READ IT + CALL CBIOS_READ + OR A + JP NZ,DB_ERR + CALL PC_PERIOD + +; ; *DEBUG* PRINT FIRST WORD OF DATA LOADED +; CALL PC_SPACE +; LD HL,(BL_LDCLOC) +; LD A,(HL) +; INC HL +; LD B,(HL) +; LD C,A +; CALL PRTHEXWORD + + ; INCREMENT MEMORY POINTER + LD HL,(BL_LDCLOC) + LD DE,128 + ADD HL,DE + LD (BL_LDCLOC),HL + + ; CHECK TO SEE IF WE ARE DONE + LD DE,(BL_LDEND) + LD A,H + CP D + JR NZ,DB_CONT + LD A,L + CP E + JR NZ,DB_CONT + + JP DB_DONE + +DB_CONT: + ; INCREMENT SECTOR + LD BC,(BL_LDCSEC) + INC BC + LD (BL_LDCSEC),BC + + ; TEST FOR END OF TRACK (LDCSEC/BC == LDSPT/DE) + LD DE,(BL_LDSPT) + LD A,C + CP E + JR NZ,DB_LOOP ; B != D, NOT AT EOT + LD A,B + CP D + JR NZ,DB_LOOP ; C != E, NOT AT EOT + + ; END OF TRACK, RESET SECTOR & INCREMENT TRACK + LD BC,0 + LD (BL_LDCSEC),BC + LD BC,(BL_LDCTRK) + INC BC + LD (BL_LDCTRK),BC + + JP DB_LOOP + +DB_NODISK: + ; SELDSK DID NOT LIKE DRIVE SELECTION + LD DE,STR_NODISK + CALL WRITESTR + JP DOBOOTMENU + +DB_NOBOOT: + ; DISK IS NOT BOOTABLE + LD DE,STR_NOBOOT + CALL WRITESTR + JP DOBOOTMENU + +DB_ERR: + ; I/O ERROR DURING BOOT ATTEMPT + LD DE,STR_BOOTERR + CALL WRITESTR + JP DOBOOTMENU + +DB_DONE: + CALL NEWLINE +; ; *DEBUG* +; CALL NEWLINE +; LD BC,BL_LDLOC +; CALL PRTHEXWORD +; CALL PC_SPACE +; LD BC,(BL_CPMLOC) +; CALL PRTHEXWORD +; CALL PC_SPACE +; LD BC,(BL_LDSIZ) +; CALL PRTHEXWORD +; CALL PC_SPACE +; LD BC,(BL_CPMENT) +; CALL PRTHEXWORD + +; JP DOBOOTMENU ; *DEBUG* + + ; ALL DONE, NOW RELOCATE IMAGE BY COPYING + LD DE,(BL_LDSIZ) ; BYTES TO MOVE + LD HL,(BL_CPMLOC) + ADD HL,DE + DEC HL ; HL = PTR TO DEST (TOP) + PUSH HL ; SAVE IT + LD HL,BL_LDLOC + ADD HL,DE + DEC HL ; HL = PTR TO SRC (TOP) + POP DE ; RECOVER DEST PTR + LD BC,(BL_LDSIZ) ; BC = BYTES TO COPY + LDDR + + ; PATCH BOOT DRIVE INFO INTO CONFIG DATA + LD A,1 + CALL RAMPG + LD HL,$020D ; LOCATION OF BOOTINFO IN SYSCFG IN RAM PAGE 0 + CALL PATBI + CALL RAMPGZ + +; ; IF BILOC IS SET, THEN ALSO PATCH BOOT INFO INTO OS IMAGE +; LD HL,(BL_BILOC) +; LD A,H +; OR L +; CALL NZ,PATBI ; PATCH IF BL_BILOC <> 0 + + ; JUMP TO COLD BOOT ENTRY + LD HL,(BL_CPMENT) + JP (HL) + +PATBI: + ; PATCH BOOT DRIVE INFO AT ADDRESS SPECIFIED BY HL + LD A,TRUE ; BOOT FROM DISK = TRUE + LD (HL),A ; SAVE IT + INC HL + LD A,(BL_BOOTDEVICE) ; GET BOOT DEVICE/UNIT + LD (HL),A ; SAVE IT + INC HL + LD DE,(BL_BOOTLU) ; GET BOOT LU + LD (HL),E ; SAVE LSB + INC HL + LD (HL),D ; SAVE MSB + RET +; +; +; +DOSETUPMENU: + LD DE,STR_SETUPMENU + CALL WRITESTR + CALL CINUC + + CP 'F' ; FORMAT RAM DISK + JP Z,FMTRAMDSK + CP 'X' ; EXIT + JP Z,DOBOOTMENU + JP DOSETUPMENU ; NO VALID KEY, LOOP +; +FMTRAMDSK: + JP DOSETUPMENU +; +; DISPLAY LIST OF DRIVES +; +LISTDRIVES: +#IF (DRIVES) + call NEWLINE + + ld c,0 ; start with drive 0 + ld b,16 ; loop through 16 drives +dmloop: + push bc ; preserve drive and loop counter + ld a,c ; drive letter into a + add a,'A' ; convert to alpha version of drive letter + ld (BL_TMPDRV),a ; save it for printing if needed + call CBIOS_GETDSK ; get drive into, c still has drive number + or a ; set flags on result + jr nz,dmdone ; error, skip this drive + ld (BL_TMPLU),de ; save lu for later + ld a,b ; device/unit into a for matching below + + ld de,str_devrom + cp DIODEV_MD+0 ; ROM + jr z,dmprt + + ld de,str_devram + cp DIODEV_MD+1 ; RAM + jr z,dmprt + + and $f0 ; after ram/rom, compare on high nibble only + + ld de,str_devfd + cp DIODEV_FD ; floppy disk + jr z,dmprt + + ld de,str_devide + cp DIODEV_IDE ; IDE + jr z,dmprt + + ld de,str_devatapi + cp DIODEV_ATAPI ; ATAPI + jr z,dmprt + + ld de,str_devppide + cp DIODEV_PPIDE ; PPIDE + jr z,dmprt + + ld de,str_devsd + cp DIODEV_SD ; Generic SD + jr z,dmprt + + ld de,str_devprpsd + cp DIODEV_PRPSD ; PropIO SD + jr z,dmprt + + ld de,str_devpppsd + cp DIODEV_PPPSD ; ParPortProp SD + jr z,dmprt + + ld de,str_devhdsk + cp DIODEV_HDSK ; SIMH HDSK + jr z,dmprt + + jr dmdone + +dmprt: + ld a,(BL_TMPDRV) ; recover drive letter + call COUT ; print it + ld a,'=' ; load equal sign + call COUT ; print it + call WRITESTR ; print device name now (str ptr in de) + ld a,b ; a = device/unit + and $f0 ; isolate device + jr z,dmprt1 ; bypass unit printing for mem disk + ld a,b ; a = device/unit + and $0f ; remove device nibble + add a,'0' ; convert to alpha + call COUT ; print unit number + ld a,h ; load slice max msb + or l ; compare to lsb + jr z,dmprt1 ; if zero, no lu support + ld a,'-' ; slice prefix + call COUT ; print slice prefix + ld de,(BL_TMPLU) ; recover LU + ld a,e ; ignore msb, load lsb in a + call PRTHEXBYTE ; print it + +dmprt1: + call PC_SPACE ; padding + +dmdone: + pop bc ; recover drive num and loop counter + inc c ; increment drive number + dec b ; decrement loop counter + jp nz,dmloop ; loop if more drives to check + ret ; done +#ENDIF +; +#IF (DSKYENABLE) +; +; +;__SEGDISPLAY________________________________________________________________________________________ +; +; DISPLAY CONTENTS OF DISPLAYBUF IN DECODED HEX BITS 0-3 ARE DISPLAYED DIG, BIT 7 IS DP +;____________________________________________________________________________________________________ +; +SEGDISPLAY: + PUSH AF ; STORE AF + PUSH BC ; STORE BC + PUSH HL ; STORE HL + LD BC,0007H + ADD HL,BC + LD B,08H ; SET DIGIT COUNT + LD A,40H+30H ; SET CONTROL PORT 7218 TO OFF + OUT (PIOC),A ; OUTPUT + CALL DELAY ; WAIT + LD A,0F0H ; SET CONTROL TO 1111 (DATA COMING, HEX DECODE,NO DECODE, NORMAL) + +SEGDISPLAY1: ; + OUT (PIOA),A ; OUTPUT TO PORT + LD A,80H+30H ; STROBE WRITE PULSE WITH CONTROL=1 + OUT (PIOC),A ; OUTPUT TO PORT + CALL DELAY ; WAIT + LD A,40H+30H ; SET CONTROL PORT 7218 TO OFF + OUT (PIOC),A ; OUTPUT + +SEGDISPLAY_LP: + LD A,(HL) ; GET DISPLAY DIGIT + OUT (PIOA),A ; OUT TO PIOA + LD A,00H+30H ; SET WRITE STROBE + OUT (PIOC),A ; OUT TO PIOC + CALL DELAY ; DELAY + LD A,40H+30H ; SET CONTROL PORT OFF + OUT (PIOC),A ; OUT TO PIOC + CALL DELAY ; WAIT + DEC HL ; INC POINTER + DJNZ SEGDISPLAY_LP ; LOOP FOR NEXT DIGIT + POP HL ; RESTORE HL + POP BC ; RESTORE BC + POP AF ; RESTORE AF + RET +#ENDIF +; +;__TEXT_STRINGS_________________________________________________________________________________________________________________ +; +; STRINGS +;_____________________________________________________________________________________________________________________________ +; +STR_BOOTDISK .DB "BOOT FROM DISK\r\n$" +STR_BOOTDISK1 .DB "\r\nReading disk information...$" +STR_BOOTMON .DB "START MONITOR\r\n$" +STR_BOOTROM .DB "BOOT FROM ROM\r\n$" +STR_INVALID .DB "INVALID SELECTION\r\n$" +STR_SETUP .DB "SYSTEM SETUP\r\n$" +STR_SIG .DB "SIGNATURE=$" +STR_CPMLOC .DB "LOC=$" +STR_CPMEND .DB "END=$" +STR_CPMENT .DB "ENT=$" +STR_LABEL .DB "LABEL=$" +STR_LOADING .DB "\r\nLoading$" +STR_NODISK .DB "\r\nNo disk!$" +STR_NOBOOT .DB "\r\nDisk not bootable!$" +STR_BOOTERR .DB "\r\nBoot failure!$" +; +STR_BANNER: + .DB "\r\n\r\n", PLATFORM_NAME, " Boot Loader v", BIOSVER + .DB " (", VARIANT, "-", TIMESTAMP, ")\r\n$" +STR_BOOTMENU: + .DB "\r\nBoot: (M)onitor, (R)OM, or Drive Letter ===> $" +; +STR_SETUPMENU: + .DB "\r\n\r\n", PLATFORM_NAME, " Setup & Configuration v", BIOSVER + .DB " (", VARIANT, "-", TIMESTAMP, ")\r\n\r\n" +; .DB "(F)ormat RAM Disk\r\n" + .DB "e(X)it Setup\r\n" + .DB "\r\n===> $" +; + .IF DSKYENABLE +BOOT: +; . . t o o b + .DB 00H, 00H, 80H, 80H, 094H, 09DH, 09DH, 09FH + .ENDIF +; +#DEFINE CIOMODE_CBIOS +#DEFINE DSKY_KBD +#INCLUDE "util.asm" +; +#INCLUDE "memmgr.asm" +; +; READ A CONSOLE CHARACTER AND CONVERT TO UPPER CASE +; +CINUC: + CALL CIN + AND 7FH ; STRIP HI BIT + CP 'A' ; KEEP NUMBERS, CONTROLS + RET C ; AND UPPER CASE + CP 7BH ; SEE IF NOT LOWER CASE + RET NC + AND 5FH ; MAKE UPPER CASE + RET +; +;================================================================================================== +; WORKING DATA STORAGE +;================================================================================================== +; +; WE USE A 256 BYTE AREA JUST AT THE START OF RAM (TOP 32KB) +; FOR WORKING DATA STORAGE. THE FIRST 128 BYTES ARE RESERVED +; TO LOAD THE BLOCK CONTAINING THE BOOT LOAD METADATA. THE +; METADATA IS IN THE LAST 6 BYTES OF THIS BLOCK. +; +;__________________________________________________________________________________________________ +; +;BL_METABUF .ORG 8000H ; START OF RAM +BL_METABUF .EQU $ +BL_SIG .DW 0 ; SIGNATURE (WILL BE 0A55AH IF SET) +BL_PLATFORM .DB 0 ; Formatting Platform +BL_DEVICE .DB 0 ; Formatting Device +BL_FORMATTER .FILL 8,0 ; Formatting Program +BL_DRIVE .DB 0 ; Physical Disk Drive # +BL_LU .DW 0 ; Logical Unit (slice) +; +; .ORG (BL_METABUF + 128 - 32) + .FILL (BL_METABUF + 128) - $ - 32 +BL_PROTECT .DB 0 ; write protect boolean +BL_UPDATES .DW 0 ; update counter +BL_RMJ .DB 0 ; RMJ Major Version Number +BL_RMN .DB 0 ; RMN Minor Version Number +BL_RUP .DB 0 ; RUP Update Number +BL_RTP .DB 0 ; RTP Patch Level +BL_LABEL .FILL 16,0 ; 16 Character Drive Label +BL_TERM .DB 0 ; LABEL TERMINATOR ('$') +BL_BILOC .DW 0 ; LOC TO PATCH BOOT DRIVE INFO TO (IF NOT ZERO) +BL_CPMLOC .DW 0 ; FINAL RAM DESTINATION FOR CPM/CBIOS +BL_CPMEND .DW 0 ; END ADDRESS FOR LOAD +BL_CPMENT .DW 0 ; CP/M ENTRY POINT (CBIOS COLD BOOT) +; +; WORKING STORAGE STARTS HERE +; +BL_STACKSIZ .EQU 40H + .FILL BL_STACKSIZ,0 +BL_STACK .EQU $ +; +BL_LDSPT .DW 0 ; SECTORS PER TRACK FOR LOAD DEVICE +BL_LDCTRK .DW 0 ; CURRENT TRACK FOR LOAD +BL_LDCSEC .DW 0 ; CURRENT SECTOR FOR LOAD +BL_LDCLOC .DW 0 ; CURRENT MEM LOC BEING LOADED +BL_LDEND .DW 0 ; RAM LOCATION TO STOP LOAD +BL_LDSIZ .DW 0 ; SIZE OF CPM/CBIOS IMAGE TO LOAD +BL_TIMEOUT .DW 0 ; AUTOBOOT TIMEOUT COUNTDOWN COUNTER +BL_BOOTDRIVE .DB 0 ; TEMPORARY STORAGE FOR BOOT DRIVE +BL_BOOTDEVICE .DB 0 ; TEMPORARY STORAGE FOR BOOT DEVICE/UNIT +BL_BOOTLU .DW 0 ; TEMPORARY STORAGE FOR BOOT LU +BL_TMPDRV .DB 0 ; TEMP STORAGE FOR DRIVE LETTER +BL_TMPLU .DW 0 ; TEMP STORAGE FOR LU +; +BL_LDLOC .EQU 100H ; LOAD IMAGE HERE BEFORE RELOCATING +; +#IF (DRIVES) +str_devrom .DB "ROM$" +str_devram .DB "RAM$" +str_devfd .DB "FD$" +str_devide .DB "IDE$" +str_devatapi .DB "ATAPI$" +str_devppide .DB "PPIDE$" +str_devsd .DB "SD$" +str_devprpsd .DB "PRPSD$" +str_devpppsd .DB "PPPSD$" +str_devhdsk .DB "HDSK$" +#ENDIF +; +;================================================================================================== +; FILL REMAINDER OF BANK +;================================================================================================== +; +SLACK: .EQU (9000H - $) + .FILL SLACK +; + .ECHO "LOADER space remaining: " + .ECHO SLACK + .ECHO " bytes.\n" + .END diff --git a/trunk/Source/makefile b/trunk/Source/makefile new file mode 100644 index 00000000..dcdbe78a --- /dev/null +++ b/trunk/Source/makefile @@ -0,0 +1,209 @@ +# +# GCC based makefile +# +# 05/24/2012 2.0 wbw - changed to handle HBIOS +# +# 01/11/2011 1.4 wbw - added support for ZSDOS/ZDDOS/ZCPR +# +# 12/22/2011 1.3 wbw - removed all built-in config stuff, operation is now entirely +# dependent on variables CONFIG, ROMSIZE, and CPU +# +# 12/02/2011 1.3 wbw - replaced makever functionality with built-in makefile stuff +# +# 11/29/2011 1.3 dwg - uses makever to generate stdincl.inc from the version.hpp file +# +# 11/19/2011 1.3 dwg - added n8vem_vdu to "usage" and "all" rules +# enhanced clean to get files in $(OUTDIR) +# added custom to "all" rule + +# +# The operation of this makefile is entirely dependent on the setting +# of three variables: CONFIG, ROMSIZE, and CPU: +# +# CONFIG determines which configuration to build which means that +# it will determine the config_xxx.asm config settings file to +# include as well as the output file names. So, for example, +# if CONFIG is "n8vem", the config_n8vem.asm file will be used +# for BIOS configuration settings and the output files will be +# n8vem.rom, n8vem.sys, and n8vem.com. +# +# ROMSIZE specifies the size of the ROM image to be produced and +# currently must be either "1024" for a 1MB ROM or "512" for a +# 512KB ROM. +# +# CPU specifies the instruction set to be used in assembly and +# must be either "80" for Z80 or "180" for Z180. Currently, +# you should use 180 for N8 ROMs and 80 for everything else. +# +# SYS specifies the system variant to build in. CPM will +# build traditional CP/M. ZSYS will build ZSystem which +# currently means ZSDOS 1.2 & ZCPR 1.0 +# +# ROMNAME names the output file. It defaults to +# CONFIG. The output of the build will be: +# .rom, .sys, and .com. +# +# These variables can be passed into the makefile by the command +# line, hardcoded in this file, or set as environment variables +# in the OS. To use a command line, use the following format: +# +# make CONFIG= ROMSIZE= CPU= SYS= ROMNAME= +# +# An example of this is: +# +# make CONFIG=n8vem ROMSIZE=512 CPU=80 SYS=CPM ROMNAME=n8vem +# +# Alternatively, you can specify the variables by hardcoding them +# in this file. To do so, uncomment the five lines after these +# comments and change the values as desired. +# If the variables are specified this way, you would then invoke +# the make by simply using "make" +# +# If you want to set them as environment variables, you can +# do this with commands like the following at an OS command +# prompt or in a batch file: +# +# SET CONFIG=n8vem +# SET ROMSIZE=512 +# SET CPU=80 +# SET SYS=CPM +# SET ROMNAME=n8vem +# +# Note: use "make clean" to delete temporary and output files +# +# A good idea is to do a clean with every build and this can be +# accomplished on one command line doing something like this: +# +# make clean all CONFIG=n8vem ROMSIZE=512 CPU=80 SYS=CPM ROMNAME=n8vem +# +# or, if you are using hard coded variables above: +# +# make clean all +# +# Uncomment and update values below to hardcode settings: +# +#CONFIG := n8vem +#ROMSIZE := 512 +#CPU := 80 +#SYS := CPM +#ROMNAME := n8vem + +ifndef ROMNAME +ROMNAME := $(CONFIG) +endif + +CPMTOOLSPATH := ../tools/cpmtools +CPMCP := $(CPMTOOLSPATH)/cpmcp.exe + +ROMDSKFILES := ../RomDsk/$(SYS)_$(ROMSIZE)KB/*.* ../RomDsk/cfg_$(CONFIG)/*.* ../Apps/core/*.* + +ifeq "$(SYS)" "CPM" +DOSBIN := bdosb01.bin +CPBIN := ccpb03.bin +else +DOSBIN := zsdos.bin +CPBIN := zcprw.bin +endif + +OUTDIR := ..\Output + +TASMPATH := ../tools/tasm32 +TASM := $(TASMPATH)/tasm.exe +TASMTABS := $(TASMPATH) +export TASMTABS + +ASMOPT80 := -t$(CPU) -g3 +ASMOPT85 := -t85 -g3 + +ASM80 := $(TASM) $(ASMOPT80) +ASM85 := $(TASM) $(ASMOPT85) +ASMIMG := $(TASM) $(ASMOPT80) -b -fE5 + +NULL := +SPACE := ${NULL} ${NULL} + +%.bin: %.asm + $(ASM80) $< $@ + +%.com: %.asm + $(ASM80) $< $@ + +%.img: %.asm + $(ASMIMG) $< $@ + +%.exe: %.cpp + $(CC) $< -o $@ + +ifneq ($(MAKECMDGOALS),clean) +ifeq "$(and $(CONFIG), $(ROMSIZE), $(CPU), $(SYS), $(ROMNAME))" "" +$(error Usage: make CONFIG= ROMSIZE=[512|1024] CPU=[80|180] SYS=[CPM|ZSYS] ROMNAME=) +endif +endif + +all: $(OUTDIR)\$(ROMNAME).rom $(OUTDIR)\$(ROMNAME).sys $(OUTDIR)\$(ROMNAME).com + +build.inc: + echo ; >$@ + echo ; RomWBW Configured for $(CONFIG), %date% %time% >>$@ + echo ; >>$@ + echo #DEFINE TIMESTAMP "%date:~-4,4%%date:~-10,2%%date:~-7,2%T%time:~0,2%%time:~3,2%" >>$@ + echo #DEFINE VARIANT "WBW-%username%" >>$@ + echo ; >>$@ + echo ROMSIZE .EQU $(ROMSIZE) >>$@ + echo ; >>$@ + echo #INCLUDE "config_$(CONFIG).asm" >>$@ + echo ; >>$@ + +bootrom.bin : bootrom.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +bootapp.bin : bootapp.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +pgzero.bin : pgzero.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +zcprw.bin : zcprw.asm zcpr.asm + $(TASM) $(ASMOPT85) $< $@ + +zsdos.bin : zsdos.asm zsdos.lib zsdos-gp.z80 + $(TASM) $(ASMOPT80) $< $@ + +cbios.bin: cbios.asm fd_data.asm ide_data.asm ppide_data.asm sd_data.asm prp_data.asm ppp_data.asm uart.asm vdu.asm std.asm ver.inc build.inc + $(TASM) $(ASMOPT80) -dBLD_SYS=SYS_$(SYS) $< $@ + +dbgmon.bin: dbgmon.asm std.asm ver.inc build.inc + +syscfg.bin: syscfg.asm std.asm build.inc ver.inc + +os.bin: $(CPBIN) $(DOSBIN) cbios.bin + copy /B $(subst $(SPACE),+,$(^)) $@ + +rom0.bin: pgzero.bin bootrom.bin syscfg.bin loader.bin romfill.bin dbgmon.bin os.bin hbfill.bin + copy /B $(subst $(SPACE),+,$(^)) $@ + +rom1.bin: pgzero.bin bootrom.bin syscfg.bin loader.bin bnk1.bin + copy /B $(subst $(SPACE),+,$(^)) $@ + +$(OUTDIR)\$(ROMNAME).rom: rom0.bin rom1.bin $(ROMDISKFILES) $(OUTDIR)\$(ROMNAME).sys + copy blank$(ROMSIZE)KB.dat RomDisk.tmp + $(CPMCP) -f rom$(ROMSIZE)KB RomDisk.tmp $(ROMDSKFILES) 0: + $(CPMCP) -f rom$(ROMSIZE)KB RomDisk.tmp ../Output/$(ROMNAME).sys 0:$(SYS).sys + copy /B rom0.bin+rom1.bin+RomDisk.tmp $@ + +$(OUTDIR)\$(ROMNAME).com: bootapp.bin syscfg.bin loader.bin bnk1.bin dbgmon.bin os.bin + copy /B $(subst $(SPACE),+,$(^)) $@ + +$(OUTDIR)\$(ROMNAME).sys: prefix.bin os.bin + copy /B $(subst $(SPACE),+,$(^)) $@ + +clean: + if exist *.bin del *.bin + if exist *.com del *.com + if exist *.img del *.img + if exist *.rom del *.rom + if exist *.lst del *.lst + if exist *.exp del *.exp + if exist *.tmp del *.tmp + if exist build.inc del build.inc + if exist $(OUTDIR)\*.* erase /Q $(OUTDIR)\*.* \ No newline at end of file diff --git a/trunk/Source/makefile.linux b/trunk/Source/makefile.linux new file mode 100644 index 00000000..a57268df --- /dev/null +++ b/trunk/Source/makefile.linux @@ -0,0 +1,206 @@ +# +# GCC based makefile +# +# 06/18/2012 2.0 dgg - updated for v2.0 +# +# 02/22/2012 1.5 dgg - modified for assembly under Linux +# +# 01/11/2011 1.4 wbw - added support for ZSDOS/ZDDOS/ZCPR +# +# 12/22/2011 1.3 wbw - removed all built-in config stuff, operation is now entirely +# dependent on variables CONFIG, ROMSIZE, and CPU +# +# 12/02/2011 1.3 wbw - replaced makever functionality with built-in makefile stuff +# +# 11/29/2011 1.3 dwg - uses makever to generate stdincl.inc from the version.hpp file +# +# 11/19/2011 1.3 dwg - added n8vem_vdu to "usage" and "all" rules +# enhanced clean to get files in $(OUTDIR) +# added custom to "all" rule + +# +# The operation of this makefile is entirely dependent on the setting +# of three variables: CONFIG, ROMSIZE, and CPU: +# +# CONFIG determines which configuration to build which means that +# it will determine the config_xxx.asm config settings file to +# include as well as the output file names. So, for example, +# if CONFIG is "n8vem", the config_n8vem.asm file will be used +# for BIOS configuration settings and the output files will be +# n8vem.rom, n8vem.sys, and n8vem.com. +# +# ROMSIZE specifies the size of the ROM image to be produced and +# currently must be either "1024" for a 1MB ROM or "512" for a +# 512KB ROM. +# +# CPU specifies the instruction set to be used in assembly and +# must be either "80" for Z80 or "180" for Z180. Currently, +# you should use 180 for N8 ROMs and 80 for everything else. +# +# SYS specifies the system variant to build in. CPM will +# build traditional CP/M. ZSYS will build ZSystem which +# currently means ZSDOS 1.2 & ZCPR 1.0 +# +# ROMNAME names the output file. It defaults to +# CONFIG. The output of the build will be: +# .rom, .sys, and .com. +# +# These variables can be passed into the makefile by the command +# line, hardcoded in this file, or set as environment variables +# in the OS. To use a command line, use the following format: +# +# make CONFIG= ROMSIZE= CPU= SYS= ROMNAME= +# +# An example of this is: +# +# make CONFIG=n8vem ROMSIZE=512 CPU=80 SYS=CPM ROMNAME=n8vem +# +# Alternatively, you can specify the variables by hardcoding them +# in this file. To do so, uncomment the five lines after these +# comments and change the values as desired. +# If the variables are specified this way, you would then invoke +# the make by simply using "make" +# +# If you want to set them as environment variables, you can +# do this with commands like the following at an OS command +# prompt or in a batch file: +# +# SET CONFIG=n8vem +# SET ROMSIZE=512 +# SET CPU=80 +# SET SYS=CPM +# SET ROMNAME=n8vem +# +# Note: use "make clean" to delete temporary and output files +# +# A good idea is to do a clean with every build and this can be +# accomplished on one command line doing something like this: +# +# make clean all CONFIG=n8vem ROMSIZE=512 CPU=80 SYS=CPM ROMNAME=n8vem +# +# or, if you are using hard coded variables above: +# +# make clean all +# +# Uncomment and update values below to hardcode settings: +# +#CONFIG := n8vem +#ROMSIZE := 512 +#CPU := 80 +#SYS := CPM +#ROMNAME := n8vem + +ifndef ROMNAME +ROMNAME := $(CONFIG) +endif + +CPMCP := /usr/bin/cpmcp + +ROMDSKFILES := ../RomDsk/$(SYS)_$(ROMSIZE)KB/*.* ../RomDsk/cfg_$(CONFIG)/*.* ../Apps/core/*.* + +ifeq "$(SYS)" "CPM" +DOSBIN := bdosb01.bin +CPBIN := ccpb03.bin +else +DOSBIN := zsdos.bin +CPBIN := zcprw.bin +endif + +OUTDIR := ../Output + +TASM := /usr/local/bin/tasm +TASMTABS := /usr/local/lib +export TASMTABS + +ASMOPT80 := -t$(CPU) -g3 +ASMOPT85 := -t85 -g3 + +ASM80 := $(TASM) $(ASMOPT80) +ASM85 := $(TASM) $(ASMOPT85) +ASMIMG := $(TASM) $(ASMOPT80) -b -fE5 + +NULL := +SPACE := ${NULL} ${NULL} + +%.bin: %.asm + $(ASM80) $< $@ + +%.com: %.asm + $(ASM80) $< $@ + +%.img: %.asm + $(ASMIMG) $< $@ + +%.exe: %.cpp + $(CC) $< -o $@ + +ifneq ($(MAKECMDGOALS),clean) +ifeq "$(and $(CONFIG), $(ROMSIZE), $(CPU), $(SYS), $(ROMNAME))" "" +$(error Usage: make CONFIG= ROMSIZE=[512|1024] CPU=[80|180] SYS=[CPM|ZSYS] ROMNAME=) +endif +endif + +all: $(OUTDIR)/$(ROMNAME).rom $(OUTDIR)/$(ROMNAME).sys $(OUTDIR)/$(ROMNAME).com + +build.inc: + echo ';' >$@ + echo -n '; RomWBW Configured for '$(CONFIG)' ' >>$@ + date >> $@ + echo ; >>$@ + echo -n '#DEFINE TIMESTAMP "' >>$@ + date '+%Y %m %d %H%M"' >>$@ + echo ; >>$@ + echo '#DEFINE VARIANT "WBW-$(USERNAME)"' >>$@ + echo ; >>$@ + echo ROMSIZE .EQU $(ROMSIZE) >>$@ + echo ; >>$@ + echo '#INCLUDE "config_'$(CONFIG)'.asm"' >>$@ + echo ; >>$@ + +bootrom.bin : bootrom.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +bootapp.bin : bootapp.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +pgzero.bin : pgzero.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +zcprw.bin : zcprw.asm zcpr.asm + $(TASM) $(ASMOPT85) $< $@ + +zsdos.bin : zsdos.asm zsdos.lib zsdos-gp.z80 + $(TASM) $(ASMOPT80) $< $@ + +cbios.bin: cbios.asm fd_data.asm ide_data.asm ppide_data.asm sd_data.asm prp_data.asm ppp_data.asm uart.asm vdu.asm std.asm ver.inc build.inc + $(TASM) $(ASMOPT80) -dBLD_SYS=SYS_$(SYS) $< $@ + +dbgmon.bin: dbgmon.asm std.asm ver.inc build.inc + +syscfg.bin: syscfg.asm std.asm build.inc ver.inc + +os.bin: $(CPBIN) $(DOSBIN) cbios.bin + cat $(CPBIN) $(DOSBIN) cbios.bin >>$@ + +rom0.bin: pgzero.bin bootrom.bin syscfg.bin loader.bin romfill.bin dbgmon.bin os.bin hbfill.bin + cat pgzero.bin bootrom.bin syscfg.bin loader.bin romfill.bin dbgmon.bin os.bin hbfill.bin >>$@ + +rom1.bin: pgzero.bin bootrom.bin syscfg.bin loader.bin bnk1.bin + cat pgzero.bin bootrom.bin syscfg.bin loader.bin bnk1.bin >>$@ + +$(OUTDIR)/$(ROMNAME).rom: rom0.bin rom1.bin $(ROMDISKFILES) $(OUTDIR)/$(ROMNAME).sys + cp blank$(ROMSIZE)KB.dat RomDisk.tmp + $(CPMCP) -f rom$(ROMSIZE)KB RomDisk.tmp $(ROMDSKFILES) 0: + $(CPMCP) -f rom$(ROMSIZE)KB RomDisk.tmp ../Output/$(ROMNAME).sys 0:$(SYS).sys + cat rom0.bin rom1.bin RomDisk.tmp >>$@ + +$(OUTDIR)/$(ROMNAME).com: bootapp.bin syscfg.bin loader.bin bnk1.bin dbgmon.bin os.bin + cat bootapp.bin syscfg.bin loader.bin bnk1.bin dbgmon.bin os.bin >>$@ + +$(OUTDIR)/$(ROMNAME).sys: prefix.bin os.bin + cat prefix.bin os.bin >>$@ + +clean: + rm -f *.bin *.com *.img *.rom *.lst *.exp *.tmp + rm -f build.inc + rm -f $(OUTDIR)/*.* diff --git a/trunk/Source/memmgr.asm b/trunk/Source/memmgr.asm new file mode 100644 index 00000000..ff79d6df --- /dev/null +++ b/trunk/Source/memmgr.asm @@ -0,0 +1,79 @@ +;================================================================================================== +; MEMORY PAGE MANAGEMENT +;================================================================================================== +; +; PAGE THE REQUESTED 32K BLOCK OF RAM/ROM INTO THE LOWER 32K OF CPU ADDRESS SPACE. +; LOAD DESIRED PAGE INDEX INTO A AND CALL EITHER RAMPG OR ROMPG AS DESIRED. +; RAMPGZ AND ROMPGZ ARE SHORTCUTS TO PAGE IN THE RAM/ROM ZERO PAGE. +;______________________________________________________________________________________________________________________ +; +#IF (PLATFORM = PLT_N8) +RAMPGZ: ; SELECT RAM PAGE ZERO + XOR A + +RAMPG: + RLCA + RLCA + RLCA + OUT0 (CPU_BBR),A + LD A,DEFACR | 80H + OUT0 (ACR),A + RET +; +ROMPGZ: ; SELECT ROM PAGE ZERO + XOR A + +ROMPG: + OUT0 (RMAP),A + XOR A + OUT0 (CPU_BBR),A + LD A,DEFACR + OUT0 (ACR),A + RET +#ELSE +RAMPGZ: ; SELECT RAM PAGE ZERO + XOR A + +RAMPG: + OR 80H ; TURN ON BIT 7 TO SELECT RAM PAGES + JR PGSEL + +ROMPGZ: ; SELECT ROM PAGE ZERO + XOR A + +ROMPG: + AND 7FH ; TURN OFF BIT 7 TO SELECT ROM PAGES + JR PGSEL + +PGSEL: + OUT (MPCL_ROM),A + OUT (MPCL_RAM),A + RET +#ENDIF + +; +;______________________________________________________________________________________________________________________ +; +; MACROS TO PERFORM RAM/ROM PAGE SELECTION INTO LOWER 32K OF MEMORY SPACE +; PGRAM(P) SELECT RAM PAGE P +; PGRAMF(P) SELECT RAM PAGE P, FAST VERSION ASSUMES CURRENT PAGE IS A RAM PAGE +; PGROM(P) SELECT ROM PAGE P +; PGROMF(P) SELECT ROM PAGE P, FAST VERSION ASSUMES CURRENT PAGE IS A ROM PAGE +; +; REGISTER A IS DESTROYED +;______________________________________________________________________________________________________________________ +; + +#IF (PLATFORM = PLT_N8) + #DEFINE PGRAM(P) LD A,P << 3 \ OUT0 (CPU_BBR),A \ LD A,DEFACR | 80H \ OUT0 (ACR),A + #DEFINE PGRAMF(P) LD A,P << 3 \ OUT0 (CPU_BBR),A + + #DEFINE PGROM(P) LD A,P \ OUT0 (RMAP),A \ XOR A \ OUT0 (CPU_BBR),A \ LD A,DEFACR \ OUT0 (ACR),A + #DEFINE PGROMF(P) LD A,P \ OUT0 (RMAP),A +#ELSE + #DEFINE PGRAM(P) LD A,P | 80H \ OUT (MPCL_ROM),A \ OUT (MPCL_RAM),A + #DEFINE PGRAMF(P) LD A,P | 80H \ OUT (MPCL_RAM),A + + #DEFINE PGROM(P) LD A,P & 7FH \ OUT (MPCL_ROM),A \ OUT (MPCL_RAM),A + #DEFINE PGROMF(P) LD A,P & 7FH \ OUT (MPCL_ROM),A +#ENDIF diff --git a/trunk/Source/pgzero.asm b/trunk/Source/pgzero.asm new file mode 100644 index 00000000..d8cc6904 --- /dev/null +++ b/trunk/Source/pgzero.asm @@ -0,0 +1,28 @@ +;___PGZERO_____________________________________________________________________________________________________________ +; + .ORG 0000H +; +; NORMAL PAGE ZERO SETUP, RET/RETI/RETN AS APPROPRIATE +; + .FILL (000H - $),0FFH ; RST 0 + JP 0100H ; JUMP TO BOOT CODE + .FILL (008H - $),0FFH ; RST 8 + RET + .FILL (010H - $),0FFH ; RST 10 + RET + .FILL (018H - $),0FFH ; RST 18 + RET + .FILL (020H - $),0FFH ; RST 20 + RET + .FILL (028H - $),0FFH ; RST 28 + RET + .FILL (030H - $),0FFH ; RST 30 + RET + .FILL (038H - $),0FFH ; INT + RETI + .FILL (066H - $),0FFH ; NMI + RETN +; + .FILL (100H - $),0FFH +; + .END diff --git a/trunk/Source/ppide.asm b/trunk/Source/ppide.asm new file mode 100644 index 00000000..9e66d5b2 --- /dev/null +++ b/trunk/Source/ppide.asm @@ -0,0 +1,674 @@ +; +;================================================================================================== +; PPIDE DISK DRIVER +;================================================================================================== +; +; 11/29/2011 dwg - DOUGDEBUG controls the embedded NOPs which adjust for +; recovery time while using the parallel port to talk to the PPIDE and IDE +; device. Using this stabilized by Zeta (8MHz) with a CF chip. +; +; 12/02/2011 wbw - renamed DOUGDEBUG to PPIDESLOW and exposed in config +; PPIDESLOW now controls the RECOVERY macro definition. +; +#IF (PPIDESLOW) +#DEFINE RECOVERY NOP\ NOP\ NOP\ NOP +#ELSE +#DEFINE RECOVERY ; +#ENDIF +; +; MAP PPI PORTS TO PPIDE PORTS +; +#IF (PPIDEMODE == PPIDEMODE_DIO3) +IDELSB .EQU 20H ; LSB +IDEMSB .EQU 21H ; MSB +IDECTL .EQU 22H ; CONTROL SIGNALS +PPI1CONT .EQU 23H ; CONTROL BYTE PPI 82C55 +#ELSE +IDELSB .EQU PIOA ; LSB +IDEMSB .EQU PIOB ; MSB +IDECTL .EQU PIOC ; CONTROL SIGNALS +PPI1CONT .EQU PIOX ; CONTROL BYTE PPI 82C55 +#ENDIF +; +; PPI control bytes for read and write to IDE drive +; +RD_IDE_8255 .EQU 10010010B ; IDE_8255_CTL OUT, IDE_8255_LSB/MSB INPUT +WR_IDE_8255 .EQU 10000000B ; ALL THREE PORTS OUTPUT +; +; IDE CONTROL LINES FOR USE WITH IDE_8255_CTL. CHANGE THESE 8 +; CONSTANTS TO REFLECT WHERE EACH SIGNAL OF THE 8255 EACH OF THE +; IDE CONTROL SIGNALS IS CONNECTED. ALL THE CONTROL SIGNALS MUST +; BE ON THE SAME PORT, BUT THESE 8 LINES LET YOU CONNECT THEM TO +; WHICHEVER PINS ON THAT PORT. +; +PPIDE_A0_LINE .EQU 01H ; DIRECT FROM 8255 TO IDE INTERFACE +PPIDE_A1_LINE .EQU 02H ; DIRECT FROM 8255 TO IDE INTERFACE +PPIDE_A2_LINE .EQU 04H ; DIRECT FROM 8255 TO IDE INTERFACE +PPIDE_CS0_LINE .EQU 08H ; INVERTER BETWEEN 8255 AND IDE INTERFACE +PPIDE_CS1_LINE .EQU 10H ; INVERTER BETWEEN 8255 AND IDE INTERFACE +PPIDE_WR_LINE .EQU 20H ; INVERTER BETWEEN 8255 AND IDE INTERFACE +PPIDE_RD_LINE .EQU 40H ; INVERTER BETWEEN 8255 AND IDE INTERFACE +PPIDE_RST_LINE .EQU 80H ; INVERTER BETWEEN 8255 AND IDE INTERFACE +; +;------------------------------------------------------------------ +; MORE SYMBOLIC CONSTANTS... THESE SHOULD NOT BE CHANGED, UNLESS OF +; COURSE THE IDE DRIVE INTERFACE CHANGES, PERHAPS WHEN DRIVES GET +; TO 128G AND THE PC INDUSTRY WILL DO YET ANOTHER KLUDGE. +; +; SOME SYMBOLIC CONSTANTS FOR THE IDE REGISTERS, WHICH MAKES THE +; CODE MORE READABLE THAN ALWAYS SPECIFYING THE ADDRESS PINS +; +PPIDE_DATA .EQU PPIDE_CS0_LINE +PPIDE_ERROR .EQU PPIDE_CS0_LINE + PPIDE_A0_LINE +PPIDE_SEC_CNT .EQU PPIDE_CS0_LINE + PPIDE_A1_LINE +PPIDE_SECTOR .EQU PPIDE_CS0_LINE + PPIDE_A1_LINE + PPIDE_A0_LINE +PPIDE_CYL_LSB .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE +PPIDE_CYL_MSB .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE + PPIDE_A0_LINE +PPIDE_HEAD .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE +PPIDE_COMMAND .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE + PPIDE_A0_LINE +PPIDE_STTS .EQU PPIDE_CS0_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE + PPIDE_A0_LINE +PPIDE_CONTROL .EQU PPIDE_CS1_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE +PPIDE_ASTTS .EQU PPIDE_CS1_LINE + PPIDE_A2_LINE + PPIDE_A1_LINE + PPIDE_A0_LINE +; +; IDE COMMAND CONSTANTS. THESE SHOULD NEVER CHANGE. +; +PPIDECMD_RECAL .EQU 010H +PPIDECMD_READ .EQU 020H +PPIDECMD_WRITE .EQU 030H +PPIDECMD_INIT .EQU 091H +PPIDECMD_ID .EQU 0ECH +PPIDECMD_SPINDOWN .EQU 0E0H +PPIDECMD_SPINUP .EQU 0E1H +PPIDECMD_SETFEAT .EQU 0EFH +; +PPIDERC_OK .EQU 0 +PPIDERC_CMDERR .EQU 1 +PPIDERC_RDYTO .EQU 2 +PPIDERC_BUFTO .EQU 3 +; +; UNIT CONFIGURATION +; +PPIDE0_DEVICE .DB 11100000B ; LBA, MASTER DEVICE +PPIDE1_DEVICE .DB 11110000B ; LBA, SLAVE DEVICE +; +; +; +PPIDE_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F + JR Z,PPIDE_RD + DEC A + JR Z,PPIDE_WR + DEC A + JR Z,PPIDE_ST + DEC A + JR Z,PPIDE_MED + CALL PANIC +; +PPIDE_RD: + JP PPIDE_XREAD +PPIDE_WR: + JP PPIDE_XWRITE +PPIDE_ST: + JP PPIDE_STATUS +PPIDE_MED: + JP PPIDE_MEDIA +; +; PPIDE_MEDIA +; +PPIDE_MEDIA: + LD A,MID_HD + RET +; +; +; +PPIDE_INIT: + CALL PPIDE_RESET + XOR A + DEC A ; INITIAL STATUS IS NOT READY $FF + LD (PPIDE_STAT),A ; SAVE IT + RET +; +; +; +PPIDE_STATUS: + LD A,(PPIDE_STAT) ; LOAD STATUS + OR A ; SET FLAGS + RET +; +; +; +PPIDE_XREAD: + LD A,PPIDECMD_READ + LD (PPIDEP_CMD),A + JP PPIDE_RW +; +; +; +PPIDE_XWRITE: + LD A,PPIDECMD_WRITE + LD (PPIDEP_CMD),A + JP PPIDE_RW +; +; +; +PPIDE_RW: + ; CLEAR RESULTS + XOR A ; A = 0 + LD (PPIDE_RC),A ; CLEAR RETURN CODE + LD (PPIDEP_STTS),A ; CLEAR SAVED STTS + LD (PPIDEP_ERR),A ; CLEAR SAVED ERR + + ; INIT REQUIRED? + LD A,(PPIDE_STAT) + OR A ; SET FLAGS + JR Z,PPIDE_RW0 ; IF STATUS OK, BYPASS RESET + + CALL PPIDE_RESET ; DO THE RESET + +#IF (PPIDE8BIT) + CALL PPIDE_WAITRDY + + LD C,01H + LD A,PPIDE_ERROR + CALL PPIDE_WRITE + LD C,PPIDECMD_SETFEAT + LD A,PPIDE_COMMAND + CALL PPIDE_WRITE + CALL PPIDE_WAITRDY + JP NC,PPIDE_ERR + CALL PPIDE_CHKERR ; CHECK FOR ERRORS + JP NC,PPIDE_ERR +#IF (PPIDETRACE >= 2) + CALL IDE_PRT +#ENDIF +#ENDIF + +PPIDE_RW0: + CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY + JP NC,PPIDE_ERR + CALL PPIDE_SETUP ; SETUP CYL, TRK, HEAD + LD A,(PPIDEP_CMD) + LD C,A + LD A,PPIDE_COMMAND + CALL PPIDE_WRITE + CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY + JP NC,PPIDE_ERR + CALL PPIDE_CHKERR ; CHECK FOR ERRORS + JP NC,PPIDE_ERR + CALL PPIDE_WAITBUF ; WAIT FOR BUFFER READY + JP NC,PPIDE_ERR + + LD A,(PPIDEP_CMD) ; DISPATCH TO READ OR WRITE SPECIFIC LOGIC + CP PPIDECMD_WRITE + JP Z,PPIDE_RW1 + + CALL PPIDE_BUFRD ; READ BUFFER + CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY + JP NC,PPIDE_ERR + CALL PPIDE_CHKERR ; CHECK FOR ERRORS + JP NC,PPIDE_ERR + JP PPIDE_OK + +PPIDE_RW1: + CALL PPIDE_BUFWR ; WRITE BUFFER + CALL PPIDE_WAITRDY ; WAIT FOR DRIVE READY + JP NC,PPIDE_ERR + CALL PPIDE_CHKERR ; CHECK FOR ERRORS + JP NC,PPIDE_ERR + JP PPIDE_OK + +PPIDE_ERR: + XOR A + DEC A ; A = $FF TO SIGNAL ERROR + LD (PPIDE_STAT),A ; SAVE IT +#IF (PPIDETRACE >= 1) + PUSH AF + CALL PPIDE_PRT + POP AF +#ENDIF + RET + +PPIDE_OK: +#IF (PPIDETRACE >= 2) + CALL PPIDE_PRT +#ENDIF + XOR A + RET +; +; +; +PPIDE_RESET: + LD C,000001110B ; NO INTERRUPTS, ASSERT RESET BOTH DRIVES + LD A,PPIDE_CONTROL + CALL PPIDE_WRITE + LD DE,8 ; DELAY ABOUT 200ms + CALL VDELAY + LD C,000000010B ; NO INTERRUPTS, DEASSERT RESET + LD A,PPIDE_CONTROL + CALL PPIDE_WRITE + XOR A ; STATUS OK + LD (PPIDE_STAT),A ; SAVE IT + + RET +; +; +; +PPIDE_WAITRDY: + LD DE,0 ; TIMEOUT IS 250us * 65536 = 15 SECONDS +PPIDE_WBSY: + PUSH DE + LD DE,10 ; INNER LOOP DELAY IS 250us (25us * 10) + CALL VDELAY + POP DE + DEC DE + LD A,D + OR E + JP Z,PPIDE_TO + LD A,PPIDE_STTS + CALL PPIDE_READ + LD A,C + LD (PPIDEP_STTS),A ; SAVE IT + AND 011000000B ; ISOLATE BUSY AND RDY BITS + XOR 001000000B ; WE WANT BUSY(7) TO BE 0 AND RDY(6) TO BE 1 + JP NZ,PPIDE_WBSY + SCF ; CARRY 1 = OK + RET +PPIDE_TO: + LD A,PPIDERC_RDYTO + LD (PPIDE_RC),A + XOR A ; CARRY 0 = TIMEOUT + RET +; +; +; +PPIDE_CHKERR: + LD A,PPIDE_STTS + CALL PPIDE_READ + LD A,C + LD (PPIDEP_STTS),A ; SAVE IT + AND 000000001B ; ERROR BIT SET? + SCF ; ASSUME NO ERR + RET Z ; NO ERR, RETURN WITH CF SET + + LD A,PPIDE_ERROR + CALL PPIDE_READ + LD A,C + LD (PPIDEP_ERR),A ; SAVE IT + + LD A,PPIDERC_CMDERR ; COMMAND ERROR + LD (PPIDE_RC),A ; SAVE IT + + OR A ; CLEAR CF TO SIGNAL ERROR + RET +; +; +; +PPIDE_WAITBUF: + LD DE,0 +PPIDE_WDRQ: + CALL DELAY + INC DE + LD A,D + OR E + JP Z,PPIDE_TO2 + LD A,PPIDE_STTS + CALL PPIDE_READ + LD A,C + LD (PPIDEP_STTS),A ; SAVE IT + AND 010001000B ; TO FILL (OR READY TO FILL) + XOR 000001000B + JP NZ,PPIDE_WDRQ + SCF ; CARRY 1 = OK + RET +PPIDE_TO2: + LD A,PPIDERC_BUFTO + LD (PPIDE_RC),A + XOR A ; CARRY 0 = TIMED OUT + RET +; +; +; +#IF (PPIDE8BIT) +PPIDE_BUFRD: + LD HL,(DIOBUF) + LD DE,200H +PPIDE_BUFRD1: + LD A,PPIDE_DATA + CALL PPIDE_READ + LD (HL),C + INC HL + DEC DE + LD A,D + OR E + JP NZ,PPIDE_BUFRD1 + RET +#ELSE +PPIDE_BUFRD: + LD HL,(DIOBUF) + LD D,0 +PPIDE_BUFRD1: + LD A,PPIDE_DATA + CALL PPIDE_READ + LD (HL),C + INC HL + LD (HL),B + INC HL + DEC D + JP NZ,PPIDE_BUFRD1 + RET +#ENDIF +; +; +; +#IF (PPIDE8BIT) +PPIDE_BUFWR: + LD HL,(DIOBUF) + LD DE,200H +PPIDE_BUFWR1: + LD C,(HL) + LD A,PPIDE_DATA + CALL PPIDE_WRITE + INC HL + DEC DE + LD A,D + OR E + JP NZ,PPIDE_BUFWR1 +#ELSE +PPIDE_BUFWR: + LD HL,(DIOBUF) + LD D,0 +PPIDE_BUFWR1: + LD C,(HL) + INC HL + LD B,(HL) + INC HL + LD A,PPIDE_DATA + CALL PPIDE_WRITE + DEC D + JP NZ,PPIDE_BUFWR1 + RET +#ENDIF +; +; +; +PPIDE_SETUP: + LD C,1 + LD A,PPIDE_SEC_CNT + CALL PPIDE_WRITE + + LD A,(HSTDSK) ; HSTDSK -> HEAD BIT 4 TO SELECT UNIT + AND 0FH + CP 0 + JP Z,PPIDE_SETUP_UNIT0 + CP 1 + JP Z,PPIDE_SETUP_UNIT1 + CALL PANIC +PPIDE_SETUP_UNIT0: + LD A,(PPIDE0_DEVICE) +; LD DE,(PPIDE0_OFFSET) + JP PPIDE_SETUP1 +PPIDE_SETUP_UNIT1: + LD A,(PPIDE1_DEVICE) +; LD DE,(PPIDE1_OFFSET) + JP PPIDE_SETUP1 +PPIDE_SETUP1: + LD (PPIDEP_HEAD),A + LD C,A + LD A,PPIDE_HEAD + CALL PPIDE_WRITE + + LD HL,(HSTTRK) ; HSTTRK -> IDECYLHI/LO + LD A,H + LD (PPIDEP_CYLHI),A + LD C,A + LD A,PPIDE_CYL_MSB + CALL PPIDE_WRITE + LD A,L + LD (PPIDEP_CYLLO),A + LD C,A + LD A,PPIDE_CYL_LSB + CALL PPIDE_WRITE + + LD BC,(HSTSEC) ; HSTSEC -> IDESECTN + LD A,C + LD (PPIDEP_SEC),A + LD C,A + LD A,PPIDE_SECTOR + CALL PPIDE_WRITE + +#IF (DSKYENABLE) + CALL PPIDE_DSKY +#ENDIF + + RET +; +; +; +PPIDE_READ: + PUSH AF ; save register value + LD A,RD_IDE_8255 + OUT (PPI1CONT),A ; Config 8255 chip, read mode + RECOVERY + POP AF ; restore register value + + OUT (IDECTL),A ; Drive address onto control lines + RECOVERY + OR PPIDE_RD_LINE ; assert RD pin + + OUT (IDECTL),A + RECOVERY + + PUSH AF ; save register value + IN A,(IDELSB) ; read lower byte + RECOVERY + LD C,A ; save in reg C + + IN A,(IDEMSB) ; read upper byte + RECOVERY + LD B,A ; save in reg C + + POP AF ; restore register value + XOR PPIDE_RD_LINE ; de-assert RD signal + OUT (IDECTL),A + RECOVERY + + XOR A + OUT (IDECTL),A ; Deassert all control pins + RECOVERY + RET +; +; +; +PPIDE_WRITE: + PUSH AF ; save IDE register value + LD A,WR_IDE_8255 + OUT (PPI1CONT),A ; Config 8255 chip, write mode + RECOVERY + + LD A,C ; get value to be written + OUT (IDELSB),A + RECOVERY + + LD A,B ; get value to be written + OUT (IDEMSB),A + RECOVERY + + + POP AF ; get saved IDE register + OUT (IDECTL),A ; Drive address onto control lines + RECOVERY + OR PPIDE_WR_LINE ; assert write pin + OUT (IDECTL),A + RECOVERY + + XOR PPIDE_WR_LINE ; de assert WR pin + OUT (IDECTL),A ; Drive address onto control lines + RECOVERY + + XOR A + OUT (IDECTL),A ; release bus signals + RECOVERY + RET +; +; +; +#IF (DSKYENABLE) +PPIDE_DSKY: + LD HL,DSKY_HEXBUF + LD A,(PPIDEP_HEAD) + LD (HL),A + INC HL + LD A,(PPIDEP_CYLHI) + LD (HL),A + INC HL + LD A,(PPIDEP_CYLLO) + LD (HL),A + INC HL + LD A,(PPIDEP_SEC) + LD (HL),A + CALL DSKY_HEXOUT + RET +#ENDIF +; +; +; +PPIDE_PRT: + CALL NEWLINE + + LD DE,PPIDESTR_PREFIX + CALL WRITESTR + + CALL PC_SPACE + LD DE,PPIDESTR_CMD + CALL WRITESTR + LD A,(PPIDEP_CMD) + CALL PRTHEXBYTE + + CALL PC_SPACE + CALL PC_LBKT + LD A,(PPIDEP_CMD) + LD DE,PPIDESTR_READ + CP PPIDECMD_READ + JP Z,PPIDE_PRTCMD + LD DE,PPIDESTR_WRITE + CP PPIDECMD_READ + JP Z,PPIDE_PRTCMD + LD DE,PPIDESTR_UNKCMD +PPIDE_PRTCMD: + CALL WRITESTR + CALL PC_RBKT + + CALL PC_SPACE + LD A,(PPIDEP_HEAD) + CALL PRTHEXBYTE + LD A,(PPIDEP_CYLHI) + CALL PRTHEXBYTE + LD A,(PPIDEP_CYLLO) + CALL PRTHEXBYTE + LD A,(PPIDEP_SEC) + CALL PRTHEXBYTE + + CALL PC_SPACE + LD DE,PPIDESTR_ARROW + CALL WRITESTR + + CALL PC_SPACE + LD A,PPIDE_STTS + CALL PPIDE_READ + LD A,C + CALL PRTHEXBYTE + + CALL PC_SPACE + LD A,PPIDE_ERROR + CALL PPIDE_READ + LD A,C + CALL PRTHEXBYTE + + CALL PC_SPACE + LD DE,PPIDESTR_RC + CALL WRITESTR + LD A,(PPIDE_RC) + CALL PRTHEXBYTE + + CALL PC_SPACE + CALL PC_LBKT + LD A,(PPIDE_RC) + LD DE,PPIDESTR_RCOK + CP PPIDERC_OK + JP Z,PPIDE_PRTRC + LD DE,PPIDESTR_RCCMDERR + CP PPIDERC_CMDERR + JP Z,PPIDE_PRTRC + LD DE,PPIDESTR_RCRDYTO + CP PPIDERC_RDYTO + JP Z,PPIDE_PRTRC + LD DE,PPIDESTR_RCBUFTO + CP PPIDERC_BUFTO + JP Z,PPIDE_PRTRC + LD DE,PPIDESTR_RCUNK +PPIDE_PRTRC: + CALL WRITESTR + CALL PC_RBKT + + RET +; +; +; +PPIDESTR_PREFIX .TEXT "PPIDE:$" +PPIDESTR_CMD .TEXT "CMD=$" +PPIDESTR_RC .TEXT "RC=$" +PPIDESTR_ARROW .TEXT "-->$" +PPIDESTR_READ .TEXT "READ$" +PPIDESTR_WRITE .TEXT "WRITE$" +PPIDESTR_UNKCMD .TEXT "UNKCMD" +PPIDESTR_RCOK .TEXT "OK$" +PPIDESTR_RCCMDERR .TEXT "COMMAND ERROR$" +PPIDESTR_RCRDYTO .TEXT "READY TIMEOUT$" +PPIDESTR_RCBUFTO .TEXT "BUFFER TIMEOUT$" +PPIDESTR_RCUNK .TEXT "UNKNOWN ERROR$" +; +;================================================================================================== +; PPIDE DISK DRIVER - DATA +;================================================================================================== +; +PPIDE_STAT .DB 0 +PPIDE_RC .DB 0 +; +; PPIDE PARAMETERS +; +PPIDEP_CMD .DB 0 +PPIDEP_HEAD .DB 0 +PPIDEP_CYLHI .DB 0 +PPIDEP_CYLLO .DB 0 +PPIDEP_SEC .DB 0 +PPIDEP_STTS .DB 0 +PPIDEP_ERR .DB 0 +; +; +; +; +; +; +; +; Error Register (ERR bit being set in the Status Register) +; +; Bit 7: BBK (Bad Block Detected) Set when a Bad Block is detected. +; Bit 6: UNC (Uncorrectable Data Error) Set when Uncorrectable Error is encountered. +; Bit 5: MC (Media Changed) Set to 0. +; Bit 4: IDNF (ID Not Found) Set when Sector ID not found. +; Bit 3: MCR (Media Change Request) Set to 0. +; Bit 2: ABRT (Aborted Command) Set when Command Aborted due to drive error. +; Bit 1: TKONF (Track 0 Not Found) Set when Executive Drive Diagnostic Command. +; Bit 0: AMNF (Address mark Not Found) Set in case of a general error. +; +; Status Register (When the contents of this register are read by the host, the IREQ# bit is cleared) +; +; Bit 7: BSY (Busy) Set when the drive is busy and unable to process any new ATA commands. +; Bit 6: DRDY (Data Ready) Set when the device is ready to accept ATA commands from the host. +; Bit 5: DWF (Drive Write Fault) Always set to 0. +; Bit 4: DSC (Drive Seek Complete) Set when the drive heads have been positioned over a specific track. +; Bit 3: DRQ (Data Request) Set when device is ready to transfer a word or byte of data to or from the host and the device. +; Bit 2: CORR (Corrected Data) Always set to 0. +; Bit 1: IDX (Index) Always set to 0. +; Bit 0: ERR (Error) Set when an error occurred during the previous ATA command. \ No newline at end of file diff --git a/trunk/Source/ppide_data.asm b/trunk/Source/ppide_data.asm new file mode 100644 index 00000000..2fb4c2b3 --- /dev/null +++ b/trunk/Source/ppide_data.asm @@ -0,0 +1,61 @@ +; +;================================================================================================== +; PPIDE DISK DRIVER - DATA +;================================================================================================== +; +PPIDE_SLICETRKS .EQU 65 ; TRACKS PER SLICE +PPIDE_TRKSIZE .EQU 128 ; SIZE OF TRACK (IN KB) +PPIDE_SLICESIZE .EQU ((PPIDE_SLICETRKS * PPIDE_TRKSIZE) + 1023) / 1024 ; SIZE OF EACH SLICE (IN MB) +PPIDE_NUMSLICES .EQU PPIDECAPACITY / PPIDE_SLICESIZE ; TOTAL SLICES IN DEVICE +PPIDE0_SLICEDEF .EQU 0 ; DEFAULT SLICE FOR UNIT 0 +PPIDE1_SLICEDEF .EQU 1 ; DEFAULT SLICE FOR UNIT 1 +PPIDE2_SLICEDEF .EQU 2 ; DEFAULT SLICE FOR UNIT 0 +PPIDE3_SLICEDEF .EQU 3 ; DEFAULT SLICE FOR UNIT 1 +; + .DB DIODEV_PPIDE + 0 +PPIDEDPH0 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PPIDECSV0,PPIDEALV0 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PPIDE0_SLICE .DW PPIDE0_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PPIDE_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PPIDE + 0 +PPIDEDPH1 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,0FFFFH + .DW PPIDECSV1,PPIDEALV1 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PPIDE1_SLICE .DW PPIDE1_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PPIDE_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PPIDE + 0 +PPIDEDPH2 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,0FFFFH + .DW PPIDECSV2,PPIDEALV2 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PPIDE2_SLICE .DW PPIDE2_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PPIDE_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PPIDE + 0 +PPIDEDPH3 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,0FFFFH + .DW PPIDECSV3,PPIDEALV3 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PPIDE3_SLICE .DW PPIDE3_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PPIDE_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; +PPIDECKS .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA +PPIDEALS .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP) +; +PPIDECSV0: .FILL PPIDECKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PPIDEALV0: .FILL PPIDEALS ; MAX OF 2048 DATA BLOCKS +PPIDECSV1: .FILL PPIDECKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PPIDEALV1: .FILL PPIDEALS ; MAX OF 2048 DATA BLOCKS +PPIDECSV2: .FILL PPIDECKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PPIDEALV2: .FILL PPIDEALS ; MAX OF 2048 DATA BLOCKS +PPIDECSV3: .FILL PPIDECKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PPIDEALV3: .FILL PPIDEALS ; MAX OF 2048 DATA BLOCKS diff --git a/trunk/Source/ppp.asm b/trunk/Source/ppp.asm new file mode 100644 index 00000000..22a80d1c --- /dev/null +++ b/trunk/Source/ppp.asm @@ -0,0 +1,472 @@ +; +;================================================================================================== +; PARPORTPROP DRIVER +;================================================================================================== +; +; COMMAND BYTES +; +PPP_CMDNOP .EQU $00 ; DO NOTHING +PPP_CMDECHOBYTE .EQU $01 ; RECEIVE A BYTE, INVERT IT, SEND IT BACK +PPP_CMDECHOBUF .EQU $02 ; RECEIVE 512 BYTE BUFFER, SEND IT BACK +; +PPP_CMDDSKRES .EQU $10 ; RESTART SD CARD SUPPORT +PPP_CMDDSKSTAT .EQU $11 ; SEND LAST SD CARD STATUS (4 BYTES) +PPP_CMDDSKPUT .EQU $12 ; PPI -> SECTOR BUFFER -> PPP +PPP_CMDDSKGET .EQU $13 ; PPP -> SECTOR BUFFER -> PPI +PPP_CMDDSKRD .EQU $14 ; READ SCTOR FROM SD CARD INTO PPP BUFFER, RETURN 1 BYTE STATUS +PPP_CMDDSKWR .EQU $15 ; WRITE SECTOR TO SD CARD FROM PPP BUFFER, RETURN 1 BYTE STATUS +; +PPP_CMDVIDOUT .EQU $20 ; WRITE A BYTE TO THE TERMINAL EMULATOR +; +PPP_CMDKBDSTAT .EQU $30 ; RETURN A BYTE WITH NUMBER OF CHARACTERS IN BUFFER +PPP_CMDKBDRD .EQU $31 ; RETURN A CHARACTER, WAIT IF NECESSARY +; +PPP_CMDSPKTONE .EQU $40 ; EMIT SPEAKER TONE AT SPECIFIED FREQUENCY AND DURATION +; +PPP_CMDSIOINIT .EQU $50 ; RESET SERIAL PORT AND ESTABLISH A NEW BAUD RATE (4 BYTE BAUD RATE) +PPP_CMDSIORX .EQU $51 ; RECEIVE A BYTE IN FROM SERIAL PORT +PPP_CMDSIOTX .EQU $52 ; TRANSMIT A BYTE OUT OF THE SERIAL PORT +PPP_CMDSIORXST .EQU $53 ; SERIAL PORT RECEIVE STATUS (RETURNS # BYTES OF RX BUFFER USED) +PPP_CMDSIOTXST .EQU $54 ; SERIAL PORT TRANSMIT STATUS (RETURNS # BYTES OF TX BUFFER SPACE AVAILABLE) +PPP_CMDSIORXFL .EQU $55 ; SERIAL PORT RECEIVE BUFFER FLUSH +PPP_CMDSIOTXFL .EQU $56 ; SERIAL PORT TRANSMIT BUFFER FLUSH (NOT IMPLEMENTED) +; +PPP_CMDRESET .EQU $F0 ; SOFT RESET PROPELLER +; +; GLOBAL PARPORTPROP INITIALIZATION +; +PPP_INIT: + LD A,$9B ; PPI MODE 0, ALL PINS INPUT + OUT (PIOX),A ; SEND IT + + LD A,11000010B ; PPI MODE 2 (BI HANDSHAKE), PC0-2 OUT, PB IN + OUT (PIOX),A + + CALL DELAY ; PROBABLY NOT NEEDED + + LD A,00000000B ; SET PC0 -> 0 + OUT (PIOX),A + LD A,00000010B ; SET PC1 -> 0 + OUT (PIOX),A + LD A,00000101B ; SET PC2 -> 1 - ASSERT RESET ON PPP + OUT (PIOX),A + LD A,00000110B ; SET PC3 -> 0 + OUT (PIOX),A + + CALL DELAY ; PROBABLY NOT NEEDED + + IN A,(PIOA) ; CLEAR GARBAGE??? + + CALL DELAY ; PROBABLY NOT NEEDED + + LD A,00000001B ; SET CMD FLAG + OUT (PIOX),A ; SEND IT + LD E,PPP_CMDRESET + CALL PUTBYTE ; SEND THE COMMAND BYTE + CALL DELAY + LD A,00000000B ; CLEAR CMD FLAG + OUT (PIOX),A + + LD A,00000100B ; SET PC2 -> 0 - DEASSERT RESET ON PPP + OUT (PIOX),A + + CALL DELAY ; PROBABLY NOT NEEDED + + LD BC,0 +INIT1: + PUSH BC + CALL DELAY + CALL DELAY + CALL DELAY + CALL DELAY + IN A,(PIOA) + POP BC + CP $AA + RET Z + DEC BC + LD A,B + OR C + JR NZ,INIT1 + + CALL NEWLINE + LD DE,PPPSTR_TIMEOUT + CALL WRITESTR + + CALL PPPSD_INIT ; SD CARD INITIALIZATION + + RET +; +;================================================================================================== +; PARPORTPROP CONSOLE DRIVER +;================================================================================================== +; +; DISPATCH FOR CONSOLE SUBFUNCTIONS +; +PPPCON_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JR Z,PPPCON_IN ; JUMP IF CHARACTER IN + DEC A ; NEXT SUBFUNCTION + JR Z,PPPCON_OUT ; JUMP IF CHARACTER OUT + DEC A ; NEXT SUBFUCNTION + JR Z,PPPCON_IST ; JUMP IF INPUT STATUS + DEC A ; NEXT SUBFUNCTION + JR Z,PPPCON_OST ; JUMP IF OUTPUT STATUS + CALL PANIC ; OTHERWISE SOMETHING IS BADLY BROKEN +; +; CHARACTER INPUT +; WAIT FOR A CHARACTER AND RETURN IT IN E +; +PPPCON_IN: + CALL PPPCON_IST ; CHECK FOR CHAR PENDING + JR Z,PPPCON_IN ; WAIT FOR IT IF NECESSARY + LD D,PPP_CMDKBDRD ; CMD = KEYBOARD READ + CALL SENDCMD ; SEND COMMAND + CALL GETBYTE ; GET CHARACTER READ + XOR A ; CLEAR A (SUCCESS) + RET ; AND RETURN +; +; CHARACTER INPUT STATUS +; RETURN STATUS IN A, 0 = NOTHING PENDING, > 0 CHAR PENDING +; +PPPCON_IST: + LD D,PPP_CMDKBDSTAT ; CMD = KEYBOARD STATUS + CALL SENDCMD ; SEND COMMAND + CALL GETBYTE ; GET RESPONSE + LD A,E ; MOVE IT TO A + OR A ; SET FLAGS + RET NZ ; A <> 0, CHAR(S) PENDING + JP CIO_IDLE ; OTHERWISE RET VIA IDLE PROCESSING +; +; CHARACTER OUTPUT +; WRITE CHARACTER IN E +; +PPPCON_OUT: + CALL PPPCON_OST ; CHECK FOR OUTPUT READY + JR Z,PPPCON_OUT ; WAIT IF NECESSARY + LD D,PPP_CMDVIDOUT ; CMD = VIDEO OUTPUT + CALL SENDCMD ; SEND COMMAND + CALL PUTBYTE ; SEND IT + RET ; RETURN +; +; CHARACTER OUTPUT STATUS +; RETURN STATUS IN A, 0 = NOT READY, > 0 READY TO SEND +; CONSOLE IS ALWAYS READY TO SEND (SYNCHRONOUS OUTPUT) +; +PPPCON_OST: + XOR A ; SET A=$01 TO SIGNAL READY + INC A + RET +; +;================================================================================================== +; PARPORTPROP SD CARD DRIVER +;================================================================================================== +; +PPPSD_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F + JP Z,PPPSD_READ ; READ + DEC A + JP Z,PPPSD_WRITE ; WRITE + DEC A + JP Z,PPPSD_STATUS ; STATUS + DEC A + JP Z,PPPSD_MEDIA ; MEDIA ID + CALL PANIC +; +; SETUP FOR SUBSEQUENT ACCESS +; INIT CARD IF NOT READY OR ON DRIVE LOG IN +; +PPPSD_MEDIA: + ; REINITIALIZE THE CARD HERE TO DETERMINE PRESENCE + CALL PPPSD_INITCARD + LD A,MID_NONE ; ASSUME FAILURE + RET NZ + + ; ALL IS WELL, RETURN MEDIA IDENTIFIER + LD A,MID_HD ; SET MEDIA ID + RET +; +; SD CARD INITIALIZATION +; +PPPSD_INIT: + ; MARK DRIVE NOT READY + ; HARDWARE INIT DEFERRED UNTIL DRIVE SELECT + XOR A + DEC A + LD (PPPSD_STAT),A + RET +; +; REPORT SD CARD READY STATE +; +PPPSD_STATUS: + LD A,(PPPSD_STAT) ; GET THE CURRENT READY STATUS + OR A + RET +; +; READ AN LBA BLOCK FROM THE SD CARD +; +PPPSD_READ: + CALL PPPSD_CHKCARD ; CHECK / REINIT CARD AS NEEDED + RET NZ ; BAIL OUT ON ERROR + + ; READ A SECTOR + CALL PPPSD_SETBLK ; SETUP PPP_LBA WITH BLOCK NUMBER + LD D,PPP_CMDDSKRD ; COMMAND = DSKWR + CALL SENDCMD ; SEND COMMAND + CALL PPPSD_SENDBLK ; SEND THE LBA BLOCK NUMBER + CALL GETBYTE + LD A,E + LD (PPPSD_STAT),A ; SAVE STATUS + CALL PPPSD_PRTREAD ; PRINT DIAGNOSTICS AS NEEDED + OR A ; SET FLAGS + RET NZ ; BAIL OUT ON ERROR + + ; GET THE SECTOR DATA + LD D,PPP_CMDDSKGET ; COMMAND = DSKGET + CALL SENDCMD ; SEND COMMAND + + ; READ THE SECTOR DATA + LD BC,512 + LD HL,(DIOBUF) +DSKREAD1: + CALL GETBYTE + LD (HL),E + INC HL + DEC BC + LD A,B + OR C + JP NZ,DSKREAD1 + + XOR A ; SUCCESS + RET +; +; WRITE AN LBA BLOCK TO THE SD CARD +; +PPPSD_WRITE: + CALL PPPSD_CHKCARD ; CHECK / REINIT CARD AS NEEDED + RET NZ ; BAIL OUT ON ERROR + + CALL PPPSD_SETBLK ; SETUP THE LBA BLOCK INDEX + + ; PUT THE SECTOR DATA + LD D,PPP_CMDDSKPUT ; COMMAND = DSKPUT + CALL SENDCMD ; SEND COMMAND + + ; SEND OVER THE SECTOR CONTENTS + LD BC,512 + LD HL,(DIOBUF) +DSKWRITE1: + LD E,(HL) + INC HL + CALL PUTBYTE + DEC BC + LD A,B + OR C + JP NZ,DSKWRITE1 + + ; WRITE THE SECTOR + LD D,PPP_CMDDSKWR ; COMMAND = DSKWR + CALL SENDCMD + CALL PPPSD_SENDBLK ; SEND THE LBA BLOCK NUMBER + CALL GETBYTE + LD A,E + LD (PPPSD_STAT),A ; SAVE STATUS + CALL PPPSD_PRTWRITE ; PRINT DIAGNOSTICS AS NEEDED + OR A ; SET FLAGS + RET ; ALL DONE +; +; REINITIALIZE THE SD CARD +; +PPPSD_INITCARD: + ; RESET & STATUS DISK + LD D,PPP_CMDDSKRES ; COMMAND = DSKRESET + CALL SENDCMD + CALL GETBYTE + LD A,E + LD (PPPSD_STAT),A ; SAVE UPDATED STATUS + OR A + RET ; Z/NZ SET, A HAS RESULT CODE +; +; CHECK THE SD CARD, ATTEMPT TO REINITIALIZE IF NEEDED +; +PPPSD_CHKCARD: + LD A,(PPPSD_STAT) ; GET STATUS + OR A ; SET FLAGS + CALL NZ,PPPSD_INITCARD ; INIT CARD IF NOT READY + RET ; RETURN WITH STATUS IN A +; +; SET UP LBA BLOCK INDEX BASED ON HSTTRK AND HSTSEC +; NOTE THAT BYTE ORDER IS LITTLE ENDIAN FOR PROPLELLER! +; SEE MAPPING IN COMMENTS +; NOTE THAT HSTSEC:MSB IS UNUSED +; +PPPSD_SETBLK: + LD HL,PPP_LBA + 3 ; WORK BACKWARDS, START WITH END OF LBA + XOR A ; MSB OF LBA IS ALWAYS ZERO + LD (HL),A ; LBAHI:MSB = 0 + DEC HL ; POINT TO NEXT BYTE + LD DE,(HSTTRK) ; DE = HSTTRK + LD (HL),D ; LBAHI:LSB = D = HSTTRK:MSB + DEC HL ; POINT TO NEXT BYTE + LD (HL),E ; LBALO:MSB = E = HSTTRK:LSB + DEC HL ; POINT TO NEXT BYTE + LD A,(HSTSEC) ; A = HSTSEC:LSB + LD (HL),A ; LBALO:LSB = A = HSTSEC:LSB + RET +; +; SEND INDEX OF BLOCK TO READ FROM SD CARD +; 32 BIT VALUE (4 BYTES) +; NOTE THAT BYTES ARE SENT REVERSED, PROPELLER IS LITTLE ENDIAN +; +PPPSD_SENDBLK: + LD HL,PPP_LBA + LD B,4 +PPPSD_SENDBLK1: + LD E,(HL) + INC HL + CALL PUTBYTE + DJNZ PPPSD_SENDBLK1 + RET +; +; PRINT DIAGNOSTICS AFTER COMMAND EXECUTION +; +PPPSD_PRTREAD: + LD DE,PPPSTR_READ + JR PPPSD_PRT + +PPPSD_PRTWRITE: + LD DE,PPPSTR_WRITE + JR PPPSD_PRT + +PPPSD_PRT: + OR A +#IF (PPPSDTRACE == 0) + RET +#ELSE +#IF (PPPSDTRACE == 1) + RET Z +#ENDIF + PUSH AF + CALL NEWLINE + LD DE,PPPSTR_PREFIX ; PRINT DRIVER PREFIX + CALL WRITESTR + CALL PC_SPACE + CALL WRITESTR ; PRINT FUNCTION + CALL PPPSD_PRTBLK ; PRINT BLOCK NUMBER + CALL PC_SPACE + LD DE,PPPSTR_ARROW ; PRINT ARROW + CALL WRITESTR + CALL PC_SPACE + POP AF + PUSH AF + CALL PRTHEXBYTE ; PRINT RESULT BYTE + CALL NZ,PPPSD_PRTERR ; PRINT DETAILED ERROR VALUE IF APPROPRIATE + POP AF + RET ; RET WITH A = STATUS + +PPPSD_PRTBLK: + CALL PC_SPACE + LD HL,PPP_LBA + 4 + LD B,4 +PPPSD_PRTBLK1: + DEC HL + LD A,(HL) + CALL PRTHEXBYTE + DJNZ PPPSD_PRTBLK1 + RET + +PPPSD_PRTERR: + LD D,PPP_CMDDSKSTAT + CALL SENDCMD + + LD HL,PPP_DSKSTAT + LD B,4 +PPPSD_PRTERR1: + CALL GETBYTE + LD (HL),E + INC HL + DJNZ PPPSD_PRTERR1 + + CALL PC_LBKT + LD BC,(PPP_DSKSTHI) + CALL PRTHEXWORD + LD BC,(PPP_DSKSTLO) + CALL PRTHEXWORD + CALL PC_RBKT + + RET +#ENDIF +; +;================================================================================================== +; PPPSD DISK DRIVER - DATA +;================================================================================================== +; +PPPSD_STAT .DB 0 +; +PPP_LBA: +PPP_LBALO .DW 0 +PPP_LBAHI .DW 0 +PPP_DSKSTAT: +PPP_DSKSTLO .DW 0 +PPP_DSKSTHI .DW 0 +; +PPPSTR_PREFIX .TEXT "PPPDSK:$" +PPPSTR_CMD .TEXT "CMD=$" +PPPSTR_READ .TEXT "READ$" +PPPSTR_WRITE .TEXT "WRITE$" +;PPPSTR_RC .TEXT "RC=$" +PPPSTR_ARROW .TEXT "-->$" +PPPSTR_ERR .TEXT "ERR=$" +;PPPSTR_RCOK .TEXT "OK$" +;PPPSTR_RCRDYTO .TEXT "READY TIMEOUT$" +; +;================================================================================================== +; GLOBAL PPP DRIVER FUNCTIONS +;================================================================================================== +; +PUTBYTE: + IN A,(PIOC) + BIT 7,A + JR Z,PUTBYTE + LD A,E + OUT (PIOA),A + RET +; +GETBYTE: + IN A,(PIOC) + BIT 5,A + JR Z,GETBYTE + IN A,(PIOA) + LD E,A + RET +; +SENDCMD: + IN A,(PIOA) ; DISCARD ANYTHING PENDING + ; WAIT FOR OBF HIGH (OUTPUT BUFFER TO BE EMPTY) + IN A,(PIOC) + BIT 7,A + JR Z,SENDCMD + + LD A,00000001B ; SET CMD FLAG + OUT (PIOX),A ; SEND IT + +SENDCMD0: + IN A,(PIOC) + BIT 7,A + JR Z,SENDCMD0 + LD A,D + OUT (PIOA),A + +SENDCMD1: + ; WAIT FOR OBF HIGH (BYTE HAS BEEN RECEIVED) + IN A,(PIOC) + BIT 7,A + JR Z,SENDCMD1 + ; TURN OFF CMD + LD A,00000000B ; CLEAR CMD FLAG + OUT (PIOX),A + + RET +; +PPPSTR_TIMEOUT .TEXT "ParPortProp not responding!$" diff --git a/trunk/Source/ppp_data.asm b/trunk/Source/ppp_data.asm new file mode 100644 index 00000000..94e0ccc1 --- /dev/null +++ b/trunk/Source/ppp_data.asm @@ -0,0 +1,61 @@ +; +;================================================================================================== +; PPPSD DISK DRIVER - DATA +;================================================================================================== +; +PPPSD_SLICETRKS .EQU 65 ; TRACKS PER SLICE +PPPSD_TRKSIZE .EQU 128 ; SIZE OF TRACK (IN KB) +PPPSD_SLICESIZE .EQU ((PPPSD_SLICETRKS * PPPSD_TRKSIZE) + 1023) / 1024 ; SIZE OF EACH SLICE (IN MB) +PPPSD_NUMSLICES .EQU PPPSDCAPACITY / PPPSD_SLICESIZE ; TOTAL SLICES IN DEVICE +PPPSD0_SLICEDEF .EQU 0 ; DEFAULT SLICE FOR UNIT 0 +PPPSD1_SLICEDEF .EQU 1 ; DEFAULT SLICE FOR UNIT 1 +PPPSD2_SLICEDEF .EQU 2 ; DEFAULT SLICE FOR UNIT 0 +PPPSD3_SLICEDEF .EQU 3 ; DEFAULT SLICE FOR UNIT 1 +; + .DB DIODEV_PPPSD + 0 +PPPSDDPH0 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PPPSDCSV0,PPPSDALV0 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PPPSD0_SLICE .DW PPPSD0_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PPPSD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PPPSD + 0 +PPPSDDPH1 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PPPSDCSV1,PPPSDALV1 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PPPSD1_SLICE .DW PPPSD1_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PPPSD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PPPSD + 0 +PPPSDDPH2 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PPPSDCSV2,PPPSDALV2 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PPPSD2_SLICE .DW PPPSD2_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PPPSD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PPPSD + 0 +PPPSDDPH3 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PPPSDCSV3,PPPSDALV3 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PPPSD3_SLICE .DW PPPSD3_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PPPSD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; +PPPSDCKS .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA +PPPSDALS .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP) +; +PPPSDCSV0 .FILL PPPSDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PPPSDALV0 .FILL PPPSDALS ; MAX OF 2048 DATA BLOCKS +PPPSDCSV1 .FILL PPPSDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PPPSDALV1 .FILL PPPSDALS ; MAX OF 2048 DATA BLOCKS +PPPSDCSV2 .FILL PPPSDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PPPSDALV2 .FILL PPPSDALS ; MAX OF 2048 DATA BLOCKS +PPPSDCSV3 .FILL PPPSDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PPPSDALV3 .FILL PPPSDALS ; MAX OF 2048 DATA BLOCKS diff --git a/trunk/Source/prefix.asm b/trunk/Source/prefix.asm new file mode 100644 index 00000000..ddc69c08 --- /dev/null +++ b/trunk/Source/prefix.asm @@ -0,0 +1,53 @@ +;---------------------------------------------------------------------------- +; PREFIX.ASM +; +; PUT AT THE HEAD OF BOOT.BIN TO XFER TO A FLOPPY DISK +; +;---------------------------------------------------------------------------- + +; 5/11/2012 dwg - changed offset to BIOS booting fixup location +; 3/ 2/2012 dwg - fixed BOOT_INFO_LOC (moved when jump added for bnksel) +; 2/15/2012 dwg - added origin data written by formatter +; 2/ 5/2012 dwg - added version quad, updates counter, and write protect boolean to metadata +; 1/ 9/2012 wbw - added signature +; 1/ 5/2012 dwg - added version of build generating system image +; 1/ 5/2012 dwg - added drive label to metadata for 1.4 + +#INCLUDE "std.asm" + +BYT .EQU 1 ; used to describe METADATA_SIZE below +WRD .EQU 2 + +SECTOR_SIZE .EQU 512 +BLOCK_SIZE .EQU 128 +PREFIX_SIZE .EQU (3 * SECTOR_SIZE) ; 3 SECTORS +METADATA_SIZE .EQU BYT+WRD+(4*BYT)+16+BYT+WRD+WRD+WRD+WRD ; (as defined below) + +BOOT_INFO_LOC .EQU CPM_ENT + 04BH +; PTR TO LOCATION TO RECORD BOOT INFO IN MEMORY IMAGE +; FIXUP REQUIRED WHEN BIOS HEADER CHANGES + + .ORG 0000H + JP CPM_ENT +; + .FILL ((PREFIX_SIZE - BLOCK_SIZE) - $),00H +PR_SIG .DW 0A55AH ; SIGNATURE GOES HERE + +PR_PLATFORM .DB 0 +PR_DEVICE .DB 0 +PR_FORMATTER .DB 0,0,0,0,0,0,0,0 +PR_DRIVE .DB 0 +PR_LOG_UNIT .DW 0 + +; + .FILL ((PREFIX_SIZE - METADATA_SIZE) - $),00H + .DB 0 ; write protect boolean + .DW 0 ; starting update number + .DB RMJ,RMN,RUP,RTP + .DB "Unlabeled Drive ","$" + .DW BOOT_INFO_LOC ; PTR TO LOCATION TO STORE DISKBOOT & BOOTDRIVE (SEE CNFGDATA) + .DW CPM_LOC ; CCP START + .DW CPM_END ; END OF CBIOS + .DW CPM_ENT ; COLD BOOT LOCATION + + .END \ No newline at end of file diff --git a/trunk/Source/prp.asm b/trunk/Source/prp.asm new file mode 100644 index 00000000..6719348f --- /dev/null +++ b/trunk/Source/prp.asm @@ -0,0 +1,357 @@ +; +;================================================================================================== +; PROPIO DRIVER +;================================================================================================== +; +; +; GLOBAL PARPORTPROP INITIALIZATION +; +PRP_INIT: + CALL PRPSD_INIT ; SD CARD INITIALIZATION + + RET +; +;================================================================================================== +; PROPIO CONSOLE DRIVER +;================================================================================================== +; +PRPCON_CMD .EQU $40 ; PROPIO CONSOLE COMMAND PORT (WHEN WRITTEN) +PRPCON_STATUS .EQU $40 ; PROPIO CONSOLE STATUS PORT (WHEN READ) +PRPCON_DATA .EQU $41 ; PROPIO CONSOLE DATA PORT (READ=KBD, WRITE=DISPLAY) +; +PRPCON_BUSY .EQU $80 ; BIT SET WHEN PROPIO CONSOLE INTERFACE IS BUSY +PRPCON_ERR .EQU $40 ; BIT SET WHEN PROPIO CONSOLE ERROR HAS OCCURRED +PRPCON_KBDRDY .EQU $20 ; BIT SET WHEN KEYBOARD BUF HAS A BYTE READY (BUF FULL) +PRPCON_DSPRDY .EQU $10 ; BIT SET WHEN DISPLAY BUF IS READY FOR A BYTE (BUF EMPTY) +; +; +; +PRPCON_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JR Z,PRPCON_IN + DEC A + JR Z,PRPCON_OUT + DEC A + JR Z,PRPCON_IST + DEC A + JR Z,PRPCON_OST + CALL PANIC +; +; +; +PRPCON_IN: + CALL PRPCON_IST ; CHECK FOR CHAR PENDING + JR Z,PRPCON_IN ; WAIT FOR IT IF NECESSARY + IN A,(PRPCON_DATA) ; READ THE CHAR FROM PROPIO + LD E,A + RET +; +; +; +PRPCON_IST: + IN A,(PRPCON_STATUS) ; READ LINE STATUS REGISTER + AND PRPCON_KBDRDY | PRPCON_BUSY ; ISOLATE KBDRDY AND BUSY + SUB PRPCON_KBDRDY ; KBD RDY BUT NOT BUSY? + JR Z,PRPCON_IST1 ; YES, GO TO READY LOGIC + JP CIO_IDLE +PRPCON_IST1: + DEC A ; SET A=$FF TO SIGNAL READY + RET ; RETURN +; +; +; +PRPCON_OUT: + CALL PRPCON_OST ; CHECK FOR OUTPUT READY + JR Z,PRPCON_OUT ; WAIT IF NECESSARY + LD A,E ; RECOVER THE CHAR TO WRITE + OUT (PRPCON_DATA),A ; WRITE THE CHAR TO PROPIO + RET +; +PRPCON_OST: + IN A,(PRPCON_STATUS) ; READ LINE STATUS REGISTER + AND PRPCON_DSPRDY | PRPCON_BUSY ; ISOLATE DSPRDY AND BUSY + SUB PRPCON_DSPRDY ; DSP RDY BUT NOT BUSY? + JR Z,PRPCON_OST1 ; YES, GO TO READY LOGIC + JP CIO_IDLE +PRPCON_OST1: + DEC A ; SET A=$FF TO SIGNAL READY + RET ; RETURN +; +;================================================================================================== +; PRPSD DISK DRIVER +;================================================================================================== +; +; IO PORT ADDRESSES +; +PRPSD_DSKCMD .EQU 42H +PRPSD_DSKST .EQU 42H +PRPSD_DSKIO .EQU 43H +; +PRPSD_CMDRESET .EQU 10H +PRPSD_CMDINIT .EQU 20H +PRPSD_CMDREAD .EQU 30H +PRPSD_CMDPREP .EQU 40H +PRPSD_CMDWRITE .EQU 50H +; +PRPSD_STBUSY .EQU 80H +PRPSD_STERR .EQU 40H +PRPSD_STOVR .EQU 20H +PRPSD_STTO .EQU 10H +; +; +; +PRPSD_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F + JR Z,PRPSD_RD + DEC A + JR Z,PRPSD_WR + DEC A + JR Z,PRPSD_ST + DEC A + JR Z,PRPSD_MED + CALL PANIC +; +PRPSD_RD: + JP PRPSD_READ +PRPSD_WR: + JP PRPSD_WRITE +PRPSD_ST: + JP PRPSD_STATUS +PRPSD_MED: + JP PRPSD_MEDIA +; +; PRPSD_MEDIA +; +PRPSD_MEDIA: + ; REINITIALIZE THE CARD HERE + CALL PRPSD_INITCARD + LD A,MID_NONE ; ASSUME FAILURE + RET NZ + + ; ALL IS WELL, RETURN MEDIA IDENTIFIER + LD A,MID_HD ; SET MEDIA ID + RET +; +; +; +PRPSD_INIT: + ; MARK DRIVE NOT READY + ; HARDWARE INIT DEFERRED UNTIL DRIVE SELECT + XOR A + DEC A + LD (PRPSD_STAT),A + RET +; +; +; +PRPSD_STATUS: + LD A,(PRPSD_STAT) ; GET THE CURRENT READY STATUS + OR A + RET +; +; +; +PRPSD_READ: + CALL PRPSD_CHKCARD ; CHECK / REINIT CARD AS NEEDED + RET NZ ; BAIL OUT ON ERROR + + LD A,PRPSD_CMDRESET + CALL PRPSD_SNDCMD + RET NZ ; RETURN ON FAILURE, A = STATUS + + CALL PRPSD_SETBLK + + LD A,PRPSD_CMDREAD + CALL PRPSD_SNDCMD + RET NZ ; RETURN ON FAILURE, A = STATUS + + LD C,PRPSD_DSKIO + LD B,0 + LD HL,(DIOBUF) + INIR + INIR + + OR A ; SET FLAGS + RET ; RETURN WITH A = STATUS +; +; +; +PRPSD_WRITE: + CALL PRPSD_CHKCARD ; CHECK / REINIT CARD AS NEEDED + RET NZ ; BAIL OUT ON ERROR + + LD A,PRPSD_CMDRESET + CALL PRPSD_SNDCMD + RET NZ ; RETURN ON FAILURE, A = STATUS + + CALL PRPSD_SETBLK + + LD A,PRPSD_CMDPREP + CALL PRPSD_SNDCMD + RET NZ ; RETURN ON FAILURE, A = STATUS + + LD C,PRPSD_DSKIO + LD B,0 + LD HL,(DIOBUF) + OTIR + OTIR + + LD A,PRPSD_CMDWRITE + CALL PRPSD_SNDCMD + RET NZ ; RETURN ON FAILURE, A = STATUS + + OR A ; SET FLAGS + RET ; RETURN WITH A = STATUS +; +; +; +PRPSD_SNDCMD: + LD (PRPSD_CMD),A + OUT (PRPSD_DSKCMD),A + NOP ; SETTLE + NOP ; SETTLE + LD BC,0 +PRPSD_SNDCMD1: + IN A,(PRPSD_DSKST) + BIT 7,A + JR Z,PRPSD_SNDCMD2 ; RET WITH A = STATUS + LD E,A ; SAVE STATUS + CALL DELAY + DEC BC + LD A,B + OR C + JR NZ,PRPSD_SNDCMD1 + LD A,E ; RECOVER STATUS + OR PRPSD_STTO ; SET TIMEOUT BIT +PRPSD_SNDCMD2: + LD (PRPSD_STAT),A + JR PRPSD_PRT ; RET WITH A = STATUS +; +; +; +PRPSD_INITCARD: + ; RESET INTERFACE, RETURN WITH NZ ON FAILURE + LD A,PRPSD_CMDRESET + CALL PRPSD_SNDCMD + RET NZ ; NZ SET, A HAS ERROR CODE + + ; REQUEST HARDWARE INIT, RESULT IN A, Z/NZ SET + LD A,PRPSD_CMDINIT + CALL PRPSD_SNDCMD + RET ; Z/NZ SET, A HAS RESULT CODE +; +; CHECK THE SD CARD, ATTEMPT TO REINITIALIZE IF NEEDED +; +PRPSD_CHKCARD: + LD A,(PRPSD_STAT) ; GET STATUS + OR A ; SET FLAGS + CALL NZ,PRPSD_INITCARD ; INIT CARD IF NOT READY + RET ; RETURN WITH STATUS IN A +; +; SEND INDEX OF BLOCK TO READ FROM SD CARD +; 32 BIT VALUE (4 BYTES) +; NOTE THAT BYTES ARE SENT REVERSED, PROPELLER IS LITTLE ENDIAN +; +PRPSD_SETBLK: + LD DE,PRPSD_BLK + 3 + LD A,(HSTSEC) ; A = LSB OF OS SECTOR + CALL PRPSD_SETBLK1 + LD HL,(HSTTRK) ; GET OS TRACK VALUE + LD A,L ; EXTRACT LSB + CALL PRPSD_SETBLK1 + LD A,H ; EXTRACT MSB + CALL PRPSD_SETBLK1 + XOR A ; A = 0, NOT USED + CALL PRPSD_SETBLK1 + RET +PRPSD_SETBLK1: + OUT (PRPSD_DSKIO),A ; SEND IT + LD (DE),A + DEC DE + RET + +PRPSD_PRT: + BIT 6,A +#IF (PRPSDTRACE == 0) + RET +#ELSE +#IF (PRPSDTRACE == 1) + RET Z +#ENDIF + PUSH AF + CALL NEWLINE + CALL PC_LBKT + CALL PRTHEXWORD + CALL PC_RBKT + CALL PC_SPACE + LD DE,PRPSTR_PREFIX + CALL WRITESTR + CALL PC_SPACE + LD DE,PRPSTR_CMD + CALL WRITESTR + LD A,(PRPSD_CMD) + CALL PRTHEXBYTE + CP PRPSD_CMDREAD + CALL Z,PRPSD_PRTBLK + CP PRPSD_CMDWRITE + CALL Z,PRPSD_PRTBLK + CALL PC_SPACE + LD DE,PRPSTR_ARROW + CALL WRITESTR + CALL PC_SPACE + POP AF + PUSH AF + CALL PRTHEXBYTE + BIT 6,A + CALL NZ,PRPSD_PRTERR + POP AF + RET ; RET WITH A = STATUS + +PRPSD_PRTBLK: + CALL PC_SPACE + LD HL,PRPSD_BLK + LD B,4 +PRPSD_PRTBLK1: + LD A,(HL) + CALL PRTHEXBYTE + INC HL + DJNZ PRPSD_PRTBLK1 + RET + +PRPSD_PRTERR: + LD B,4 +PRPSD_PRTERR1: + IN A,(PRPSD_DSKIO) + PUSH AF + DJNZ PRPSD_PRTERR1 + CALL PC_SPACE + LD DE,PRPSTR_ERR + CALL WRITESTR + LD B,4 +PRPSD_PRTERR2: + POP AF + CALL PRTHEXBYTE + DJNZ PRPSD_PRTERR2 + RET +#ENDIF +; +; +; +PRPSTR_PREFIX .TEXT "PRPDSK:$" +PRPSTR_CMD .TEXT "CMD=$" +;PRPSTR_RC .TEXT "RC=$" +PRPSTR_ARROW .TEXT "-->$" +PRPSTR_ERR .TEXT "ERR=$" +;PRPSTR_RCOK .TEXT "OK$" +;PRPSTR_RCRDYTO .TEXT "READY TIMEOUT$" +; +;================================================================================================== +; PRPSD DISK DRIVER - DATA +;================================================================================================== +; +PRPSD_STAT .DB 0 +; +PRPSD_CMD .DB 0 +PRPSD_BLK .DB 0, 0, 0, 0 diff --git a/trunk/Source/prp_data.asm b/trunk/Source/prp_data.asm new file mode 100644 index 00000000..34041c1c --- /dev/null +++ b/trunk/Source/prp_data.asm @@ -0,0 +1,61 @@ +; +;================================================================================================== +; PRPSD DISK DRIVER - DATA +;================================================================================================== +; +PRPSD_SLICETRKS .EQU 65 ; TRACKS PER SLICE +PRPSD_TRKSIZE .EQU 128 ; SIZE OF TRACK (IN KB) +PRPSD_SLICESIZE .EQU ((PRPSD_SLICETRKS * PRPSD_TRKSIZE) + 1023) / 1024 ; SIZE OF EACH SLICE (IN MB) +PRPSD_NUMSLICES .EQU PRPSDCAPACITY / PRPSD_SLICESIZE ; TOTAL SLICES IN DEVICE +PRPSD0_SLICEDEF .EQU 0 ; DEFAULT SLICE FOR UNIT 0 +PRPSD1_SLICEDEF .EQU 1 ; DEFAULT SLICE FOR UNIT 1 +PRPSD2_SLICEDEF .EQU 2 ; DEFAULT SLICE FOR UNIT 0 +PRPSD3_SLICEDEF .EQU 3 ; DEFAULT SLICE FOR UNIT 1 +; + .DB DIODEV_PRPSD + 0 +PRPSDDPH0 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PRPSDCSV0,PRPSDALV0 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PRPSD0_SLICE .DW PRPSD0_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PRPSD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PRPSD + 0 +PRPSDDPH1 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PRPSDCSV1,PRPSDALV1 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PRPSD1_SLICE .DW PRPSD1_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PRPSD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PRPSD + 0 +PRPSDDPH2 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PRPSDCSV2,PRPSDALV2 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PRPSD2_SLICE .DW PRPSD2_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PRPSD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_PRPSD + 0 +PRPSDDPH3 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW PRPSDCSV3,PRPSDALV3 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +PRPSD3_SLICE .DW PRPSD3_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW PRPSD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; +PRPSDCKS .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA +PRPSDALS .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP) +; +PRPSDCSV0 .FILL PRPSDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PRPSDALV0 .FILL PRPSDALS ; MAX OF 2048 DATA BLOCKS +PRPSDCSV1 .FILL PRPSDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PRPSDALV1 .FILL PRPSDALS ; MAX OF 2048 DATA BLOCKS +PRPSDCSV2 .FILL PRPSDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PRPSDALV2 .FILL PRPSDALS ; MAX OF 2048 DATA BLOCKS +PRPSDCSV3 .FILL PRPSDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +PRPSDALV3 .FILL PRPSDALS ; MAX OF 2048 DATA BLOCKS diff --git a/trunk/Source/romfill.asm b/trunk/Source/romfill.asm new file mode 100644 index 00000000..e52d3bbf --- /dev/null +++ b/trunk/Source/romfill.asm @@ -0,0 +1,8 @@ +; +;================================================================================================== +; FILLER FOR ROM PAGE 0 (SEE BANKEDBIOS.TXT) +;================================================================================================== +; + .FILL 3000H +; + .END diff --git a/trunk/Source/sd.asm b/trunk/Source/sd.asm new file mode 100644 index 00000000..1dce459f --- /dev/null +++ b/trunk/Source/sd.asm @@ -0,0 +1,957 @@ +; +;============================================================================= +; SD DISK DRIVER +;============================================================================= +; +; - CATER FOR THE VARIOUS SDCARD HARDWARE VERSIONS +; CSIO IS FOR N8-2312 PRODUCTION BOARDS AND MODIFIED N8-2511 PROTOTYPE BOARDS +; RTC IS FOR UNMODIFIED N8-2511 BOARDS AND N8VEM/ZETA USING JUHA MINI-BOARDS +; PPISD IS FOR A PPISD MINI-BOARD CONNECTED TO 26-PIN PPI HEADER +; - MAKE RTC A PSEUDO-REGISTER FOR NON-CSIO +; - PERFORM BOOT INITIALIZATION OF RTC SOMEWHERE ELSE??? +; - PUT RELEVANT RTC BITS TO A KNOWN STATE AT ALL I/O ENTRY POINTS +; +; CONTROL BITS +; +#IF (PLATFORM==PLT_N8) +SD_CS .EQU $04 ; RTC BIT 2, SD CARD SELECT (ACTIVE HI) +#IF (!SDCSIO) +SD_CLK .EQU $02 ; RTC BIT 1, SD CLOCK +SD_DOUT .EQU $01 ; RTC BIT 0, SD DATA OUT +SD_DIN .EQU $40 ; RTC BIT 6, SD DATA IN +#ENDIF +#ELSE +#IF (PPISD) +SD_CS .EQU $10 ; PC4, SD CARD SELECT (ACTIVE LO) +SD_CLK .EQU $02 ; PC1, SD CLOCK +SD_DOUT .EQU $01 ; PC0, SD DATA OUT +SD_DIN .EQU $80 ; PB7, SD DATA IN +#ELSE +SD_CS .EQU $04 ; RTC BIT 2, SD CARD SELECT (ACTIVE HI) +SD_CLK .EQU $40 ; RTC BIT 6, SD CLOCK +SD_DOUT .EQU $80 ; RTC BIT 7, DATA OUT TO SD-CARD +SD_DIN .EQU $40 ; RTC BIT 6, DATA IN FROM SD-CARD +#ENDIF +#ENDIF + +;#IF (!SDCSIO) +;#IF (PLATFORM = PLT_N8) +;SD_CS .EQU $04 ; RTC BIT 2, SD CARD SELECT +;SD_CLK .EQU $02 ; RTC BIT 1, SD CLOCK +;SD_DOUT .EQU $01 ; RTC BIT 0, SD DATA OUT +;SD_DIN .EQU $40 ; RTC BIT 6, SD DATA IN +;#ELSE ; Zeta or Z80-SBC MK II +;SD_CS .EQU $04 ; RTC BIT 2, SD CARD SELECT +;SD_CLK .EQU $40 ; RTC BIT 6, SD CLOCK +;SD_DOUT .EQU $80 ; RTC BIT 7, DATA OUT TO SD-CARD +;SD_DIN .EQU $40 ; RTC BIT 6, DATA IN FROM SD-CARD +;#ENDIF +;#ENDIF +; +; SD CARD COMMANDS +; +SD_CMD0 .EQU $40 | 0 ; GO_IDLE_STATE +SD_CMD1 .EQU $40 | 1 ; SEND_OP_COND +SD_CMD8 .EQU $40 | 8 ; SEND_IF_COND +SD_CMD9 .EQU $40 | 9 ; SEND_CSD +SD_CMD10 .EQU $40 | 10 ; SEND_CID +SD_CMD16 .EQU $40 | 16 ; SET_BLOCKLEN +SD_CMD17 .EQU $40 | 17 ; READ_SINGLE_BLOCK +SD_CMD24 .EQU $40 | 24 ; WRITE_BLOCK +SD_CMD55 .EQU $40 | 55 ; APP_CMD +SD_CMD58 .EQU $40 | 58 ; READ_OCR +; SD APPLICATION SPECIFIC COMMANDS +SD_ACMD41 .EQU $40 | 41 ; SD_APP_OP_COND +; +; SD CARD TYPE +; +SD_TYPEUNK .EQU 0 +SD_TYPEMMC .EQU 1 +SD_TYPESDSC .EQU 2 +SD_TYPESDHC .EQU 3 +; +; +; +SD_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F + JR Z,SD_READ + DEC A + JR Z,SD_WRITE + DEC A + JR Z,SD_STATUS + DEC A + JR Z,SD_MEDIA + CALL PANIC +; +; +; +SD_MEDIA: + ; INITIALIZE THE SD CARD TO ACCOMMODATE HOT SWAPPING + CALL SD_INITCARD + LD A,MID_NONE ; ASSUME FAILURE + RET NZ ; INIT FAILED, RETURN WITH HL=0 + + ; SET READY AND RETURN + XOR A + LD (SD_STAT),A ; SD_STAT = 0 = OK + LD A,MID_HD + RET +; +SD_INIT: + LD A,20H ; PUT RTC LATCH TO IDLE + OUT (RTC),A +#IF (PPISD) + LD A,82H ; PPI PORT A=OUT, B=IN, C=OUT + OUT (PIOX),A + LD A,30H ; PC4,5 /CS HIGH + OUT (PIOC),A +#ENDIF + XOR A + DEC A + LD (SD_STAT),A + RET +; +SD_STATUS: + LD A,(SD_STAT) + OR A + RET +; +SD_READ: + JP SD_RDSEC +; +SD_WRITE: + JP SD_WRSEC +; +;============================================================================= +; SD INTERFACE ROUTINES +;============================================================================= +; +; SD_SENDCLKS: A=RTC MASK, B=# OF CLK TRANSITIONS +; For bit bang versions B is number of transitions +; For PPISD B is number of bits +; For CSIO B is number of bytes +SD_SENDCLKS: +#IF (!SDCSIO) + #IF (PPISD) + LD A,03 ;PC1=1, TOGGLE CLOCK + OUT (PIOX),A + NOP + LD A,02 ;PC1=0, RESET CLOCK + OUT (PIOX),A + #ELSE + OUT (RTC),A + XOR SD_CLK ; TOGGLE CLOCK BIT + #ENDIF + DJNZ SD_SENDCLKS + RET +#ELSE +SD_SENDCLKS1: + CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING + LD A,0FFH + OUT0 (CPU_TRDR),A ; put byte in buffer + IN0 A,(CPU_CNTR) + SET 4,A ; set transmit enable + OUT0 (CPU_CNTR),A + DJNZ SD_SENDCLKS + RET + +SD_WAITTX: ; WAIT FOR TX EMPTY + IN0 A,(CPU_CNTR) ; get CSIO status + BIT 4,A ; Tx empty? + JR NZ,SD_WAITTX + RET + +SD_WAITRX: + IN0 A,(CPU_CNTR) ; wait for receiver to finish + BIT 5,A + JR NZ,SD_WAITRX + RET +#ENDIF +; +; COMPLETE A TRANSACTION - PRESERVE AF +; +SD_DONE: + PUSH AF +#IF (!SDCSIO) + #IF (PPISD) + LD A,30H + OUT (PIOC),A ;PC4=1 /CS INACTIVE + LD B,16 + #ELSE + XOR A + LD B,17 + #ENDIF + CALL SD_SENDCLKS +#ELSE + CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING + IN A,(RTC) + AND ~SD_CS ; CLEAR CS + OUT (RTC),A + LD B,2 + CALL SD_SENDCLKS +#ENDIF + POP AF + RET +; +; SEND ONE BYTE +; +SD_PUT: +#IF (PPISD) +; CALL PRTHEXBYTE ; *DEBUG* + LD C,A ; C=BYTE TO SEND + LD B,8 ; SEND 8 BITS (LOOP 8 TIMES) + LD A,08H ;PC4=0, /CS ACTIVE + OUT (PIOX),A +SD_PUT1: + RL C ;ROTATE NEXT BIT FROM C INTO CF + LD A,01 ;PC0=1, DATA OUT=1 + JR C,SD_PUT2 + LD A,00 ;PC0=0, DATA OUT =0 +SD_PUT2: + OUT (PIOX),A ;SEND DATA OUT + LD A,03 ;PC1=1, TOGGLE CLOCK + OUT (PIOX),A + LD A,02 ;PC1=0, RESET CLOCK + OUT (PIOX),A + DJNZ SD_PUT1 ;REPEAT FOR ALL 8 BITS + RET +#ELSE +#IF (!SDCSIO) +; CALL PRTHEXBYTE ; *DEBUG* + LD C,A ; C=BYTE TO SEND + LD B,8 ; SEND 8 BITS (LOOP 8 TIMES) +SD_PUT1: +#IF (PLATFORM=PLT_N8) + LD A,2 ; SD_CS >> 1 (SD_CS WILL BE SET AFTER ROTATE) + RL C ; ROTATE NEXT BIT FROM C INTO CF + RLA ; ROTATE CF INTO A:0, SD_DOUT is RTC:0 +#ELSE + LD A,8 ; SD_CS WILL BE IN BIT2 AFTER ROTATE + RL C ; ROTATE NEXT BIT FROM C INTO CF + RRA ; ROTATE CARRY INTO A:7, SD_DOUT is RTC:7 +#ENDIF + OUT (RTC),A ; CLOCK LOW (ABOUT TO SEND BIT) + OR SD_CLK ; SET CLOCK BIT + OUT (RTC),A ; CLOCK HIGH (SEND BIT) + DJNZ SD_PUT1 ; REPEAT FOR ALL 8 BITS + AND ~SD_CLK ; RESET CLOCK + OUT (RTC),A ; LEAVE WITH CLOCK LOW + RET +#ELSE + CALL MIRROR ; MSB<-->LSB mirror bits, result in C + CALL SD_WAITRX ; MAKE SURE WE ARE DONE SENDING + OUT0 (CPU_TRDR),C ; put byte in buffer + IN0 A,(CPU_CNTR) + SET 4,A ; set transmit enable + OUT0 (CPU_CNTR),A + RET ; let it do the rest +#ENDIF +#ENDIF +; +; RECEIVE ONE BYTE +; +SD_GET: +#IF (PPISD) + LD B,8 ; RECEIVE 8 BITS (LOOP 8 TIMES) +SD_GET1: + IN A,(PIOB) ; GET BIT FROM SD-CARD + RLA ; ROTATE PB7 INTO CARRY + RL C ; ROTATE CARRY INTO C + LD A,03 ; PC1=1, TOGGLE CLOCK + OUT (PIOX),A + LD A,02 ; PC1=0, RESET CLOCK + OUT (PIOX),A + DJNZ SD_GET1 ; REPEAT FOR ALL 8 BITS + LD A,C ; GET BYTE RECEIVED INTO A +; CALL PRTHEXBYTE ; *DEBUG* + RET +#ELSE +#IF (!SDCSIO) + LD B,8 ; RECEIVE 8 BITS (LOOP 8 TIMES) +SD_GET1: + IN A,(RTC) ; GET RTC BITS + RLA ; ROTATE RTC:6 (SD_IN) INTO CF + RLA + RL C ; ROTATE CF INTO C:0 + LD A,SD_CS | SD_DOUT | SD_CLK + OUT (RTC),A ; CLOCK HIGH (ACK BIT RECEIVED) + AND ~SD_CLK ; RESET CLOCK BIT + OUT (RTC),A ; CLOCK LOW (READY FOR NEXT BIT) + DJNZ SD_GET1 ; REPEAT FOR ALL 8 BITS + LD A,C ; GET BYTE RECEIVED INTO A +; CALL PRTHEXBYTE ; *DEBUG* + RET +#ELSE + CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING + IN0 A,(CPU_CNTR) ; get CSIO status + SET 5,A ; start receiver + OUT0 (CPU_CNTR),A + CALL SD_WAITRX + IN0 A,(CPU_TRDR) ; get received byte + CALL MIRROR ; MSB<-->LSB mirror bits + LD A,C ; keep result + RET +#ENDIF +#ENDIF + +#IF (SDCSIO) +MIRROR: ; MSB<-->LSB mirror bits in A, result in C +#IF (!SDCSIOFAST) ; slow speed, least code space + LD B,8 ; bit counter +MIRROR1: + RLA ; rotate bit 7 into carry + RR C ; rotate carry into result + DJNZ MIRROR1 ; do all 8 bits + RET +#ELSE ; fastest but uses most code space + LD BC,MIRTAB ; 256 byte mirror table + ADD A,C ; add offset + LD C,A + JR NC,MIRROR2 + INC B +MIRROR2: + LD A,(BC) ; get result + LD C,A ; return result in C + RET +#ENDIF +#ENDIF + +; +; SELECT CARD AND WAIT FOR IT TO BE READY ($FF) +; +SD_WAITRDY: +#IF (PPISD) + LD A,21H ;/CS ACTIVE (PC4), DOUT=1 (PC0) + OUT (PIOC),A +#ELSE + IN A,(RTC) +#IF (!SDCSIO) + OR SD_CS | SD_DOUT ; SET SD_CS (CHIP SELECT) +#ELSE + CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING + OR SD_CS ; SET SD_CS (CHIP SELECT) +#ENDIF + OUT (RTC),A +#ENDIF + LD DE,0 ; LOOP MAX (TIMEOUT) +SD_WAITRDY1: +; CALL PC_SPACE ; *DEBUG* + CALL SD_GET +; CALL PRTHEXBYTE ; *DEBUG* +; XOR A ; *DEBUG* TO SIMULATE READY TIMEOUT + INC A ; $FF -> $00 + RET Z ; IF READY, RETURN + DEC DE + LD A,D + OR E + JR NZ,SD_WAITRDY1 ; KEEP TRYING UNTIL TIMEOUT + LD A,$FF ; SIGNAL TIMEOUT ERROR + OR A ; SET FLAGS + RET ; TIMEOUT +; +; SD_GETDATA +; +SD_GETDATA: + PUSH BC ; SAVE LENGTH TO RECEIVE + LD DE,$7FFF ; LOOP MAX (TIMEOUT) +SD_GETDATA1: + CALL SD_GET + CP $FF ; WANT BYTE != $FF + JR NZ,SD_GETDATA2 ; NOT $FF, MOVE ON + DEC DE + BIT 7,D + JR Z,SD_GETDATA1 ; KEEP TRYING UNTIL TIMEOUT +SD_GETDATA2: + LD (SD_TOK),A + POP DE ; RESTORE LENGTH TO RECEIVE + CP $FE ; PACKET START? + JR NZ,SD_GETDATA4 ; NOPE, ABORT, A HAS ERROR CODE + LD HL,(DIOBUF) ; RECEIVE BUFFER +SD_GETDATA3: + CALL SD_GET ; GET NEXT BYTE + LD (HL),A ; SAVE IT + INC HL + DEC DE + LD A,D + OR E + JR NZ,SD_GETDATA3 ; LOOP FOR ALL BYTES + CALL SD_GET ; DISCARD CRC BYTE 1 + CALL SD_GET ; DISCARD CRC BYTE 2 + XOR A ; RESULT IS ZERO +SD_GETDATA4: + RET +; +; SD_PUTDATA +; +SD_PUTDATA: + PUSH BC ; SAVE LENGTH TO SEND + + LD A,$FE ; PACKET START + CALL SD_PUT ; SEND IT + + POP DE ; RESTORE LENGTH TO SEND + LD HL,(DIOBUF) ; RECEIVE BUFFER +SD_PUTDATA1: + LD A,(HL) ; GET NEXT BYTE TO SEND + CALL SD_PUT ; SEND IF + INC HL + DEC DE + LD A,D + OR E + JR NZ,SD_PUTDATA1 ; LOOP FOR ALL BYTES + LD A,$FF ; DUMMY CRC BYTE + CALL SD_PUT + LD A,$FF ; DUMMY CRC BYTE + CALL SD_PUT + LD DE,$7FFF ; LOOP MAX (TIMEOUT) +SD_PUTDATA2: + CALL SD_GET + CP $FF ; WANT BYTE != $FF + JR NZ,SD_PUTDATA3 ; NOT $FF, MOVE ON + DEC DE + BIT 7,D + JR Z,SD_PUTDATA2 ; KEEP TRYING UNTIL TIMEOUT +SD_PUTDATA3: + AND $1F + LD (SD_TOK),A + CP $05 + RET NZ + XOR A + RET +; +; SETUP COMMAND BUFFER +; +SD_SETCMD0: ; NO PARMS + LD HL,SD_CMDBUF + LD (HL),A + INC HL + XOR A + LD (HL),A + INC HL + LD (HL),A + INC HL + LD (HL),A + INC HL + LD (HL),A + INC HL + LD A,$FF + LD (HL),A + RET +; +SD_SETCMDP: ; W/ PARMS IN BC & DE + CALL SD_SETCMD0 + LD HL,SD_CMDP0 + LD (HL),B + INC HL + LD (HL),C + INC HL + LD (HL),D + INC HL + LD (HL),E + RET +; +; EXECUTE A SD CARD COMMAND +; +SD_EXEC: + XOR A + LD (SD_RC),A + LD (SD_TOK),A + LD HL,SD_CMDBUF + LD E,6 ; COMMANDS ARE 6 BYTES +SD_EXEC1: +#IF (SDCSIO) + CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING + IN A,(RTC) + OR SD_CS ; SET CS + OUT (RTC),A +#ENDIF + LD A,(HL) + CALL SD_PUT + INC HL + DEC E + JR NZ,SD_EXEC1 + LD DE,$100 ; LOOP MAX (TIMEOUT) +SD_EXEC2: + CALL SD_GET + OR A ; SET FLAGS + JP P,SD_EXEC3 ; IF HIGH BIT IS 0, WE HAVE RESULT + DEC DE + BIT 7,D + JR Z,SD_EXEC2 +SD_EXEC3: + LD (SD_RC),A +#IF (SDTRACE >= 2) + CALL SD_PRTTRN +#ENDIF +#IF (DSKYENABLE) + CALL SD_DSKY +#ENDIF + RET +; +SD_EXECCMD0: ; EXEC COMMAND, NO PARMS + CALL SD_SETCMD0 + JR SD_EXEC +; +SD_EXECCMDP: ; EXEC CMD W/ PARMS IN BC/DE + CALL SD_SETCMDP + JR SD_EXEC +; +; PUT CARD IN IDLE STATE +; +SD_GOIDLE: + ; SMALL DELAY HERE HELPS SOME CARDS + LD DE,200 ; 5 MILISECONDS + CALL VDELAY + + ; PUT CARD IN IDLE STATE + LD A,SD_CMD0 ; CMD0 = ENTER IDLE STATE + CALL SD_SETCMD0 + LD A,$95 + LD (SD_CMDBUF+5),A ; SET CRC=$95 + CALL SD_EXEC ; EXEC CMD + CP $01 ; IN IDLE STATE? + CALL SD_DONE + RET +; +; INIT CARD +; +SD_INITCARD: +#IF (PPISD) + LD A,82H ; PPI PORT A=OUT, B=IN, C=OUT + OUT (PIOX),A + LD A,30H ; PC4,5 /CS HIGH + OUT (PIOC),A +#ENDIF + LD A,20H ; PUT RTC LATCH TO IDLE + OUT (RTC),A + +#IF (SDCSIO) + ; CSIO SETUP +; LD A,02 ; 18MHz/20 <= 400kHz + LD A,06 ; ??? + OUT0 (CPU_CNTR),A +#ENDIF + CALL SD_DONE ; SEEMS TO HELP SOME CARDS... + +#IF (!SDCSIO) +#IF (PPISD) + LD A,21H ; /CS=0, DOUT=1, CLK=0 + OUT (PIOC),A + LD B,07FH ; 127 CLOCKS (255 TRANSITIONS STARTING WITH LO) +#ELSE + LD A,SD_CS | SD_DOUT ; CS=HI, DOUT=HI + LD B,0FFH ; 127 CLOCKS (255 TRANSITIONS STARTING WITH LO) +#ENDIF +#ELSE + CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING + IN A,(RTC) + OR SD_CS ; SET CS + OUT (RTC),A + LD B,16 +#ENDIF + CALL SD_SENDCLKS ; INIT DELAY + GO SPI MODE + + ; WAIT FOR CARD TO BE READY FOR A COMMAND + CALL SD_WAITRDY + JP NZ,SD_ERRRDYTO + + ; PUT CARD IN IDLE STATE + CALL SD_GOIDLE + CALL NZ,SD_GOIDLE ; SOME CARDS REQUIRE A SECOND ATTEMPT + JP NZ,SD_ERRCMD ; GIVE UP + +SD_INITCARD00: + LD A,SD_TYPESDSC ; ASSUME SDSC CARD TYPE + LD (SD_TYPE),A ; SAVE IT + + ; CMD8 IS REQUIRED FOR V2 CARDS. FAILURE HERE IS OK AND + ; JUST MEANS THAT IT IS A V1.X CARD + LD A,SD_CMD8 + + LD BC,0 + LD D,1 ; VHS=1, 2.7-3.6V + LD E,$AA ; CHECK PATTERN + CALL SD_SETCMDP + LD A,$87 + LD (SD_CMDBUF+5),A ; SET CRC=$87 + CALL SD_EXEC ; EXEC CMD + AND ~$01 + JR NZ,SD_INITCARD0 + + ; CMD8 WORKED, SO THIS IS V2 CARD + ; NEED TO CONSUME EXTRA CMD8 RESPONSE BYTES (4) + CALL SD_GET + CALL SD_GET + CALL SD_GET + CALL SD_GET + +SD_INITCARD0: + CALL SD_DONE + + LD B,0 ; LOOP LIMIT (TIMEOUT) +SD_INITCARD1: + ; CALL SD_APP_OP_COND UNTIL CARD IS READY (NOT IDLE) + LD DE,200 ; 5 MILLISECONDS + CALL VDELAY + LD A,SD_CMD55 ; APP CMD IS NEXT + PUSH BC + CALL SD_EXECCMD0 + POP BC + AND ~$01 ; ONLY 0 (OK) OR 1 (IDLE) ARE OK + CALL SD_DONE + JP NZ,SD_ERRCMD + LD A,SD_ACMD41 ; SD_APP_OP_COND + PUSH BC + LD BC,$4000 ; INDICATE WE SUPPORT HC + LD DE,$0000 + CALL SD_EXECCMDP + POP BC + PUSH AF + AND ~$01 + CALL SD_DONE + POP AF +; LD A,$01 ; *DEBUG* TO SIMULATE INIT TIMEOUT ERROR + CP $00 ; INIT DONE? + JR Z,SD_INITCARD2 ; YUP, MOVE ON + CP $01 ; IDLE? + JP NZ,SD_ERRCMD ; NOPE, MUST BE CMD ERROR, ABORT + DJNZ SD_INITCARD1 ; KEEP CHECKING + LD A,$FF ; SIGNAL TIMEOUT + OR A + JP SD_ERRINITTO + +SD_INITCARD2: + ; CMD58 RETURNS THE 32 BIT OCR REGISTER, WE WANT TO CHECK + ; BIT 30, IF SET THIS IS SDHC/XC CARD + LD A,SD_CMD58 + CALL SD_EXECCMD0 + CALL NZ,SD_DONE + JP NZ,SD_ERRCMD + + ; CMD58 WORKED, GET OCR DATA AND SET CARD TYPE + CALL SD_GET ; BITS 31-24 + AND $40 ; ISOLATE BIT 30 (CCS) + JR Z,SD_INITCARD21 ; NOT HC/XC, BYPASS + LD A,SD_TYPESDHC ; CARD TYPE = SDHC + LD (SD_TYPE),A ; SAVE IT +SD_INITCARD21: + CALL SD_GET ; BITS 23-16, DISCARD + CALL SD_GET ; BITS 15-8, DISCARD + CALL SD_GET ; BITS 7-0, DISCARD + CALL SD_DONE + + ; SET OUR DESIRED BLOCK LENGTH (512 BYTES) + LD A,SD_CMD16 ; SET_BLOCK_LEN + LD BC,0 + LD DE,512 + CALL SD_EXECCMDP + CALL SD_DONE + JP NZ,SD_ERRCMD + +#IF (SDTRACE >= 2) + CALL NEWLINE + LD DE,SDSTR_SDTYPE + CALL WRITESTR + LD A,(SD_TYPE) + CALL PRTHEXBYTE +#ENDIF + +; RET NZ ; IF ERROR, ABORT NOW WITH A SET CORRECTLY + +#IF (SDCSIO) + CALL SD_WAITTX ; MAKE SURE WE ARE DONE SENDING + XOR A ; NOW SET CSIO PORT TO FULL SPEED + OUT (CPU_CNTR),A +#ENDIF + + XOR A ; A = 0 (STATUS = OK) + LD (SD_STAT),A ; SAVE IT + RET ; RETURN WITH A=0, AND Z SET +;; +;; GET AND PRINT CSD, CID +;; +;SD_CARDINFO: +; LD A,SD_CMD9 ; SEND_CSD +; CALL SD_EXECCMD0 +; CALL SD_DONE +; JP NZ,SD_ERRCMD ; ABORT IF PROBLEM +; LD BC,16 ; 16 BYTES OF CSD +; CALL SD_GETDATA +; CALL SD_DONE +; +; LD DE,SDSTR_CSD +; CALL WRITESTR +; LD DE,SECBUF +; LD A,16 +; CALL PRTHEXBUF +; +; LD A,SD_CMD10 ; SEND_CID +; CALL SD_EXECCMD0 +; CALL SD_DONE +; JP NZ,SD_ERRCMD ; ABORT IF PROBLEM +; LD BC,16 ; 16 BYTES OF CID +; CALL SD_GETDATA +; CALL SD_DONE +; +; LD DE,SDSTR_CID +; CALL WRITESTR +; LD DE,SECBUF +; LD A,16 +; CALL PRTHEXBUF +; +; RET +; +; READ ONE SECTOR +; + +; +; CHECK THE SD CARD, ATTEMPT TO REINITIALIZE IF NEEDED +; +SD_CHKCARD: + LD A,(SD_STAT) ; GET STATUS + OR A ; SET FLAGS + CALL NZ,SD_INITCARD ; INIT CARD IF NOT READY + RET ; RETURN WITH STATUS IN A + +SD_RDSEC: + CALL SD_CHKCARD ; CHECK / REINIT CARD AS NEEDED + RET NZ + + CALL SD_WAITRDY ; WAIT FOR CARD TO BE READY FOR A COMMAND + JP NZ,SD_ERRRDYTO ; HANDLE NOT READY TIMEOUT ERROR + + CALL SD_SETADDR ; SETUP BLOCK ADDRESS + + LD A,SD_CMD17 ; READ_SINGLE_BLOCK + CALL SD_EXECCMDP ; EXEC CMD WITH BLOCK ADDRESS AS PARM + CALL NZ,SD_DONE ; TRANSACTION DONE IF ERROR OCCURRED + JP NZ,SD_ERRCMD ; ABORT ON ERROR + + LD BC,512 ; LENGTH TO READ + CALL SD_GETDATA ; GET THE BLOCK + CALL SD_DONE + JP NZ,SD_ERRDATA ; DATA XFER ERROR + RET +; +; WRITE ONE SECTOR +; +SD_WRSEC: + CALL SD_CHKCARD ; CHECK / REINIT CARD AS NEEDED + RET NZ + + CALL SD_WAITRDY ; WAIT FOR CARD TO BE READY FOR A COMMAND + JP NZ,SD_ERRRDYTO ; HANDLE NOT READY TIMEOUT ERROR + + CALL SD_SETADDR ; SETUP BLOCK ADDRESS + + LD A,SD_CMD24 ; WRITE_BLOCK + CALL SD_EXECCMDP ; EXEC CMD WITH BLOCK ADDRESS AS PARM + CALL NZ,SD_DONE ; TRANSACTION DONE IF ERROR OCCURRED + JP NZ,SD_ERRCMD ; ABORT ON ERROR + + LD BC,512 ; LENGTH TO WRITE + CALL SD_PUTDATA ; PUT THE BLOCK + CALL SD_DONE + JP NZ,SD_ERRDATA ; DATA XFER ERROR + RET +; +; +; +SD_SETADDR: + LD A,(SD_TYPE) + CP SD_TYPESDSC + JR Z,SD_SETADDRSDSC + CP SD_TYPESDHC + JR Z,SD_SETADDRSDHC + CALL PANIC + +SD_SETADDRSDSC: + LD HL,(HSTSEC) + LD E,0 + LD D,L + LD HL,(HSTTRK) + LD C,L + LD B,H + XOR A + RL D + RL C + RL B + RET + +SD_SETADDRSDHC: + LD A,(HSTSEC) ; GET SECTOR (LSB ONLY) + LD E,A ; PUT IN E + LD HL,(HSTTRK) ; GET TRACK + LD D,L ; TRACK LSB -> D + LD C,H ; TRACK MSB -> C + LD B,0 ; B ALWAYS ZERO + RET +; +; HANDLE READY TIMEOUT ERROR +; +SD_ERRRDYTO: +#IF (SDTRACE >= 1) + CALL SD_PRTPREFIX + LD DE,SDSTR_ERRRDYTO +#ENDIF + JR SD_CARDERR +; +; HANDLE INIT TIMEOUT ERROR +; +SD_ERRINITTO: +#IF (SDTRACE >= 1) + CALL SD_PRTPREFIX + LD DE,SDSTR_ERRINITTO +#ENDIF + JR SD_CARDERR +; +; HANDLE COMMAND ERROR +; +SD_ERRCMD: +#IF (SDTRACE == 1) + CALL SD_PRTTRN +#ENDIF +#IF (SDTRACE >= 1) + LD DE,SDSTR_ERRCMD +#ENDIF + JR SD_CARDERR +; +; HANDLE COMMAND ERROR +; +SD_ERRDATA: +#IF (SDTRACE == 1) + CALL SD_PRTTRN +#ENDIF +#IF (SDTRACE >= 1) + LD DE,SDSTR_ERRDATA +#ENDIF + JR SD_CARDERR +; +; GENERIC ERROR HANDLER, DE POINTS TO ERROR STRING +; +SD_CARDERR: + PUSH AF + XOR A + DEC A + LD A,FALSE + LD (SD_STAT),A +#IF (SDTRACE >= 1) + CALL PC_SPACE + CALL PC_LBKT + CALL WRITESTR + CALL PC_RBKT +#ENDIF + POP AF + LD (SD_STAT),A + RET +; +; PRINT DIAGNONSTIC PREFIX +; +SD_PRTPREFIX: + CALL NEWLINE + LD DE,SDSTR_PREFIX + CALL WRITESTR + RET +; +; PRT COMMAND TRACE +; +SD_PRTTRN: + PUSH AF + + CALL SD_PRTPREFIX + + LD DE,SD_CMDBUF + LD A,6 + CALL PRTHEXBUF + CALL PC_SPACE + LD DE,SDSTR_ARROW + CALL WRITESTR + CALL PC_SPACE + + LD DE,SDSTR_RC + CALL WRITESTR + LD A,(SD_RC) + CALL PRTHEXBYTE + CALL PC_SPACE + + LD DE,SDSTR_TOK + CALL WRITESTR + LD A,(SD_TOK) + CALL PRTHEXBYTE + + POP AF + RET + +; +; DISPLAY COMMAND, LOW ORDER WORD OF PARMS, AND RC +; +#IF (DSKYENABLE) +SD_DSKY: + PUSH AF + LD HL,DSKY_HEXBUF + LD A,(SD_CMD) + LD (HL),A + INC HL + LD A,(SD_CMDP2) + LD (HL),A + INC HL + LD A,(SD_CMDP3) + LD (HL),A + INC HL + LD A,(SD_RC) + CALL DSKY_HEXOUT + POP AF + RET +#ENDIF +; +; +; +#IF (SDCSIOFAST) +MIRTAB: .DB 00H, 80H, 40H, 0C0H, 20H, 0A0H, 60H, 0E0H, 10H, 90H, 50H, 0D0H, 30H, 0B0H, 70H, 0F0H + .DB 08H, 88H, 48H, 0C8H, 28H, 0A8H, 68H, 0E8H, 18H, 98H, 58H, 0D8H, 38H, 0B8H, 78H, 0F8H + .DB 04H, 84H, 44H, 0C4H, 24H, 0A4H, 64H, 0E4H, 14H, 94H, 54H, 0D4H, 34H, 0B4H, 74H, 0F4H + .DB 0CH, 8CH, 4CH, 0CCH, 2CH, 0ACH, 6CH, 0ECH, 1CH, 9CH, 5CH, 0DCH, 3CH, 0BCH, 7CH, 0FCH + .DB 02H, 82H, 42H, 0C2H, 22H, 0A2H, 62H, 0E2H, 12H, 92H, 52H, 0D2H, 32H, 0B2H, 72H, 0F2H + .DB 0AH, 8AH, 4AH, 0CAH, 2AH, 0AAH, 6AH, 0EAH, 1AH, 9AH, 5AH, 0DAH, 3AH, 0BAH, 7AH, 0FAH + .DB 06H, 86H, 46H, 0C6H, 26H, 0A6H, 66H, 0E6H, 16H, 96H, 56H, 0D6H, 36H, 0B6H, 76H, 0F6H + .DB 0EH, 8EH, 4EH, 0CEH, 2EH, 0AEH, 6EH, 0EEH, 1EH, 9EH, 5EH, 0DEH, 3EH, 0BEH, 7EH, 0FEH + .DB 01H, 81H, 41H, 0C1H, 21H, 0A1H, 61H, 0E1H, 11H, 91H, 51H, 0D1H, 31H, 0B1H, 71H, 0F1H + .DB 09H, 89H, 49H, 0C9H, 29H, 0A9H, 69H, 0E9H, 19H, 99H, 59H, 0D9H, 39H, 0B9H, 79H, 0F9H + .DB 05H, 85H, 45H, 0C5H, 25H, 0A5H, 65H, 0E5H, 15H, 95H, 55H, 0D5H, 35H, 0B5H, 75H, 0F5H + .DB 0DH, 8DH, 4DH, 0CDH, 2DH, 0ADH, 6DH, 0EDH, 1DH, 9DH, 5DH, 0DDH, 3DH, 0BDH, 7DH, 0FDH + .DB 03H, 83H, 43H, 0C3H, 23H, 0A3H, 63H, 0E3H, 13H, 93H, 53H, 0D3H, 33H, 0B3H, 73H, 0F3H + .DB 0BH, 8BH, 4BH, 0CBH, 2BH, 0ABH, 6BH, 0EBH, 1BH, 9BH, 5BH, 0DBH, 3BH, 0BBH, 7BH, 0FBH + .DB 07H, 87H, 47H, 0C7H, 27H, 0A7H, 67H, 0E7H, 17H, 97H, 57H, 0D7H, 37H, 0B7H, 77H, 0F7H + .DB 0FH, 8FH, 4FH, 0CFH, 2FH, 0AFH, 6FH, 0EFH, 1FH, 9FH, 5FH, 0DFH, 3FH, 0BFH, 7FH, 0FFH +#ENDIF +; +; +; +SDSTR_PREFIX .TEXT "SD:$" +SDSTR_ARROW .TEXT "-->$" +SDSTR_RC .TEXT "RC=$" +SDSTR_TOK .TEXT "TOK=$" +SDSTR_OK .TEXT "OK$" +SDSTR_ERR .TEXT "ERR$" +SDSTR_ERRRDYTO .TEXT "READY TIMEOUT$" +SDSTR_ERRINITTO .TEXT "INIT TIMEOUT$" +SDSTR_ERRCMD .TEXT "CMD ERR$" +SDSTR_ERRDATA .TEXT "DATA ERR$" +SDSTR_SDTYPE .TEXT "SD CARD TYPE: $" +; +;================================================================================================== +; SD DISK DRIVER - DATA +;================================================================================================== +; +SD_STAT .DB 0 +SD_TYPE .DB 0 +SD_RC .DB 0 +SD_TOK .DB 0 +SD_CMDBUF .EQU $ +SD_CMD .DB 0 +SD_CMDP0 .DB 0 +SD_CMDP1 .DB 0 +SD_CMDP2 .DB 0 +SD_CMDP3 .DB 0 +SD_CMDCRC .DB 0 diff --git a/trunk/Source/sd_data.asm b/trunk/Source/sd_data.asm new file mode 100644 index 00000000..0a6e665e --- /dev/null +++ b/trunk/Source/sd_data.asm @@ -0,0 +1,61 @@ +; +;================================================================================================== +; IDE DISK DRIVER - DATA +;================================================================================================== +; +SD_SLICETRKS .EQU 65 ; TRACKS PER SLICE +SD_TRKSIZE .EQU 128 ; SIZE OF TRACK (IN KB) +SD_SLICESIZE .EQU ((SD_SLICETRKS * SD_TRKSIZE) + 1023) / 1024 ; SIZE OF EACH SLICE (IN MB) +SD_NUMSLICES .EQU SDCAPACITY / SD_SLICESIZE ; TOTAL SLICES IN DEVICE +SD0_SLICEDEF .EQU 0 ; DEFAULT SLICE FOR UNIT 0 +SD1_SLICEDEF .EQU 1 ; DEFAULT SLICE FOR UNIT 1 +SD2_SLICEDEF .EQU 2 ; DEFAULT SLICE FOR UNIT 0 +SD3_SLICEDEF .EQU 3 ; DEFAULT SLICE FOR UNIT 1 +; + .DB DIODEV_SD + 0 +SDDPH0 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW SDCSV0,SDALV0 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +SD0_SLICE .DW SD0_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW SD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_SD + 0 +SDDPH1 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW SDCSV1,SDALV1 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +SD1_SLICE .DW SD1_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW SD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_SD + 0 +SDDPH2 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW SDCSV2,SDALV2 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +SD2_SLICE .DW SD2_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW SD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; + .DB DIODEV_SD + 0 +SDDPH3 .DW 0000,0000 + .DW 0000,0000 + .DW DIRBF,DPB_HD + .DW SDCSV3,SDALV3 + .DB "LU" ; LOGICAL UNIT ENHANCEMENT SIGNATURE +SD3_SLICE .DW SD3_SLICEDEF ; CURRENTLY ACTIVE SLICE + .DW SD_NUMSLICES ; NUMBER OF SLICES AVAILABLE +; +SDCKS .EQU 0 ; CKS: 0 FOR NON-REMOVABLE MEDIA +SDALS .EQU 256 ; ALS: BLKS / 8 = 2048 / 8 = 256 (ROUNDED UP) +; +SDCSV0: .FILL SDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +SDALV0: .FILL SDALS ; MAX OF 2048 DATA BLOCKS +SDCSV1: .FILL SDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +SDALV1: .FILL SDALS ; MAX OF 2048 DATA BLOCKS +SDCSV2: .FILL SDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +SDALV2: .FILL SDALS ; MAX OF 2048 DATA BLOCKS +SDCSV3: .FILL SDCKS ; NO DIRECTORY CHECKSUM, NON-REMOVABLE DRIVE +SDALV3: .FILL SDALS ; MAX OF 2048 DATA BLOCKS diff --git a/trunk/Source/std.asm b/trunk/Source/std.asm new file mode 100644 index 00000000..5076ba65 --- /dev/null +++ b/trunk/Source/std.asm @@ -0,0 +1,577 @@ +; +;================================================================================================== +; STANDARD INCLUDE STUFF +;================================================================================================== +; +; 5/21/2012 2.0.0.0 dwg - added B1F0PEEK & B1F0POKE +; +; 5/11/2012 2.0.0.0 dwg - moved BIOS JMPS together +; +; 3/04/2012 2.0.0.0 dwg - added CBIOS_BNKSEL for new BIOS jump (OEM extension) +; +; 2/21/2012 dwg - added TERM_VT52 terminal type for VDU +; 12/12/2011 dwg - changed TERM_NOT_SPEC to TERM_TTY & TTY=0 ANSI=1 WYSE=2 +; +; 12/11/2011 dwg - added TERM_ANSI and TERM_WYSE for TERMTYPE +; +; 11/29/2011 dwg - now uses dynamically generated include file +; instead of static definitions. +; +;--------------------------------------------------------------------------------------------------- +; +TRUE: .EQU 1 +FALSE: .EQU 0 +; +; PRIMARY HARDWARE PLATFORMS +; +PLT_N8VEM .EQU 1 ; N8VEM ECB Z80 SBC +PLT_ZETA .EQU 2 ; ZETA Z80 SBC +PLT_N8 .EQU 3 ; N8 (HOME COMPUTER) Z180 SBC +; +; BOOT STYLE +; +BT_MENU .EQU 1 ; WAIT FOR MENU SELECTION AT LOADER PROMPT +BT_AUTO .EQU 2 ; AUTO SELECT BOOT_DEFAULT AFTER BOOT_TIMEOUT +; +; VDU MODE SELECTIONS +; +VDUMODE_VDU .EQU 1 ; ORIGINAL ECB VDU (6545 CHIP) +VDUMODE_CVDU .EQU 2 ; ECB VDU COLOR (PENDING HARDWARE DEVELOPMENT) +VDUMODE_N8 .EQU 3 ; N8 ONBOARD VIDEO SUBSYSTEM (NOT IMPLEMENTED) +; +; CHARACTER DEVICES +; +CIODEV_UART .EQU $00 +CIODEV_PRPCON .EQU $10 +CIODEV_VDU .EQU $20 +CIODEV_CVDU .EQU $30 +CIODEV_PPPCON .EQU $40 +CIODEV_BAT .EQU $E0 +CIODEV_NUL .EQU $F0 +; +; DISK DEVICES (ONLY FIRST NIBBLE RELEVANT, SECOND NIBBLE RESERVED FOR UNIT) +; +DIODEV_MD .EQU $00 +DIODEV_FD .EQU $10 +DIODEV_IDE .EQU $20 +DIODEV_ATAPI .EQU $30 +DIODEV_PPIDE .EQU $40 +DIODEV_SD .EQU $50 +DIODEV_PRPSD .EQU $60 +DIODEV_PPPSD .EQU $70 +DIODEV_HDSK .EQU $80 +; +; RAM DISK INITIALIZATION OPTIONS +; +CLR_NEVER .EQU 0 ; NEVER CLEAR RAM DISK +CLR_AUTO .EQU 1 ; CLEAR RAM DISK IF INVALID DIR ENTRIES +CLR_ALWAYS .EQU 2 ; ALWAYS CLEAR RAM DISK +; +; DISK MAP SELECTION OPTIONS +; +DM_ROM .EQU 1 ; ROM DRIVE PRIORITY +DM_RAM .EQU 2 ; RAM DRIVE PRIORITY +DM_FD .EQU 3 ; FLOPPY DRIVE PRIORITY +DM_IDE .EQU 4 ; IDE DRIVE PRIORITY +DM_PPIDE .EQU 5 ; PPIDE DRIVE PRIORITY +DM_SD .EQU 6 ; SD DRIVE PRIORITY +DM_PRPSD .EQU 7 ; PROPIO SD DRIVE PRIORITY +DM_PPPSD .EQU 8 ; PROPIO SD DRIVE PRIORITY +DM_HDSK .EQU 9 ; SIMH HARD DISK DRIVE PRIORITY +; +; FLOPPY DISK MEDIA SELECTIONS (ID'S MUST BE INDEX OF ENTRY IN FCD_TBL) +; +FDM720 .EQU 0 ; 3.5" FLOPPY, 720KB, 2 SIDES, 80 TRKS, 9 SECTORS +FDM144 .EQU 1 ; 3.5" FLOPPY, 1.44MB, 2 SIDES, 80 TRKS, 18 SECTORS +FDM360 .EQU 2 ; 5.25" FLOPPY, 360KB, 2 SIDES, 40 TRKS, 9 SECTORS +FDM120 .EQU 3 ; 5.25" FLOPPY, 1.2MB, 2 SIDES, 80 TRKS, 15 SECTORS +FDM111 .EQU 4 ; 8" FLOPPY, 1.11MB, 2 SIDES, 74 TRKS, 15 SECTORS +; +; MEDIA ID VALUES +; +MID_NONE .EQU 0 +MID_MDROM .EQU 1 +MID_MDRAM .EQU 2 +MID_HD .EQU 3 +MID_FD720 .EQU 4 +MID_FD144 .EQU 5 +MID_FD360 .EQU 6 +MID_FD120 .EQU 7 +MID_FD111 .EQU 8 +; +; FD MODE SELECTIONS +; +FDMODE_DIO .EQU 1 ; DISKIO V1 +FDMODE_ZETA .EQU 2 ; ZETA +FDMODE_DIDE .EQU 3 ; DUAL IDE +FDMODE_N8 .EQU 4 ; N8 +FDMODE_DIO3 .EQU 5 ; DISKIO V3 +; +; IDE MODE SELECTIONS +; +IDEMODE_DIO .EQU 1 ; DISKIO V1 +IDEMODE_DIDE .EQU 2 ; DUAL IDE +; +; PPIDE MODE SELECTIONS +; +PPIDEMODE_STD .EQU 1 ; STANDARD N8VEM PARALLEL PORT +PPIDEMODE_DIO3 .EQU 2 ; DISKIO V3 PARALLEL PORT +; +; CONSOLE DEVICE CHOICES FOR LDRCON AND DBGCON IN CONFIG SETTINGS +; +CON_UART .EQU 1 +CON_VDU .EQU 2 +CON_PRP .EQU 3 +CON_PPP .EQU 4 +; +; CONSOLE TERMINAL TYPE CHOICES +; +TERM_TTY .EQU 0 +TERM_ANSI .EQU 1 +TERM_WYSE .EQU 2 +TERM_VT52 .EQU 3 +; +; SYSTEM GENERATION SETTINGS +; +SYS_CPM .EQU 1 ; CPM (IMPLIES BDOS + CCP) +SYS_ZSYS .EQU 2 ; ZSYSTEM OS (IMPLIES ZSDOS + ZCPR) +; +DOS_BDOS .EQU 1 ; BDOS +DOS_ZDDOS .EQU 2 ; ZDDOS VARIANT OF ZSDOS +DOS_ZSDOS .EQU 3 ; ZSDOS +; +CP_CCP .EQU 1 ; CCP COMMAND PROCESSOR +CP_ZCPR .EQU 2 ; ZCPR COMMAND PROCESSOR +; +; CONFIGURE DOS (DOS) AND COMMAND PROCESSOR (CP) BASED ON SYSTEM SETTING (SYS) +; +#IFNDEF BLD_SYS +SYS .EQU SYS_CPM +#ELSE +SYS .EQU BLD_SYS +#ENDIF +; +#IF (SYS == SYS_CPM) +DOS .EQU DOS_BDOS +CP .EQU CP_CCP +#DEFINE OSLBL "CP/M-80 2.2C" +#ENDIF +; +#IF (SYS == SYS_ZSYS) +DOS .EQU DOS_ZSDOS +CP .EQU CP_ZCPR +#DEFINE OSLBL "ZSDOS 1.1" +#ENDIF +; +; INCLUDE VERSION AND BUILD SETTINGS +; +#INCLUDE "ver.inc" ; ADD BIOSVER +; +#INCLUDE "build.inc" ; INCLUDE USER CONFIG, ADD VARIANT, TIMESTAMP, & ROMSIZE +; +#IF (PLATFORM != PLT_N8) +; +; N8VEM HARDWARE IO PORT ADDRESSES AND MEMORY LOCATIONS +; +MPCL_RAM .EQU 78H ; BASE IO ADDRESS OF RAM MEMORY PAGER CONFIGURATION LATCH +MPCL_ROM .EQU 7CH ; BASE IO ADDRESS OF ROM MEMORY PAGER CONFIGURATION LATCH +RTC .EQU 70H ; ADDRESS OF RTC LATCH AND INPUT PORT + +;__HARDWARE_INTERFACES________________________________________________________________________________________________________________ +; +; PIO 82C55 I/O IS DECODED TO PORT 60-67 +; +PIOA .EQU 60H ; PORT A +PIOB .EQU 61H ; PORT B +PIOC .EQU 62H ; PORT C +PIOX .EQU 63H ; PIO CONTROL PORT +; +; 16C550 SERIAL LINE UART +; +SIO_BASE .EQU 68H +SIO_RBR .EQU SIO_BASE + 0 ; DLAB=0: RCVR BUFFER REG (READ ONLY) +SIO_THR .EQU SIO_BASE + 0 ; DLAB=0: XMIT HOLDING REG (WRITE ONLY) +SIO_IER .EQU SIO_BASE + 1 ; DLAB=0: INT ENABLE REG +SIO_IIR .EQU SIO_BASE + 2 ; INT IDENT REGISTER (READ ONLY) +SIO_FCR .EQU SIO_BASE + 2 ; FIFO CONTROL REG (WRITE ONLY) +SIO_LCR .EQU SIO_BASE + 3 ; LINE CONTROL REG +SIO_MCR .EQU SIO_BASE + 4 ; MODEM CONTROL REG +SIO_LSR .EQU SIO_BASE + 5 ; LINE STATUS REG +SIO_MSR .EQU SIO_BASE + 6 ; MODEM STATUS REG +SIO_SCR .EQU SIO_BASE + 7 ; SCRATCH REGISTER +SIO_DLL .EQU SIO_BASE + 0 ; DLAB=1: DIVISOR LATCH (LS) +SIO_DLM .EQU SIO_BASE + 1 ; DLAB=1: DIVISOR LATCH (MS) +; +#ENDIF ; (PLATFORM != PLT_N8) +; +#IF (PLATFORM == PLT_N8) +; +; Z180 REGISTERS +; +CPU_IOBASE .EQU 40H ; ONLY RELEVANT FOR Z180 +; +CPU_CNTLA0: .EQU CPU_IOBASE+$00 ;ASCI0 control A +CPU_CNTLA1: .EQU CPU_IOBASE+$01 ;ASCI1 control A +CPU_CNTLB0: .EQU CPU_IOBASE+$02 ;ASCI0 control B +CPU_CNTLB1: .EQU CPU_IOBASE+$03 ;ASCI1 control B +CPU_STAT0: .EQU CPU_IOBASE+$04 ;ASCI0 status +CPU_STAT1: .EQU CPU_IOBASE+$05 ;ASCI1 status +CPU_TDR0: .EQU CPU_IOBASE+$06 ;ASCI0 transmit +CPU_TDR1: .EQU CPU_IOBASE+$07 ;ASCI1 transmit +CPU_RDR0: .EQU CPU_IOBASE+$08 ;ASCI0 receive +CPU_RDR1: .EQU CPU_IOBASE+$09 ;ASCI1 receive +CPU_CNTR: .EQU CPU_IOBASE+$0A ;CSI/O control +CPU_TRDR: .EQU CPU_IOBASE+$0B ;CSI/O transmit/receive +CPU_TMDR0L: .EQU CPU_IOBASE+$0C ;Timer 0 data lo +CPU_TMDR0H: .EQU CPU_IOBASE+$0D ;Timer 0 data hi +CPU_RLDR0L: .EQU CPU_IOBASE+$0E ;Timer 0 reload lo +CPU_RLDR0H: .EQU CPU_IOBASE+$0F ;Timer 0 reload hi +CPU_TCR: .EQU CPU_IOBASE+$10 ;Timer control +; +CPU_ASEXT0: .EQU CPU_IOBASE+$12 ;ASCI0 extension control (Z8S180) +CPU_ASEXT1: .EQU CPU_IOBASE+$13 ;ASCI1 extension control (Z8S180) +; +CPU_TMDR1L: .EQU CPU_IOBASE+$14 ;Timer 1 data lo +CPU_TMDR1H: .EQU CPU_IOBASE+$15 ;Timer 1 data hi +CPU_RLDR1L: .EQU CPU_IOBASE+$16 ;Timer 1 reload lo +CPU_RLDR1H: .EQU CPU_IOBASE+$17 ;Timer 1 reload hi +CPU_FRC: .EQU CPU_IOBASE+$18 ;Free running counter + +CPU_ASTC0L: .EQU CPU_IOBASE+$1A ;ASCI0 Time constant lo (Z8S180) +CPU_ASTC0H: .EQU CPU_IOBASE+$1B ;ASCI0 Time constant hi (Z8S180) +CPU_ASTC1L: .EQU CPU_IOBASE+$1C ;ASCI1 Time constant lo (Z8S180) +CPU_ASTC1H: .EQU CPU_IOBASE+$1D ;ASCI1 Time constant hi (Z8S180) +CPU_CMR: .EQU CPU_IOBASE+$1E ;Clock multiplier (latest Z8S180) +CPU_CCR: .EQU CPU_IOBASE+$1F ;CPU control (Z8S180) +; +CPU_SAR0L: .EQU CPU_IOBASE+$20 ;DMA0 source addr lo +CPU_SAR0H: .EQU CPU_IOBASE+$21 ;DMA0 source addr hi +CPU_SAR0B: .EQU CPU_IOBASE+$22 ;DMA0 source addr bank +CPU_DAR0L: .EQU CPU_IOBASE+$23 ;DMA0 dest addr lo +CPU_DAR0H: .EQU CPU_IOBASE+$24 ;DMA0 dest addr hi +CPU_DAR0B: .EQU CPU_IOBASE+$25 ;DMA0 dest addr bank +CPU_BCR0L: .EQU CPU_IOBASE+$26 ;DMA0 byte count lo +CPU_BCR0H: .EQU CPU_IOBASE+$27 ;DMA0 byte count hi +CPU_MAR1L: .EQU CPU_IOBASE+$28 ;DMA1 memory addr lo +CPU_MAR1H: .EQU CPU_IOBASE+$29 ;DMA1 memory addr hi +CPU_MAR1B: .EQU CPU_IOBASE+$2A ;DMA1 memory addr bank +CPU_IAR1L: .EQU CPU_IOBASE+$2B ;DMA1 I/O addr lo +CPU_IAR1H: .EQU CPU_IOBASE+$2C ;DMA1 I/O addr hi +CPU_IAR1B: .EQU CPU_IOBASE+$2D ;DMA1 I/O addr bank (Z8S180) +CPU_BCR1L: .EQU CPU_IOBASE+$2E ;DMA1 byte count lo +CPU_BCR1H: .EQU CPU_IOBASE+$2F ;DMA1 byte count hi +CPU_DSTAT: .EQU CPU_IOBASE+$30 ;DMA status +CPU_DMODE: .EQU CPU_IOBASE+$31 ;DMA mode +CPU_DCNTL: .EQU CPU_IOBASE+$32 ;DMA/WAIT control +CPU_IL: .EQU CPU_IOBASE+$33 ;Interrupt vector load +CPU_ITC: .EQU CPU_IOBASE+$34 ;INT/TRAP control +; +CPU_RCR: .EQU CPU_IOBASE+$36 ;Refresh control +; +CPU_CBR: .EQU CPU_IOBASE+$38 ;MMU common base register +CPU_BBR: .EQU CPU_IOBASE+$39 ;MMU bank base register +CPU_CBAR .EQU CPU_IOBASE+$3A ;MMU common/bank area register +; +CPU_OMCR: .EQU CPU_IOBASE+$3E ;Operation mode control +CPU_ICR: .EQU $3F ;I/O control register (not relocated!!!) +; +; N8 ONBOARD I/O REGISTERS +; +N8_IOBASE .EQU $80 +; +PIO .EQU N8_IOBASE+$00 +PIOA .EQU PIO+$00 ; PORT A +PIOB .EQU PIO+$01 ; PORT B +PIOC .EQU PIO+$02 ; PORT C +PIOX .EQU PIO+$03 ; PIO CONTROL PORT +; +PIO2 .EQU N8_IOBASE+$04 +PIO2A .EQU PIO2+$00 ; PORT A +PIO2B .EQU PIO2+$01 ; PORT B +PIO2C .EQU PIO2+$02 ; PORT C +PIO2X .EQU PIO2+$03 ; PIO CONTROL PORT +; +RTC: .EQU N8_IOBASE+$08 ;RTC latch and buffer +;FDC: .EQU N8_IOBASE+$0C ;Floppy disk controller +;UTIL: .EQU N8_IOBASE+$10 ;Floppy disk utility +ACR: .EQU N8_IOBASE+$14 ;auxillary control register +RMAP: .EQU N8_IOBASE+$16 ;ROM page register +VDP: .EQU N8_IOBASE+$18 ;Video Display Processor (TMS9918A) +PSG: .EQU N8_IOBASE+$1C ;Programmable Sound Generator (AY-3-8910) +; +DEFACR .EQU $1B +; +#ENDIF +; +; CHARACTER DEVICE FUNCTIONS +; +CF_INIT .EQU 0 +CF_IN .EQU 1 +CF_IST .EQU 2 +CF_OUT .EQU 3 +CF_OST .EQU 4 +; +; DISK OPERATIONS +; +DOP_READ .EQU 0 ; READ OPERATION +DOP_WRITE .EQU 1 ; WRITE OPERATION +DOP_FORMAT .EQU 2 ; FORMAT OPERATION +DOP_READID .EQU 3 ; READ ID OPERATION +; +; DISK DRIVER FUNCTIONS +; +DF_READY .EQU 1 +DF_SELECT .EQU 2 +DF_READ .EQU 3 +DF_WRITE .EQU 4 +DF_FORMAT .EQU 5 +; +; BIOS FUNCTIONS +; +BF_CIO .EQU $00 +BF_CIOIN .EQU BF_CIO + 0 ; CHARACTER INPUT +BF_CIOOUT .EQU BF_CIO + 1 ; CHARACTER OUTPUT +BF_CIOIST .EQU BF_CIO + 2 ; CHARACTER INPUT STATUS +BF_CIOOST .EQU BF_CIO + 3 ; CHARACTER OUTPUT STATUS +; +BF_DIO .EQU $10 +BF_DIORD .EQU BF_DIO + 0 ; DISK READ +BF_DIOWR .EQU BF_DIO + 1 ; DISK WRITE +BF_DIOST .EQU BF_DIO + 2 ; DISK STATUS +BF_DIOMED .EQU BF_DIO + 3 ; DISK MEDIA +BF_DIOID .EQU BF_DIO + 4 ; DISK IDENTIFY +BF_DIOGBA .EQU BF_DIO + 8 ; DISK GET BUFFER ADR +BF_DIOSBA .EQU BF_DIO + 9 ; DISK SET BUFFER ADR +; +BF_CLK .EQU $20 +BF_CLKRD .EQU BF_CLK + 0 +BF_CLKWR .EQU BF_CLK + 1 +; +BF_VDU .EQU $30 +BF_VDUIN .EQU BF_VDU + 0 ; VDU CHARACTER INPUT +BF_VDUOUT .EQU BF_VDU + 1 ; VDU CHARACTER OUTPUT +BF_VDUIST .EQU BF_VDU + 2 ; VDU CHARACTER INPUT STATUS +BF_VDUOST .EQU BF_VDU + 3 ; VDU CHARACTER OUTPUT STATUS +BF_VDUXY .EQU BF_VDU + 4 ; VDU CURSOR POSITION X/Y +; +BF_SYS .EQU $F0 +BF_SYSGETCFG .EQU BF_SYS + 0 ; GET CONFIGURATION DATA BLOCK +BF_SYSSETCFG .EQU BF_SYS + 1 ; SET CONFIGURATION DATA BLOCK +BF_SYSBNKCPY .EQU BF_SYS + 2 ; COPY TO/FROM RAM/ROM MEMORY BANK +; +; +; MEMORY LAYOUT +; +CPM_LOC .EQU 0D000H ; CONFIGURABLE: LOCATION OF CPM FOR RUNNING SYSTEM +CPM_SIZ .EQU 2F00H ; SIZE OF CPM IMAGE (CCP + BDOS + CBIOS (INCLUDING DATA)) +CPM_END .EQU CPM_LOC + CPM_SIZ +; +CCP_LOC .EQU CPM_LOC ; START OF COMMAND PROCESSOR +CCP_SIZ .EQU 800H +CCP_END .EQU CCP_LOC + CCP_SIZ +; +BDOS_LOC .EQU CCP_END ; START OF BDOS +BDOS_SIZ .EQU 0E00H +BDOS_END .EQU BDOS_LOC + BDOS_SIZ +; +CBIOS_LOC .EQU BDOS_END +CBIOS_SIZ .EQU CPM_END - CBIOS_LOC +CBIOS_END .EQU CBIOS_LOC + CBIOS_SIZ +; +CPM_ENT .EQU CBIOS_LOC +; +HB_LOC .EQU CPM_END +HB_SIZ .EQU 100H +HB_END .EQU HB_LOC + HB_SIZ +; +MON_LOC .EQU 0C000H ; LOCATION OF MONITOR FOR RUNNING SYSTEM +MON_SIZ .EQU 01000H ; SIZE OF MONITOR BINARY IMAGE +MON_END .EQU MON_LOC + MON_SIZ +MON_DSKY .EQU MON_LOC ; MONITOR ENTRY (DSKY) +MON_UART .EQU MON_LOC + 3 ; MONITOR ENTRY (UART) +; +CBIOS_BOOT .EQU CBIOS_LOC + 0 +CBIOS_WBOOT .EQU CBIOS_LOC + 3 +CBIOS_CONST .EQU CBIOS_LOC + 6 +CBIOS_CONIN .EQU CBIOS_LOC + 9 +CBIOS_CONOUT .EQU CBIOS_LOC + 12 +CBIOS_LIST .EQU CBIOS_LOC + 15 +CBIOS_PUNCH .EQU CBIOS_LOC + 18 +CBIOS_READER .EQU CBIOS_LOC + 21 +CBIOS_HOME .EQU CBIOS_LOC + 24 +CBIOS_SELDSK .EQU CBIOS_LOC + 27 +CBIOS_SETTRK .EQU CBIOS_LOC + 30 +CBIOS_SETSEC .EQU CBIOS_LOC + 33 +CBIOS_SETDMA .EQU CBIOS_LOC + 36 +CBIOS_READ .EQU CBIOS_LOC + 39 +CBIOS_WRITE .EQU CBIOS_LOC + 42 +CBIOS_LISTST .EQU CBIOS_LOC + 45 +CBIOS_SECTRN .EQU CBIOS_LOC + 48 +; +; EXTENDED CBIOS FUNCTIONS +; +CBIOS_BNKSEL .EQU CBIOS_LOC + 51 +CBIOS_GETDSK .EQU CBIOS_LOC + 54 +CBIOS_SETDSK .EQU CBIOS_LOC + 57 +CBIOS_GETINFO .EQU CBIOS_LOC + 60 +; +; PLACEHOLDERS FOR FUTURE CBIOS EXTENSIONS +; +CBIOS_RSVD1 .EQU CBIOS_LOC + 63 +CBIOS_RSVD2 .EQU CBIOS_LOC + 76 +CBIOS_RSVD3 .EQU CBIOS_LOC + 69 +CBIOS_RSVD4 .EQU CBIOS_LOC + 72 +; +CDISK: .EQU 00004H ; LOC IN PAGE 0 OF CURRENT DISK NUMBER 0=A,...,15=P +IOBYTE: .EQU 00003H ; LOC IN PAGE 0 OF I/O DEFINITION BYTE. +; +; MEMORY CONFIGURATION +; +MSIZE .EQU 59 ; CP/M VERSION MEMORY SIZE IN KILOBYTES +; +; "BIAS" IS ADDRESS OFFSET FROM 3400H FOR MEMORY SYSTEMS +; THAN 16K (REFERRED TO AS "B" THROUGHOUT THE TEXT) +; +BIAS: .EQU (MSIZE-20)*1024 +CCP: .EQU 3400H+BIAS ; BASE OF CCP +BDOS: .EQU CCP+806H ; BASE OF BDOS +BIOS: .EQU CCP+1600H ; BASE OF BIOS +CCPSIZ: .EQU 00800H +; +#IF (PLATFORM == PLT_N8VEM) + #DEFINE PLATFORM_NAME "N8VEM Z80 SBC" +#ENDIF +#IF (PLATFORM == PLT_ZETA) + #DEFINE PLATFORM_NAME "ZETA Z80 SBC" +#ENDIF +#IF (PLATFORM == PLT_N8) + #DEFINE PLATFORM_NAME "N8 Z180 SBC" +#ENDIF +; +#IF (DSKYENABLE) + #DEFINE DSKYLBL ", DSKY" +#ELSE + #DEFINE DSKYLBL "" +#ENDIF +; +#IF (VDUENABLE) + #DEFINE VDULBL ", VDU" +#ELSE + #DEFINE VDULBL "" +#ENDIF +; +#IF (FDENABLE) + #IF (FDMAUTO) + #DEFINE FDLBL ", FLOPPY (AUTOSIZE)" + #ELSE + #IF (FDMEDIA == FDM720) + #DEFINE FDLBL ", FLOPPY (720KB)" + #ENDIF + #IF (FDMEDIA == FDM144) + #DEFINE FDLBL ", FLOPPY (1.44MB)" + #ENDIF + #IF (FDMEDIA == FDM120) + #DEFINE FDLBL ", FLOPPY (1.20MB)" + #ENDIF + #IF (FDMEDIA == FDM360) + #DEFINE FDLBL ", FLOPPY (360KB)" + #ENDIF + #IF (FDMEDIA == FDM111) + #DEFINE FDLBL ", FLOPPY (1.11MB)" + #ENDIF + #ENDIF +#ELSE + #DEFINE FDLBL "" +#ENDIF +; +#IF (IDEENABLE) + #IF (IDEMODE == IDEMODE_DIO) + #DEFINE IDELBL ", IDE (DISKIO)" + #ENDIF + #IF (IDEMODE == IDEMODE_DIDE) + #DEFINE IDELBL ", IDE (DUAL IDE)" + #ENDIF +#ELSE + #DEFINE IDELBL "" +#ENDIF +; +#IF (PPIDEENABLE) + #IF (PPIDEMODE == PPIDEMODE_STD) + #DEFINE PPIDELBL ", PPIDE (STD)" + #ENDIF + #IF (PPIDEMODE == PPIDEMODE_DIO3) + #DEFINE PPIDELBL ", PPIDE (DISKIO V3)" + #ENDIF +#ELSE + #DEFINE PPIDELBL "" +#ENDIF +; +#IF (SDENABLE) + #DEFINE SDLBL ", SD CARD" +#ELSE + #DEFINE SDLBL "" +#ENDIF +; +#IF (IDEENABLE) + #DEFINE IDELBL ", IDE" +#ELSE + #DEFINE IDELBL "" +#ENDIF +; +#IF (PPIDEENABLE) + #DEFINE PPIDELBL ", PPIDE" +#ELSE + #DEFINE PPIDELBL "" +#ENDIF + +#IF (SDENABLE) + #DEFINE SDLBL ", SD CARD" +#ELSE + #DEFINE SDLBL "" +#ENDIF + +#IF (PRPENABLE) + #IF (PRPCONENABLE & PRPSDENABLE) + #DEFINE PRPLBL ", PROPIO (CONSOLE, SD CARD)" + #ENDIF + #IF (PRPCONENABLE & !PRPSDENABLE) + #DEFINE PRPLBL ", PROPIO (CONSOLE)" + #ENDIF + #IF (!PRPCONENABLE & PRPSDENABLE) + #DEFINE PRPLBL ", PROPIO (SD CARD)" + #ENDIF + #IF (!PRPCONENABLE & !PRPSDENABLE) + #DEFINE PRPLBL ", PROPIO ()" + #ENDIF +#ELSE + #DEFINE PRPLBL "" +#ENDIF + +#IF (PPPENABLE) + #IF (PPPCONENABLE & PPPSDENABLE) + #DEFINE PPPLBL ", PARPORTPROP (CONSOLE, SD CARD)" + #ENDIF + #IF (PPPCONENABLE & !PPPSDENABLE) + #DEFINE PPPLBL ", PARPORTPROP (CONSOLE)" + #ENDIF + #IF (!PPPCONENABLE & PPPSDENABLE) + #DEFINE PPPLBL ", PARPORTPROP (SD CARD)" + #ENDIF + #IF (!PPPCONENABLE & !PPPSDENABLE) + #DEFINE PPPLBL ", PARPORTPROP ()" + #ENDIF +#ELSE + #DEFINE PPPLBL "" +#ENDIF + + .ECHO "Configuration: " + .ECHO PLATFORM_NAME + .ECHO DSKYLBL + .ECHO VDULBL + .ECHO FDLBL + .ECHO IDELBL + .ECHO PPIDELBL + .ECHO SDLBL + .ECHO PRPLBL + .ECHO PPPLBL + .ECHO "\n" diff --git a/trunk/Source/syscfg.asm b/trunk/Source/syscfg.asm new file mode 100644 index 00000000..d0102776 --- /dev/null +++ b/trunk/Source/syscfg.asm @@ -0,0 +1,34 @@ +;___SYSCFG_____________________________________________________________________________________________________________ +; +; syscfg.asm 3/04/2012 2.0.0.0 dwg - added required configuration information +; +; Include standard BIOS definitions +; +#INCLUDE "std.asm" +; + .ORG 0000H ; ALL ADDRESSES GENERATED WILL BE ZERO BASED +; + JP 0000H ; DUMMY JP INSTRUCTION FOR COMPATIBILITY +; +; Reserved for Configuration Information +; + .DW cnf_loc + .DW tst_loc1 + .DW var_loc1 +; +; BIOS configuration data +; +cnf_loc: +#INCLUDE "cnfgdata.inc" +; +; Build information strings +; +tst_loc1 .DB TIMESTAMP +var_loc1 .DB VARIANT + .DB '$' ; provide terminator for variable length field +; + .EXPORT DISKBOOT,BOOTDEVICE,BOOTLU +; + .FILL 200H - $,$FF +; + .END diff --git a/trunk/Source/uart.asm b/trunk/Source/uart.asm new file mode 100644 index 00000000..6b544879 --- /dev/null +++ b/trunk/Source/uart.asm @@ -0,0 +1,229 @@ +; +;================================================================================================== +; UART DRIVER (SERIAL PORT) +;================================================================================================== +; +#IF (PLATFORM != PLT_N8) +UART0_DIV .EQU (1843200 / (16 * BAUDRATE)) +#ENDIF +; +; CHARACTER DEVICE DRIVER ENTRY +; A: RESULT (OUT), CF=ERR +; B: FUNCTION (IN) +; C: CHARACTER (IN/OUT) +; E: DEVICE/UNIT (IN) +; +; +UART_DISPATCH: +#IF (PLATFORM == PLT_N8) + LD A,C ; GET DEVICE/UNIT + AND $0F ; ISOLATE UNIT + JR Z,UART0 + DEC A + JR Z,UART1 + CALL PANIC +#ENDIF +; +UART0: +; LD C,E ; FIX: COMPAT W/OLD DRIVERS, GET CHAR INTO C + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JR Z,UART0_IN + DEC A + JR Z,UART0_OUT + DEC A + JR Z,UART0_IST + DEC A + JR Z,UART0_OST + CALL PANIC +; +; +; +UART_INIT: +#IF (PLATFORM == PLT_N8) + ; ASCI0 + LD A,66H + OUT0 (CPU_ASEXT0),A + LD A,64H + OUT0 (CPU_CNTLA0),A + LD A,Z180_CNTLB0 + OUT0 (CPU_CNTLB0),A + + ; ASCI1 + LD A,66H + OUT0 (CPU_ASEXT1),A + LD A,64H + OUT0 (CPU_CNTLA1),A + LD A,Z180_CNTLB1 + OUT0 (CPU_CNTLB1),A +#ELSE + LD A,80H + OUT (SIO_LCR),A ; DLAB ON + LD A,UART0_DIV + OUT (SIO_DLL),A ; SET DIVISOR (LS) + LD A,00H + OUT (SIO_DLM),A ; SET DIVISOR (MS) + + LD B,03H ; B = DEFAULT SETTING FOR MCR (DTR + RTS) + +#IF (UARTAFC) + LD A,$55 ; TEST VALUE + OUT (SIO_SCR),A ; SET SCRATCH REG TO TEST VALUE + LD A,0BFH + OUT (SIO_LCR),A ; SET LCR=$BF TO ATTEMPT TO ACCESS EFR + IN A,(SIO_SCR) ; READ SCRATCH REGISTER + CP $55 ; IF $55, NO EFR + JR NZ,UART_AFC1 ; NZ, HAVE EFR, DO IT + SET 5,B ; ENABLE AUTO FLOW CONTROL + JR UART_AFC2 +UART_AFC1: + LD A,0C0H ; ENABLE CTS/RTS FLOW CONTROL + OUT (SIO_EFR),A ; SAVE IT +UART_AFC2: +#ENDIF + + LD A,03H + OUT (SIO_LCR),A ; DLAB OFF, 8 DATA, 1 STOP, NO PARITY + + LD A,B ; LOAD MCR VALUE TO SET + OUT (SIO_MCR),A ; SAVE IT + +#IF (UARTFIFO) + LD A,07H ; ENABLE AND RESET FIFOS + OUT (SIO_FCR),A +#ENDIF + +#ENDIF + RET +; +; +; +UART0_IN: + CALL UART0_IST + OR A + JR Z,UART0_IN +#IF (PLATFORM == PLT_N8) + IN0 A,(CPU_RDR0) ; READ THE CHAR FROM THE UART +#ELSE + IN A,(SIO_RBR) ; READ THE CHAR FROM THE UART +#ENDIF + LD E,A + RET +; +; +; +UART0_IST: +#IF (PLATFORM == PLT_N8) + ; CHECK FOR ERROR FLAGS + IN0 A,(CPU_STAT0) + AND 70H ; PARITY, FRAMING, OR OVERRUN ERROR + JR Z,UART0_IST1 ; ALL IS WELL, CHECK FOR DATA + + ; CLEAR ERROR(S) OR NOTHING FURTHER CAN BE RECEIVED!!! + IN0 A,(CPU_CNTLA0) + RES 3,A ; CLEAR EFR (ERROR FLAG RESET) + OUT0 (CPU_CNTLA0),A + +UART0_IST1: ; CHECK FOR STAT0.RDRF (DATA READY) + IN0 A,(CPU_STAT0) ; READ LINE STATUS REGISTER + AND $80 ; TEST IF DATA IN RECEIVE BUFFER +#ELSE + IN A,(SIO_LSR) ; READ LINE STATUS REGISTER + AND $01 ; TEST IF DATA IN RECEIVE BUFFER +#ENDIF + JP Z,CIO_IDLE ; DO IDLE PROCESSING + LD A,$01 ; SIGNAL DATA PENDING + RET +; +; +; +UART0_OUT: + CALL UART0_OST + OR A + JR Z,UART0_OUT + LD A,E +#IF (PLATFORM == PLT_N8) + OUT0 (CPU_TDR0),A +#ELSE + OUT (SIO_THR),A ; THEN WRITE THE CHAR TO UART +#ENDIF + RET +; +UART0_OST: +#IF (PLATFORM == PLT_N8) + IN0 A,(CPU_STAT0) + AND $02 + JR Z,UART0_OST +#ELSE + IN A,(SIO_LSR) ; READ LINE STATUS REGISTER + AND $20 + JR Z,UART0_OST ; IF NOT REPEAT +#ENDIF + JP Z,CIO_IDLE ; DO IDLE PROCESSING + LD A,$01 ; SIGNAL DATA PENDING + RET +; +; +; +#IF (PLATFORM == PLT_N8) +; +UART1: + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JR Z,UART0_IN + DEC A + JR Z,UART0_OUT + DEC A + JR Z,UART0_IST + DEC A + JR Z,UART0_OST + CALL PANIC +; +; +; +UART1_IN: + CALL UART1_IST + OR A + JR Z,UART1_IN + IN0 A,(CPU_RDR1) ; READ THE CHAR FROM THE UART + LD E,A + RET +; +; +; +UART1_IST: + ; CHECK FOR ERROR FLAGS + IN0 A,(CPU_STAT1) + AND 70H ; PARITY, FRAMING, OR OVERRUN ERROR + JR Z,UART1_IST1 ; ALL IS WELL, CHECK FOR DATA + + ; CLEAR ERROR(S) OR NOTHING FURTHER CAN BE RECEIVED!!! + IN0 A,(CPU_CNTLA1) + RES 3,A ; CLEAR EFR (ERROR FLAG RESET) + OUT0 (CPU_CNTLA1),A + +UART1_IST1: ; CHECK FOR STAT0.RDRF (DATA READY) + IN0 A,(CPU_STAT1) ; READ LINE STATUS REGISTER + AND $80 ; TEST IF DATA IN RECEIVE BUFFER + JP Z,CIO_IDLE ; DO IDLE PROCESSING + LD A,$01 ; SIGNAL DATA PENDING + RET +; +; +; +UART1_OUT: + CALL UART1_OST + OR A + JR Z,UART1_OUT + LD A,E + OUT0 (CPU_TDR1),A + RET +; +UART1_OST: + IN0 A,(CPU_STAT1) + AND $02 + JR Z,UART1_OST + JP Z,CIO_IDLE ; DO IDLE PROCESSING + LD A,$01 ; SIGNAL DATA PENDING + RET +#ENDIF diff --git a/trunk/Source/util.asm b/trunk/Source/util.asm new file mode 100644 index 00000000..13190bdf --- /dev/null +++ b/trunk/Source/util.asm @@ -0,0 +1,632 @@ +; +;================================================================================================== +; UTILITY FUNCTIONS +;================================================================================================== +; +; +CHR_CR .EQU 0DH +CHR_LF .EQU 0AH +CHR_BS .EQU 08H +CHR_ESC .EQU 1BH +; +;__________________________________________________________________________________________________ +; +; UTILITY PROCS TO PRINT SINGLE CHARACTERS WITHOUT TRASHING ANY REGISTERS +; +PC_SPACE: + PUSH AF + LD A,' ' + JR PC_PRTCHR + +PC_PERIOD: + PUSH AF + LD A,'.' + JR PC_PRTCHR + +PC_COLON: + PUSH AF + LD A,':' + JR PC_PRTCHR + +PC_COMMA: + PUSH AF + LD A,',' + JR PC_PRTCHR + +PC_LBKT: + PUSH AF + LD A,'[' + JR PC_PRTCHR + +PC_RBKT: + PUSH AF + LD A,']' + JR PC_PRTCHR + +PC_LPAREN: + PUSH AF + LD A,'(' + JR PC_PRTCHR + +PC_RPAREN: + PUSH AF + LD A,')' + JR PC_PRTCHR + +PC_ASTERISK: + PUSH AF + LD A,'*' + JR PC_PRTCHR + +PC_CR: + PUSH AF + LD A,CHR_CR + JR PC_PRTCHR + +PC_LF: + PUSH AF + LD A,CHR_LF + JR PC_PRTCHR + +PC_PRTCHR: + CALL COUT + POP AF + RET + +NEWLINE: + CALL PC_CR + CALL PC_LF + RET +; +; PRINT THE HEX BYTE VALUE IN A +; +PRTHEXBYTE: + PUSH AF + PUSH DE + LD DE,HEXSTRBUF + CALL HEXSTRBYTE + LD A,'$' + LD (DE),A + LD DE,HEXSTRBUF + CALL WRITESTR + POP DE + POP AF + RET +; +; PRINT THE HEX WORD VALUE IN BC +; +PRTHEXWORD: + PUSH AF + LD A,B + CALL PRTHEXBYTE + LD A,C + CALL PRTHEXBYTE + POP AF + RET +; +; CONVERT VALUE IN A TO A 2 CHARACTER HEX STRING AT DE +; +HEXCHR .TEXT "0123456789ABCDEF" +; +HEXSTRBYTE: + PUSH BC + PUSH HL + PUSH AF + LD BC,0 + RRA + RRA + RRA + RRA + AND 0FH + LD C,A + LD HL,HEXCHR + ADD HL,BC + LD A,(HL) + LD (DE),A + INC DE + POP AF + PUSH AF + LD BC,0 + AND 0FH + LD C,A + LD HL,HEXCHR + ADD HL,BC + LD A,(HL) + LD (DE),A + INC DE + POP AF + POP HL + POP BC + RET +; +; CONVERT VALUE IN BC TO A 4 CHARACTER HEX STRING AT DE +; +HEXSTRWORD: + LD A,B + CALL HEXSTRBYTE + LD A,C + CALL HEXSTRBYTE + RET + +; +; PRINT A BYTE BUFFER IN HEX POINTED TO BY DE +; REGISTER A HAS SIZE OF BUFFER +; +PRTHEXBUF: + CP 0 ; EMPTY BUFFER? + JP Z,PRTHEXBUF2 + + LD B,A +PRTHEXBUF1: + CALL PC_SPACE + LD A,(DE) + CALL PRTHEXBYTE + INC DE + DJNZ PRTHEXBUF1 + JP PRTHEXBUFX + +PRTHEXBUF2: + CALL PC_SPACE + LD DE,STR_EMPTY + CALL WRITESTR + +PRTHEXBUFX: + RET +; +; OUTPUT A '$' TERMINATED STRING +; +WRITESTR: + PUSH AF +WRITESTR1: + LD A,(DE) + CP '$' ; TEST FOR STRING TERMINATOR + JP Z,WRITESTR2 + CALL COUT + INC DE + JP WRITESTR1 +WRITESTR2: + POP AF + RET +; +; PANIC: TRY TO DUMP MACHINE STATE AND HALT +; +PANIC: + PUSH HL + PUSH DE + PUSH BC + PUSH AF + LD DE,STR_PANIC + CALL WRITESTR + LD DE,STR_AF + CALL WRITESTR + POP BC + CALL PRTHEXWORD + LD DE,STR_BC + CALL WRITESTR + POP BC + CALL PRTHEXWORD + LD DE,STR_DE + CALL WRITESTR + POP BC + CALL PRTHEXWORD + LD DE,STR_HL + CALL WRITESTR + POP BC + CALL PRTHEXWORD + LD DE,STR_PC + CALL WRITESTR + POP BC + CALL PRTHEXWORD + LD DE,STR_SP + CALL WRITESTR + LD (PANIC_SP),SP + LD BC,(PANIC_SP) + CALL PRTHEXWORD + JP 0 +; +;================================================================================================== +; CONSOLE CHARACTER I/O HELPER ROUTINES (REGISTERS PRESERVED) +;================================================================================================== +; +; OUTPUT CHARACTER FROM A +COUT: + PUSH AF + PUSH BC + PUSH DE + PUSH HL +#IFDEF CIOMODE_CONSOLE + #DEFINE CIOMODE_NONDOS + LD E,A + LD A,(CONDEV) + LD C,A + LD B,BF_CIOOUT + CALL BIOS_DISPATCH +#ENDIF +#IFDEF CIOMODE_CBIOS + #DEFINE CIOMODE_NONDOS + LD C,A + CALL CBIOS_CONOUT +#ENDIF +#IFNDEF CIOMODE_NONDOS + LD E,A + LD C,03H + CALL 0005H +#ENDIF + POP HL + POP DE + POP BC + POP AF + RET +; +; INPUT CHARACTER TO A +; +CIN: + PUSH BC + PUSH DE + PUSH HL +#IFDEF CIOMODE_CONSOLE + #DEFINE CIOMODE_NONDOS + LD A,(CONDEV) + LD C,A + LD B,BF_CIOIN + CALL BIOS_DISPATCH + LD A,E +#ENDIF +#IFDEF CIOMODE_CBIOS + #DEFINE CIOMODE_NONDOS + CALL CBIOS_CONIN +#ENDIF +#IFNDEF CIOMODE_NONDOS + LD C,01H + CALL 0005H +#ENDIF + POP HL + POP DE + POP BC + RET +; +; RETURN INPUT STATUS IN A (0 = NO CHAR, !=0 CHAR WAITING) +; +CST: + PUSH BC + PUSH DE + PUSH HL +#IFDEF CIOMODE_CONSOLE + #DEFINE CIOMODE_NONDOS + LD B,BF_CIOIST + LD A,(CONDEV) + LD C,A + CALL BIOS_DISPATCH +#ENDIF +#IFDEF CIOMODE_CBIOS + #DEFINE CIOMODE_NONDOS + CALL CBIOS_CONST +#ENDIF +#IFNDEF CIOMODE_NONDOS + LD C,0BH + CALL 0005H +#ENDIF + POP HL + POP DE + POP BC + RET +; +STR_PANIC .DB "\r\n\r\n>>> FATAL ERROR:$" +STR_AF .DB " AF=$" +STR_BC .DB " BC=$" +STR_DE .DB " DE=$" +STR_HL .DB " HL=$" +STR_PC .DB " PC=$" +STR_SP .DB " SP=$" +; +; INDIRECT JUMP TO ADDRESS IN HL +; +; MOSTLY USEFUL TO PERFORM AN INDIRECT CALL LIKE: +; LD HL,xxxx +; CALL JPHL +; +JPHL: JP (HL) +; +; DELAY ABOUT 25us (100 TSTATES INCLUDING CALL AND RET) +; +; TOTAL T STATES = ((B*13) + 51) +; 4MHZ CPU, B=4, 103 T STATES = 25.75us +; 8MHZ CPU, B=12, 207 TSTATES = 25.875us +; B = ((2 * FREQ) - 4) +; +DELAY: ; 17 T STATES (FOR CALL) + PUSH BC ; 11 T STATES + LD B,((CPUFREQ * 2) - 4) ; 8 T STATES + DJNZ $ ; (B*13) - 5 T STATES + POP BC ; 10 T STATES + RET ; 10 T STATES +; +; DELAY 25us * VALUE IN DE (VARIABLE DELAY) +; +VDELAY: + CALL DELAY + DEC DE + LD A,D + OR E + JP NZ,VDELAY + RET +; +; DELAY ABOUT 0.5 SECONDS = 25us * 20,000 +; +LDELAY: + PUSH DE + LD DE,20000 + CALL VDELAY + POP DE + RET +; +; MULTIPLY 8-BIT VALUES +; IN: MULTIPLY H WITH E +; OUT: HL = RESULT +; +MULT8: + LD D,0 + LD L,D + LD B,8 +MULT8_LOOP: + ADD HL,HL + JR NC,MULT8_NOADD + ADD HL,DE +MULT8_NOADD: + DJNZ MULT8_LOOP + RET +; +;================================================================================================== +; DSKY KEYBOARD ROUTINES +;================================================================================================== +; +#IF (DSKYENABLE) +; +; ____C0______C1______C2______C3__ +;B5 | 20 D 60 E A0 F E0 BO +;B4 | 10 A 50 B 90 C D0 GO +;B3 | 08 7 48 8 88 9 C8 EX +;B2 | 04 4 44 5 84 6 C4 DE +;B1 | 02 1 42 2 82 3 C2 EN +;B0 | 01 FW 41 0 81 BK C1 CL +; +KY_0 .EQU 000H +KY_1 .EQU 001H +KY_2 .EQU 002H +KY_3 .EQU 003H +KY_4 .EQU 004H +KY_5 .EQU 005H +KY_6 .EQU 006H +KY_7 .EQU 007H +KY_8 .EQU 008H +KY_9 .EQU 009H +KY_A .EQU 00AH +KY_B .EQU 00BH +KY_C .EQU 00CH +KY_D .EQU 00DH +KY_E .EQU 00EH +KY_F .EQU 00FH +KY_FW .EQU 010H ; FORWARD +KY_BK .EQU 011H ; BACKWARD +KY_CL .EQU 012H ; CLEAR +KY_EN .EQU 013H ; ENTER +KY_DE .EQU 014H ; DEPOSIT +KY_EX .EQU 015H ; EXAMINE +KY_GO .EQU 016H ; GO +KY_BO .EQU 017H ; BOOT +; +;__DSKY_INIT_________________________________________________________________________________________ +; +; CHECK FOR KEY PRESS, SAVE RAW VALUE, RETURN STATUS +;____________________________________________________________________________________________________ +; +DSKY_INIT: + LD A,82H + OUT (PIOX),A + LD A,30H ;disable /CS on PPISD card(s) + OUT (PIOC),A + XOR A + LD (KY_BUF),A + RET +#IFDEF DSKY_KBD +; +;__KY_STAT___________________________________________________________________________________________ +; +; CHECK FOR KEY PRESS, SAVE RAW VALUE, RETURN STATUS +;____________________________________________________________________________________________________ +; +KY_STAT: + ; IF WE ALREADY HAVE A KEY, RETURN WITH NZ + LD A,(KY_BUF) + OR A + RET NZ + ; SCAN FOR A KEYPRESS, A=0 NO DATA OR A=RAW BYTE + CALL KY_SCAN ; SCAN KB ONCE + OR A ; SET FLAGS + RET Z ; NOTHING FOUND, GET OUT + LD (KY_BUF),A ; SAVE RAW KEYCODE + RET ; RETURN +; +;__KY_GET____________________________________________________________________________________________ +; +; GET A SINGLE KEY (WAIT FOR ONE IF NECESSARY) +;____________________________________________________________________________________________________ +; +KY_GET: + ; SEE IF WE ALREADY HAVE A KEY SAVED, GO TO DECODE IF SO + LD A,(KY_BUF) + OR A + JR NZ,KY_DECODE + ; NO KEY SAVED, WAIT FOR ONE +KY_STATLOOP: + CALL KY_STAT + OR A + JR Z,KY_STATLOOP + ; DECODE THE RAW VALUE +KY_DECODE: + LD D,00H + LD HL,KY_KEYMAP ; POINT TO BEGINNING OF TABLE +KY_GET_LOOP: + CP (HL) ; MATCH? + JR Z,KY_GET_DONE ; FOUND, DONE + INC HL + INC D ; D + 1 + JR NZ,KY_GET_LOOP ; NOT FOUND, LOOP UNTIL EOT +KY_GET_DONE: + ; CLEAR OUT KEY_BUF + XOR A + LD (KY_BUF),A + ; RETURN THE INDEX POSITION WHERE THE RAW VALUE WAS FOUND + LD A,D + RET +; +;__KY_SCAN____________________________________________________________________________________________ +; +; SCAN KEYBOARD MATRIX FOR AN INPUT +;____________________________________________________________________________________________________ +; +KY_SCAN: + LD C,0000H + LD A,41H+30H ; SCAN COL ONE + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL DELAY ; DEBOUNCE + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KY_SCAN_FOUND ; YES, EXIT + + LD C,0040H + LD A,42H+30H ; SCAN COL TWO + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL DELAY ; DEBOUNCE + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KY_SCAN_FOUND ; YES, EXIT + + LD C,0080H + LD A,44H+30H ; SCAN COL THREE + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL DELAY ; DEBOUNCE + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KY_SCAN_FOUND ; YES, EXIT + + LD C,00C0H ; + LD A,48H+30H ; SCAN COL FOUR + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL DELAY ; DEBOUNCE + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KY_SCAN_FOUND ; YES, EXIT + + LD A,040H+30H ; TURN OFF ALL COLUMNS + OUT (PIOC),A ; SEND TO COLUMN LINES + LD A,00H ; RETURN NULL + RET ; EXIT + +KY_SCAN_FOUND: + AND 3FH ; CLEAR TOP TWO BITS + OR C ; ADD IN ROW BITS + LD C,A ; STORE VALUE + + ; WAIT FOR KEY TO BE RELEASED + LD A,4FH+30H ; SCAN ALL COL LINES + OUT (PIOC),A ; SEND TO COLUMN LINES + CALL DELAY ; DEBOUNCE +KY_CLEAR_LOOP: ; WAIT FOR KEY TO CLEAR + IN A,(PIOB) ; GET ROWS + AND 7FH ;ignore PB7 for PPISD + CP 00H ; ANYTHING PRESSED? + JR NZ,KY_CLEAR_LOOP ; YES, LOOP UNTIL KEY RELEASED + + LD A,040H+30H ; TURN OFF ALL COLUMNS + OUT (PIOC),A ; SEND TO COLUMN LINES + + LD A,C ; RESTORE VALUE + RET +; +;_KEYMAP_TABLE_____________________________________________________________________________________________________________ +; +KY_KEYMAP: +; 0 1 2 3 4 5 6 7 + .DB 041H,002H,042H,082H,004H,044H,084H,008H +; 8 9 A B C D E F + .DB 048H,088H,010H,050H,090H,020H,060H,0A0H +; FW BK CL EN DE EX GO BO + .DB 001H,081H,0C1H,0C2H,0C4H,0C8H,0D0H,0E0H +#ENDIF ; DSKY_KBD +; +;================================================================================================== +; DSKY HEX DISPLAY +;================================================================================================== +; +DSKY_HEXOUT: + LD B,DSKY_HEXBUFLEN + LD HL,DSKY_BUF + LD DE,DSKY_HEXBUF +DSKY_HEXOUT1: + LD A,(DE) ; FIRST NIBBLE + SRL A + SRL A + SRL A + SRL A + LD (HL),A + INC HL + LD A,(DE) ; SECOND NIBBLE + AND 0FH + LD (HL),A + INC HL + INC DE ; NEXT BYTE + DJNZ DSKY_HEXOUT1 + + LD A,82H ; SETUP PPI + OUT (PIOX),A + CALL DSKY_COFF + LD A,0D0H ; 7218 -> (DATA COMING, HEXA DECODE) + OUT (PIOA),A + CALL DSKY_STROBEC + + LD HL,DSKY_BUF ; POINT TO START OF BUF + LD B,DSKY_BUFLEN ; NUMBER OF DIGITS + LD C,PIOA +DSKY_HEXOUT2: + OUTI + JP Z,DSKY_STROBE ; DO FINAL STROBE AND RETURN + CALL DSKY_STROBE + JR DSKY_HEXOUT2 + +DSKY_STROBEC: + LD A,80H+30H + JP DSKY_STROBE0 + +DSKY_STROBE: + LD A,00H+30H ; SET WRITE STROBE + +DSKY_STROBE0: + OUT (PIOC),A ; OUT TO PORTC + CALL DELAY ; DELAY +DSKY_COFF + LD A,40H+30H ; SET CONTROL PORT OFF + OUT (PIOC),A ; OUT TO PORTC + CALL DELAY ; WAIT + RET +#ENDIF +; +;================================================================================================== +; DATA +;================================================================================================== +; +STR_EMPTY .TEXT "$" +; +HEXSTRBUF .TEXT "XX$" +; +KY_BUF .DB 0 +DSKY_BUF: .FILL 8,0 +DSKY_BUFLEN .EQU $ - DSKY_BUF +DSKY_HEXBUF .FILL 4,0 +DSKY_HEXBUFLEN .EQU $ - DSKY_HEXBUF +; +PANIC_SP .DW 0 diff --git a/trunk/Source/vdu.asm b/trunk/Source/vdu.asm new file mode 100644 index 00000000..9cdd9294 --- /dev/null +++ b/trunk/Source/vdu.asm @@ -0,0 +1,1516 @@ +;__VDUDRIVER_______________________________________________________________________________________ +; +; VDUDRIVER FOR CBIOS 2.2, PAGED. +; +; VDU DRIVERS BY: ANDREW LYNCH +; KEYBOARD DRIVERS BY: DR JAMES MOXHAM +; REMAINDER WRITTEN BY: DAN WERNER -- 11/7/2009 +;__________________________________________________________________________________________________ +; +;__________________________________________________________________________________________________ +; DATA CONSTANTS +;__________________________________________________________________________________________________ +;IDE REGISTER IO PORT ; FUNCTION +READR .EQU 0F0h ; READ VDU +WRITR .EQU 0F1h ; WRITE VDU +SY6545S .EQU 0F2h ; VDU STATUS/REGISTER +SY6545D .EQU 0F3h ; +PPIA .EQU 0F4h ; PPI PORT A +PPIB .EQU 0F5h ; PPI PORT B +PPIC .EQU 0F6h ; PPI PORT C +PPICONT .EQU 0F7h ; PPI CONTROL PORT + +STATE_NORMAL .EQU 00H ; NORMAL TERMINAL OPS +STATE_ESC .EQU 01H ; ESC MODE +STATE_DIR_L .EQU 02H ; ESC-Y X * +STATE_DIR_C .EQU 03H ; ESC-Y * X + +ESC_KEY .EQU 1BH ; ESCAPE CODE +; +;__________________________________________________________________________________________________ +; FUNCTION JUMP TABLE +;__________________________________________________________________________________________________ +; +VDU_DISPATCH: + LD A,B ; GET REQUESTED FUNCTION + AND $0F ; ISOLATE SUB-FUNCTION + JR Z,VDU_IN + DEC A + JR Z,VDU_OUT + DEC A + JR Z,VDU_IST + DEC A + JR Z,VDU_OST + CALL PANIC +; +VDU_INIT: + CALL INITVDU + RET +; +VDU_IN: + CALL GET_KEY + LD E,A + RET +; +VDU_IST: + CALL IS_KBHIT + RET +; +VDU_OUT: + LD C,E + CALL CHARIN + RET +; +VDU_OST: + CALL PANIC +; +;__________________________________________________________________________________________________ +; INITIALIZATION +;__________________________________________________________________________________________________ +INITVDU: + CALL VDUINIT ; INIT VDU + CALL KB_INITIALIZE ; INIT KB +; CALL PR_INITIALIZE ; INIT PR + +; CALL DSPMATRIX ; DISPLAY INIT MATRIX SCREEN +; CALL WAIT_KBHIT ; WAIT FOR A KEYSTROKE + LD A,0 ; EMPTY KB QUEUE + LD (KB_QUEUE_PTR),A ; + + CALL PERF_ERASE_EOS ; CLEAR SCREEN + CALL PERF_CURSOR_HOME ; CURSOR HOME + RET +; +;__CHARIN__________________________________________________________________________________________ +; +; PROCESS INCOMMING CHARACTER AND DISPLAY ON SCREEN OR PERFORM FUNCTION +; C: INCOMMING CHARACTER +;__________________________________________________________________________________________________ +CHARIN: + LD A,C + PUSH AF ; STORE AF + LD A,(TERMSTATE) ; MOVE CURRENT STATE INTO A + CP STATE_NORMAL ; NORMAL PROCESSING STATE? + JP Z,CHARIN_NORM ; + CP STATE_ESC ; ESCAPE PROCESSING STATE? + JP Z,CHARIN_ESCSTATE ; + CP STATE_DIR_L ; WAITING FOR Y COORD STATE? + JP Z,CHARIN_DIR_L_STATE ; + CP STATE_DIR_C ; WAITING FOR X COORD STATE? + JP Z,CHARIN_DIR_C_STATE ; + LD A,STATE_NORMAL ; UNKNOWN STATE, RESET STATE + LD (TERMSTATE),A ; + POP AF ; + RET ; + +;__CHARIN_DIR_L_STATE______________________________________________________________________________ +; +; PROCESS "WAITING FOR Y COORD STATE" +;__________________________________________________________________________________________________ +CHARIN_DIR_L_STATE: + LD A,32 ; MOVE 32 (' ') INTO A + LD C,A ; PARK INTO C + POP AF ; GET CHAR FROM STACK + SUB C ; DECODE CHAR INTO USABLE Y COORD + CP 24 ; IS OFF SCREEN? + JP M,CHARIN_DIR_L_STATE_CONT + LD A,23 ; YES, PLACE CRSR ON LAST ROW +CHARIN_DIR_L_STATE_CONT: + LD (TERM_Y),A ; NO, USE DECODED VALUE + LD A,STATE_DIR_C ; SET UP STATE TO GET X COORD + LD (TERMSTATE),A ; + RET + +;__CHARIN_DIR_C_STATE______________________________________________________________________________ +; +; PROCESS "WAITING FOR X COORD STATE" +;__________________________________________________________________________________________________ +CHARIN_DIR_C_STATE: + LD A,32 ; MOVE 32 (' ') INTO A + LD C,A ; PARK INTO C + POP AF ; GET CHAR FROM STACK + SUB C ; DECODE CHAR INTO USABLE X COORD + CP 80 ; IS OFF SCREEN? + JP M,CHARIN_DIR_C_STATE_CONT + LD A,79 ; YES, PLACE CRSR IN LAST COLUMN +CHARIN_DIR_C_STATE_CONT: + LD (TERM_X),A ; NO, USE DECODED VALUE + CALL GOTO_XY ; SET CURSOR POS + LD A,STATE_NORMAL ; RESET STATE TO NORMAL + LD (TERMSTATE),A ; + RET + + +;__CHARIN_NORM_____________________________________________________________________________________ +; +; PROCESS NORMAL STATE +;__________________________________________________________________________________________________ +CHARIN_NORM: + POP AF ; GET CHAR FROM STACK + CP 0AH ; IS LINEFEED? + JP Z,CHARIN_LF ; + CP 09H ; IS TAB? + JP Z,CHARIN_TAB ; + CP 08H ; IS BS? + JP Z,CHARIN_BS ; + CP 0DH ; IS CR? + JP Z,CHARIN_CR ; + CP 07H ; IS BELL? + JP Z,CHARIN_BELL ; + CP 13H ; IS XOFF? + JP Z,CHARIN_XOFF ; + CP 11H ; IS XON? + JP Z,CHARIN_XON ; + CP ESC_KEY ; IS ESC? + JP Z,CHARIN_ESC ; + JP VDU_PUTCHAR ; NORMAL OUTPUT CHAR + +;__CHARIN_ESC______________________________________________________________________________________ +; +; PROCESS "ESC" STATE +;__________________________________________________________________________________________________ +CHARIN_ESC: + LD A,STATE_ESC ; ESC PRESSED, STATE TO ESCPRESSED + LD (TERMSTATE),A ; + RET + +;__CHARIN_LF_______________________________________________________________________________________ +; +; PROCESS LINE FEED +;__________________________________________________________________________________________________ +CHARIN_LF: + LD A,(TERM_Y) ; MOVE CRSR Y COORD INTO A + INC A ; INC A + LD (TERM_Y),A ; STORE NEW Y COORD + JP GOTO_XY ; SET CRSR POSITION + + +;__CHARIN_TAB______________________________________________________________________________________ +; +; PROCESS TABS +;__________________________________________________________________________________________________ +CHARIN_TAB: + LD HL,TABSTOPS ; SET HL TO TAB STOP TABLE + LD A,(TERM_X) ; MOVE CURENT CRSR X COORD INTO A + INC A ; INC A + LD C,A ; STORE CRSR X COORD INTO A +CHARIN_TAB_LOOP: + LD A,(HL) ; GET NEXT TAB STOP + OR A ; IS ZERO? + JP Z,CHARIN_TAB_EXIT ; END OF TABLE, PROCESS 73+ + INC HL ; SET POINTER TO NEXT TABLE ENTRY + CP C ; IS CURRENT ENTRY > X COORD? + JP M,CHARIN_TAB_LOOP ; NO, LOOP + LD (TERM_X),A ; YES, USE IT + JP GOTO_XY ; SET CRSR POSITION +CHARIN_TAB_EXIT: + LD A,(TERM_X) ; COLUMN IS PAST LAST TAB STOP, SET A TO CRSR POS + CP 79 ; IS LAST PHYSICAL POS? + RET Z ; YES, DO NOTHING + INC A ; NO, INC CRSR BY ONE + LD (TERM_X),A ; STORE NEW X COORD + JP GOTO_XY ; SET CRSR POSITION + +TABSTOPS: + .DB 09,17,25,33,41,49,57,65,73,00 + + +;__CHARIN_BS_______________________________________________________________________________________ +; +; PROCESS BACKSPACE +;__________________________________________________________________________________________________ +CHARIN_BS: + JP PERF_CURSOR_LEFT ; PERFORM CRSR LEFT FUNCTION + + +;__CHARIN_CR_______________________________________________________________________________________ +; +; PROCESS CARRAGE RETURN +;__________________________________________________________________________________________________ +CHARIN_CR: + LD A,00H ; MOVE 0 TO X COORD + LD (TERM_X),A ; + JP GOTO_XY ; GOTO XY COORDS + + +;__CHARIN_BELL_____________________________________________________________________________________ +; +; PROCESS BELL +;__________________________________________________________________________________________________ +CHARIN_BELL: + ; + ; NO HARDWARE FOR THIS, DO NOTHING + ; + RET + + +;__CHARIN_XOFF_____________________________________________________________________________________ +; +; PROCESS XOFF +;__________________________________________________________________________________________________ +CHARIN_XOFF: + ; + ; SHOULD NOT BE NECESSARY FOR LOCAL IMPLIMENTATION + ; + RET + + +;__CHARIN_XON______________________________________________________________________________________ +; +; PROCESS XON +;__________________________________________________________________________________________________ +CHARIN_XON: + ; + ; SHOULD NOT BE NECESSARY FOR LOCAL IMPLIMENTATION + ; + RET + + +;__CHARIN_ESCSTATE_________________________________________________________________________________ +; +; PROCESS ESC STATE +;__________________________________________________________________________________________________ +CHARIN_ESCSTATE: + POP AF ; + CP 'A' ; IS CURSOR UP? + JP Z, PERF_CURSOR_UP ; + CP 'B' ; IS CURSOR DOWN? + JP Z, PERF_CURSOR_DOWN ; + CP 'C' ; IS CURSOR RIGHT? + JP Z, PERF_CURSOR_RIGHT ; + CP 'D' ; IS CURSOR LEFT? + JP Z, PERF_CURSOR_LEFT ; + CP 'F' ; IS ENTER GRAPHICS MODE? + JP Z, PERF_ENTER_GR ; + CP 'G' ; IS EXIT GRAPHICS MODE? + JP Z, PERF_EXIT_GR ; + CP 'H' ; IS CURSOR HOME? + JP Z, PERF_CURSOR_HOME ; + CP 'I' ; IS CURSOR HOME? + JP Z, PERF_REVERSE_LF ; + CP 'Y' ; IS REVERSE LINE FEED? + JP Z, PERF_DIRECT_ADDRESS ; + CP 'K' ; IS ERASE TO END OF LINE? + JP Z,PERF_ERASE_EOL ; + CP 'J' ; IS ERASE TO END OF SCREEN? + JP Z,PERF_ERASE_EOS ; + CP 'Z' ; IS TERMINAL IDENTIFY? + JP Z,PERF_IDENTIFY ; + CP '{' ; IS ENTER HOLD SCREEN MODE? + JP Z,PERF_ENTER_HOLD ; + CP 05CH ; IS EXIT HOLD SCREEN MODE? + JP Z,PERF_EXIT_HOLD ; + CP '=' ; IS ENTER ALT KEYPAD MODE? + JP Z,PERF_ENTER_ALT ; + CP '}' ; IS EXIT ALT KEYPAD MODE? + JP Z,PERF_EXIT_ALT ; + CALL VDU_PUTCHAR ; NORMAL OUTPUT CHAR + JP SET_STATE_NORMAL ; + + +;__PERF_REVERSE_LF_________________________________________________________________________________ +; +; PERFORM REVERSE LINE FEED +;__________________________________________________________________________________________________ +PERF_REVERSE_LF: + CALL SET_STATE_NORMAL ; SET STATE TO NORMAL + LD A,(TERM_Y) ; GET CURRENT Y COORD INTO A + OR A ; IS ZERO + JP Z,REVERSE_SCROLL ; YES, SCROLL SCREEN DOWN ONE LINE + DEC A ; NO, MOVE CRSR UP ONE LINE + LD (TERM_Y),A ; STORE NEW CRSR POSITION + JP GOTO_XY ; POSITION CRSR + + +;__PERF_DIRECT_ADDRESS_____________________________________________________________________________ +; +; PERFORM DIRECT CURSOR ADDRESSING +;__________________________________________________________________________________________________ +PERF_DIRECT_ADDRESS: + LD A,STATE_DIR_L ; SET STATE "WAITING FOR Y COORD" + LD (TERMSTATE),A ; + RET ; + +;__PERF_ENTER_GR___________________________________________________________________________________ +; +; PERFORM ENTER GRAPHICS MODE +;__________________________________________________________________________________________________ +PERF_ENTER_GR: + LD A,0FFH ; + LD (GR_MODE),A ; GRAPHICS MODE + JP SET_STATE_NORMAL ; + + +;__PERF_EXIT_GR____________________________________________________________________________________ +; +; PERFORM EXIT GRAPHICS MODE +;__________________________________________________________________________________________________ +PERF_EXIT_GR: + LD A,00FH ; + LD (GR_MODE),A ; GRAPHICS MODE + JP SET_STATE_NORMAL ; + + +;__PERF_ENTER_ALT___________________________________________________________________________________ +; +; PERFORM ENTER ALTERNATE KEYPAD MODE +;__________________________________________________________________________________________________ +PERF_ENTER_ALT: + LD A,0FFH ; + LD (ALT_KEYPAD),A ; ALT KEYPAD + JP SET_STATE_NORMAL ; + + +;__PERF_EXIT_ALT___________________________________________________________________________________ +; +; PERFORM EXIT ALTERNATE KEYPAD MODE +;__________________________________________________________________________________________________ +PERF_EXIT_ALT: + LD A,00H ; + LD (ALT_KEYPAD),A ; ALT KEYPAD + JP SET_STATE_NORMAL ; + +;__PERF_ENTER_HOLD_________________________________________________________________________________ +; +; PERFORM ENTER HOLD MODE +;__________________________________________________________________________________________________ +PERF_ENTER_HOLD: + ; ********* IGNORE HOLD MODE !! + JP SET_STATE_NORMAL ; + + +;__PERF_EXIT_HOLD__________________________________________________________________________________ +; +; PERFORM EXIT HOLD MODE +;__________________________________________________________________________________________________ +PERF_EXIT_HOLD: + ; ********* IGNORE HOLD MODE !! + JP SET_STATE_NORMAL ; + + +;__SET_STATE_NORMAL________________________________________________________________________________ +; +; SET NORMAL STATE +;__________________________________________________________________________________________________ +SET_STATE_NORMAL: + LD A,STATE_NORMAL ; RESET STATE + LD (TERMSTATE),A ; + RET + +;__PERF_ERASE_EOL__________________________________________________________________________________ +; +; PERFORM ERASE FROM CURSOR POS TO END OF LINE +;__________________________________________________________________________________________________ +PERF_ERASE_EOL: + LD A,(TERM_X) ; GET CURRENT CURSOR X COORD + LD C,A ; STORE IT IN C + LD A,80 ; MOVE CURRENT LINE WIDTH INTO A + SUB C ; GET REMAINING POSITIONS ON CURRENT LINE + LD B,A ; MOVE IT INTO B + LD A, 31 ; UPDATE TOGGLE VDU CHIP + OUT (SY6545S),A ; +PERF_ERASE_EOL_LOOP: + CALL VDU_UPDATECHECK ; WAIT FOR VDU CHIP TO BE READY + LD A,32 ; MOVE SPACE CHARACTER INTO A + OUT (WRITR),A ; WRITE IT TO SCREEN, VDU WILL AUTO INC TO NEXT ADDRESS + DJNZ PERF_ERASE_EOL_LOOP ; LOOP UNTIL DONE + CALL GOTO_XY ; MOVE CURSOR BACK TO ORIGINAL POSITION + CALL SET_STATE_NORMAL ; SET NORMAL STATE + RET + +;__PERF_ERASE_EOS__________________________________________________________________________________ +; +; PERFORM ERASE FROM CURSOR POS TO END OF SCREEN +;__________________________________________________________________________________________________ +PERF_ERASE_EOS: + LD HL,0780H ; SET SCREEN SIZE INTO HL + PUSH HL ; MOVE IT TO DE + POP DE ; + LD A, 31 ; UPDATE TOGGLE VDU CHIP + OUT (SY6545S),A ; +PERF_ERASE_EOS_LOOP: + CALL VDU_UPDATECHECK ; WAIT FOR VDU CHIP TO BE READY + LD A, ' ' ; MOVE SPACE CHARACTER INTO A + OUT (WRITR),A ; WRITE IT TO SCREEN, VDU WILL AUTO INC TO NEXT ADDRESS + DEC DE ; DEC COUNTER + LD A,D ; IS COUNTER 0 YET? + OR E ; + JP NZ,PERF_ERASE_EOS_LOOP ; NO, LOOP + CALL GOTO_XY ; YES, MOVE CURSOR BACK TO ORIGINAL POSITION + CALL SET_STATE_NORMAL ; SET NORMAL STATE + RET + + +;__PERF_IDENTIFY___________________________________________________________________________________ +; +; PERFORM TERMINAL IDENTIFY FUNCTION +;__________________________________________________________________________________________________ +PERF_IDENTIFY: + LD A,ESC_KEY ; + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'/' ; + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'K' ; + CALL KB_ENQUEUE ; STORE ON KB QUEUE + CALL SET_STATE_NORMAL ; SET NORMAL STATE + RET + +;__PERF_CURSOR_HOME________________________________________________________________________________ +; +; PERFORM CURSOR HOME +;__________________________________________________________________________________________________ +PERF_CURSOR_HOME: + LD A,0 ; LOAD 0 INTO A + LD (TERM_X),A ; SET X COORD + LD (TERM_Y),A ; SET Y COORD + CALL SET_STATE_NORMAL ; SET NORMAL STATE + JP GOTO_XY ; MOVE CURSOR TO POSITION + +;__PERF_CURSOR_LEFT________________________________________________________________________________ +; +; PERFORM CURSOR LEFT +;__________________________________________________________________________________________________ +PERF_CURSOR_LEFT: + LD A,(TERM_X) ; GET CURRENT X COORD INTO A + OR A ; IS ZERO? + JP Z,PERF_CURSOR_ABORT ; YES, ABORT + DEC A ; MOVE ONE TO THE LEFT + LD (TERM_X),A ; STORE NEW CURSOR POSITION + CALL SET_STATE_NORMAL ; SET NORMAL STATE + JP GOTO_XY ; MOVE CURSOR TO POSITION + +;__PERF_CURSOR_RIGHT_______________________________________________________________________________ +; +; PERFORM CURSOR RIGHT +;__________________________________________________________________________________________________ +PERF_CURSOR_RIGHT: + LD A,(TERM_X) ; GET CURRENT X COORD INTO A + CP 79 ; IS END OF LINE? + JP Z,PERF_CURSOR_ABORT ; YES, ABORT + INC A ; MOVE ONE TO THE RIGHT + LD (TERM_X),A ; STORE NEW CURSOR POSITION + CALL SET_STATE_NORMAL ; SET NORMAL STATE + JP GOTO_XY ; MOVE CURSOR TO POSITION + +;__PERF_CURSOR_UP__________________________________________________________________________________ +; +; PERFORM CURSOR UP +;__________________________________________________________________________________________________ +PERF_CURSOR_UP: + LD A,(TERM_Y) ; GET CURRENT Y COORD INTO A + OR A ; IS ZERO? + JP Z,PERF_CURSOR_ABORT ; YES, ABORT + DEC A ; MOVE UP ONE POSITION + LD (TERM_Y),A ; STORE NEW CURSOR POSITION + CALL SET_STATE_NORMAL ; SET NORMAL STATE + JP GOTO_XY ; MOVE CURSOR TO POSTION + + +;__PERF_CURSOR_DOWN________________________________________________________________________________ +; +; PERFORM CURSOR DOWN +;__________________________________________________________________________________________________ +PERF_CURSOR_DOWN: + LD A,(TERM_Y) ; GET CURRENT Y COORD INTO A + CP 23 ; IS END OF SCREEN? + JP Z,PERF_CURSOR_ABORT ; YES, ABORT + INC A ; NO, MOVE DOWN ONE POSITION + LD (TERM_Y),A ; STORE NEW CURSOR POSITION +PERF_CURSOR_ABORT: + CALL SET_STATE_NORMAL ; SET NORMAL STATE + JP GOTO_XY ; MOVE CURSOR TO POSITION + + + + + +;__DO_SCROLL_______________________________________________________________________________________ +; +; SCROLL THE SCREEN UP ONE LINE +;__________________________________________________________________________________________________ +DO_SCROLL: + PUSH AF ; STORE AF +DO_SCROLL1: + PUSH HL ; STORE HL + PUSH BC ; STORE BC + LD A, 31 ; TOGGLE VDU FOR UPDATE + OUT (SY6545S),A ; + CALL VDU_UPDATECHECK ; WAIT FOR VDU TO BE READY + LD HL, (VDU_DISPLAY_START) ; GET UP START OF DISPLAY + LD DE,0050H ; SET AMOUNT TO ADD + ADD HL,DE ; ADD TO START POS + LD (VDU_DISPLAY_START),HL ; STORE DISPLAY START + LD A, 12 ; SAVE START OF DISPLAY TO VDU + CALL VDU_HL2WREG_A ; + LD A,23 ; SET CURSOR TO BEGINNING OF LAST LINE + LD (TERM_Y),A ; + LD A,(TERM_X) ; + PUSH AF ; STORE X COORD + LD A,0 ; + LD (TERM_X),A ; + CALL GOTO_XY ; SET CURSOR POSITION TO BEGINNING OF LINE + CALL PERF_ERASE_EOL ; ERASE SCROLLED LINE + POP AF ; RESTORE X COORD + LD (TERM_X),A ; + CALL GOTO_XY ; SET CURSOR POSITION + POP BC ; RESTORE BC + POP HL ; RESTORE HL + POP AF ; RESTORE AF + RET ; + +;__REVERSE_SCROLL__________________________________________________________________________________ +; +; SCROLL THE SCREEN DOWN ONE LINE +;__________________________________________________________________________________________________ +REVERSE_SCROLL: + PUSH AF ; STORE AF + PUSH HL ; STORE HL + PUSH BC ; STORE BC + LD A, 31 ; TOGGLE VDU FOR UPDATE + OUT (SY6545S),A ; + CALL VDU_UPDATECHECK ; WAIT FOR VDU TO BE READY + LD HL, (VDU_DISPLAY_START) ; GET UP START OF DISPLAY + LD DE,0FFB0H ; SET AMOUNT TO SUBTRACT (TWOS COMPLEMENT 50H) + ADD HL,DE ; ADD TO START POS + LD (VDU_DISPLAY_START),HL ; STORE DISPLAY START + LD A, 12 ; SAVE START OF DISPLAY TO VDU + CALL VDU_HL2WREG_A ; + LD A,23 ; SET CURSOR TO BEGINNING OF LAST LINE + LD (TERM_Y),A ; + LD A,(TERM_X) ; + PUSH AF ; STORE X COORD + LD A,0 ; + LD (TERM_X),A ; + CALL GOTO_XY ; SET CURSOR POSITION TO BEGINNING OF LINE + CALL PERF_ERASE_EOL ; ERASE SCROLLED LINE + POP AF ; RESTORE X COORD + LD (TERM_X),A ; + CALL GOTO_XY ; SET CURSOR POSITION + POP BC ; RESTORE BC + POP HL ; RESTORE HL + POP AF ; RESTORE AF + RET ; + + + +;__IS_KBHIT________________________________________________________________________________________ +; +; WAS A KEY PRESSED? +;__________________________________________________________________________________________________ +IS_KBHIT: + CALL KB_PROCESS ; CALL KEYBOARD ROUTINE + LD A,(KB_QUEUE_PTR) ; ASK IF KEYBOARD HAS KEY WAITING + OR A + JP Z,CIO_IDLE + LD A,$FF ; SIGNAL DATA PENDING + RET + + +;__WAIT_KBHIT______________________________________________________________________________________ +; +; WAIT FOR A KEY PRESS +;__________________________________________________________________________________________________ +WAIT_KBHIT: + CALL IS_KBHIT + JR Z,WAIT_KBHIT + RET + + +;__GET_KEY_________________________________________________________________________________________ +; +; GET KEY PRESS VALUE +;__________________________________________________________________________________________________ +GET_KEY: + CALL WAIT_KBHIT ; WAIT FOR A KEY + LD A,(KB_QUEUE_PTR) ; GET QUEUE POINTER + OR A ; + RET Z ; ABORT IF QUEUE EMPTY + PUSH BC ; STORE BC + LD B,A ; STORE QUEUE COUNT FOR LATER + PUSH HL ; STORE HL + LD A,(KB_QUEUE) ; GET TOP BYTE FROM QUEUE + PUSH AF ; STORE IT + LD HL,KB_QUEUE ; GET POINTER TO QUEUE +GET_KEY_LOOP: ; + INC HL ; POINT TO NEXT VALUE IN QUEUE + LD A,(HL) ; GET VALUE + DEC HL ; + LD (HL),A ; MOVE IT UP ONE + INC HL ; + DJNZ GET_KEY_LOOP ; LOOP UNTIL DONE + LD A,(KB_QUEUE_PTR) ; DECREASE QUEUE POINTER BY ONE + DEC A ; + LD (KB_QUEUE_PTR),A ; + POP AF ; RESTORE VALUE + POP HL ; RESTORE HL + POP BC ; RESTORE BC + RET + + + + + + +;__VDUINIT__________________________________________________________________________________________ +; +; INITIALIZE VDU +;__________________________________________________________________________________________________ +VDUINIT: + PUSH AF ; STORE AF + PUSH DE ; STORE DE + PUSH HL ; STORE HL + + CALL VDU_CRTINIT ; INIT 6545 VDU CHIP + LD A, 31 ; TOGGLE VDU FOR UPDATE + OUT (SY6545S),A ; + LD HL,0 ; SET-UP START OF DISPLAY + LD DE, 2048 ; SET-UP DISPLAY SIZE + LD A, 18 ; WRITE HL TO R18 AND R19 (UPDATE ADDRESS) + CALL VDU_HL2WREG_A ; + LD A, 31 ; TOGGLE VDU FOR UPDATE + OUT (SY6545S),A ; +VDU_CRTSPACELOOP: ; + CALL VDU_UPDATECHECK ; WAIT FOR VDU TO BE READY + LD A, ' ' ; CLEAR SCREEN + OUT (WRITR),A ; SEND SPACE TO DATAPORT + DEC DE ; DECREMENT DE + LD A,D ; IS ZERO? + OR E ; + JP NZ, VDU_CRTSPACELOOP ; NO, LOOP + LD A, 31 ; TOGGLE VDU FOR UPDATE + OUT (SY6545S),A ; + LD HL, 0 ; SET UP START OF DISPLAY + LD (VDU_DISPLAY_START),HL ; STORE DISPLAY START + LD A, 12 ; SAVE START OF DISPLAY TO VDU + CALL VDU_HL2WREG_A ; + POP HL ; + POP DE ; + POP AF ; + CALL PERF_CURSOR_HOME ; CURSOR HOME + CALL PERF_ERASE_EOS ; CLEAR SCREEN + CALL VDU_CURSORON ; TURN ON CURSOR + RET + + +;;__DSPMATRIX_______________________________________________________________________________________ +;; +;; DISPLAY INTRO SCREEN +;;__________________________________________________________________________________________________ +;DSPMATRIX: +; CALL PERF_CURSOR_HOME ; RESET CURSOR TO HOME POSITION +; LD HL,TESTMATRIX ; SET HL TO SCREEN IMAGE +; LD DE, 1918 ; SET IMAGE SIZE +;DSPMATRIX_LOOP: +; LD A,(HL) ; GET NEXT CHAR FROM IMAGE +; CALL VDU_PUTCHAR ; DUMP CHAR TO DISPLAY +; INC HL ; INC POINTER +; DEC DE ; DEC COUNTER +; LD A,D ; IS COUNTER ZERO? +; OR E ; +; JP NZ,DSPMATRIX_LOOP ; NO, LOOP +; CALL PERF_CURSOR_HOME ; YES, RESET CURSOR TO HOME POSITION +; RET + +;TESTMATRIX: +; .TEXT "0 1 2 3 4 5 6 7 " +; .TEXT "01234567890123456789012345678901234567890123456789012345678901234567890123456789" +; .TEXT "2 " +; .TEXT "3 " +; .TEXT "4 " +; .TEXT "5 " +; .TEXT "6 NN NN 8888 VV VV EEEEEEEEEE MM MM " +; .TEXT "7 NNNN NN 88 88 VV VV EE MMMM MMMM " +; .TEXT "8 NN NN NN 88 88 VV VV EE MM MM MM MM " +; .TEXT "9 NN NNNN 88 88 VV VV EE MM MM MM " +; .TEXT "10 NN NN 8888 VV VV EEEEEEE MM MM " +; .TEXT "11 NN NN 88 88 VV VV EE MM MM " +; .TEXT "12 NN NN 88 88 VV VV EE MM MM " +; .TEXT "13 NN NN 88 88 VVV EE MM MM " +; .TEXT "14 NN NN 8888 V EEEEEEEEEE MM MM S B C " +; .TEXT "15 " +; .TEXT "16 " +; .TEXT "17 " +; .TEXT "18 * VDU OK * VT-52 EMULATION " +; .TEXT "19 " +; .TEXT "20 ** PRESS ANY KEY TO ENTER TERMINAL MODE ** " +; .TEXT "21 " +; .TEXT "22 " +; .TEXT "23 " +; .TEXT "24 " + + +;__VDU_HL2WREG_A___________________________________________________________________________________ +; +; WRITE VALUE IN HL TO REGISTER IN A +; A: REGISTER TO UPDATE +; HL: WORD VALUE TO WRITE +;__________________________________________________________________________________________________ +VDU_HL2WREG_A: + PUSH BC ; STORE BC + PUSH AF ; STORE AF + CALL VDU_UPDATECHECK ; WAIT FOR VDU TO BE READY + POP AF ; RESTORE AF + LD C, SY6545S ; ADDRESS REGISTER + OUT (C), A ; SELECT REGISTER (A) + INC C ; NEXT WRITE IN REGISTER + OUT (C), H ; WRITE H TO SELECTED REGISTER + DEC C ; NEXT WRITE SELECT REGISTER + INC A ; INCREASE REGISTER NUMBER + OUT (C), A ; SELECT REGISTER (A+1) + INC C ; NEXT WRITE IN REGISTER + OUT (C), L ; WRITE L TO SELECTED REGISTER + POP BC ; RESTORE BC + RET + +;__VDU_UPDATECHECK_________________________________________________________________________________ +; +; WAIT FOR VDU TO BE READY +;__________________________________________________________________________________________________ +VDU_UPDATECHECK: + IN A,(SY6545S) ; READ ADDRESS/STATUS REGISTER + BIT 7,A ; IF BIT 7 = 1 THAN AN UPDATE STROBE HAS OCCURED + RET NZ ; + JR VDU_UPDATECHECK ; WAIT FOR READY + +VDU_INIT6845: +; DB 07FH, 50H, 60H, 7CH, 19H, 1FH, 19H, 1AH, 78H, 09H, 60H, 09H, 00H, 00H, 00H, 00H + .DB 07Fh, 50h, 60h, 0Ch, 1Eh, 02h, 18h, 1Ch, 78h, 09h, 60h, 09h, 00h, 00h, 00h, 00h + + +;__VDU_CRTINIT_____________________________________________________________________________________ +; +; INIT VDU CHIP +;__________________________________________________________________________________________________ +VDU_CRTINIT: + PUSH AF ; STORE AF + PUSH BC ; STORE BC + PUSH DE ; STORE DE + PUSH HL ; STORE HL + LD BC,010F2h ; B = 16, C = SY6545S + LD HL,VDU_INIT6845 ; HL = POINTER TO THE DEFAULT VALUES + XOR A ; A = 0 +VDU_CRTINITLOOP: + OUT (C), A ; SY6545S SET REGISTER + INC C ; 0F3h + LD D,(HL) ; LOAD THE NEXT DEFAULT VALUE IN D + OUT (C),D ; 0F3h ADDRESS + DEC C ; SY6545S + INC HL ; TAB + 1 + INC A ; REG + 1 + DJNZ VDU_CRTINITLOOP ; LOOP UNTIL DONE + POP HL ; RESTORE HL + POP DE ; RESTORE DE + POP BC ; RESTORE BC + POP AF ; RESTORE AF + RET + + +;__VDU_CURSORON____________________________________________________________________________________ +; +; TURN ON CURSOR +;__________________________________________________________________________________________________ +VDU_CURSORON: + PUSH AF ; STORE AF + LD A, 060h ; SET CURSOR VALUE + JP VDU_CURSORSET ; + +;__VDU_CURSOROFF___________________________________________________________________________________ +; +; TURN OFF CURSOR +;__________________________________________________________________________________________________ +VDU_CURSOROFF: + PUSH AF ; STORE AF + LD A, 020h ; SET CURSOR VALUE +VDU_CURSORSET: + PUSH BC ; STORE BC + LD C,A ; MOVE A TO C + CALL VDU_UPDATECHECK ; WAIT FOR VDU TO BE READY + LD A, 10 ; R10, CURSOR START AND STATUS + OUT (SY6545S), A ; + LD A,C ; STORE CURSOR VALUE + OUT (SY6545D), A ; + POP BC ; RESTORE BC + POP AF ; RESTORE AF + RET + +;__GOTO_XY_________________________________________________________________________________________ +; +; MOVE CURSOR TO POSITON IN TERM_X AND TERM_Y +;__________________________________________________________________________________________________ +GOTO_XY: + PUSH AF ; STORE AF + + LD A,(TERM_Y) ; PLACE Y COORD IN A + CP 24 ; IS 24? + JP Z,DO_SCROLL1 ; YES, MUST SCROLL + + PUSH BC ; STORE BC + PUSH DE ; STORE DE + LD A,(TERM_X) ; + LD H,A ; + LD A,(TERM_Y) ; + LD L,A ; + PUSH HL ; STORE HL + LD B, A ; B = Y COORD + LD DE, 80 ; MOVE LINE LENGTH INTO DE + LD HL, 0 ; MOVE 0 INTO HL + LD A, B ; A=B + CP 0 ; Y=0? + JP Z, VDU_YLOOPEND ; THEN DO NOT MULTIPLY BY 80 +VDU_YLOOP: ; HL = 80 * Y + ADD HL, DE ; HL=HL+DE + DJNZ VDU_YLOOP ; LOOP +VDU_YLOOPEND: ; + POP DE ; DE = ORG HL + LD E, D ; E = X + LD D, 0 ; D = 0 + ADD HL, DE ; HL = HL + X + LD (VDU_DISPLAYPOS), HL ; + PUSH HL ; + POP DE ; + LD HL,(VDU_DISPLAY_START) ; + ADD HL,DE ; + LD A, 18 ; SET UPDATE ADDRESS IN VDU + CALL VDU_HL2WREG_A ; + LD A, 31 ; TOGGLE VDU FOR UPDATE + OUT (SY6545S),A ; + LD A, 14 ; SET CURSOR POS + CALL VDU_HL2WREG_A ; + POP DE ; RESTORE DE + POP BC ; RESTORE BC + POP AF ; RESTORE AF + RET + +;__VDU_PUTCHAR______________________________________________________________________________________ +; +; PLACE CHARACTER ON SCREEN +; A: CHARACTER TO OUTPUT +;__________________________________________________________________________________________________ +VDU_PUTCHAR: + PUSH DE ; STORE DE + PUSH AF ; STORE AF + LD A,(TERM_X) ; PLACE X COORD IN A + INC A ; INC X COORD + LD (TERM_X),A ; STORE IN A + CP 80 ; IS 80? + JP NZ,VDU_PUTCHAR1 ; NO, PLACE CHAR ON DISPLAY + LD A,0 ; YES, WRAP TO NEXT LINE + LD (TERM_X),A ; STORE X + LD A,(TERM_Y) ; A= Y COORD + INC A ; INC Y COORD + LD (TERM_Y),A ; STORE Y + CP 24 ; IS PAST END OF SCREEN? + CALL Z,GOTO_XY ; YES, HANDLE SCROLLING +VDU_PUTCHAR1: ; + CALL VDU_UPDATECHECK ; WAIT FOR VDU TO BE READY + ; + LD A, 31 ; TOGGLE VDU FOR UPDATE + OUT (SY6545S),A ; + ; + CALL VDU_UPDATECHECK ; WAIT FOR VDU TO BE READY + ; + LD A, 31 ; TOGGLE VDU FOR UPDATE + OUT (SY6545S),A ; + ; + POP AF ; RESTORE CHAR + OUT (WRITR), A ; OUTPUT CHAR TO VDU + PUSH AF ; STORE AF + PUSH HL ; STORE HL + LD HL, (VDU_DISPLAYPOS) ; GET CURRENT DISPLAY ADDRESS + INC HL ; INCREMENT IT + LD (VDU_DISPLAYPOS), HL ; STORE CURRENT DISPLAY ADDRESS + PUSH HL ; MOVE HL TO DE + POP DE ; + LD HL,(VDU_DISPLAY_START) ; + ADD HL,DE ; + LD A, 14 ; UPDATE CURSOR POSITION IN HARDWARE + CALL VDU_HL2WREG_A ; + POP HL ; RESTORE HL + POP AF ; RESTORE AF + POP DE ; RESTORE DE + RET + + + + + + +;;__PR_OUTCHAR______________________________________________________________________________________ +;; +;; PR_OUTCHAR- OUTPUT CHAR TO PRINTER PORT +;; A: CHAR TO OUTPUT +;;__________________________________________________________________________________________________ +;PR_OUTCHAR: +; PUSH AF ; STORE AF +;PR_OUTCHAR_LOOP: +; IN A,(PPIB) ; GET STATUS INFO +; AND 10000000B ; ONLY INTERESTED IN BUSY FLAG +; JP NZ,PR_OUTCHAR_LOOP ; LOOP IF BUSY +; POP AF ; RESTORE AF +; OUT (PPIA),A ; OUTPUT DATA TO PORT +; LD A,1 ; 01 SECOND DELAY +; CALL KB_DELAY ; IGNORE ANYTHING BACK AFTER A RESET +; CALL KB_PORTCBIT0LOW ; STROBE +; LD A,1 ; 01 SECOND DELAY +; CALL KB_DELAY ; IGNORE ANYTHING BACK AFTER A RESET +; CALL KB_PORTCBIT0HIGH ; STROBE +; RET + +;;__PR_INITIALIZE___________________________________________________________________________________ +;; +;; INITIALISE - SET UP PORT FOR PRINTING +;;__________________________________________________________________________________________________ +;PR_INITIALIZE: +; CALL KB_PORTCBIT0HIGH ; STROBE +; CALL KB_PORTCBIT1HIGH ; FORM FEED +; CALL KB_PORTCBIT2LOW ; DEVICE SELECT +; CALL KB_PORTCBIT3LOW ; DEVICE INIT +; LD A,200 ; 1 SECOND DELAY +; CALL KB_DELAY ; IGNORE ANYTHING BACK AFTER A RESET +; CALL KB_PORTCBIT3HIGH ; DEVICE INIT +; RET + + +;__KB_INITIALIZE___________________________________________________________________________________ +; +; INITIALISE - CLEAR SOME LOCATIONS AND SEND A RESET TO THE KEYBOARD +;__________________________________________________________________________________________________ +KB_INITIALIZE: + CALL KB_SETPORTC ; SETS PORT C SO CAN INPUT AND OUTPUT + CALL KB_RESET ; RESET TO THE KEYBOARD + LD A,200 ; 1 SECOND DELAY AS KEYBOARD SENDS STUFF BACK WHEN RESET + CALL KB_DELAY ; IGNORE ANYTHING BACK AFTER A RESET + LD A,0 ; EMPTY KB QUEUE + LD (KB_QUEUE_PTR),A ; + RET + + +;__KB_RESET________________________________________________________________________________________ +; +; RESET THE KEYBOARD +;__________________________________________________________________________________________________ +KB_RESET: + CALL KB_DATAHIGH ; + CALL KB_CLOCKHIGH ; + LD B,255 ; +SF1: DJNZ SF1 ; + CALL KB_CLOCKLOW ; STEP 1 + LD B,255 ; +SF2: DJNZ SF2 ; + CALL KB_DATALOW ; STEP 2 + CALL KB_CLOCKHIGH ; STEP 3 + CALL KB_WAITCLOCKLOW ; STEP 4 + LD B,9 ; 8 DATA BITS + 1 PARITY BIT LOW +SF3: PUSH BC ; + CALL KB_DATAHIGH ; STEP 5 + CALL KB_WAITCLOCKHIGH ; STEP 6 + CALL KB_WAITCLOCKLOW ; STEP 7 + POP BC ; + DJNZ SF3 ; + CALL KB_DATAHIGH ; STEP9 + CALL KB_WAITCLOCKLOW ; STEP 10 COULD READ THE ACK BIT HERE IF WANT TO + CALL KB_WAITCLOCKHIGH ; STEP 11 + LD B,255 ; +SF4: DJNZ SF4 ; FINISH UP DELAY + RET + +;__KB_SETPORTC_____________________________________________________________________________________ +; +; SETUP PORT C OF 8255 FOR KEYBOARD +;__________________________________________________________________________________________________ +KB_SETPORTC: + LD A,10000010B ; A=OUT B=IN, C HIGH=OUT, CLOW=OUT + OUT (PPICONT),A ; PPI CONTROL PORT + LD A,00000000B ; PORT A TO ZERO AS NEED THIS FOR COMMS TO WORK + OUT (PPIA),A ; PPI PORT A + CALL KB_DATAHIGH ; + CALL KB_CLOCKHIGH ; + LD A,0 ; + LD (CAPSLOCK),A ; SET CAPSLOCK OFF TO START + LD (CTRL),A ; CONTROL OFF + LD (NUMLOCK),A ; NUMLOCK OFF + RET +;_________________________________________________________________________________________________ +; +; PORT C BIT ROUTINES +;__________________________________________________________________________________________________ +KB_PORTCBIT0HIGH: ; + LD A,01110001B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_PORTCBIT1HIGH: ; + LD A,01110011B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_PORTCBIT2HIGH: ; + LD A,01110101B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_PORTCBIT3HIGH: ; + LD A,01110111B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_PORTCBIT0LOW: ; + LD A,01110000B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_PORTCBIT1LOW: ; + LD A,01110010B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_PORTCBIT2LOW: ; + LD A,01110100B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_PORTCBIT3LOW: ; + LD A,01110110B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_DATAHIGH: +KB_PORTCBIT4HIGH: ; + LD A,01111001B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_DATALOW: ; +KB_PORTCBIT4LOW: ; + LD A,01111000B ; SEE THE 8255 DATA SHEET + JP KB_SETBITS ; +KB_CLOCKHIGH: ; +KB_PORTCBIT5HIGH: ; + LD A,01111011B ; BIT 5 HIGH + JP KB_SETBITS ; +KB_CLOCKLOW: ; +PORTCBIT5LOW: ; + LD A,01111010B ; +KB_SETBITS: ; + OUT (PPICONT),A ; + RET ; + + + +;__KB_WAITCLOCKLOW_________________________________________________________________________________ +; +; WAITCLOCKLOW SAMPLES DATA BIT 0, AND WAITS TILL +; IT GOES LOW, THEN RETURNS +; ALSO TIMES OUT AFTER 0 001 SECONDS +; USES A, CHANGES B +;__________________________________________________________________________________________________ +KB_WAITCLOCKLOW: + LD B,255 ; FOR TIMEOUT COUNTER +WL1: IN A,(PPIB) ; GET A BYTE FROM PORT B + BIT 1,A ; TEST THE CLOCK BIT + RET Z ; EXIT IF IT WENT LOW + DJNZ WL1 ; LOOP B TIMES + RET + + +;__KB_WAITCLOCKHIGH_________________________________________________________________________________ +; +; WAITCLOCKHIGH SAMPLES DATA BIT 0, AND WAITS TILL +; IT GOES HIGH, THEN RETURNS +; ALSO TIMES OUT AFTER 0 001 SECONDS +; USES A, CHANGES B +;__________________________________________________________________________________________________ +KB_WAITCLOCKHIGH: + LD B,255 ; FOR TIMEOUT COUNTER +WH1: IN A,(PPIB) ; GET A BYTE FROM PORT B + BIT 1,A ; TEST THE CLOCK BIT + RET NZ ; EXIT IF IT WENT HIGH + DJNZ WH1 ; LOOP B TIMES + RET + +;__KB_DELAY________________________________________________________________________________________ +; +; PASS A - DELAY IS B*0 005 SECONDS, BCDEHL ALL PRESERVED +;__________________________________________________________________________________________________ +KB_DELAY: + PUSH BC ; STORE ALL VARIABLES + PUSH DE ; + PUSH HL ; + LD B,A ; PUT THE VARIABLE DELAY IN B + LD DE,1 ; +LOOP1: LD HL,740 ; ADJUST THIS VALUE FOR YOUR CLOCK 1481=3 68MHZ, 3219=8MHZ (TEST WITH A=1000=10 SECS) +LOOP2: SBC HL,DE ; HL-1 + JR NZ,LOOP2 ; + DJNZ LOOP1 ; + POP HL ; RESTORE VARIABLES + POP DE ; + POP BC ; + RET ; + + +;__KB_PROCESS______________________________________________________________________________________ +; +; A=0 IF WANT TO KNOW IF A BYTE IS AVAILABLE, AND A=1 TO ASK FOR THE BYTE +;__________________________________________________________________________________________________ +KB_PROCESS: + CALL SKIP ; DON'T TEST EVERY ONE AS TAKES TIME + OR A ; IS IT ZERO + RET Z ; RETURN IF ZERO + CALL KB_WAITBYTE ; TEST KEYBOARD TIMES OUT AFTER A BIT + CALL KB_DECODECHAR ; RETURNS CHAR OR 0 FOR THINGS LIKE KEYUP, SOME RETURN DIRECTLY TO CP/M + RET ; RETURN TO CP/M + + +;----------------------------------------------- +; CPM CALLS THE KEYBOARD QUITE FREQUENTLY IF A KEYBOARD WAS LIKE A UART WHICH CAN BE CHECKED +; WITH ONE INSTRUCTION, THAT WOULD BE FINE BUT CHECKING A KEYBOARD INVOLVES PUTTING THE CLOCK LINE LOW +; THEN WAITING SOME TIME FOR A POSSIBLE REPLY, THEN READING IN BITS WITH TIMEOUTS AND THEN RETURNING +; THIS SLOWS DOWN A LOT OF CP/M PROCESSES, EG TRY TYPE MYPROG AND PRINTING OUT TEXT +SKIP: + LD B,0 ; + LD A,(SKIPCOUNT) ; + DEC A ; SUBTRACT 1 + LD (SKIPCOUNT),A ; STORE IT BACK + CP 0 ; + JP NZ,SK1 ; WORDSTAR IS VERY SLOW EVEN TRIED A VALUE OF 5 TO 200 HERE + LD A,200 ; ONLY ACT ON EVERY N CALLS - BIGGER=BETTER BECAUSE THIS SUB IS QUICKER THAN READBITS + LD (SKIPCOUNT),A ; RESET COUNTER + LD B,1 ; FLAG TO SAY RESET COUNTER +SK1: ; + LD A,B ; RETURN THE VALUE IN A + RET + + +;__KB_DECODECHAR____________________________________________________________________________________ +; +; DECODE CHARACTER PASS A AND PRINTS OUT THE CHAR +; ON THE LCD SCREEN +;__________________________________________________________________________________________________ +KB_DECODECHAR: + CP 0 ; IS IT ZERO + RET Z ; RETURN IF A ZERO - NO NEED TO DO ANYTHING + CP 0F0H ; IS A KEY UP (NEED TO DO SPECIAL CODE FOR SHIFT) + JP Z,DECKEYUP ; IGNORE CHAR UP + CP 0E0H ; TWO BYTE KEYPRESSES + JP Z,TWOBYTE ; + CP 058H ; CAPS LOCK SO TOGGLE + JP Z,CAPSTOG ; + CP 12H ; SHIFT (DOWN, BECAUSE UP WOULD BE TRAPPED BY 0F ABOVE) + JP Z,SHIFTDOWN ; + CP 59H ; OTHER SHIFT KEY + JP Z,SHIFTDOWN ; + CP 014H ; CONTROL KEY + JP Z,CONTROLDOWN ; + CP 05AH ; ENTER KEY + JP Z,RETURN ; + CP 066H ; BACKSPACE KEY + JP Z,BACKSPACE ; + CP 0DH ; TAB KEY + JP Z,TABKEY ; + CP 076H ; ESCAPE KEY + JP Z,ESCAPE ; + LD C,A ; + LD B,0 ; ADD BC TO HL + LD HL,NORMALKEYS ; OFFSET TO ADD + ADD HL,BC ; + JP TESTCONTROL ; IS THE CONTROL KEY DOWN? +DC1: LD A,(CAPSLOCK) ; + CP 0 ; IS IT 0, IF SO THEN DON'T ADD THE CAPS OFFSET + JR Z,DC2 ; + LD C,080H ; ADD ANOTHER 50H TO SMALLS TO GET CAPS + ADD HL,BC ; +DC2: LD A,(HL) ; + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +TESTCONTROL: + LD A,(CTRL) ; + CP 0 ; IS CONTROL BEING HELD DOWN? + JP Z,DC1 ; NO SO GO BACK TO TEST CAPS LOCK ON + LD A,(HL) ; GET THE LETTER, SHOULD BE SMALLS + SUB 96 ; A=97 SO SUBTRACT 96 A=1=^A + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; RETURN INSTEAD OF THE RET AFTER DC2 +TABKEY: ; + LD A,9 ; + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ;TAB +BACKSPACE: ; + LD A,8 ; BACKSPACE + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +ESCAPE: ; + LD A,27 ; + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +RETURN: ; + LD A,13 ; CARRIAGE RETURN + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +DECKEYUP: + CALL KB_WAITBYTE ; IGNORE KEY UP THROW AWAY THE CHARACTER UNLESS A SHIFT + CP 012H ; IS IT A SHIFT + JP Z,SHIFTUP ; + CP 59H ; OTHER SHIFT KEY + JP Z,SHIFTUP ; + CP 014H ; CONTROL UP + JP Z,CONTROLUP ; CONTROL UP + LD A,0 ; NOTHING CAPTURED SO SEND BACK A ZERO + RET +TWOBYTE:; ALREADY GOT EO SO GET THE NEXT CHARACTER + CALL KB_WAITBYTE + CP 0F0H ; SEE THE NOTES - KEYUP FOR E0 KEYS IS EO F0 NN NOT F0 EO!! + JP Z,TWOBYTEUP ; + CP 071H ; DELETE + JP Z,DELETEKEY ; + CP 05AH ; RETURN ON NUMBER PAD + JP Z,RETURNKEY ; + CP 072H ; + JP Z,DOWNARROW ; + CP 074H ; + JP Z,RIGHTARROW ; + CP 06BH ; + JP Z,LEFTARROW ; + CP 075H ; + JP Z,UPARROW ; + CP 070H ; + JP Z,INSERT ; + CP 07DH ; + JP Z,PAGEUP ; + CP 07AH ; + JP Z,PAGEDOWN ; + CP 06CH ; + JP Z,HOME ; + CP 069H ; + JP Z,END ; + LD A,0 ; RETURNS NOTHING + RET +TWOBYTEUP: ;EXPECT A BYTE AND IGNORE IT + CALL KB_WAITBYTE ; + LD A,0 ; + RET ; +HOME: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'?' ; ? + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'W' ; W + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +END: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'?' ; ? + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'Q' ; Q + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +DOWNARROW: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'B' ; B + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +RIGHTARROW: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'C' ; C + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +LEFTARROW: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'D' ; D + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +UPARROW: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'A' ; A + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +INSERT: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'?' ; ? + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'P' ; P + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +PAGEUP: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'?' ; ? + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'Y' ; Y + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +PAGEDOWN: ; + LD A,1BH ; ESC + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'?' ; ? + CALL KB_ENQUEUE ; STORE ON KB QUEUE + LD A,'S' ; S + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +CONTROLDOWN: ; SAME CODE AS SHIFTDOWN BUT DIFF LOCATION + LD A,0FFH ; + LD (CTRL),A ; CONTROL DOWN + LD A,0 ; + RET ; +CONTROLUP: ; CONTROL KEY UP SEE SHIFT FOR EXPLANATION + LD A,0 ; + LD (CTRL),A ; + LD A,0 ; + RET ; +RETURNKEY: ; + LD A,13 ; + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +DELETEKEY: ; + LD A,07FH ; DELETE KEY VALUE THAT CP/M USES + CALL KB_ENQUEUE ; STORE ON KB QUEUE + RET ; +CAPSTOG: ; + LD A,(CAPSLOCK) ; + XOR 11111111B ; SWAP ALL THE BITS + LD (CAPSLOCK),A ; + LD A,0 ; RETURNS NOTHING + RET ; +SHIFTDOWN: ; SHIFT IS SPECIAL - HOLD IT DOWN AND IT AUTOREPEATS + ; SO ONCE IT IS DOWN, TURN CAPS ON AND IGNORE ALL FURTHER SHIFTS + ; ONLY AN F0+SHIFT TURNS CAPS LOCK OFF AGAIN + LD A,0FFH ; + LD (CAPSLOCK),A ; + LD A,0 ; RETURNS NOTHING + RET ; +SHIFTUP: ; SHIFTUP TURNS OFF CAPS LOCK DEFINITELY + LD A,0 ; + LD (CAPSLOCK),A ; + LD A,0 ; RETURNS NOTHING + RET ; + +;__KB_ENQUEUE______________________________________________________________________________________ +; +; STORE A BYTE IN THE KEYBOARD QUEUE +; A: BYTE TO ENQUEUE +;__________________________________________________________________________________________________ +KB_ENQUEUE: + PUSH DE ; STORE DE + PUSH HL ; STORE HL + PUSH AF ; STORE VALUE + LD A,(KB_QUEUE_PTR); PUT QUEUE POINTER IN A + CP 15 ; IS QUEUE FULL + JP P,KB_ENQUEUE_AB ; YES, ABORT + LD HL,KB_QUEUE ; GET QUEUE POINTER + PUSH HL ; MOVE HL TO BC + POP BC ; + LD H,0 ; ZERO OUT H + LD L,A ; PLACE QUEUE POINTER IN L + ADD HL,BC ; POINT HL AT THE NEXT LOACTION TO ADD VALUE + POP AF ; RESTORE VALUE + LD (HL),A ; ENQUEUE VALUE + LD A,(KB_QUEUE_PTR); GET QUEUE POINTER + INC A ; INC IT + LD (KB_QUEUE_PTR),A ;STORE QUEUE POINTER +KB_ENQUEUE_AB: + POP HL ; RESTORE HL + POP DE ; RESTORE DE + RET + + +;__KB_WAITBYTE_____________________________________________________________________________________ +; +; WAIT FOR A BYTE - TESTS A NUMBER OF TIMES IF THERE IS A KEYBOARD INPUT, +; OVERWRITES ALL REGISTERS, RETURNS BYTE IN A +;__________________________________________________________________________________________________ +KB_WAITBYTE: + CALL KB_CLOCKHIGH ; TURN ON KEYBOARD + LD HL,500 ; NUMBER OF TIMES TO CHECK 200=SLOW TYPE + ; 10=ERROR, 25 ?ERROR 50 OK - + ; THIS DELAY HAS TO BE THERE OTHERWISE WEIRD KEYUP ERRORS +WB1: PUSH HL ; STORE COUNTER + CALL KB_READBITS ; TEST FOR A LOW ON THE CLOCK LINE + POP HL ; GET THE COUNTER BACK + CP 0 ; TEST FOR A ZERO BACK FROM READBITS + JR NZ,WB2 ; IF NOT A ZERO THEN MUST HAVE A BYTE IE A KEYBOARD PRESS + LD DE,1 ; LOAD WITH 1 + SBC HL,DE ; SUBTRACT 1 + JR NZ,WB1 ; LOOP WAITING FOR A RESPONSE +WB2: PUSH AF ; STORE THE VALUE IN A + CALL KB_CLOCKLOW ; TURN OFF KEYBOARD + POP AF ; GET BACK BYTE AS CLOCKLOW ERASED IT + RET + +;__KB_READBITS_____________________________________________________________________________________ +; +; READBITS READS 11 BITS IN FROM THE KEYBOARD +; FIRST BIT IS A START BIT THEN 8 BITS FOR THE BYTE +; THEN A PARITY BIT AND A STOP BIT +; RETURNS AFTER ONE MACHINE CYCLE IF NOT LOW +; USES A, B,D, E +; RETURNS A=0 IF NO DATA, A= SCANCODE (OR PART THEREOF) +;__________________________________________________________________________________________________ +KB_READBITS: + IN A,(PPIB) + BIT 1,A ; TEST THE CLOCK BIT + JR Z,R1 ; IF LOW THEN START THE CAPTURE + LD A,0 ; RETURNS A=0 IF NOTHING + RET ; +R1: CALL KB_WAITCLOCKHIGH; IF GETS TO HERE THEN MUST BE LOW SO WAIT TILL HIGH + LD B,8 ; SAMPLE 8 TIMES + LD E,0 ; START WITH E=0 +R2: LD D,B ; STORE BECAUSE WAITCLOCKHIGH DESTROYS + CALL KB_WAITCLOCKLOW ; WAIT TILL CLOCK GOES LOW + IN A,(PPIB) ; SAMPLE THE DATA LINE + RRA ; MOVE THE DATA BIT INTO THE CARRY REGISTER + LD A,E ; GET THE BYTE WE ARE BUILDING IN E + RRA ; MOVE THE CARRY BIT INTO BIT 7 AND SHIFT RIGHT + LD E,A ; STORE IT BACK AFTER 8 CYCLES 1ST BIT READ WILL BE IN B0 + CALL KB_WAITCLOCKHIGH; WAIT TILL GOES HIGH + LD B,D ; RESTORE FOR LOOP + DJNZ R2 ; DO THIS 8 TIMES + CALL KB_WAITCLOCKLOW ; GET THE PARITY BIT + CALL KB_WAITCLOCKHIGH; + CALL KB_WAITCLOCKLOW ; GET THE STOP BIT + CALL KB_WAITCLOCKHIGH; + LD A,E ; RETURNS WITH ANSWER IN A + RET + +NORMALKEYS: + ; THE TI CHARACTER CODES, OFFSET FROM LABEL BY KEYBOARD SCAN CODE + .DB $00, $00, $00, $00, $00, $00, $00, $00 + .DB $00, $00, $00, $00, $00, $09, "`", $00 ; $09=TAB + .DB $00, $00, $00, $00, $00, "q", "1", $00 + .DB $00, $00, "z", "s", "a", "w", "2", $00 + .DB $00, "c", "x", "d", "e", "4", "3", $00 + .DB $00, " ", "v", "f", "t", "r", "5", $00 + .DB $00, "n", "b", "h", "g", "y", "6", $00 + .DB $00, $00, "m", "j", "u", "7", "8", $00 + .DB $00, ",", "k", "i", "o", "0", "9", $00 + .DB $00, ".", "/", "l", ";", "p", "-", $00 + .DB $00, $00, $27, $00, "[", "=", $00, $00 ; $27=APOSTROPHE + .DB $00, $00, $00, "]", $00, $5C, $00, $00 ; $5C=BACKSLASH + .DB $00, $00, $00, $00, $00, $00, $00, $00 + .DB $00, "1", $00, "4", "7", $00, $00, $00 + .DB "0", ".", "2", "5", "6", "8", $00, $00 + .DB $00, "+", "3", "-", "*", "9", $00, $00 + +SHIFTKEYS: + .DB $00, $00, $00, $00, $00, $00, $00, $00 + .DB $00, $00, $00, $00, $00, 009, "~", $00 ; $09=TAB + .DB $00, $00, $00, $00, $00, "Q", "!", $00 + .DB $00, $00, "Z", "S", "A", "W", "@", $00 + .DB $00, "C", "X", "D", "E", "$", "#", $00 + .DB $00, " ", "V", "F", "T", "R", "%", $00 + .DB $00, "N", "B", "H", "G", "Y", "^", $00 + .DB $00, $00, "M", "J", "U", "&", "*", $00 + .DB $00, "<", "K", "I", "O", ")", "(", $00 + .DB $00, ">", "?", "L", ":", "P", "_", $00 + .DB $00, $00, 034, $00, "{", "+", $00, $00 ; $22=DBLQUOTE + .DB $00, $00, $00, "}", $00, "|", $00, $00 + .DB $00, $00, $00, $00, $00, $00, $00, $00 + .DB $00, "1", $00, "4", "7", $00, $00, $00 + .DB "0", ".", "2", "5", "6", "8", $00, $00 + .DB $00, "+", "3", "-", "*", "9", $00, $00 +; +;================================================================================================== +; VDU DRIVER - DATA +;================================================================================================== +; +ALT_KEYPAD .DB 0 ; ALT KEYPAD ENABLED? +GR_MODE .DB 0 ; GRAPHICS MODE ENABLED? +TERM_X .DB 0 ; CURSOR X +TERM_Y .DB 0 ; CURSOR Y +TERMSTATE .DB 0 ; TERMINAL STATE + ; 0 = NORMAL + ; 1 = ESC RCVD +VDU_DISPLAYPOS .DW 0 ; CURRENT DISPLAY POSITION +VDU_DISPLAY_START .DW 0 ; CURRENT DISPLAY POSITION +CAPSLOCK .DB 0 ; location for caps lock, either 00000000 or 11111111 +CTRL .DB 0 ; location for ctrl on or off 00000000 or 11111111 +NUMLOCK .DB 0 ; location for num lock +SKIPCOUNT .DB 0 ; only check some calls, speeds up a lot of cp/m +KB_QUEUE .FILL 16,0 ; 16 BYTE KB QUEUE +KB_QUEUE_PTR .DB 0 ; POINTER TO QUEUE diff --git a/trunk/Source/ver.inc b/trunk/Source/ver.inc new file mode 100644 index 00000000..93886ba7 --- /dev/null +++ b/trunk/Source/ver.inc @@ -0,0 +1,6 @@ +#DEFINE RMJ 2 +#DEFINE RMN 1 +#DEFINE RUP 1 +#DEFINE RTP 0 +#DEFINE BIOSVER "2.1.1" +#DEFINE REVISION 1741 diff --git a/trunk/Source/zcpr.asm b/trunk/Source/zcpr.asm new file mode 100644 index 00000000..bf989674 --- /dev/null +++ b/trunk/Source/zcpr.asm @@ -0,0 +1,2050 @@ +; WW - TASM adaptation (requires wrapper!) +; WW - Globally replaced squote -> dquote for all strings +; WW - Globally updated conditional expressions to use TASM operators +; WW - Commented out all of the Z80 macros (see wrapper) +; + TITLE "ZCPR Version 1.0" +; +; CP/M Z80 Command Processor Replacement (CPR) Version 1.0 +; CCPZ CREATED AND CUSTOMIZED FOR ARIES-II BY RLC +; FURTHER MODIFIED BY RGF AS V2.0 +; FURTHER MODIFIED BY RLC AS V2.1 +; FURTHER MODIFIED BY KBP AS V2.2 +; FURTHER MODIFIED BY RLC AS V2.4 (V2.3 skipped) +; FURTHER MODIFIED BY RLC AS V2.5 +; FURTHER MODIFIED BY RLC AS V2.6 +; FURTHUR MODIFIED BY SBB AS V2.7 +; FURTHER MODIFIED BY RLC AS V2.8 +; FURTHER MODIFIED BY RLC AS V2.9 +; FURTHER MODIFIED BY RLC AS V3.0 +; FURTHER MODIFIED BY RLC AS V3.1 +; FURTHER MODIFIED BY RLC AS V4.0 +; ZCPR VERSION 1.0 CREATED FROM CCPZ VERSION 4.0 BY RLC IN +; A COORDINATED EFFORT WITH CCP-GROUP +; +; ZCPR is a group effort by CCP-GROUP, whose active membership involved +; in this project consists of the following: +; RLC - Richard Conn +; RGF - Ron Fowler +; KBP - Keith Peterson +; FJW - Frank Wancho +; The following individual also provided a contribution: +; SBB - Steve Bogolub +; +; +;******** Structure Notes ******** +; +; This CPR is divided into a number of major sections. The following +; is an outline of these sections and the names of the major routines +; located therein. +; +; Section Function/Routines +; ------- ----------------- +; +; -- Opening Comments, Equates, and Macro Definitions +; +; 0 JMP Table into CPR +; +; 1 Buffers +; +; 2 CPR Starting Modules +; CPR1 CPR RESTRT RSTCPR RCPRNL +; PRNNF +; +; 3 Utilities +; CRLF CONOUT CONIN LCOUT LSTOUT +; READF READ BDOSB PRINTC PRINT +; GETDRV DEFDMA DMASET RESET BDOSJP +; LOGIN OPENF OPEN GRBDOS CLOSE +; SEARF SEAR1 SEARN SUBKIL DELETE +; RESETUSR GETUSR SETUSR +; +; 4 CPR Utilities +; SETUD SETU0D UCASE REDBUF CNVBUF +; BREAK USRNUM ERROR SDELM ADVAN +; SBLANK ADDAH NUMBER NUMERR HEXNUM +; DIRPTR SLOGIN DLOGIN COMLOG SCANER +; CMDSER +; +; 5 CPR-Resident Commands and Functions +; 5A DIR DIRPR FILLQ +; 5B ERA +; 5C LIST +; 5D TYPE PAGER +; 5E SAVE +; 5F REN +; 5G USER +; 5H DFU +; 5I JUMP +; 5J GO +; 5K COM CALLPROG ERRLOG ERRJMP +; 5L GET MEMLOAD PRNLE +; +; +FALSE EQU 0 +TRUE EQU ~FALSE +; +; CUSTOMIZATION EQUATES +; +; The following equates may be used to customize this CPR for the user's +; system and integration technique. The following constants are provided: +; +; REL - TRUE if integration is to be done via MOVCPM +; - FALSE if integration is to be done via DDT and SYSGEN +; +; BASE - Base Address of user's CP/M system (normally 0 for DR version) +; This equate allows easy modification by non-standard CP/M (eg,H89) +; +; CPRLOC - Base Page Address of CPR; this value can be obtained by running +; the BDOSLOC program on your system, or by setting the +; MSIZE and BIOSEX equates to the system memory size in +; K-bytes and the "extra" memory required by your BIOS +; in K-bytes. BIOSEX is zero if your BIOS is normal size, +; and can be negative if your BIOS is in PROM or in +; non-contiguous memory. +; +; RAS - Remote-Access System; setting this equate to TRUE disables +; certain CPR commands that are considered harmful in a Remote- +; Access environment; use under Remote-Access Systems (RBBS) for +; security purposes +; +REL EQU FALSE ;SET TO TRUE FOR MOVCPM INTEGRATION +; +BASE EQU 0 ;BASE OF CP/M SYSTEM (SET FOR STANDARD CP/M) +; + IF REL +CPRLOC EQU 0 ;MOVCPM IMAGE + ELSE +; +; If REL is FALSE, the value of CPRLOC may be set in one +; of two ways. The first way is to set MSIZE and BIOSEX +; as described above using the following three lines: +; +;MSIZE EQU 56 ;SIZE OF MEM IN K-BYTES +;BIOSEX EQU 0 ;EXTRA # K-BYTES IN BIOS +;CPRLOC EQU 3400H+(MSIZE-20-BIOSEX)*1024 ;CPR ORIGIN +; +; The second way is to obtain the origin of your current +; CPR using BDSLOC or its equivalent, then merely set CPRLOC +; to that value as as in the following line: +; +CPRLOC EQU 0D000H ;FILL IN WITH BDOSLOC SUPPLIED VALUE +; +; Note that you should only use one method or the other. +; Do NOT define CPRLOC twice! +; +; The following gives the required offset to load the CPR into the +; CP/M SYSGEN Image through DDT (the Roffset command); Note that this +; value conforms with the standard value presented in the CP/M reference +; manuals, but it may not necessarily conform with the location of the +; CPR in YOUR CP/M system; several systems (Morrow Designs, P&T, Heath +; Org-0 to name a few) have the CPR located at a non-standard address in +; the SYSGEN Image +; +;CPRR EQU 0980H-CPRLOC ;DDT LOAD OFFSET +CPRR EQU 1100H-CPRLOC ;DDT LOAD OFFSET FOR MORROW DESIGNS + ENDIF +; +RAS EQU FALSE ;SET TO TRUE IF CPR IS FOR A REMOTE-ACCESS SYSTEM +; +; The following is presented as an option, but is not generally user-customiz- +; able. A basic design choice had to be made in the design of ZCPR concerning +; the execution of SUBMIT files. The original CCP had a problem in this sense +; in that it ALWAYS looked for the SUBMIT file from drive A: and the SUBMIT +; program itself (SUBMIT.COM) would place the $$$.SUB file on the currently +; logged-in drive, so when the user was logged into B: and he issued a SUBMIT +; command, the $$$.SUB was placed on B: and did not execute because the CCP +; looked for it on A: and never found it. +; After much debate it was decided to have ZCPR perform the same type of +; function as CCP (look for the $$$.SUB file on A:), but the problem with +; SUBMIT.COM still exists. Hence, RGF designed SuperSUB and RLC took his +; SuperSUB and designed SUB from it; both programs are set up to allow the +; selection at assembly time of creating the $$$.SUB on the logged-in drive +; or on drive A:. +; A final definition of the Indirect Command File ($$$.SUB or SUBMIT +; File) is presented as follows: +; "An Indirect Command File is one which contains +; a series of commands exactly as they would be +; entered from a CP/M Console. The SUBMIT Command +; (or SUB Command) reads this files and transforms +; it for processing by the ZCPR (the $$$.SUB File). +; ZCPR will then execute the commands indicated +; EXACTLY as if they were typed at the Console." +; Hence, to permit this to happen, the $$$.SUB file must always +; be present on a specific drive, and A: is the choice for said drive. +; With this facility engaged as such, Indirect Command Files like: +; DIR +; A: +; DIR +; can be executed, even though the currently logged-in drive is changed +; during execution. If the $$$.SUB file was present on the currently +; logged-in drive, the above series of commands would not work since the +; ZCPR would be looking for $$$.SUB on the logged-in drive, and switching +; logged-in drives without moving the $$$.SUB file as well would cause +; processing to abort. +; +SUBA equ TRUE ; Set to TRUE to have $$$.SUB always on A: + ; Set to FALSE to have $$$.SUB on the logged-in drive +; +; The following flag enables extended processing for user-program supplied +; command lines. This is for Command Level 3 of ZCPR. Under the CCPZ Version +; 4.0 philosophy, three command levels exist: +; (1) that command issued by the user from his console at the '>' prompt +; (2) that command issued by a $$$.SUB file at the '$' prompt +; (3) that command issued by a user program by placing the command into +; CIBUFF and setting the character count in CBUFF +; Setting CLEVEL3 to TRUE enables extended processing of the third level of +; ZCPR command. All the user program need do is to store the command line and +; set the character count; ZCPR will initialize the pointers properly, store +; the ending zero properly, and capitalize the command line for processing. +; Once the command line is properly stored, the user executes the command line +; by reentering the ZCPR through CPRLOC [NOTE: The C register MUST contain +; a valid User/Disk Flag (see location 4) at this time.] +; +CLEVEL3 equ TRUE ;ENABLE COMMAND LEVEL 3 PROCESSING +; +; +;*** TERMINAL AND 'TYPE' CUSTOMIZATION EQUATES +; +NLINES EQU 24 ;NUMBER OF LINES ON CRT SCREEN +WIDE EQU TRUE ;TRUE IF WIDE DIR DISPLAY +FENCE EQU '|' ;SEP CHAR BETWEEN DIR FILES +; +PGDFLT EQU TRUE ;SET TO FALSE TO DISABLE PAGING BY DEFAULT +PGDFLG EQU 'P' ;FOR TYPE COMMAND: PAGE OR NOT (DEP ON PGDFLT) + ; THIS FLAG REVERSES THE DEFAULT EFFECT +; +MAXUSR EQU 15 ;MAXIMUM USER NUMBER ACCESSABLE +; +SYSFLG EQU 'A' ;FOR DIR COMMAND: LIST $SYS AND $DIR +; +SOFLG EQU 'S' ;FOR DIR COMMAND: LIST $SYS FILES ONLY +; +SUPRES EQU TRUE ;SUPRESSES USER # REPORT FOR USER 0 +; +DEFUSR EQU 0 ;DEFAULT USER NUMBER FOR COM FILES +; +SPRMPT EQU '$' ;CPR PROMPT INDICATING SUBMIT COMMAND +CPRMPT EQU '>' ;CPR PROMPT INDICATING USER COMMAND +; +NUMBASE EQU 'H' ;CHARACTER USED TO SWITCH FROM DEFAULT + ; NUMBER BASE +; +SECTFLG EQU 'S' ;OPTION CHAR FOR SAVE COMMAND TO SAVE SECTORS +; +; END OF CUSTOMIZATION SECTION +; +CR EQU 0DH +LF EQU 0AH +TAB EQU 09H +; +WBOOT EQU BASE+0000H ;CP/M WARM BOOT ADDRESS +UDFLAG EQU BASE+0004H ;USER NUM IN HIGH NYBBLE, DISK IN LOW +BDOS EQU BASE+0005H ;BDOS FUNCTION CALL ENTRY PT +TFCB EQU BASE+005CH ;DEFAULT FCB BUFFER +TBUFF EQU BASE+0080H ;DEFAULT DISK I/O BUFFER +TPA EQU BASE+0100H ;BASE OF TPA +; +; WW - MOVED MACROS BELOW TO ADDINSTR'S IN WRAPPER +; +;; +;; +;; MACROS TO PROVIDE Z80 EXTENSIONS +;; MACROS INCLUDE: +;; +;$-MACRO ;FIRST TURN OFF THE EXPANSIONS +;; +;; JR - JUMP RELATIVE +;; JRC - JUMP RELATIVE IF CARRY +;; JRNC - JUMP RELATIVE IF NO CARRY +;; JRZ - JUMP RELATIVE IF ZERO +;; JRNZ - JUMP RELATIVE IF NO ZERO +;; DJNZ - DECREMENT B AND JUMP RELATIVE IF NO ZERO +;; LDIR - MOV @HL TO @DE FOR COUNT IN BC +;; LXXD - LOAD DOUBLE REG DIRECT +;; SXXD - STORE DOUBLE REG DIRECT +;; +;; +;; +;; @GENDD MACRO USED FOR CHECKING AND GENERATING +;; 8-BIT JUMP RELATIVE DISPLACEMENTS +;; +;@GENDD MACRO ?DD ;;USED FOR CHECKING RANGE OF 8-BIT DISPLACEMENTS +; IF (?DD GT 7FH) AND (?DD LT 0FF80H) +; DB 100H ;Displacement Range Error on Jump Relative +; ELSE +; DB ?DD +; ENDIF +; ENDM +;; +;; +;; Z80 MACRO EXTENSIONS +;; +;JR MACRO ?N ;;JUMP RELATIVE +; DB 18H +; @GENDD ?N-$-1 +; ENDM +;; +;JRC MACRO ?N ;;JUMP RELATIVE ON CARRY +; DB 38H +; @GENDD ?N-$-1 +; ENDM +;; +;JRNC MACRO ?N ;;JUMP RELATIVE ON NO CARRY +; DB 30H +; @GENDD ?N-$-1 +; ENDM +;; +;JRZ MACRO ?N ;;JUMP RELATIVE ON ZERO +; DB 28H +; @GENDD ?N-$-1 +; ENDM +;; +;JRNZ MACRO ?N ;;JUMP RELATIVE ON NO ZERO +; DB 20H +; @GENDD ?N-$-1 +; ENDM +;; +;DJNZ MACRO ?N ;;DECREMENT B AND JUMP RELATIVE ON NO ZERO +; DB 10H +; @GENDD ?N-$-1 +; ENDM +;; +;LDIR MACRO ;;LDIR +; DB 0EDH,0B0H +; ENDM +;; +;LDED MACRO ?N ;;LOAD DE DIRECT +; DB 0EDH,05BH +; DW ?N +; ENDM +;; +;LBCD MACRO ?N ;;LOAD BC DIRECT +; DB 0EDH,4BH +; DW ?N +; ENDM +;; +;SDED MACRO ?N ;;STORE DE DIRECT +; DB 0EDH,53H +; DW ?N +; ENDM +;; +;SBCD MACRO ?N ;;STORE BC DIRECT +; DB 0EDH,43H +; DW ?N +; ENDM +;; +;; END OF Z80 MACRO EXTENSIONS +; +; +;**** Section 0 **** +; + ORG CPRLOC +; +; ENTRY POINTS INTO ZCPR +; If the ZCPR is entered at location CPRLOC (at the JMP to CPR), then +; the default command in CIBUFF will be processed. If the ZCPR is entered +; at location CPRLOC+3 (at the JMP to CPR1), then the default command in +; CIBUFF will NOT be processed. +; NOTE: Entry into ZCPR in this way is permitted under ZCPR Version 4.0, +; but in order for this to work, CIBUFF and CBUFF MUST be initialized properly +; AND the C register MUST contain a valid User/Disk Flag (see Location 4: the +; most significant nybble contains the User Number and the least significant +; nybble contains the Disk Number). +; Some user programs (such as SYNONYM3) attempt to use the default +; command facility. Under the original CPR, it was necessary to initialize +; the pointer after the reserved space for the command buffer to point to +; the first byte of the command buffer. Under Version 4.x of ZCPR, this is +; no longer the case. The CIBPTR (Command Input Buffer PoinTeR) is located +; to be compatable with such programs (provided they determine the buffer +; length from the byte at MBUFF [CPRLOC + 6]), but under Version 4.x of ZCPR +; this is no longer necessary. ZCPR Version 4.x automatically initializes +; this buffer pointer in all cases. +; +ENTRY: + JMP CPR ; Process potential default command + JMP CPR1 ; Do NOT process potential default command +; +;**** Section 1 **** +; BUFFERS ET AL +; +; INPUT COMMAND LINE AND DEFAULT COMMAND +; The command line to be executed is stored here. This command line +; is generated in one of three ways: +; (1) by the user entering it through the BDOS READLN function at +; the du> prompt [user input from keyboard] +; (2) by the SUBMIT File Facility placing it there from a $$$.SUB +; file +; (3) by an external program or user placing the required command +; into this buffer +; In all cases, the command line is placed into the buffer starting at +; CIBUFF. This command line is terminated by the last character (NOT Carriage +; Return), and a character count of all characters in the command line +; up to and including the last character is placed into location CBUFF +; (immediately before the command line at CIBUFF). The placed command line +; is then parsed, interpreted, and the indicated command is executed. +; If CLEVEL3 is permitted, a terminating zero is placed after the command +; (otherwise the user program has to place this zero) and the CIBPTR is +; properly initialized (otherwise the user program has to init this ptr). +; If the command is placed by a user program, entering at CPRLOC is enough +; to have the command processed. Again, under CCPZ Version 4.0, it is not +; necessary to store the pointer to CIBUFF in CIBPTR; ZCPR will do this for +; the calling program if CLEVEL3 is made TRUE. +; WARNING: The command line must NOT exceed BUFLEN characters in length. +; For user programs which load this command, the value of BUFLEN can be +; obtained by examining the byte at MBUFF (CPRLOC + 6). +; +BUFLEN EQU 80 ;MAXIMUM BUFFER LENGTH +MBUFF: + DB BUFLEN ;MAXIMUM BUFFER LENGTH +CBUFF: + DB 0 ;NUMBER OF VALID CHARS IN COMMAND LINE +CIBUFF: + DB " " ;DEFAULT (COLD BOOT) COMMAND +CIBUF: + DB 0 ;COMMAND STRING TERMINATOR + DS BUFLEN-($-CIBUFF)+1 ;TOTAL IS 'BUFLEN' BYTES +; +CIBPTR: + DW CIBUFF ;POINTER TO COMMAND INPUT BUFFER +CIPTR: + DW CIBUF ;CURRENT POINTER +; + DS 26 ;STACK AREA +STACK EQU $ ;TOP OF STACK +; +; FILE TYPE FOR COMMAND +; +COMMSG: + DB "COM" +; +; SUBMIT FILE CONTROL BLOCK +; +SUBFCB: + IF SUBA ;IF $$$.SUB ON A: + DB 1 ;DISK NAME SET TO DEFAULT TO DRIVE A: + ENDIF +; + IF ~SUBA ;IF $$$.SUB ON CURRENT DRIVE + DB 0 ;DISK NAME SET TO DEFAULT TO CURRENT DRIVE + ENDIF +; + DB "$$$" ;FILE NAME + DB " " + DB "SUB" ;FILE TYPE + DB 0 ;EXTENT NUMBER + DB 0 ;S1 +SUBFS2: + DS 1 ;S2 +SUBFRC: + DS 1 ;RECORD COUNT + DS 16 ;DISK GROUP MAP +SUBFCR: + DS 1 ;CURRENT RECORD NUMBER +; +; COMMAND FILE CONTROL BLOCK +; +FCBDN: + DS 1 ;DISK NAME +FCBFN: + DS 8 ;FILE NAME +FCBFT: + DS 3 ;FILE TYPE + DS 1 ;EXTENT NUMBER + DS 2 ;S1 AND S2 + DS 1 ;RECORD COUNT +FCBDM: + DS 16 ;DISK GROUP MAP +FCBCR: + DS 1 ;CURRENT RECORD NUMBER +; +; OTHER BUFFERS +; +PAGCNT: + DB NLINES-2 ;LINES LEFT ON PAGE +CHRCNT: + DB 0 ;CHAR COUNT FOR TYPE +QMCNT: + DB 0 ;QUESTION MARK COUNT FOR FCB TOKEN SCANNER +; +; CPR BUILT-IN COMMAND TABLE +; +NCHARS EQU 4 ;NUMBER OF CHARS/COMMAND +; +; CPR COMMAND NAME TABLE +; EACH TABLE ENTRY IS COMPOSED OF THE 4-BYTE COMMAND AND 2-BYTE ADDRESS +; +CMDTBL: + DB "DIR " + DW DIR + DB "LIST" + DW LIST + DB "TYPE" + DW TYPE + DB "USER" + DW USER + DB "DFU " + DW DFU +; + IF ~RAS ;FOR NON-RAS + DB "GO " + DW GO + DB "ERA " + DW ERA + DB "SAVE" + DW SAVE + DB "REN " + DW REN + DB "GET " + DW GET + DB "JUMP" + DW JUMP + ENDIF +; +NCMNDS EQU ($-CMDTBL)/(NCHARS+2) +; +; +;**** Section 2 **** +; CPR STARTING POINTS +; +; START CPR AND DON'T PROCESS DEFAULT COMMAND STORED +; +CPR1: + XRA A ;SET NO DEFAULT COMMAND + STA CBUFF +; +; START CPR AND POSSIBLY PROCESS DEFAULT COMMAND +; +; NOTE ON MODIFICATION BY RGF: BDOS RETURNS 0FFH IN +; ACCUMULATOR WHENEVER IT LOGS IN A DIRECTORY, IF ANY +; FILE NAME CONTAINS A '$' IN IT. THIS IS NOW USED AS +; A CLUE TO DETERMINE WHETHER OR NOT TO DO A SEARCH +; FOR SUBMIT FILE, IN ORDER TO ELIMINATE WASTEFUL SEARCHES. +; +CPR: + LXI SP,STACK ;RESET STACK + PUSH B + MOV A,C ;C=USER/DISK NUMBER (SEE LOC 4) + RAR ;EXTRACT USER NUMBER + RAR + RAR + RAR + ANI 0FH + MOV E,A ;SET USER NUMBER + CALL SETUSR + CALL RESET ;RESET DISK SYSTEM + STA RNGSUB ;SAVE SUBMIT CLUE FROM DRIVE A: + POP B + MOV A,C ;C=USER/DISK NUMBER (SEE LOC 4) + ANI 0FH ;EXTRACT DEFAULT DISK DRIVE + STA TDRIVE ;SET IT + JRZ NOLOG ;SKIP IF 0...ALREADY LOGGED + CALL LOGIN ;LOG IN DEFAULT DISK +; + IF ~SUBA ;IF $$$.SUB IS ON CURRENT DRIVE + STA RNGSUB ;BDOS '$' CLUE + ENDIF +; +NOLOG: + LXI D,SUBFCB ;CHECK FOR $$$.SUB ON CURRENT DISK +RNGSUB EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION + MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS THE RNGSUB FLAG + ORA A ;SET FLAGS ON CLUE + CMA ;PREPARE FOR COMING 'CMA' + CNZ SEAR1 + CMA ;0FFH IS RETURNED IF NO $$$.SUB, SO COMPLEMENT + STA RNGSUB ;SET FLAG (0=NO $$$.SUB) + LDA CBUFF ;EXECUTE DEFAULT COMMAND? + ORA A ;0=NO + JRNZ RS1 +; +; PROMPT USER AND INPUT COMMAND LINE FROM HIM +; +RESTRT: + LXI SP,STACK ;RESET STACK +; +; PRINT PROMPT (DU>) +; + CALL CRLF ;PRINT PROMPT + CALL GETDRV ;CURRENT DRIVE IS PART OF PROMPT + ADI 'A' ;CONVERT TO ASCII A-P + CALL CONOUT + CALL GETUSR ;GET USER NUMBER +; + IF SUPRES ;IF SUPPRESSING USR # REPORT FOR USR 0 + ORA A + JRZ RS000 + ENDIF +; + CPI 10 ;USER < 10? + JRC RS00 + SUI 10 ;SUBTRACT 10 FROM IT + PUSH PSW ;SAVE IT + MVI A,'1' ;OUTPUT 10'S DIGIT + CALL CONOUT + POP PSW +RS00: + ADI '0' ;OUTPUT 1'S DIGIT (CONVERT TO ASCII) + CALL CONOUT +; +; READ INPUT LINE FROM USER OR $$$.SUB +; +RS000: + CALL REDBUF ;INPUT COMMAND LINE FROM USER (OR $$$.SUB) +; +; PROCESS INPUT LINE +; +RS1: +; + IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED + CALL CNVBUF ;CAPITALIZE COMMAND LINE, PLACE ENDING 0, + ; AND SET CIBPTR VALUE + ENDIF +; + CALL DEFDMA ;SET TBUFF TO DMA ADDRESS + CALL GETDRV ;GET DEFAULT DRIVE NUMBER + STA TDRIVE ;SET IT + CALL SCANER ;PARSE COMMAND NAME FROM COMMAND LINE + CNZ ERROR ;ERROR IF COMMAND NAME CONTAINS A '?' + LXI D,RSTCPR ;PUT RETURN ADDRESS OF COMMAND + PUSH D ;ON THE STACK + LDA TEMPDR ;IS COMMAND OF FORM 'D:COMMAND'? + ORA A ;NZ=YES + JNZ COM ; IMMEDIATELY + CALL CMDSER ;SCAN FOR CPR-RESIDENT COMMAND + JNZ COM ;NOT CPR-RESIDENT + MOV A,M ;FOUND IT: GET LOW-ORDER PART + INX H ;GET HIGH-ORDER PART + MOV H,M ;STORE HIGH + MOV L,A ;STORE LOW + PCHL ;EXECUTE CPR ROUTINE +; +; ENTRY POINT FOR RESTARTING CPR AND LOGGING IN DEFAULT DRIVE +; +RSTCPR: + CALL DLOGIN ;LOG IN DEFAULT DRIVE +; +; ENTRY POINT FOR RESTARTING CPR WITHOUT LOGGING IN DEFAULT DRIVE +; +RCPRNL: + CALL SCANER ;EXTRACT NEXT TOKEN FROM COMMAND LINE + LDA FCBFN ;GET FIRST CHAR OF TOKEN + SUI ' ' ;ANY CHAR? + LXI H,TEMPDR + ORA M + JNZ ERROR + JR RESTRT +; +; No File Error Message +; +PRNNF: + CALL PRINTC ;NO FILE MESSAGE + DB "No Fil",'e'+80H + RET +; +;**** Section 3 **** +; I/O UTILITIES +; +; OUTPUT CHAR IN REG A TO CONSOLE AND DON'T CHANGE BC +; +; +; OUTPUT +; +CRLF: + MVI A,CR + CALL CONOUT + MVI A,LF ;FALL THRU TO CONOUT +; +CONOUT: + PUSH B + MVI C,02H +OUTPUT: + MOV E,A + PUSH H + CALL BDOS + POP H + POP B + RET +; +CONIN: + MVI C,01H ;GET CHAR FROM CON: WITH ECHO + CALL BDOSB + JMP UCASE ;CAPITALIZE +; +LCOUT: + PUSH PSW ;OUTPUT CHAR TO CON: OR LST: DEP ON PRFLG +PRFLG EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION + MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS THE PRINT FLAG + ORA A ;0=TYPE + JRZ LC1 + POP PSW ;GET CHAR +; +; OUTPUT CHAR IN REG A TO LIST DEVICE +; +LSTOUT: + PUSH B + MVI C,05H + JR OUTPUT +LC1: + POP PSW ;GET CHAR + PUSH PSW + CALL CONOUT ;OUTPUT TO CON: + POP PSW + CPI LF ;CHECK FOR PAGING + JZ PAGER + RET +; +READF: + LXI D,FCBDN ;FALL THRU TO READ +READ: + MVI C,14H ;FALL THRU TO BDOSB +; +; CALL BDOS AND SAVE BC +; +BDOSB: + PUSH B + CALL BDOS + POP B + ORA A + RET +; +; PRINT STRING (ENDING IN 0) PTED TO BY RET ADR;START WITH +; +PRINTC: + PUSH PSW ;SAVE FLAGS + CALL CRLF ;NEW LINE + POP PSW +; +PRINT: + XTHL ;GET PTR TO STRING + PUSH PSW ;SAVE FLAGS + CALL PRIN1 ;PRINT STRING + POP PSW ;GET FLAGS + XTHL ;RESTORE HL AND RET ADR + RET +; +; PRINT STRING (ENDING IN 0) PTED TO BY HL +; +PRIN1: + MOV A,M ;GET NEXT BYTE + ANI 7FH ;WW - CLEAR MSB + CALL CONOUT ;PRINT CHAR + MOV A,M ;GET NEXT BYTE AGAIN FOR TEST + INX H ;PT TO NEXT BYTE + ORA A ;SET FLAGS + RZ ;DONE IF ZERO + RM ;DONE IF MSB SET + JR PRIN1 +; +; BDOS FUNCTION ROUTINES +; +; +; RETURN NUMBER OF CURRENT DISK IN A +; +GETDRV: + MVI C,19H + JR BDOSJP +; +; SET 80H AS DMA ADDRESS +; +DEFDMA: + LXI D,TBUFF ;80H=TBUFF +DMASET: + MVI C,1AH + JR BDOSJP +; +RESET: + MVI C,0DH +BDOSJP: + JMP BDOS +; +LOGIN: + MOV E,A + MVI C,0EH + JR BDOSJP ;SAVE SOME CODE SPACE +; +OPENF: + XRA A + STA FCBCR + LXI D,FCBDN ;FALL THRU TO OPEN +; +OPEN: + MVI C,0FH ;FALL THRU TO GRBDOS +; +GRBDOS: + CALL BDOS + INR A ;SET ZERO FLAG FOR ERROR RETURN + RET +; +CLOSE: + MVI C,10H + JR GRBDOS +; +SEARF: + LXI D,FCBDN ;SPECIFY FCB +SEAR1: + MVI C,11H + JR GRBDOS +; +SEARN: + MVI C,12H + JR GRBDOS +; +; CHECK FOR SUBMIT FILE IN EXECUTION AND ABORT IT IF SO +; +SUBKIL: + LXI H,RNGSUB ;CHECK FOR SUBMIT FILE IN EXECUTION + MOV A,M + ORA A ;0=NO + RZ + MVI M,0 ;ABORT SUBMIT FILE + LXI D,SUBFCB ;DELETE $$$.SUB +; +DELETE: + MVI C,13H + JR BDOSJP ;SAVE MORE SPACE +; +; RESET USER NUMBER IF CHANGED +; +RESETUSR: +TMPUSR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION + MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TMPUSR + MOV E,A ;PLACE IN E + JR SETUSR ;THEN GO SET USER +GETUSR: + MVI E,0FFH ;GET CURRENT USER NUMBER +SETUSR: + MVI C,20H ;SET USER NUMBER TO VALUE IN E (GET IF E=FFH) + JR BDOSJP ;MORE SPACE SAVING +; +; END OF BDOS FUNCTIONS +; +; +;**** Section 4 **** +; CPR UTILITIES +; +; SET USER/DISK FLAG TO CURRENT USER AND DEFAULT DISK +; +SETUD: + CALL GETUSR ;GET NUMBER OF CURRENT USER + ADD A ;PLACE IT IN HIGH NYBBLE + ADD A + ADD A + ADD A + LXI H,TDRIVE ;MASK IN DEFAULT DRIVE NUMBER (LOW NYBBLE) + ORA M ;MASK IN + STA UDFLAG ;SET USER/DISK NUMBER + RET +; +; SET USER/DISK FLAG TO USER 0 AND DEFAULT DISK +; +SETU0D: +TDRIVE EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION + MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TDRIVE + STA UDFLAG ;SET USER/DISK NUMBER + RET +; +; CONVERT CHAR IN A TO UPPER CASE +; +UCASE: + CPI 61H ;LOWER-CASE A + RC + CPI 7BH ;GREATER THAN LOWER-CASE Z? + RNC + ANI 5FH ;CAPITALIZE + RET +; +; INPUT NEXT COMMAND TO CPR +; This routine determines if a SUBMIT file is being processed +; and extracts the command line from it if so or from the user's console +; +REDBUF: + LDA RNGSUB ;SUBMIT FILE CURRENTLY IN EXECUTION? + ORA A ;0=NO + JRZ RB1 ;GET LINE FROM CONSOLE IF NOT + LXI D,SUBFCB ;OPEN $$$.SUB + PUSH D ;SAVE DE + CALL OPEN + POP D ;RESTORE DE + JRZ RB1 ;ERASE $$$.SUB IF END OF FILE AND GET CMND + LDA SUBFRC ;GET VALUE OF LAST RECORD IN FILE + DCR A ;PT TO NEXT TO LAST RECORD + STA SUBFCR ;SAVE NEW VALUE OF LAST RECORD IN $$$.SUB + CALL READ ;DE=SUBFCB + JRNZ RB1 ;ABORT $$$.SUB IF ERROR IN READING LAST REC + LXI D,CBUFF ;COPY LAST RECORD (NEXT SUBMIT CMND) TO CBUFF + LXI H,TBUFF ; FROM TBUFF + LXI B,BUFLEN ;NUMBER OF BYTES + LDIR + LXI H,SUBFS2 ;PT TO S2 OF $$$.SUB FCB + MVI M,0 ;SET S2 TO ZERO + INX H ;PT TO RECORD COUNT + DCR M ;DECREMENT RECORD COUNT OF $$$.SUB + LXI D,SUBFCB ;CLOSE $$$.SUB + CALL CLOSE + JRZ RB1 ;ABORT $$$.SUB IF ERROR + MVI A,SPRMPT ;PRINT SUBMIT PROMPT + CALL CONOUT + LXI H,CIBUFF ;PRINT COMMAND LINE FROM $$$.SUB + CALL PRIN1 + CALL BREAK ;CHECK FOR ABORT (ANY CHAR) +; + IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED + RZ ;IF (NO ABORT), RETURN TO CALLER AND RUN + ENDIF +; + IF ~CLEVEL3 ;IF THIRD COMMAND LEVEL IS NOT PERMITTED + JRZ CNVBUF ;IF (NO ABORT), CAPITALIZE COMMAND + ENDIF +; + CALL SUBKIL ;KILL $$$.SUB IF ABORT + JMP RESTRT ;RESTART CPR +; +; INPUT COMMAND LINE FROM USER CONSOLE +; +RB1: + CALL SUBKIL ;ERASE $$$.SUB IF PRESENT + CALL SETUD ;SET USER AND DISK + MVI A,CPRMPT ;PRINT PROMPT + CALL CONOUT + MVI C,0AH ;READ COMMAND LINE FROM USER + LXI D,MBUFF + CALL BDOS +; + IF CLEVEL3 ;IF THIRD COMMAND LEVEL IS PERMITTED + JMP SETU0D ;SET CURRENT DISK NUMBER IN LOWER PARAMS + ENDIF +; + IF ~CLEVEL3 ;IF THIRD COMMAND LEVEL IS NOT PERMITTED + CALL SETU0D ;SET CURRENT DISK NUMBER IF LOWER PARAMS + ; AND FALL THRU TO CNVBUF + ENDIF +; +; CAPITALIZE STRING (ENDING IN 0) IN CBUFF AND SET PTR FOR PARSING +; +CNVBUF: + LXI H,CBUFF ;PT TO USER'S COMMAND + MOV B,M ;CHAR COUNT IN B + INR B ;ADD 1 IN CASE OF ZERO +CB1: + INX H ;PT TO 1ST VALID CHAR + MOV A,M ;CAPITALIZE COMMAND CHAR + CALL UCASE + MOV M,A + DJNZ CB1 ;CONTINUE TO END OF COMMAND LINE +CB2: + MVI M,0 ;STORE ENDING + LXI H,CIBUFF ;SET COMMAND LINE PTR TO 1ST CHAR + SHLD CIBPTR + RET +; +; CHECK FOR ANY CHAR FROM USER CONSOLE;RET W/ZERO SET IF NONE +; +BREAK: + PUSH D ;SAVE DE + MVI C,11 ;CSTS CHECK + CALL BDOSB + CNZ CONIN ;GET INPUT CHAR +BRKBK: + POP D + RET +; +; GET THE REQUESTED USER NUMBER FROM THE COMMAND LINE AND VALIDATE IT. +; +USRNUM: + CALL NUMBER + CPI MAXUSR+1 + RC +; +; INVALID COMMAND -- PRINT IT +; +ERROR: + CALL CRLF ;NEW LINE + LHLD CIPTR ;PT TO BEGINNING OF COMMAND LINE +ERR2: + MOV A,M ;GET CHAR + CPI ' '+1 ;SIMPLE '?' IF OR LESS + JRC ERR1 + PUSH H ;SAVE PTR TO ERROR COMMAND CHAR + CALL CONOUT ;PRINT COMMAND CHAR + POP H ;GET PTR + INX H ;PT TO NEXT + JR ERR2 ;CONTINUE +ERR1: + CALL PRINT ;PRINT '?' + DB '?'+80H + CALL SUBKIL ;TERMINATE ACTIVE $$$.SUB IF ANY + JMP RESTRT ;RESTART CPR +; +; CHECK TO SEE IF DE PTS TO DELIMITER; IF SO, RET W/ZERO FLAG SET +; +SDELM: + LDAX D + ORA A ;0=DELIMITER + RZ + CPI ' ' ;ERROR IF < + JRC ERROR + RZ ;=DELIMITER + CPI '=' ;'='=DELIMITER + RZ + CPI 5FH ;UNDERSCORE=DELIMITER + RZ + CPI '.' ;'.'=DELIMITER + RZ + CPI ':' ;':'=DELIMITER + RZ +;WW CPI ';' ;';'=DELIMITER + CPI 3BH ;';'=DELIMITER + RZ + CPI '<' ;'<'=DELIMITER + RZ + CPI '>' ;'>'=DELIMITER + RET +; +; ADVANCE INPUT PTR TO FIRST NON-BLANK AND FALL THROUGH TO SBLANK +; +ADVAN: + LDED CIBPTR +; +; SKIP STRING PTED TO BY DE (STRING ENDS IN 0) UNTIL END OF STRING +; OR NON-BLANK ENCOUNTERED (BEGINNING OF TOKEN) +; +SBLANK: + LDAX D + ORA A + RZ + CPI ' ' + RNZ + INX D + JR SBLANK +; +; ADD A TO HL (HL=HL+A) +; +ADDAH: + ADD L + MOV L,A + RNC + INR H + RET +; +; EXTRACT DECIMAL NUMBER FROM COMMAND LINE +; RETURN WITH VALUE IN REG A;ALL REGISTERS MAY BE AFFECTED +; +NUMBER: + CALL SCANER ;PARSE NUMBER AND PLACE IN FCBFN + LXI H,FCBFN+10 ;PT TO END OF TOKEN FOR CONVERSION + MVI B,11 ;11 CHARS MAX +; +; CHECK FOR SUFFIX FOR HEXADECIMAL NUMBER +; +NUMS: + MOV A,M ;GET CHARS FROM END, SEARCHING FOR SUFFIX + DCX H ;BACK UP + CPI ' ' ;SPACE? + JRNZ NUMS1 ;CHECK FOR SUFFIX + DJNZ NUMS ;COUNT DOWN + JR NUM0 ;BY DEFAULT, PROCESS +NUMS1: + CPI NUMBASE ;CHECK AGAINST BASE SWITCH FLAG + JRZ HNUM0 +; +; PROCESS DECIMAL NUMBER +; +NUM0: + LXI H,FCBFN ;PT TO BEGINNING OF TOKEN + LXI B,1100H ;C=ACCUMULATED VALUE, B=CHAR COUNT + ; (C=0, B=11) +NUM1: + MOV A,M ;GET CHAR + CPI ' ' ;DONE IF + JRZ NUM2 + INX H ;PT TO NEXT CHAR + SUI '0' ;CONVERT TO BINARY (ASCII 0-9 TO BINARY) + CPI 10 ;ERROR IF >= 10 + JRNC NUMERR + MOV D,A ;DIGIT IN D + MOV A,C ;NEW VALUE = OLD VALUE * 10 + RLC + RLC + RLC + ADD C ;CHECK FOR RANGE ERROR + JRC NUMERR + ADD C ;CHECK FOR RANGE ERROR + JRC NUMERR + ADD D ;NEW VALUE = OLD VALUE * 10 + DIGIT + JRC NUMERR ;CHECK FOR RANGE ERROR + MOV C,A ;SET NEW VALUE + DJNZ NUM1 ;COUNT DOWN +; +; RETURN FROM NUMBER +; +NUM2: + MOV A,C ;GET ACCUMULATED VALUE + RET +; +; NUMBER ERROR ROUTINE FOR SPACE CONSERVATION +; +NUMERR: + JMP ERROR ;USE ERROR ROUTINE - THIS IS RELATIVE PT +; +; EXTRACT HEXADECIMAL NUMBER FROM COMMAND LINE +; RETURN WITH VALUE IN REG A; ALL REGISTERS MAY BE AFFECTED +; +HEXNUM: + CALL SCANER ;PARSE NUMBER AND PLACE IN FCBFN +HNUM0: + LXI H,FCBFN ;PT TO TOKEN FOR CONVERSION + LXI D,0 ;DE=ACCUMULATED VALUE + MVI B,11 ;B=CHAR COUNT +HNUM1: + MOV A,M ;GET CHAR + CPI ' ' ;DONE? + JRZ HNUM3 ;RETURN IF SO + CPI NUMBASE ;DONE IF NUMBASE SUFFIX + JRZ HNUM3 + SUI '0' ;CONVERT TO BINARY + JRC NUMERR ;RETURN AND DONE IF ERROR + CPI 10 ;0-9? + JRC HNUM2 + SUI 7 ;A-F? + CPI 10H ;ERROR? + JRNC NUMERR +HNUM2: + INX H ;PT TO NEXT CHAR + MOV C,A ;DIGIT IN C + MOV A,D ;GET ACCUMULATED VALUE + RLC ;EXCHANGE NYBBLES + RLC + RLC + RLC + ANI 0F0H ;MASK OUT LOW NYBBLE + MOV D,A + MOV A,E ;SWITCH LOW-ORDER NYBBLES + RLC + RLC + RLC + RLC + MOV E,A ;HIGH NYBBLE OF E=NEW HIGH OF E, + ; LOW NYBBLE OF E=NEW LOW OF D + ANI 0FH ;GET NEW LOW OF D + ORA D ;MASK IN HIGH OF D + MOV D,A ;NEW HIGH BYTE IN D + MOV A,E + ANI 0F0H ;MASK OUT LOW OF E + ORA C ;MASK IN NEW LOW + MOV E,A ;NEW LOW BYTE IN E + DJNZ HNUM1 ;COUNT DOWN +; +; RETURN FROM HEXNUM +; +HNUM3: + XCHG ;RETURNED VALUE IN HL + MOV A,L ;LOW-ORDER BYTE IN A + RET +; +; PT TO DIRECTORY ENTRY IN TBUFF WHOSE OFFSET IS SPECIFIED BY A AND C +; +DIRPTR: + LXI H,TBUFF ;PT TO TEMP BUFFER + ADD C ;PT TO 1ST BYTE OF DIR ENTRY + CALL ADDAH ;PT TO DESIRED BYTE IN DIR ENTRY + MOV A,M ;GET DESIRED BYTE + RET +; +; CHECK FOR SPECIFIED DRIVE AND LOG IT IN IF NOT DEFAULT +; +SLOGIN: + XRA A ;SET FCBDN FOR DEFAULT DRIVE + STA FCBDN + CALL COMLOG ;CHECK DRIVE + RZ + JR DLOG5 ;DO LOGIN OTHERWISE +; +; CHECK FOR SPECIFIED DRIVE AND LOG IN DEFAULT DRIVE IF SPECIFIED<>DEFAULT +; +DLOGIN: + CALL COMLOG ;CHECK DRIVE + RZ ;ABORT IF SAME + LDA TDRIVE ;LOG IN DEFAULT DRIVE +; +DLOG5: JMP LOGIN +; +; ROUTINE COMMON TO BOTH LOGIN ROUTINES; ON EXIT, Z SET MEANS ABORT +; +COMLOG: +TEMPDR EQU $+1 ;POINTER FOR IN-THE-CODE MODIFICATION + MVI A,0 ;2ND BYTE (IMMEDIATE ARG) IS TEMPDR + ORA A ;0=NO + RZ + DCR A ;COMPARE IT AGAINST DEFAULT + LXI H,TDRIVE + CMP M + RET ;ABORT IF SAME +; +; EXTRACT TOKEN FROM COMMAND LINE AND PLACE IT INTO FCBDN; +; FORMAT FCBDN FCB IF TOKEN RESEMBLES FILE NAME AND TYPE (FILENAME.TYP); +; ON INPUT, CIBPTR PTS TO CHAR AT WHICH TO START SCAN; +; ON OUTPUT, CIBPTR PTS TO CHAR AT WHICH TO CONTINUE AND ZERO FLAG IS RESET +; IF '?' IS IN TOKEN +; +; ENTRY POINTS: +; SCANER - LOAD TOKEN INTO FIRST FCB +; SCANX - LOAD TOKEN INTO FCB PTED TO BY HL +; +SCANER: + LXI H,FCBDN ;POINT TO FCBDN +SCANX: + XRA A ;SET TEMPORARY DRIVE NUMBER TO DEFAULT + STA TEMPDR + CALL ADVAN ;SKIP TO NON-BLANK OR END OF LINE + SDED CIPTR ;SET PTR TO NON-BLANK OR END OF LINE + LDAX D ;END OF LINE? + ORA A ;0=YES + JRZ SCAN2 + SBI 'A'-1 ;CONVERT POSSIBLE DRIVE SPEC TO NUMBER + MOV B,A ;STORE NUMBER (A:=0, B:=1, ETC) IN B + INX D ;PT TO NEXT CHAR + LDAX D ;SEE IF IT IS A COLON (:) + CPI ':' + JRZ SCAN3 ;YES, WE HAVE A DRIVE SPEC + DCX D ;NO, BACK UP PTR TO FIRST NON-BLANK CHAR +SCAN2: + LDA TDRIVE ;SET 1ST BYTE OF FCBDN AS DEFAULT DRIVE + MOV M,A + JR SCAN4 +SCAN3: + MOV A,B ;WE HAVE A DRIVE SPEC + STA TEMPDR ;SET TEMPORARY DRIVE + MOV M,B ;SET 1ST BYTE OF FCBDN AS SPECIFIED DRIVE + INX D ;PT TO BYTE AFTER ':' +; +; EXTRACT FILENAME FROM POSSIBLE FILENAME.TYP +; +SCAN4: + XRA A ;A=0 + STA QMCNT ;INIT COUNT OF NUMBER OF QUESTION MARKS IN FCB + MVI B,8 ;MAX OF 8 CHARS IN FILE NAME + CALL SCANF ;FILL FCB FILE NAME +; +; EXTRACT FILE TYPE FROM POSSIBLE FILENAME.TYP +; + MVI B,3 ;PREPARE TO EXTRACT TYPE + CPI '.' ;IF (DE) DELIMITER IS A '.', WE HAVE A TYPE + JRNZ SCAN15 ;FILL FILE TYPE BYTES WITH + INX D ;PT TO CHAR IN COMMAND LINE AFTER '.' + CALL SCANF ;FILL FCB FILE TYPE + JR SCAN16 ;SKIP TO NEXT PROCESSING +SCAN15: + CALL SCANF4 ;SPACE FILL +; +; FILL IN EX, S1, S2, AND RC WITH ZEROES +; +SCAN16: + MVI B,4 ;4 BYTES +SCAN17: + INX H ;PT TO NEXT BYTE IN FCBDN + MVI M,0 + DJNZ SCAN17 +; +; SCAN COMPLETE -- DE PTS TO DELIMITER BYTE AFTER TOKEN +; + SDED CIBPTR +; +; SET ZERO FLAG TO INDICATE PRESENCE OF '?' IN FILENAME.TYP +; + LDA QMCNT ;GET NUMBER OF QUESTION MARKS + ORA A ;SET ZERO FLAG TO INDICATE ANY '?' + RET +; +; SCANF -- SCAN TOKEN PTED TO BY DE FOR A MAX OF B BYTES; PLACE IT INTO +; FILE NAME FIELD PTED TO BY HL; EXPAND AND INTERPRET WILD CARDS OF +; '*' AND '?'; ON EXIT, DE PTS TO TERMINATING DELIMITER +; +SCANF: + CALL SDELM ;DONE IF DELIMITER ENCOUNTERED - FILL + JRZ SCANF4 + INX H ;PT TO NEXT BYTE IN FCBDN + CPI '*' ;IS (DE) A WILD CARD? + JRNZ SCANF1 ;CONTINUE IF NOT + MVI M,'?' ;PLACE '?' IN FCBDN AND DON'T ADVANCE DE IF SO + CALL SCQ ;SCANNER COUNT QUESTION MARKS + JR SCANF2 +SCANF1: + MOV M,A ;STORE FILENAME CHAR IN FCBDN + INX D ;PT TO NEXT CHAR IN COMMAND LINE + CPI '?' ;CHECK FOR QUESTION MARK (WILD) + CZ SCQ ;SCANNER COUNT QUESTION MARKS +SCANF2: + DJNZ SCANF ;DECREMENT CHAR COUNT UNTIL 8 ELAPSED +SCANF3: + CALL SDELM ;8 CHARS OR MORE - SKIP UNTIL DELIMITER + RZ ;ZERO FLAG SET IF DELIMITER FOUND + INX D ;PT TO NEXT CHAR IN COMMAND LINE + JR SCANF3 +; +; FILL MEMORY POINTED TO BY HL WITH SPACES FOR B BYTES +; +SCANF4: + INX H ;PT TO NEXT BYTE IN FCBDN + MVI M,' ' ;FILL FILENAME PART WITH + DJNZ SCANF4 + RET +; +; INCREMENT QUESTION MARK COUNT FOR SCANNER +; THIS ROUTINE INCREMENTS THE COUNT OF THE NUMBER OF QUESTION MARKS IN +; THE CURRENT FCB ENTRY +; +SCQ: + LDA QMCNT ;GET COUNT + INR A ;INCREMENT + STA QMCNT ;PUT COUNT + RET +; +; CMDTBL (COMMAND TABLE) SCANNER +; ON RETURN, HL PTS TO ADDRESS OF COMMAND IF CPR-RESIDENT +; ON RETURN, ZERO FLAG SET MEANS CPR-RESIDENT COMMAND +; +CMDSER: + LXI H,CMDTBL ;PT TO COMMAND TABLE + MVI C,NCMNDS ;SET COMMAND COUNTER +CMS1: + LXI D,FCBFN ;PT TO STORED COMMAND NAME + MVI B,NCHARS ;NUMBER OF CHARS/COMMAND (8 MAX) +CMS2: + LDAX D ;COMPARE AGAINST TABLE ENTRY + CMP M + JRNZ CMS3 ;NO MATCH + INX D ;PT TO NEXT CHAR + INX H + DJNZ CMS2 ;COUNT DOWN + LDAX D ;NEXT CHAR IN INPUT COMMAND MUST BE + CPI ' ' + JRNZ CMS4 + RET ;COMMAND IS CPR-RESIDENT (ZERO FLAG SET) +CMS3: + INX H ;SKIP TO NEXT COMMAND TABLE ENTRY + DJNZ CMS3 +CMS4: + INX H ;SKIP ADDRESS + INX H + DCR C ;DECREMENT TABLE ENTRY NUMBER + JRNZ CMS1 + INR C ;CLEAR ZERO FLAG + RET ;COMMAND IS DISK-RESIDENT (ZERO FLAG CLEAR) +; +;**** Section 5 **** +; CPR-Resident Commands +; +; +;Section 5A +;Command: DIR +;Function: To display a directory of the files on disk +;Forms: +; DIR Displays the DIR files +; DIR S Displays the SYS files +; DIR A Display both DIR and SYS files +; +DIR: + MVI A,80H ;SET SYSTEM BIT EXAMINATION + PUSH PSW + CALL SCANER ;EXTRACT POSSIBLE D:FILENAME.TYP TOKEN + CALL SLOGIN ;LOG IN DRIVE IF NECESSARY + LXI H,FCBFN ;MAKE FCB WILD (ALL '?') IF NO FILENAME.TYP + MOV A,M ;GET FIRST CHAR OF FILENAME.TYP + CPI ' ' ;IF , ALL WILD + CZ FILLQ + CALL ADVAN ;LOOK AT NEXT INPUT CHAR + MVI B,0 ;SYS TOKEN DEFAULT + JRZ DIR2 ;JUMP; THERE ISN'T ONE + CPI SYSFLG ;SYSTEM FLAG SPECIFIER? + JRZ GOTSYS ;GOT SYSTEM SPECIFIER + CPI SOFLG ;SYS ONLY? + JRNZ DIR2 + MVI B,80H ;FLAG SYS ONLY +GOTSYS: + INX D + SDED CIBPTR + CPI SOFLG ;SYS ONLY SPEC? + JRZ DIR2 ;THEN LEAVE BIT SPEC UNCHAGNED + POP PSW ;GET FLAG + XRA A ;SET NO SYSTEM BIT EXAMINATION + PUSH PSW +DIR2: + POP PSW ;GET FLAG +DIR2A: + ;DROP INTO DIRPR TO PRINT DIRECTORY + ; THEN RESTART CPR +; +; DIRECTORY PRINT ROUTINE; ON ENTRY, MSB OF A IS 1 (80H) IF SYSTEM FILES EXCL +; +DIRPR: + MOV D,A ;STORE SYSTEM FLAG IN D + MVI E,0 ;SET COLUMN COUNTER TO ZERO + PUSH D ;SAVE COLUMN COUNTER (E) AND SYSTEM FLAG (D) + MOV A,B ;SYS ONLY SPECIFIER + STA SYSTST + CALL SEARF ;SEARCH FOR SPECIFIED FILE (FIRST OCCURRANCE) + CZ PRNNF ;PRINT NO FILE MSG;REG A NOT CHANGED +; +; ENTRY SELECTION LOOP; ON ENTRY, A=OFFSET FROM SEARF OR SEARN +; +DIR3: + JRZ DIR11 ;DONE IF ZERO FLAG SET + DCR A ;ADJUST TO RETURNED VALUE + RRC ;CONVERT NUMBER TO OFFSET INTO TBUFF + RRC + RRC + ANI 60H + MOV C,A ;OFFSET INTO TBUFF IN C (C=OFFSET TO ENTRY) + MVI A,10 ;ADD 10 TO PT TO SYSTEM FILE ATTRIBUTE BIT + CALL DIRPTR + POP D ;GET SYSTEM BIT MASK FROM D + PUSH D + ANA D ;MASK FOR SYSTEM BIT +SYSTST EQU $+1 ;POINTER TO IN-THE-CODE BUFFER SYSTST + CPI 0 + JRNZ DIR10 + POP D ;GET ENTRY COUNT (= COUNTER) + MOV A,E ;ADD 1 TO IT + INR E + PUSH D ;SAVE IT + ANI 03H ;OUTPUT IF 4 ENTRIES PRINTED IN LINE + PUSH PSW + JRNZ DIR4 + CALL CRLF ;NEW LINE + JR DIR5 +DIR4: + CALL PRINT +; + IF WIDE + DB " " ;2 SPACES + DB FENCE ;THEN FENCE CHAR + DB ' ',' '+80H ;THEN 2 MORE SPACES + ENDIF +; + IF ~WIDE + DB ' ' ;SPACE + DB FENCE ;THEN FENCE CHAR + DB ' '+80H ;THEN SPACE + ENDIF +; +DIR5: + MVI B,01H ;PT TO 1ST BYTE OF FILE NAME +DIR6: + MOV A,B ;A=OFFSET + CALL DIRPTR ;HL NOW PTS TO 1ST BYTE OF FILE NAME + ANI 7FH ;MASK OUT MSB + CPI ' ' ;NO FILE NAME? + JRNZ DIR8 ;PRINT FILE NAME IF PRESENT + POP PSW + PUSH PSW + CPI 03H + JRNZ DIR7 + MVI A,09H ;PT TO 1ST BYTE OF FILE TYPE + CALL DIRPTR ;HL NOW PTS TO 1ST BYTE OF FILE TYPE + ANI 7FH ;MASK OUT MSB + CPI ' ' ;NO FILE TYPE? + JRZ DIR9 ;CONTINUE IF SO +DIR7: + MVI A,' ' ;OUTPUT +DIR8: + CALL CONOUT ;PRINT CHAR + INR B ;INCR CHAR COUNT + MOV A,B + CPI 12 ;END OF FILENAME.TYP? + JRNC DIR9 ;CONTINUE IF SO + CPI 09H ;END IF FILENAME ONLY? + JRNZ DIR6 ;PRINT TYP IF SO + MVI A,'.' ;PRINT DOT BETWEEN FILE NAME AND TYPE + CALL CONOUT + JR DIR6 +DIR9: + POP PSW +DIR10: + CALL BREAK ;CHECK FOR ABORT + JRNZ DIR11 + CALL SEARN ;SEARCH FOR NEXT FILE + JR DIR3 ;CONTINUE +DIR11: + POP D ;RESTORE STACK + RET +; +; FILL FCB @HL WITH '?' +; +FILLQ: + MVI B,11 ;NUMBER OF CHARS IN FN & FT +FQLP: + MVI M,'?' ;STORE '?' + INX H + DJNZ FQLP + RET +; +;Section 5B +;Command: ERA +;Function: Erase files +;Forms: +; ERA Erase Specified files and print their names +; + IF ~RAS ;NOT FOR REMOTE-ACCESS SYSTEM +; +ERA: + CALL SCANER ;PARSE FILE SPECIFICATION + CPI 11 ;ALL WILD (ALL FILES = 11 '?')? + JRNZ ERA1 ;IF NOT, THEN DO ERASES + CALL PRINTC + DB "All",'?'+80H + CALL CONIN ;GET REPLY + CPI 'Y' ;YES? + JNZ RESTRT ;RESTART CPR IF NOT + CALL CRLF ;NEW LINE +ERA1: + CALL SLOGIN ;LOG IN SELECTED DISK IF ANY + XRA A ;PRINT ALL FILES (EXAMINE SYSTEM BIT) + MOV B,A ;NO SYS-ONLY OPT TO DIRPR + CALL DIRPR ;PRINT DIRECTORY OF ERASED FILES + LXI D,FCBDN ;DELETE FILE SPECIFIED + CALL DELETE + RET ;REENTER CPR +; + ENDIF ;RAS +; +;Section 5C +;Command: LIST +;Function: Print out specified file on the LST: Device +;Forms: +; LIST Print file (NO Paging) +; +LIST: + MVI A,0FFH ;TURN ON PRINTER FLAG + JR TYPE0 +; +;Section 5D +;Command: TYPE +;Function: Print out specified file on the CON: Device +;Forms: +; TYPE Print file +; TYPE P Print file with paging flag +; +TYPE: + XRA A ;TURN OFF PRINTER FLAG +; +; ENTRY POINT FOR CPR LIST FUNCTION (LIST) +; +TYPE0: + STA PRFLG ;SET FLAG + CALL SCANER ;EXTRACT FILENAME.TYP TOKEN + JNZ ERROR ;ERROR IF ANY QUESTION MARKS + CALL ADVAN ;GET PGDFLG IF IT'S THERE + STA PGFLG ;SAVE IT AS A FLAG + JRZ NOSLAS ;JUMP IF INPUT ENDED + INX D ;PUT NEW BUF POINTER + XCHG + SHLD CIBPTR +NOSLAS: + CALL SLOGIN ;LOG IN SELECTED DISK IF ANY + CALL OPENF ;OPEN SELECTED FILE + JZ TYPE4 ;ABORT IF ERROR + CALL CRLF ;NEW LINE + MVI A,NLINES-1 ;SET LINE COUNT + STA PAGCNT + LXI H,CHRCNT ;SET CHAR POSITION/COUNT + MVI M,0FFH ;EMPTY LINE + MVI B,0 ;SET TAB CHAR COUNTER +TYPE1: + LXI H,CHRCNT ;PT TO CHAR POSITION/COUNT + MOV A,M ;END OF BUFFER? + CPI 80H + JRC TYPE2 + PUSH H ;READ NEXT BLOCK + CALL READF + POP H + JRNZ TYPE3 ;ERROR? + XRA A ;RESET COUNT + MOV M,A +TYPE2: + INR M ;INCREMENT CHAR COUNT + LXI H,TBUFF ;PT TO BUFFER + CALL ADDAH ;COMPUTE ADDRESS OF NEXT CHAR FROM OFFSET + MOV A,M ;GET NEXT CHAR + ANI 7FH ;MASK OUT MSB + CPI 1AH ;END OF FILE (^Z)? + RZ ;RESTART CPR IF SO +; +; OUTPUT CHAR TO CON: OR LST: DEVICE WITH TABULATION +; + CPI CR ;RESET TAB COUNT? + JRZ TABRST + CPI LF ;RESET TAB COUNT? + JRZ TABRST + CPI TAB ;TAB? + JRZ LTAB + CALL LCOUT ;OUTPUT CHAR + INR B ;INCREMENT CHAR COUNT + JR TYPE2L +TABRST: + CALL LCOUT ;OUTPUT OR + MVI B,0 ;RESET TAB COUNTER + JR TYPE2L +LTAB: + MVI A,' ' ; + CALL LCOUT + INR B ;INCR POS COUNT + MOV A,B + ANI 7 + JRNZ LTAB +; +; CONTINUE PROCESSING +; +TYPE2L: + CALL BREAK ;CHECK FOR ABORT + JRZ TYPE1 ;CONTINUE IF NO CHAR + CPI 'C'-'@' ;^C? + RZ ;RESTART IF SO + JR TYPE1 +TYPE3: + DCR A ;NO ERROR? + RZ ;RESTART CPR +TYPE4: + JMP ERRLOG +; +; PAGING ROUTINES +; PAGER COUNTS DOWN LINES AND PAUSES FOR INPUT (DIRECT) IF COUNT EXPIRES +; PAGSET SETS LINES/PAGE COUNT +; +PAGER: + PUSH H + LXI H,PAGCNT ;COUNT DOWN + DCR M + JRNZ PGBAK ;JUMP IF NOT END OF PAGE + MVI M,NLINES-2 ;REFILL COUNTER +; +PGFLG EQU $+1 ;POINTER TO IN-THE-CODE BUFFER PGFLG + MVI A,0 ;0 MAY BE CHANGED BY PGFLG EQUATE + CPI PGDFLG ;PAGE DEFAULT OVERRIDE OPTION WANTED? +; + IF PGDFLT ;IF PAGING IS DEFAULT + JRZ PGBAK ; PGDFLG MEANS NO PAGING, PLEASE + ELSE ;IF PAGING NOT DEFAULT + JRNZ PGBAK ; PGDFLG MEANS PLEASE PAGINATE + ENDIF +; + CALL CONIN ;GET CHAR TO CONTINUE + CPI 'C'-'@' ;^C + JZ RSTCPR ;RESTART CPR +PGBAK: + POP H ;RESTORE HL + RET +; +;Section 5E +;Command: SAVE +;Function: To save the contents of the TPA onto disk as a file +;Forms: +; SAVE +; Save specified number of pages (start at 100H) +; from TPA into specified file; is in DEC +; SAVE S +; Like SAVE above, but numeric argument specifies +; number of sectors rather than pages +; + IF ~RAS ;NOT FOR REMOTE-ACCESS SYSTEM +; +SAVE: + CALL NUMBER ;EXTRACT NUMBER FROM COMMAND LINE + MOV L,A ;HL=PAGE COUNT + MVI H,0 + PUSH H ;SAVE PAGE COUNT + CALL EXTEST ;TEST FOR EXISTENCE OF FILE AND ABORT IF SO + MVI C,16H ;BDOS MAKE FILE + CALL GRBDOS + POP H ;GET PAGE COUNT + JRZ SAVE3 ;ERROR? + XRA A ;SET RECORD COUNT FIELD OF NEW FILE'S FCB + STA FCBCR + CALL ADVAN ;LOOK FOR 'S' FOR SECTOR OPTION + INX D ;PT TO AFTER 'S' TOKEN + CPI SECTFLG + JRZ SAVE0 + DCX D ;NO 'S' TOKEN, SO BACK UP + DAD H ;DOUBLE IT FOR HL=SECTOR (128 BYTES) COUNT +SAVE0: + SDED CIBPTR ;SET PTR TO BAD TOKEN OR AFTER GOOD TOKEN + LXI D,TPA ;PT TO START OF SAVE AREA (TPA) +SAVE1: + MOV A,H ;DONE WITH SAVE? + ORA L ;HL=0 IF SO + JRZ SAVE2 + DCX H ;COUNT DOWN ON SECTORS + PUSH H ;SAVE PTR TO BLOCK TO SAVE + LXI H,128 ;128 BYTES PER SECTOR + DAD D ;PT TO NEXT SECTOR + PUSH H ;SAVE ON STACK + CALL DMASET ;SET DMA ADDRESS FOR WRITE (ADDRESS IN DE) + LXI D,FCBDN ;WRITE SECTOR + MVI C,15H ;BDOS WRITE SECTOR + CALL BDOSB ;SAVE BC + POP D ;GET PTR TO NEXT SECTOR IN DE + POP H ;GET SECTOR COUNT + JRNZ SAVE3 ;WRITE ERROR? + JR SAVE1 ;CONTINUE +SAVE2: + LXI D,FCBDN ;CLOSE SAVED FILE + CALL CLOSE + INR A ;ERROR? + JRNZ SAVE4 +SAVE3: + CALL PRNLE ;PRINT 'NO SPACE' ERROR +SAVE4: + CALL DEFDMA ;SET DMA TO 0080 + RET ;RESTART CPR +; +; Test File in FCB for existence, ask user to delete if so, and abort if he +; choses not to +; +EXTEST: + CALL SCANER ;EXTRACT FILE NAME + JNZ ERROR ;'?' IS NOT PERMITTED + CALL SLOGIN ;LOG IN SELECTED DISK + CALL SEARF ;LOOK FOR SPECIFIED FILE + LXI D,FCBDN ;PT TO FILE FCB + RZ ;OK IF NOT FOUND + PUSH D ;SAVE PTR TO FCB + CALL PRINTC + DB "Delete File",'?'+80H + CALL CONIN ;GET RESPONSE + POP D ;GET PTR TO FCB + CPI 'Y' ;KEY ON YES + JNZ RSTCPR ;RESTART IF NO + PUSH D ;SAVE PTR TO FCB + CALL DELETE ;DELETE FILE + POP D ;GET PTR TO FCB + RET +; + ENDIF ;RAS +; +;Section 5F +;Command: REN +;Function: To change the name of an existing file +;Forms: +; REN = Perform function +; + IF ~RAS ;NOT FOR REMOTE-ACCESS SYSTEM +; +REN: + CALL EXTEST ;TEST FOR FILE EXISTENCE AND RETURN + ; IF FILE DOESN'T EXIST; ABORT IF IT DOES + LDA TEMPDR ;SAVE CURRENT DEFAULT DISK + PUSH PSW ;SAVE ON STACK +REN0: + LXI H,FCBDN ;SAVE NEW FILE NAME + LXI D,FCBDM + LXI B,16 ;16 BYTES + LDIR + CALL ADVAN ;ADVANCE CIBPTR + CPI '=' ;'=' OK + JRNZ REN4 +REN1: + XCHG ;PT TO CHAR AFTER '=' IN HL + INX H + SHLD CIBPTR ;SAVE PTR TO OLD FILE NAME + CALL SCANER ;EXTRACT FILENAME.TYP TOKEN + JRNZ REN4 ;ERROR IF ANY '?' + POP PSW ;GET OLD DEFAULT DRIVE + MOV B,A ;SAVE IT + LXI H,TEMPDR ;COMPARE IT AGAINST CURRENT DEFAULT DRIVE + MOV A,M ;MATCH? + ORA A + JRZ REN2 + CMP B ;CHECK FOR DRIVE ERROR + MOV M,B + JRNZ REN4 +REN2: + MOV M,B + XRA A + STA FCBDN ;SET DEFAULT DRIVE + LXI D,FCBDN ;RENAME FILE + MVI C,17H ;BDOS RENAME FCT + CALL GRBDOS + RNZ +REN3: + CALL PRNNF ;PRINT NO FILE MSG +REN4: + JMP ERRLOG +; + ENDIF ;RAS +; +;Section 5G +;Command: USER +;Function: Change current USER number +;Forms: +; USER Select specified user number; is in DEC +; +USER: + CALL USRNUM ;EXTRACT USER NUMBER FROM COMMAND LINE + MOV E,A ;PLACE USER NUMBER IN E + CALL SETUSR ;SET SPECIFIED USER +RSTJMP: + JMP RCPRNL ;RESTART CPR +; +;Section 5H +;Command: DFU +;Function: Set the Default User Number for the command/file scanner +; (MEMLOAD) +;Forms: +; DFU Select Default User Number; is in DEC +; +DFU: + CALL USRNUM ;GET USER NUMBER + STA DFUSR ;PUT IT AWAY + JR RSTJMP ;RESTART CPR (NO DEFAULT LOGIN) +; +;Section 5I +;Command: JUMP +;Function: To Call the program (subroutine) at the specified address +; without loading from disk +;Forms: +; JUMP Call at ; is in HEX +; + IF ~RAS ;NOT FOR REMOTE-ACCESS SYSTEM +; +JUMP: + CALL HEXNUM ;GET LOAD ADDRESS IN HL + JR CALLPROG ;PERFORM CALL +; + ENDIF ;RAS +; +;Section 5J +;Command: GO +;Function: To Call the program in the TPA without loading +; loading from disk. Same as JUMP 100H, but much +; more convenient, especially when used with +; parameters for programs like STAT. Also can be +; allowed on remote-access systems with no problems. +; +;Form: +; GO +; + IF ~RAS ;ONLY IF RAS +; +GO: LXI H,TPA ;Always to TPA + JR CALLPROG ;Perform call +; + ENDIF ;END OF GO FOR RAS +; +;Section 5K +;Command: COM file processing +;Function: To load the specified COM file from disk and execute it +;Forms: +; +; +COM: + LDA FCBFN ;ANY COMMAND? + CPI ' ' ;' ' MEANS COMMAND WAS 'D:' TO SWITCH + JRNZ COM1 ;NOT , SO MUST BE TRANSIENT OR ERROR + LDA TEMPDR ;LOOK FOR DRIVE SPEC + ORA A ;IF ZERO, JUST BLANK + JZ RCPRNL + DCR A ;ADJUST FOR LOG IN + STA TDRIVE ;SET DEFAULT DRIVE + CALL SETU0D ;SET DRIVE WITH USER 0 + CALL LOGIN ;LOG IN DRIVE + JMP RCPRNL ;RESTART CPR +COM1: + LDA FCBFT ;FILE TYPE MUST BE BLANK + CPI ' ' + JNZ ERROR + LXI H,COMMSG ;PLACE DEFAULT FILE TYPE (COM) INTO FCB + LXI D,FCBFT ;COPY INTO FILE TYPE + LXI B,3 ;3 BYTES + LDIR + LXI H,TPA ;SET EXECUTION/LOAD ADDRESS + PUSH H ;SAVE FOR EXECUTION + CALL MEMLOAD ;LOAD MEMORY WITH FILE SPECIFIED IN CMD LINE + POP H ;GET EXECUTION ADDRESS + RNZ ;RETURN (ABORT) IF LOAD ERROR +; +; CALLPROG IS THE ENTRY POINT FOR THE EXECUTION OF THE LOADED +; PROGRAM;ON ENTRY TO THIS ROUTINE, HL MUST CONTAIN THE EXECUTION +; ADDRESS OF THE PROGRAM (SUBROUTINE) TO EXECUTE +; +CALLPROG: + SHLD EXECADR ;PERFORM IN-LINE CODE MODIFICATION + CALL DLOGIN ;LOG IN DEFAULT DRIVE + CALL SCANER ;SEARCH COMMAND LINE FOR NEXT TOKEN + LXI H,TEMPDR ;SAVE PTR TO DRIVE SPEC + PUSH H + MOV A,M ;SET DRIVE SPEC + STA FCBDN + LXI H,FCBDN+10H ;PT TO 2ND FILE NAME + CALL SCANX ;SCAN FOR IT AND LOAD IT INTO FCBDN+16 + POP H ;SET UP DRIVE SPECS + MOV A,M + STA FCBDM + XRA A + STA FCBCR + LXI D,TFCB ;COPY TO DEFAULT FCB + LXI H,FCBDN ;FROM FCBDN + LXI B,33 ;SET UP DEFAULT FCB + LDIR + LXI H,CIBUFF +COM4: + MOV A,M ;SKIP TO END OF 2ND FILE NAME + ORA A ;END OF LINE? + JRZ COM5 + CPI ' ' ;END OF TOKEN? + JRZ COM5 + INX H + JR COM4 +; +; LOAD COMMAND LINE INTO TBUFF +; +COM5: + MVI B,0 ;SET CHAR COUNT + LXI D,TBUFF+1 ;PT TO CHAR POS +COM6: + MOV A,M ;COPY COMMAND LINE TO TBUFF + STAX D + ORA A ;DONE IF ZERO + JRZ COM7 + INR B ;INCR CHAR COUNT + INX H ;PT TO NEXT + INX D + JR COM6 +; +; RUN LOADED TRANSIENT PROGRAM +; +COM7: + MOV A,B ;SAVE CHAR COUNT + STA TBUFF + CALL CRLF ;NEW LINE + CALL DEFDMA ;SET DMA TO 0080 + CALL SETUD ;SET USER/DISK +; +; EXECUTION (CALL) OF PROGRAM (SUBROUTINE) OCCURS HERE +; +EXECADR EQU $+1 ;CHANGE ADDRESS FOR IN-LINE CODE MODIFICATION + CALL TPA ;CALL TRANSIENT + CALL DEFDMA ;SET DMA TO 0080, IN CASE + ;PROG CHANGED IT ON US + CALL SETU0D ;SET USER 0/DISK + CALL LOGIN ;LOGIN DISK + JMP RESTRT ;RESTART CPR +; +; TRANSIENT LOAD ERROR +; +COM8: + POP H ;CLEAR RETURN ADDRESS + CALL RESETUSR ;RESET CURRENT USER NUMBER + ; RESET MUST BE DONE BEFORE LOGIN +ERRLOG: + CALL DLOGIN ;LOG IN DEFAULT DISK +ERRJMP: + JMP ERROR +; +;Section 5L +;Command: GET +;Function: To load the specified file from disk to the specified address +;Forms: +; GET Load the specified file at the specified page; +; is in HEX +; + IF ~RAS ;NOT FOR REMOTE-ACCESS SYSTEM +; +GET: + CALL HEXNUM ;GET LOAD ADDRESS IN HL + PUSH H ;SAVE ADDRESS + CALL SCANER ;GET FILE NAME + POP H ;RESTORE ADDRESS + JRNZ ERRJMP ;MUST BE UNAMBIGUOUS +; +; FALL THRU TO MEMLOAD +; + ENDIF ;RAS +; +; LOAD MEMORY WITH THE FILE WHOSE NAME IS SPECIFIED IN THE COMMAND LINE +; ON INPUT, HL CONTAINS STARTING ADDRESS TO LOAD +; +MEMLOAD: + CALL MLOAD ;USER MEMORY LOAD SUBROUTINE + PUSH PSW ;SAVE RETURN STATUS + CALL RESETUSR ;RESET USER NUMBER + POP PSW ;GET RETURN STATUS + RET + +; +; MEMORY LOAD SUBROUTINE +; EXIT POINTS ARE A SIMPLE RETURN WITH THE ZERO FLAG SET IF NO ERROR, +; A SIMPLE RETURN WITH THE ZERO FLAG RESET (NZ) IF MEMORY FULL, OR A JMP TO +; COM8 IF COM FILE NOT FOUND +; +MLOAD: + SHLD LOADADR ;SET LOAD ADDRESS + CALL GETUSR ;GET CURRENT USER NUMBER + STA TMPUSR ;SAVE IT FOR LATER + STA TSELUSR ;TEMP USER TO SELECT +; +; MLA is a reentry point for a non-standard CP/M Modification +; This is the return point for when the .COM (or GET) file is not found the +; first time, Drive A: is selected for a second attempt +; +MLA: + CALL SLOGIN ;LOG IN SPECIFIED DRIVE IF ANY + CALL OPENF ;OPEN COMMAND.COM FILE + JRNZ MLA1 ;FILE FOUND - LOAD IT +; +; ERROR ROUTINE TO SELECT USER 0 IF ALL ELSE FAILS +; +DFUSR EQU $+1 ;MARK IN-THE-CODE VARIABLE + MVI A,DEFUSR ;GET DEFAULT USER +TSELUSR EQU $+1 ;MARK IN-THE-CODE VARIABLE + CPI DEFUSR ;SAME? + JRZ MLA0 ;JUMP IF + STA TSELUSR ;ELSE PUT DOWN NEW ONE + MOV E,A + CALL SETUSR ;GO SET NEW USER NUMBER + JR MLA ;AND TRY AGAIN +; +; ERROR ROUTINE TO SELECT DRIVE A: IF DEFAULT WAS ORIGINALLY SELECTED +; +MLA0: + LXI H,TEMPDR ;GET DRIVE FROM CURRENT COMMAND + XRA A ;A=0 + ORA M + JNZ COM8 ;ERROR IF ALREADY DISK A: + MVI M,1 ;SELECT DRIVE A: + JR MLA +; +; FILE FOUND -- PROCEED WITH LOAD +; +MLA1: +LOADADR EQU $+1 ;MEMORY LOAD ADDRESS (IN-LINE CODE MOD) + LXI H,TPA ;SET START ADDRESS OF MEMORY LOAD +ML2: + MVI A,ENTRY/256-1 ;GET HIGH-ORDER ADR OF JUST BELOW CPR + CMP H ;ARE WE GOING TO OVERWRITE THE CPR? + JRC PRNLE ;ERROR IF SO + PUSH H ;SAVE ADDRESS OF NEXT SECTOR + XCHG ;... IN DE + CALL DMASET ;SET DMA ADDRESS FOR LOAD + LXI D,FCBDN ;READ NEXT SECTOR + CALL READ + POP H ;GET ADDRESS OF NEXT SECTOR + JRNZ ML3 ;READ ERROR OR EOF? + LXI D,128 ;MOVE 128 BYTES PER SECTOR + DAD D ;PT TO NEXT SECTOR IN HL + JR ML2 +; +ML3: + DCR A ;LOAD COMPLETE + RZ ;OK IF ZERO, ELSE FALL THRU TO PRNLE +; +; LOAD ERROR +; +PRNLE: + CALL PRINTC + DB "Ful",'l'+80H + MVI A,1 ;SET NON-ZERO TO INDICATE ERROR + ORA A ;SET FLAG + RET +; + END diff --git a/trunk/Source/zcprw.asm b/trunk/Source/zcprw.asm new file mode 100644 index 00000000..ed5c2838 --- /dev/null +++ b/trunk/Source/zcprw.asm @@ -0,0 +1,64 @@ +; +;================================================================================================== +; WRAPPER FOR ZCPR FOR N8VEM PROJECT +; WAYNE WARTHEN - 2011-01-10 +;================================================================================================== +; +; THE FOLLOWING MACROS DO THE HEAVY LIFTING TO MAKE THE ZCPR SOURCE +; COMPATIBLE WITH TASM +; +;#DEFINE DS .DS +;#DEFINE ds .ds +#DEFINE DS .FILL +#DEFINE ds .fill +#DEFINE TITLE .TITLE +#DEFINE title .title +#DEFINE EQU .EQU +#define equ .equ +#DEFINE NAME \; +#DEFINE PAGE .PAGE +#DEFINE page .page +#DEFINE CSEG .CSEG +#DEFINE ORG .ORG +#DEFINE org .org +#DEFINE END .END +#DEFINE IF .IF +#DEFINE if .if +#DEFINE ELSE .ELSE +#DEFINE else .else +#DEFINE ENDIF .ENDIF +#DEFINE endif .endif +#DEFINE DEFB .DB +#DEFINE defb .db +#DEFINE DEFW .DW +#DEFINE defw .dw +#DEFINE DEFL .EQU +#DEFINE defl .equ +#DEFINE DEFS .DB +#DEFINE defs .db +#DEFINE DW .DW +#DEFINE dw .dw +#DEFINE DB .DB +#DEFINE db .db +#DEFINE END .END +#DEFINE end .end +; +; Add some Z80 instructions +; +#ADDINSTR JR * 18 2 R1 1 +#ADDINSTR JRC * 38 2 R1 1 +#ADDINSTR JRNC * 30 2 R1 1 +#ADDINSTR JRZ * 28 2 R1 1 +#ADDINSTR JRNZ * 20 2 R1 1 +#ADDINSTR LDIR "" B0ED 2 NOP 1 +#ADDINSTR DJNZ * 10 2 R1 1 +#ADDINSTR LDED * 5BED 4 NOP 1 +#ADDINSTR SDED * 53ED 4 NOP 1 +; +; NOW INCLUDE THE MAIN SOURCE +; +#INCLUDE "zcpr.asm" +; + .FILL ((CPRLOC + 0800H) - $),055H +; + .END \ No newline at end of file diff --git a/trunk/Source/zsdos-gp.z80 b/trunk/Source/zsdos-gp.z80 new file mode 100644 index 00000000..320b0b56 --- /dev/null +++ b/trunk/Source/zsdos-gp.z80 @@ -0,0 +1,3174 @@ +;WW - Globally changed dquotes to squotes for all strings +;WW - Globally changed NOT, AND, OR in conditional assembly to ~, &, | +; +;**************************************************************************** +; Z S D O S +; A CP/M 2.2 compatible replacement Basic Disk Operating System (BDOS) +; +; Copyright (C) 1986,7,8 by: +; +; Harold F. Bower and Cameron W. Cotrill +; +; 7914 Redglobe Ct. 2160 N.W. 159th Place +; Severn, MD 21144-1048 Beaverton, OR 97006 +; USA. USA. +; +; HalBower@worldnet.att.net ccotrill@symantec.com +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; either version 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License (file LICENSE.TXT) for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, write to the Free Software +; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +;--------------------------------------------------------------------------- +; ZSDOS is a CP/M 2.2 compatable BDOS replacement that contains numerous +; enhancements. It is based on P2DOS 2.1 by HAJ Ten Brugge and revisions +; to P2DOS made by Harold F. Bower, Benjamin Ho, and Cameron W. Cotrill. +; Several good ideas from both CP/M Plus(tm) and ZRDOS(tm) have been added. +; The authors wish to thank Bridger Mitchell of Plu*Perfect Systems for +; suggesting we put our heads together, for reviewing the efforts, and for +; suggesting better methods for coding some sections. Thanks also to Joe +; Wright of Alpha Systems for his review and suggestions, as well as +; squeezing a few more bytes for us. + +; Support for Plu*Perfect'a BackGrounder ii(tm) and ZDS DateStamper(tm) is +; included, as well as support for ZCPR/BGii WHEEL and PATH. +; ZSDOS is compatable with NZCOM by Joe Wright of Alpha Systems. + +; ZSDOS is designed for Z80 compatible processors ONLY!!! +; ZSDOS is coded to run in Z280 protected mode and may be ROMmed. + +; LEGAL DEPARTMENT: P2DOS was written by H.A.J. Ten Brugge, ZSDOS +; modifications were by Cameron W. Cotrill and Harold F. Bower. +; ZDDOS modifications were done by Carson Wilson, Cameron W. Cotrill +; and Harold F. Bower. + +; No author assumes responsibility or liability in the use of this +; program or any of its support utilities. + +; P2DOS is Copyright (C) 1985 by H.A.J. Ten Brugge - All Rights Reserved +; H.A.J. Ten Brugge +; F. Zernikestraat 207 +; 7553 EC Hengelo +; Netherlands +; Permission to use P2DOS code in ZSDOS granted to Harold F. Bower and +; Cameron W. Cotrill in letter 28 March 1988 + +; Code sections marked (bm) are revisions suggested by Bridger Mitchell. +; Code sections marked (bh) are from SUPRBDOS mods to P2DOS by Benjamin Ho. +; Code sections marked (crw) are revisions to support internal datestamper +; and are Copyright (C) 1988 by Carson Wilson. + +; NOTES: Backgrounder ii and DateStamper are trademarks of Plu*Perfect +; Systems. CP/M is a trademark of Digital Research, Incorporated. +; ZRDOS is a trademark of Echelon, Incorporated. + PAGE +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +; Version 1.2a, 11/04/89 +; Assemble with : SLR Z80ASMP or ZMAC +; Revisions: +; 11/04/89 Moved home call to rddir so bios hostbuf always +; updated before dir read. +; 07/18/89 Fixed tderr routine in ZDDOS so return codes not +; CWC altered from tderr unless called from 102 or 103. +; 06/20/89 Fixed bug in F10 ^R that output 256 spaces if ^R +; CWC entered with tab counter =0. +;* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + +; WW - MOVED TO N8VEM WRAPPER +; MACLIB ZSDOS.LIB ; Get initialization code + +RAMLOW EQU 0000H ; Start address memory + + CSEG +ZSDOS EQU $ ; Start address ZSDOS + + IF ZRL + COMMON /_BIOS_/ +BIOS: + CSEG + ELSE +BIOS EQU ZSDOS+0E00H + ENDIF + +BOOT EQU BIOS+0000H ; Cold Boot +WBOOT EQU BIOS+0003H ; Warm Boot +CONST EQU BIOS+0006H ; Console Status +CONIN EQU BIOS+0009H ; Console Input +CONOUT EQU BIOS+000CH ; Console Output +LIST EQU BIOS+000FH ; List Output +PUNCH EQU BIOS+0012H ; Punch Output +READER EQU BIOS+0015H ; Reader Input +HOME EQU BIOS+0018H ; Home Disk +SELDSK EQU BIOS+001BH ; Select Disk +SETTRK EQU BIOS+001EH ; Select Track +SETSEC EQU BIOS+0021H ; Select Sector +SETDMA EQU BIOS+0024H ; Set DMA Address +READ EQU BIOS+0027H ; Read 128 Bytes +WRITE EQU BIOS+002AH ; Write 128 Bytes +LISTST EQU BIOS+002DH ; List Status +SECTRN EQU BIOS+0030H ; Sector Translation + +; Internal Definitions + IF ZSDOS11 +VERMAJ EQU 1 ; Major version number +VERMIN EQU 1 ; Minor version number + ELSE +VERMAJ EQU 1 +VERMIN EQU 2 + ENDIF ;Zs +VERS EQU VERMAJ*10H+VERMIN + +CONTC EQU 03H ; Key to generate warm boot +CONTH EQU 08H ; Backspace +TAB EQU 09H ; Tab +LF EQU 0AH ; Line feed +CR EQU 0DH ; Carriage return +CONTP EQU 10H ; Set/reset print flag +CONTR EQU 12H ; Retype line +CONTS EQU 13H ; Stop console output +CONTX EQU 18H ; Delete line (backspaces) +CONTU EQU 15H ; Same as Control-X +RUBOUT EQU 7FH ; Delete last char + +MAXEXT EQU 1FH ; Maximum extent number +MAXMOD EQU 3FH ; Maximum data module number + +TDCKSM EQU 91H ; CHECKSUM OF !!!TIME&.DAT + +; Attribute Bit Definitions + +PUBATT EQU 2 ; Public attribute offset +PSFATT EQU 7 ; Public/system file (internal only) +WHLATT EQU 8 ; Wheel protect attribute offset +ROATT EQU 9 ; Read only attribute offset +SYSATT EQU 10 ; System attribute offset +ARCATT EQU 11 ; Archive attribute offset + +; FCB POSITION EQUATES + +FCBEXT EQU 12 ; Extent number +FCBUSR EQU 13 ; User valid at offset 13 if set (internal) +FCBMOD EQU 14 ; Data module number - D7 used as unmod flag +FCBREC EQU 15 ; Record number +NXTREC EQU 32 ; Next record number + PAGE +;************************************************************** +;* Z S D O S P r o g r a m S t a r t * +;************************************************************** + +; WARNING!! Do NOT change labels or sequences of ZSDOS through ZSDOS+25H +; ID string added for easy identification in running system (hfb) + + IF ZS + DEFB "ZSDOS " ; Used in CP/M for serial number. these bytes + ELSE ; are patched by INSTALOS to contain the serial + DEFB "ZDDOS " ; Number of the running system so MOVCPM can + ENDIF ; still be used without problems. + +; ZSDOS Entry Point + +START: JP ENTRY ; Jump to start of program code + +; CP/M 2.2 Compatable Error Vector Table + +STBDSC: DEFW ERROR ; Bad sector message +STSEL: DEFW ERROR ; Select error +STRO: DEFW ERROR ; Drive read only +SFILRO: DEFW ERROR ; File read only + +; External Path Name + +PATH: DEFW PATHAD ; Path address for file open, 0 if no path + +; Wheel Byte Pointer + +WHEEL: DEFW WHLADR ; Address of wheel byte, 0 if none + +; User configuration byte + +FLAGS: DEFB FLGBITS ; Flag byte set in zsdos.lib + +; Dispatch table for time/date stamp routines + +; ZSDOS uses all vectors in this table as indicated. ZDDOS uses all but +; STUPDV, GETSTV, and PUTSTV. STCRV is used to store the address of the +; stamp for ZDDOS, thus allowing ZSCONFIG to enable and disable stamping +; of Last Access and Modify. + +GSTIME: DEFW DOTDER ; Address of get/set time/date routine (hfb) + IF ZS +STLAV: DEFW DOTDER ; Address of stamp last access routine +STCRV: DEFW DOTDER ; Address of stamp create routine +STUPDV: DEFW DOTDER ; Address of stamp modify routine + ELSE +STLAV: DEFW STIME ; Address of stamp last access routine +STCRV: DEFW STIME ; Address of stamp create routine +STUPDV: DEFW STIME ; Address of stamp modify routine + ENDIF +GETSTV: DEFW DOTDER ; Address of get stamp routine +PUTSTV: DEFW DOTDER ; Address of set stamp routine + DEFW DOTDER ; Dummy vector to disable with ZSCONFIG +UNLOAD: DEFW 0 ; Pointer to remove Time Stamp routine + + PAGE +;******************************************************** +;* Z S D O S L o w R A M D a t a * +;******************************************************** + +; RAM has been moved down here to an area that is compatable with ZRDOS per +; suggestion by Hal Bower. The actual addresses used are NOT compatable with +; ZRDOS. + +; Due to ZSDOS's smaller RAM area, any program that saves RAM in accordance +; with ZRDOS's specifications for re-entry into BDOS should work under ZSDOS +; without problems. Some code will be saved also, as well as the Flag Byte, +; but this should be no problem for IOP'S. + +; The Write Protect, Login, and Hard Disk Login Vectors are kept at the top of +; ZSDOS, as they must reflect the current status of the Disk System and hence +; should NOT be saved with other system variables Under ANY Circumstance! + + IF ROM + DSEG + ENDIF +BGLORAM: +;-------------------------------------------------------------------- +; The following locations MUST remain in EXACTLY this order + +TABCNT: DEFB 0 ; Tab counter +TABCX1: DEFB 0 ; Temporary Tab counter (used by RDBUF) +;-------------------------------------------------------------------- + +FCONTP: DEFB 0 ; List enable flag (Control-P) - used by BGii +LASTCH: DEFB 0 ; Last character - used by BGii + +;-------------------------------------------------------------------- +; The following locations MUST remain in EXACTLY this order + +USER: DEFB 0 ; User number - used by BGii +DEFDRV: DEFB 0 ; Default drive number - used by BGii and DS +DRIVE: DEFB 0 ; Drive number +;-------------------------------------------------------------------- + +FCB0: DEFB 0 ; FCB byte 0 + +BGHIRAM: +DMA: DEFW 0080H ; DMA address + +TRANS: DEFW 0 ; Translation vector +TEMP0: DEFW 0 ; Number of files on drive + + +DIRBUF: DEFW 0 ; Directory buffer pointer - used by bgii +IXP: DEFW 0 ; Disk parameter block +CSV: DEFW 0 ; Check sum pointer +ALV: DEFW 0 ; Allocation vector pointer + +;-------------------------------------------------------------------- +; The following locations MUST remain in EXACTLY this order +; Copy of DPB for Current Drive + +DPBOF EQU $-ZSDOS ; Value needed by ZSDOS + +MAXSEC: DEFW 0 ; Number of sectors/track +NBLOCK: DEFB 0 ; Block shift +NMASK: DEFB 0 ; Mask number of blocks +NEXTND: DEFB 0 ; Extent mask +MAXLEN: DEFW 0 ; Maximum block number-1 +NFILES: DEFW 0 ; Maximum number of files-1 +NDIR0: DEFB 0 ; First two entries ALV buffer + DEFB 0 ; ..(NDIR1) +NCHECK: DEFW 0 ; Number of checksum entries +NFTRK: DEFW 0 ; First track number +;-------------------------------------------------------------------- +FUNCT: DEFB 0 ; Function number +PEXIT: DEFW 0 ; Exit code +;-------------------------------------------------------------------- +; The following locations MUST remain in EXACTLY this order + +FLDRV: DEFB 0 ; Drive select used flag +RDWR: DEFB 0 ; Read/write flag +SEARQU: DEFB 0 ; Search question mark used +SEARPU: DEFB 0 ; Search public file +;-------------------------------------------------------------------- +RECDIR: DEFW 0 ; Record directory (checksum) +FILCNT: DEFW 0 ; File counter +SECPNT: DEFB 0 ; Sector pointer +SUBFLG: DEFB 0 ; Submit flag (reset disk command) + +DCOPY: DEFW 0 ; Copy address FCB +SEAREX: DEFB 0 ; Exit code search +SEARNB: DEFB 0 ; Search number of bytes +ERMODE: DEFB 0 ; BDOS error mode + +ARWORD: DEFW 0 ; De argument on entry - used for BGii +DEVAL: DEFW 0 ; Return value for DE reg +SPSAVE: DEFW 0 ; Stack pointer location + IF ZS + DEFB "ZSDOS 1.1 Copyri" + ELSE + DEFB "ZDDOS 1.1 Copyri" + ENDIF + DEFB "ght (c) 1987,88 " + DEFB " C.W.Cotrill & H" + DEFB ".F.Bow" +IXSAVE: DEFB "er" ; User's IX register +ZSDOSS: ; ZSDOS stack + +BGRAMTOP EQU ZSDOSS + PAGE + CSEG +;********************************************************************** +;* Z S D O S e n t r y p o i n t * +;********************************************************************** + +ENTRY: XOR A ; Clear A + LD B,A ; For later 16 bit adds + LD L,A + LD H,A ; Set HL to zero + LD (PEXIT),HL ; Clear exit code + LD (FLDRV),HL ; Reset drive select and R/W flags + LD (SPSAVE),SP ; Save stack pointer + LD SP,ZSDOSS ; Get internal stack pointer + PUSH IX ; Save index register on our stack + PUSH DE ; Save parameter register + POP IX ; Get it back in IX + LD (ARWORD),IX ; Save in memory for BGii + IF ~PICKEY + LD (DEVAL),IX ; ..and for non-file access returns + ENDIF + LD HL,DOSEXIT ; Get exit address ZSDOS + PUSH HL ; Save it on stack to return from ZSDOS + LD A,C ; Get function code - B reg = 0 + LD (FUNCT),A ; Save it for later use + CP 12 ; Is it a non-disk function? + JR C,ENTRY0 ; ..jump if so + CP MAXCMD ; Cmnd < Maximum Command Number (48)? + JR C,ENTRY1 ; ..jump if disk function + +; Extended function scanner for added functions + + CP 98 ; Is it less than Cmd98? + RET C ; ..return if so + CP 103+1 ; Is it greater than Cmd103? + RET NC ; ..quit if so + SUB 98-MAXCMD ; Rework so 98-->49..103-->54 + LD C,A ; Save reworked function # + ; ..fall thru to entry0.. + +; If Non-disk Function (ie Function # less than 12), push the address of +; the SAVEA routine on the Stack (save A reg as return code). Saves +; code in Console Routines, as simple RET can be used in most cases. + +ENTRY0: LD HL,SAVEA + PUSH HL ; Vector return thru A reg save +ENTRY1: LD HL,CTABLE ; Load table + ADD HL,BC ; Add + ADD HL,BC ; Add twice to get word value + LD A,(HL) ; Get LSB + INC HL ; Pointer to MSB + LD H,(HL) ; Get MSB + LD L,A ; Save LSB in L + +; Copy byte argument into A and C to simplify Function calls. This allows +; direct BIOS jumps for several functions with resulting code savings. + + LD C,E ; Place arg in C for BIOS + LD A,E ; And in A for others + JP (HL) ; Jump to routine + + PAGE +;****************************************************** +;* C O M M A N D T A B L E * +;****************************************************** +CTABLE: + IF ROM + DEFW RAMINI ; Set up RAM + ELSE + DEFW ERROR5 ; Warm boot (BIOS) with ERMODE clear + ENDIF + DEFW CMND01 ; Console input + DEFW WRCON ; Console output + DEFW READER ; Reader input (BIOS) + DEFW PUNCH ; Punch output (BIOS) + DEFW LIST ; List output (BIOS) + DEFW CMND06 ; Direct console I/O + DEFW CMND07 ; Get I/O byte + DEFW CMND08 ; Set I/O byte + DEFW CMND09 ; Print string + DEFW CMND10 ; Read console buffer + DEFW CMND11 ; Get console status + DEFW CMND12 ; Return version number + DEFW CMND13 ; Reset disk system + DEFW CMND14 ; Select disk + DEFW CMND15 ; Open file + DEFW CMND16 ; Close file + DEFW CMND17 ; Search for first + DEFW CMND18 ; Search for next + DEFW CMND19 ; Delete file + DEFW CMND20 ; Read sequential + DEFW CMND21 ; Write sequential + DEFW CMND22 ; Make file + DEFW CMND23 ; Rename file + DEFW CMND24 ; Return login vector + DEFW CMND25 ; Return current disk + DEFW CMND26 ; Set DMA address + DEFW CMND27 ; Get address allocation vector + DEFW CMND28 ; Write protect disk + DEFW CMND29 ; Get R/O vector + DEFW CMND30 ; Set file attributes + DEFW CMND31 ; Get address disk parameter header (DPH) + DEFW CMND32 ; Get/set user code + DEFW CMND33 ; Read random + DEFW CMND34 ; Write random + DEFW CMND35 ; Compute file size + DEFW CMND36 ; Set random record + DEFW CMND37 ; Reset multiple drive + DEFW DUMMY ; Function 38 (unused) + DEFW CMND39 ; Return fixed disk login vector + DEFW CMND40 ; Write random with zero fill + DEFW DUMMY ; Function 41 (unused) + DEFW DUMMY ; Function 42 (unused) + DEFW DUMMY ; Function 43 (unused) + DEFW DUMMY ; Function 44 (unused) + DEFW CMND45 ; Set Error Mode + DEFW DUMMY ; Function 46 (unused) + DEFW CMND47 ; Return DMA + DEFW CMND48 ; Return DOS version + +MAXCMD EQU ($-CTABLE)/2 ; Jww + + DEFW CMD98 ; Get Time ; 49 + DEFW CMD99 ; Set Time ; 50 + DEFW CMD100 ; Get Flags ; 51 + DEFW CMD101 ; Set Flags ; 52 + DEFW CMD102 ; Get Stamp ; 53 + DEFW CMD103 ; Put Stamp ; 54 + + PAGE +;****************************************************** +;* N o n - D i s k F u n c t i o n s * +;****************************************************** + + IF ROM + +; Initialize RAM in Data Segment (ROM Systems Only) + +RAMINI: LD B,SPSAVE-BGLORAM ; Size of low RAM data segment (less stack) + XOR A + LD HL,BGLORAM ; Start of RAM +RAMIN1: LD (HL),A ; Clear first byte + INC HL + DJNZ RAMIN1 ; And everything else + IF ZS ; Need Internal path if ZSDOS + LD HL,IPATH ; Point to start of Internal Path + LD B,HDLOG+2-IPATH-1 ; and fill high mem less first byte of path + LD (HL),01 ; Set path to Drive = A + INC HL ; ..point to user and Null (Sets user=0) + ELSE ; No Path if ZDDOS + LD HL,TDFVCT + LD B,HDLOG+2-TDFVCT ; Now high RAM + ENDIF ;Zs +RAMIN2: LD (HL),A + INC HL + DJNZ RAMIN2 + LD HL,RAMLOW+80H ; Default DMA buffer + LD (DMA),HL ; And save it + RST 00 ; Now BIOS warm boot + ENDIF ; Rom + +;..... +; I/O Routines + +; ZSDOS Console Input. Read character from Console and Echo +; If Char=CR,LF,TAB,CONTH or >=Space + +CMND01: CALL GETCH ; Get character (and test it jww) + RET C ; Less than space, exit +PUTCH: PUSH HL ; Save regs for other calls + CALL WRCON ; Echo character + POP HL + RET + +; Direct Console Input/Output +; Call with Char in C and E - Enhanced to CP/M-3 Spec +; Checks ZSDOS typeahead for reliable console I/O under all conditions +; as per a suggestion by Bridger Mitchell. + +CMND06: INC E ; Test if get char if avail + JR Z,DCIO1 ; Yes do input + INC E ; Test for 0FEH + JR Z,DCIO2 ; Yes, get status + INC E ; Test for 0FDH + JR Z,GETCH ; Yes, wait for input char + JP CONOUT ; Else print char + +DCIO2: LD A,(LASTCH) ; Check for buffered char + OR A + LD A,0001B ; ..preset ready + CALL Z,CONST ; Get console status + AND A ; Test it + RET ; And return it to caller + +DCIO1: CALL DCIO2 ; Get console status + RET Z ; Exit if no character present + ; Else fall thru +; Get Character from Console + +GETCH: LD HL,LASTCH ; Check ZSDOS type ahead for char + LD A,(HL) + LD (HL),0 ; Reset last character + OR A ; ..set flags + CALL Z,CONIN ; Get character (and test it jww) + +; Test Character +; Exit Carry=0: CR,LF,TAB,CONTH or >= Space +; Carry=1: All other Characters + + CP CR ; Is it a carriage return? + RET Z ; ..return if so + CP LF ; Is it a line feed? + RET Z ; ..return if so + CP TAB ; Is it a tab? + RET Z ; ..return if so + CP CONTH ; Is it a backspace? + RET Z ; ..return if so + CP ' ' ; Test >=space + RET ; ..and return to caller + +; Set I/O Status Byte + +CMND08: LD (RAMLOW+0003H),A ; And save it in RAM and fall through + +; Get I/O Status Byte + +CMND07: LD A,(RAMLOW+0003H) ; Get I/O byte from RAM + RET + +; Buffered Console Read + +CMND10: LD A,(TABCNT) + LD (TABCX1),A ; Save start tab position + INC DE + XOR A + LD (DE),A ; Set char count to zero + INC DE ; Point to actual buffer start + +RDBUF1: PUSH DE ; Save buffer pointer + CALL GETCH ; Get next byte from user + POP DE + LD HL,RDBUF1 + PUSH HL ; Return address to stack + LD HL,(ARWORD) + LD C,(HL) ; Put buffer length in C + INC HL ; And point to current length + + CP CR + IF CTLREN + JR Z,JZRBX ; Exit if CR + ELSE + JR Z,RDBUFX + ENDIF ;Ctlren + + CP LF + IF CTLREN +JZRBX: JP Z,RDBUFX ; ..or LF + ELSE + JR Z,RDBUFX + ENDIF ;Ctlren + ;..Not CR or LF, so fall thru to next test + +; Delete Character from Buffer +; RUB, Backspace, CR, LF are NEVER in the Buffer + +RDBUF2: CP RUBOUT ; Delete char? + JR Z,DOBACK ; ..jump if so + CP CONTH ; Control-H also deletes + JR NZ,RDBUF3 ; Skip to next test if no delete + +DOBACK: LD A,(HL) + AND A ; Test if attempting del from empty line + RET Z ; ..Exit if so +DOBAK0: DEC DE ; Back up to last character + DEC (HL) ; Erase from buffer + PUSH DE ; Save buffer pointer + LD B,(HL) ; Get new char count + INC HL ; Point to first char + EX DE,HL + LD HL,TABCNT + LD C,(HL) ; Save current Tab count + INC HL + LD A,(HL) ; Get starting Tab position + DEC HL + LD (HL),A ; Init the counter + INC B ; Insure non-zero + JR DOBAK2 ; Jump to done test + +DOBAK1: LD A,(DE) ; Get char from buffer + CALL WRCON2 ; Counts chars + INC DE +DOBAK2: DJNZ DOBAK1 ; Continue count until done + LD A,C ; Get prior tab count + SUB (HL) ; Get diff between new and old + LD B,A ; Set up as count + LD (HL),C ; Restore prior count + POP DE ; Restore buffer pointer + +; Delete B Characters from Console + + PUSH DE ; Save pointer +DOBAK5: LD C,CONTH + PUSH BC ; Save counter from destruction + CALL CONOUT + LD C,' ' + CALL CONOUT ; Output backspace,space to CON: only + LD A,CONTH + CALL WRCON ; Now backspace CON:, counter, and printer + POP BC ; Restore counter + DJNZ DOBAK5 ; Loop until all done + POP DE ; Restore pointer + RET + +; Erase Buffer + +RDBUF3: CP CONTU ; Test erase line + JR Z,ERALIN ; Do it if so + CP CONTX + JR NZ,RDBUF4 ; Skip to next test if no erase line + +ERALIN: XOR A + OR (HL) ; Line empty? + RET Z ; Exit if so + PUSH HL + CALL DOBAK0 ; Else delete another (skip empty check) + POP HL + JR ERALIN + +RDBUF4: ; If CTL-R=True, do following code, else bypass + IF CTLREN + CP CONTR ; If ^R, type clean buffer version on console + JR NZ,RDBUF5 + PUSH HL ; Save pointer to buffer length + CALL CROUT ; Do CR/LF + LD HL,TABCNT + LD (HL),0 ; Init Tab count + INC HL + LD B,(HL) ; And get Tab offset count + LD A,' ' + inc b ; [1.1] insure nz value + jr rety1a ; [1.1] so case of lh side of screen ok +RETYP1: CALL WRCON ; Space off start of line +rety1a: DJNZ RETYP1 + POP HL ; Point to buffer length + LD B,(HL) ; Get how many chars to print + INC HL ; Restore buffer pointer + EX DE,HL ; Put buffer pointer in DE + INC B ; Comp for first DJNZ + JR RETYP3 ; Skip to done test +RETYP2: LD A,(DE) ; Get char from buffer + CALL WRCTL ; Output it + INC DE ; Bump pointer +RETYP3: DJNZ RETYP2 ; Loop until done + RET + ENDIF ; Ctlren + +; Toggle Line Printer Echo + +RDBUF5: CP CONTP ; Toggle printer? + JR NZ,RDBUF6 ; Next test if not + LD HL,FCONTP + LD A,(HL) ; Get printer echo flag + CPL ; Toggle it + LD (HL),A ; Put back + RET + +; Check if Control-C is First char in BUFF and Exit if so + +RDBUF6: LD (DE),A ; Put character in buffer + PUSH HL + CALL WRCTL ; Echo the character + POP HL + INC (HL) ; Increment the character count + + LD A,(HL) ; Get current length + CP C ; Test against buffer size + JR Z,RDBUFX + DEC A ; Set Z flag for first character + LD A,(DE) ; Get the character back + INC DE ; ..and bump the pointer + RET NZ ; Return if not the first character + CP CONTC ; Possible user abort? + RET NZ ; ..return if not + JP ERROR5 ; Else jump to error reset exit + +; Done with Read Console Buffer Function + +RDBUFX: POP HL ; Clear RDBUF1 return address + LD A,CR + JR WRCON ; ..and echo a CR + +; Print Control Character as '^X' + +WRCTL: CP ' ' ; Test if control char + JR NC,WRCON ; Not, send it out + CP TAB ; Test if Tab + JR Z,WRCON0 ; It is, so expand with spaces + PUSH AF ; Save char + LD A,'^' ; Output a karet + CALL WRCON1 ; No need for Tab test here + POP AF + ADD A,40H ; Convert to printable + ; And fall thru to WRCON + +; Output char with List Echo, Tab Expansion (Function 2) + +WRCON: CP TAB ; Is it a Tab? + JR NZ,WRCON1 ; ..jump if not +WRCON0: LD A,' ' ; Expand Tab with spaces + CALL WRCON1 ; Write space + LD A,(TABCNT) ; Get Tab count + AND 7 ; Test if done + JR NZ,WRCON0 ; No then repeat + LD A,TAB ; Return Tab + RET ; Return to caller + +WRCON1: PUSH BC + PUSH DE ; Save pointers + LD C,A + PUSH BC ; Save character + +BGPTCH0 EQU $+1 ;<-- BGii patches this address + + CALL CMND11 ; Test status and CONTS/CONTC + POP BC ; Get character back + PUSH BC ; Save it again + CALL CONOUT ; Output it + POP BC ; Get character back + PUSH BC ; Save it again + LD A,(FCONTP) ; Get printer echo flag + OR A ; Test it + CALL NZ,LIST ; Non zero => output char to printer + POP BC ; Restore character + LD A,C ; Fall through to count routine + POP DE + POP BC ; Restore pointers + +; Count Characters in line as shown by f10 + + LD HL,TABCNT ; Get pointer to Tab counter +WRCON2: INC (HL) ; Increment Tab counter + CP RUBOUT ; Test if character = Rubout + JR Z,WRCON3 ; Treat like Backspace + CP ' ' + RET NC ; Ok if not Control + CP TAB ; Only DOBACK ever gets Tabs through here + JR Z,WRCON4 ; Handle differently if Tab + CP CONTH + JR Z,WRCON3 ; Or Backspace + INC (HL) ; Must have been echoed as two chars + CP LF + JR Z,WRCON3 ; ..unless it's LF + CP CR ; ..or CR + RET NZ + LD (HL),2 ; Reset Tab count +WRCON3: DEC (HL) ; Decrement Tab counter + DEC (HL) + RET ; And exit + +WRCON4: LD A,7 ; Bumped by one already + ADD A,(HL) ; Tabs are every 8 spaces + AND 0F8H ; ...mod 8 + LD (HL),A ; Save updated Tab count + RET ; ..and continue + +; Get Console Status - BGII uses this routine + +BGCONST: +CMND11: CALL DCIO2 ; Get character present status + RET Z ; ..exit if none + CALL GETCH ; Get next console char + CP CONTS ; Is it stop char? + JR NZ,GCONS2 ; ..jump if Not + CALL CONIN ; Get next character + CP CONTC ; Does the user want to exit (^C)? + JR NZ,CMND11 ; ..check for another character if not + JP ERROR5 ; Else jump to warm boot & clear ERMODE + +GCONS2: LD (LASTCH),A ; Save character + LD A,1 ; Character present code + RET ; Return to caller + +; Echo CR,LF + +CROUT: LD DE,MCRLF ; Fall through to output routine + +; Output Message + +CMND09: LD A,(DE) ; Get byte from buffer + CP '$' ; Test last byte + RET Z ; Yes, then return to caller + INC DE ; Point to next byte + CALL WRCON ; Output character + JR CMND09 ; And test again + + PAGE +;********************************************** +;* E r r o r R o u t i n e s * +;********************************************** + +PRDEC: LD BC,100 + CALL NUM + LD C,10 + CALL NUM + LD BC,101H + +; Display Number + +NUM: LD D,-1 ; Load number -1 +NUM1: INC D ; Increment number + SUB C ; Divide by C + JR NC,NUM1 ; Not finished then loop + ADD A,C ; Restore last value + PUSH AF ; Save it + LD A,D ; Test if "0" + OR B ; And if leading zero + JR Z,NUM2 ; Yes, then exit + LD B,A ; Set no leading zero + LD A,D ; Get number + ADD A,'0' ; Make ASCII + CALL PUTCH ; Echo number preserving BC +NUM2: POP AF ; Restore number + RET ; And exit + +; Error Messages + +MDSKCH: DEFB "Changed$" + +MBADSC: DEFB "Bad Sector$" + +MSEL: DEFB "No Drive$" + +MFILRO: DEFB "File " + +MRO: DEFB "W/P$" + IF ZS +MBERR: DEFB "ZSDOS" + ELSE +MBERR: DEFB "ZDDOS" + ENDIF + DEFB " error on $" + +MBFUNC: DEFB CR,LF,"Call" +MDRIVE: DEFB ": $" + +MFILE: DEFB " File: $" + +MCRLF: DEFB CR,LF,'$' + +; New ZSDOS error handler - enter w/ error code in B and message pointer +; in DE + +ERROR: LD A,(ERMODE) + LD C,A ; Save error mode + RRCA ; Test supress print + JR C,ERROR3 ; Suppressed, so skip dsp + +; Print ZSDOS Error on X: Explanation + + PUSH BC + PUSH DE ; Save params + CALL CROUT ; Output CR/LF + LD DE,MBERR + CALL CMND09 ; Output ZSDOS error on + LD A,(DEFDRV) ; Get current default drive + ADD A,'A' ; Convert to ascii + CALL WRCON ; Output it to console + LD DE,MDRIVE ; Point to drive tag + CALL CMND09 ; Put it also + POP DE ; Restore error message pointer + CALL CMND09 ; Send message + +; Now print CALL: XXX [FILE: XXXXXXXX.XXX] + + LD DE,MBFUNC + CALL CMND09 ; Display 'call: ' + LD A,(FUNCT) ; Get function number + CALL PRDEC ; Output it + LD A,(FLDRV) + AND A ; Was FCB used? + JR Z,ERROR2 ; ..Skip file name display if not + POP BC + PUSH BC ; Get error type + PUSH IX ; Save FCB pointer + LD A,(FUNCT) ; ARE WE ERASING A FILE? + CP 19 ; IF SO, GET NAME FROM DIRBUF AS + JR NZ,ERROR0 ; AMBIG NAME MAY HAVE BEEN USED + CALL CALDIR ; Get DIR buffer pointer + EX (SP),HL ; To show what we really gagged on +ERROR0: LD DE,MFILE + CALL CMND09 ; Output 'file: ' + POP HL ; Point to FCB + LD B,11 ; Output this many chars +ERROR1: INC HL + LD A,3 + CP B ; Time to send '.'? + LD A,'.' ; Get ready for it + CALL Z,PUTCH ; Send it if time + LD A,(HL) ; Get char + AND 7FH ; Mask attributes + CALL PUTCH ; Output it + DJNZ ERROR1 +ERROR2: CALL CROUT ; Send CR,LF + POP BC ; Get error mode back +ERROR3: LD A,4 + SUB B ; Test if select error + JR NZ,ERROR4 ; Skip if not + ld hl,DRIVE ; point to old default + ld a,(hl) ; get it + dec hl ; point to bad drive + cp (hl) ; same? + jr z,ERROR4 ; if so, skip relog + PUSH BC + CALL SELDK ; Get BIOS back in step + POP BC +ERROR4: BIT 1,C ; Test if return error mode + JR NZ,ERROR7 ; Go if return error + LD A,1 + SUB B ; Test if fatal error + JR NC,ERROR6 ; If not a fatal error +ERROR5: XOR A + LD (ERMODE),A ; Set DOS error mode to default CP/M + RST 00 ; ..and leave + +ERROR6: CALL DCIO1 ; Get console char if present + AND A ; Test if any + JR NZ,ERROR6 ; Keep getting them until typeahead eaten + CALL GETCH ; Now get operator's response + CP CONTC ; Test if abort + RET NZ ; If operator said ignore error + JR ERROR5 ; Else boot + +ERROR7: LD A,B ; Get error + LD H,A ; Save code in H reg for return + AND A ; Test if disk changed warning + RET Z ; Continue relog if so + LD L,0FFH ; Set extended error code + LD (PEXIT),HL ; Save as return code + ; ..and fall thru to DOS exit + PAGE +;****************************************************** +;* D O S E x i t R o u t i n e * +;****************************************************** + +DOSEXIT: LD A,(FLDRV) ; Test drive select used flag + OR A + JR Z,DOSEXT0 ; No then exit + LD A,(FCB0) ; Get FCB byte 0 + LD (IX+0),A ; Save it + LD A,(DRIVE) ; Get old drive number + CALL SELDK ; Select disk + IF PICKEY + LD DE,(DEVAL) ; And DE reg for datestamper + ENDIF + +; If the error handler was invoked, the stack is in an undefined +; condition at this point. We therefore have to restore the user's +; IX register independent of stack position. Thanks to Joe Wright's +; eagle eye for catching this one! + +DOSEXT0: LD SP,(SPSAVE) ; Restore user stack + LD IX,(IXSAVE) ; Restore IX (stack is don't care) + LD HL,(PEXIT) ; Get exit code + IF ~PICKEY + LD DE,(DEVAL) ; And DE reg for DateStamper + ENDIF + LD A,L ; Copy function code + LD B,H + RET ; And return to caller + PAGE +;****************************************************** +;* D i s k F u n c t i o n s * +;****************************************************** + +; Reset Disk System + +CMND13: LD HL,RAMLOW+0080H ; Set up DMA address + LD (DMA),HL ; And save it + CALL STDMA ; Do BIOS call + XOR A ; Set default drive = 'A' + LD (DEFDRV),A ; Save it + LD DE,0FFFFH ; Reset all drives + +; Reset Multiple Login Drive - DE = Reset mask +; Fixed Disk Login vector is also altered by this call + +CMND37: CALL UNLOG ; Clear selected drives in DE from login + LD A,(FLAGS) + BIT 2,A ; Test hard R/O enabled + JR NZ,UNWPT1 ; If enabled + LD HL,DSKWP ; Get drive W/P vector + CALL ANDDEM ; Reset W/P stat only of requested drvs +UNWPT1: LD A,(FUNCT) + CP 13 ; Skip hard disk login change? + LD HL,HDLOG + CALL NZ,ANDDEM ; Clear HD Login Vector if Fcn 37 +RELOG1: + IF ZS + LD HL,(HDLOG) + CALL HLORDE ; Don't clear fixed disks from T/D + EX DE,HL ; Place modified logout in DE + LD HL,TDFVCT + CALL ANDDEM ; Clear T/D vector as needed + ENDIF + + LD A,(DEFDRV) ; Get default drive + PUSH AF +RELOG2: + IF RESDSK ; (bh) + CALL SETDSK ; Allow BIOS to detect density change (bh) + ELSE + DEFB 0,0,0 ; Make 3 NOP's to keep constant code (hfb) + ENDIF ; (bh) + POP AF + CALL SELDK ; Select default drive + +; ZSDOS watches for any $*.* in any user on any drive during re-log, +; make, and delete. In this manner, SUBFLG will always be valid - +; even under fast relog and NZCOM! Thanks to Joe Wright for suggesting +; the need for this, and suggesting ways to do it. + +SUBEXT: LD A,(SUBFLG) ; Get submit flag + JR SAVEA ; Exit + +; Check for possible existance of submit file by checking first +; byte of dir entry or FCB for '$'. Pointer to dir or FCB passed +; to routine in HL. + +CKSUB: INC HL ; Point to file name + LD A,(HL) ; Get first char filename + DEC HL + SUB '$' ; Test if '$' + RET NZ ; Not then exit + DEC A ; Load a with 0FFH + LD (SUBFLG),A ; Save it in subflg + RET + +; Unlog Drive mask in DE + +UNLOG: LD A,E ; Get LSB + CPL ; Complement it + LD E,A + LD A,D ; Get MSB + CPL ; Complement it + LD D,A ; DE = not reset + LD HL,LOGIN ; Get addr of login vector +ANDDEM: LD A,E ; Clear login bits of reset drives + AND (HL) ; ..a byte at a time + LD (HL),A ; Put to memory + INC HL + LD A,D + AND (HL) + LD (HL),A + RET + +; Search for File + +CMND17: CALL SELDRV ; Select drive from FCB + LD A,(IX+0) + SUB '?' ; Test if '?' + JR Z,CMD17B ; If so all entries match + LD A,(IX+FCBMOD) ; Get system byte + CP '?' ; Test if '?' + JR Z,CMD17A ; Yes, jump + LD (IX+FCBMOD),0 ; Load system byte with Zero +CMD17A: LD A,15 ; Test first 15 items in FCB +CMD17B: CALL SEARCH ; Do search +CMD17C: LD HL,(DIRBUF) ; Copy directory buffer + LD BC,128 ; Directory=128 bytes +MV2DMA: LD DE,(DMA) ; To DMA address + LDIR + RET ; Exit + +; Search for Next Occurence of File + +CMND18: LD IX,(DCOPY) ; Get last FCB used by search + LD (ARWORD),IX ; Save FCB pointer for BGii + CALL SELDRV ; Select drive from FCB + CALL SEARCN ; Search next file match + JR CMD17C ; And copy directory to DMA address + +; Delete File + +CMND19: CALL SELDRV ; Select drive from FCB + CALL DELETE ; Delete file +CMD19A: LD A,(SEAREX) ; Get exit byte 00=file found, 0FFH=Not + JR SAVEA ; And exit + +; Rename File + +CMND23: CALL SELDRV ; Select drive from FCB + CALL RENAM ; Rename file + JR CMD19A ; And exit + +; Return Current Drive + +CMND25: LD A,(DEFDRV) ; Get current drive +SAVEA: LD (PEXIT),A ; Return character +DUMMY: RET ; ..and exit ZSDOS + +; Set flags + +CMD101: LD (FLAGS),A ; Set ZSDOS flags + ; ..and fall thru +; Get flags + +CMD100: LD A,(FLAGS) ; Get ZSDOS flags + JR SAVEA ; ..and exit + +; Change Status + +CMND30: CALL SELDRV ; Select drive from FCB + CALL CSTAT ; Change status + JR CMD19A ; And exit + +; Return CP/M Version Number + +ZDPCH1: +CMND12: LD HL,22H ; Set CP/M compatable version number + IF ~ZS ; (crw) + CP 'D' ; IS Caller testing for DS? + JR NZ,SAVHL ; ..exit if Not + LD A,(UNLOAD+1) ; See if Clock was installed by testing + ; ..MSB of Remove vector + AND A ; ..if it's zero, then No Clock + JR Z,SAVHL ; ..and No DateStamper + LD H,E ; Otherwise, return DS Active Flag + LD DE,CMD98A ; Have a clock, so get Clock Address + ENDIF + IF ~PICKEY + LD (DEVAL),DE ; In case DS gave us a clock addr + ENDIF + JR SAVHL ; For speed + +; Following commands return status in like manner and are consolidated here +; in selected order with least-accessed commands taking longest to traverse +; string, and frequently accessed/time critical exitting quickest. + +; The code in this section is a bit obscure, as it depends on burying +; instructions within other instructions. 6502 users have long used the +; 'BIT' trick to skip instructions - this inspired me to see if similar +; things could be done with the Z80. Indeed they can, as this demonstrates. +; When the Z80 jumps in at a label, it executes the LD HL instruction. The +; DEFB 0DDH turns the LD HL instructions that follow into LD IX. In effect, +; this turns the DEFB 0DDH into a one byte relative jump to SAVHL. As IX +; is never used by these calls, its loss is of no consequence. +; A similar trick is used in SEAR15, resulting in a useless LD HL but +; saving a byte. + +; New Universal Return Version FUNCTION 48 + +CMND48: + IF ZS + LD HL,'S' << 8 + VERS ;"S" indicates ZSDOS - ZRDOS returns 0 + ELSE + LD HL,'D' << 8 + VERS ;"D" indicates ZDDOS - ZRDOS returns 0 + ENDIF + DEFB 0DDH ; Trash IX and fall through + +; Return Disk W/P Vector + +CMND29: LD HL,(DSKWP) ; Get disk W/P vector + DEFB 0DDH ; Trash IX and fall through + +; Return Fixed Disk Login Vector + +CMND39: LD HL,(HDLOG) ; Return fixed disk login vector + DEFB 0DDH ; Trash IX and fall through + +; Return ALV Vector + +CMND27: LD HL,(ALV) ; Get allocation vector + DEFB 0DDH ; Trash IX and fall through + +; Return Login Vector + +CMND24: LD HL,(LOGIN) ; Get login vector + DEFB 0DDH ; Trash IX and fall through + +; Return Drive Table + +CMND31: LD HL,(IXP) ; Get drive table + DEFB 0DDH ; Trash IX and fall through + +; Return Current DMA + +CMND47: LD HL,(DMA) ; Return current DMA addr +SAVHL: LD (PEXIT),HL ; Save it + RET ; And exit + +; Set BDOS Error Mode + +CMND45: LD (ERMODE),A ; Save error mode + RET ; And exit + +; Set/Get User Code + +CMND32: LD HL,USER ; Point to user byte location + INC A ; Test if 0FFH + LD A,(HL) ; Get old user code + JR Z,SAVEA ; If 0FFH then exit + LD A,E ; Get new user code + AND 01FH ; Mask it + LD (HL),A ; Save it + RET ; And exit + +; Compute File Size Command + +CMND35: CALL SELDR1 ; Select drive from FCB + CALL FILSZ ; Compute file size + JR CMD19A ; And exit + +; Set Random Record Count + +CMND36: LD HL,32 ; Set pointer to next record + CALL CALRRC ; Calculate random record count +LDRRC: LD (IX+33),D ; And save random record count + LD (IX+34),C + LD (IX+35),B + RET ; And exit + +; Select Disk From FCB + +BGSELDRV: +SELDRV: LD A,(ERMODE) ; Are we in modified user mode? + AND A + JR NZ,SELDR1 ; Jump if so, else.. + LD HL,(ARWORD) ; + LD BC,FCBUSR ; Point to user number + ADD HL,BC ; + LD (HL),A ; Clear user flag +SELDR1: LD A,0FFH ; Set disk select done flag + LD (FLDRV),A + LD A,(DEFDRV) ; Get current drive + LD E,A ; Save it in register E + LD HL,(ARWORD) + LD A,(HL) ; Get drive from FCB + LD (FCB0),A ; Save it + CP '?' ; Test if '?' + JR Z,CMND14 ; Yes, then select drive from register E + PUSH IX ; Save BGii's IX register + ; IX won't be altered on cmnd14 + LD IX,(ARWORD) ; Get FCB pointer +;1.1a Changed to allow proper access to Drive P: +;1.2a AND 0FH ; Mask drive + AND 1FH ;1.2a Mask Drive + PUSH HL + JR Z,SELDR0 ; Select drive from register E + LD E,(HL) ; Get drive from FCB + DEC E ; Decrement drive number so A=0 +SELDR0: CALL CMND14 ; - do select of drive + POP HL ; Restore FCB pointer + +; Resolve User for FCB - FCBPTR in IX, Returns User in A + + LD A,(IX+FCBUSR) ; ..get potential user in case + BIT 7,A ; Is this a valid user? + JR NZ,RESUS1 ; Skip if there is + LD A,(USER) ; Get user number + JR RESUS1 ; ..and bypass push IX + +; Set User in FCB to Value passed in A + +RESUSR: PUSH IX ; Preserve IX +RESUS1: LD IX,(ARWORD) + AND 1FH ; User number in A + LD (IX+0),A ; Save in FCB 0 byte + OR 80H ; Set valid DOS user flag + LD (IX+FCBUSR),A ; ..and in FCB 13 byte + POP IX ; Restore caller's IX + RET + +; Select Disk Error Exit - The stack is off by one level here, but +; this is a one way trip anyway. + +SELDK3: LD HL,(STSEL) ; Load error message address + LD B,4 ; Select error + LD DE,MSEL ; Load select error message + JP (HL) ; And display error + +; Select Disk from E register + +CMND14: LD A,(DEFDRV) ; Get current drive + LD (DRIVE),A ; Save it in memory + LD A,E ; Copy drive number + +; Select Disk +; Call w/ A = Drive Number (0..15 = A..P) + +SELDK: LD HL,(LOGIN) ; Get login vector + AND 0FH ; Mask drive number + LD B,A ; Save counter + CALL NZ,SHRHLB ; ..and rotate into position +SELDK0: EX DE,HL ; Put drive bit mask in DE + LD HL,DEFDRV ; Get pointer last drive + BIT 0,E ; Test if drive logged in + JR Z,SELDK2 ; No, login drive + CP (HL) ; Test same drive + RET Z ; Yes then exit + +; NOTE: A long standing DOS bug concerns the SELECT function. If a +; function 14 call is made and the drive doesn't exist, the default +; will still point to the bad drive unless we fix it in the error +; routine. It is for this reason that drive is saved above. We must +; allow default to assume the illegal drive value long enough for the +; error handler to print it, then re-select the old default. + +SELDK2: LD (HL),A ; Save new current drive + PUSH DE ; Save drive logged in flag + LD C,A ; Copy drive number + CALL SELDSK ; Do BIOS select + LD A,H ; Test if error + OR L + JR Z,SELDK3 ; Yes, illegal drive number + LD DE,TRANS ; Point to local translation store + LD BC,2 ; ..and move 2-byte ptr in + LDIR + LD (TEMP0),HL ; Save address temp0 + LD C,6 ; Advance to dirbuf part of DPH + ADD HL,BC ; As TEMP1 and TEMP2 unused in P?DOS + LD DE,DIRBUF ; Load DIRBUF pointer + LD C,8 ; Copy 8 bytes + LDIR + LD HL,(IXP) ; Get drive parameter address + LD C,15 ; Copy 15 bytes + LDIR + POP DE ; Get drive logged in flag + BIT 0,E ; Test it + RET NZ ; Drive logged in so return + CALL GETCDM + EX DE,HL ; Drive mask in DE + LD HL,(LOGIN) ; Get login vector + CALL HLORDE ; Set drive bit in login vector + LD (LOGIN),HL ; Save login vector + LD A,(FLAGS) ; Get flags + BIT 3,A ; Fast relog enabled? + JR Z,INITDR ; Skip if disabled + +; The following code checks the WACD size to determine if the drive +; being selected is a fixed disk. If the WACD size is 0, the disk +; is Non-Removable. However, several BIOSes support remapping of +; logical drives. This complicates matters because BDOS must catch +; the swap and clear the Hard Disk Allocation Vector and allow the +; allocation bitmaps to be rebuilt. Thus, every disk that is being +; selected for the first time traverses this code. If a disk was +; logged as a fixed disk and all of the sudden has a WACD buffer, +; the Fixed Disk Login Vector is cleared. Thus, for Bug-free +; operation of Fast Fixed Disk Logging, if drives are swapped +; NEVER SWAP TWO FIXED DRIVES! + + LD HL,(NCHECK) ; Is this a fixed drive? + LD A,H + OR L + LD C,A ; Save fixed disk flag (Z=true) + LD HL,(HDLOG) + LD A,E ; See if logged as fixed disk + AND L + LD L,A + LD A,D + AND H ; MSB + OR L ; Z flag set if HL and DE = 0 + LD A,0FFH ; Don't alter flags + JR Z,SELDK4 ; If not logged as fixed disk + INC A ; Else flag as logged +SELDK4: LD B,A ; Save logged as fixed disk flag (Z=true) + OR C ; Test if still fixed disk + RET Z ; Skip re-map if logged and not swapped + XOR A + LD H,A + LD L,A ; Null vector + OR B ; Was it logged as a fixed disk? + JR Z,SELDK5 ; Invalidate HDLOG vector - drive no longer + ; Fixed disk + LD A,C + OR A ; Wasn't fixed disk before - is it now? + JR NZ,INITDR ; Skip vector update if it isn't + LD HL,(HDLOG) + CALL HLORDE ; Else add this drive to fixed disk vector +SELDK5: LD (HDLOG),HL ; Update fixed disk vector + ;..fall thru to INITDR + +; Init Drive +; Clear ALV Bit Buffer after Drive reset + +INITDR: LD HL,(MAXLEN) ; Get length ALV buffer-1 (bits) + CALL SHRHL3 ; Divide by 8 to get bytes + LD B,H + LD C,L ; Counter to BC (will be count+1 cleared) + LD HL,(ALV) ; Get pointer ALV buffer + PUSH HL + LD D,H + LD E,L + INC DE ; ALV buffer +1 in DE + XOR A + LD (HL),A ; Clear first 8 bits + LDIR ; And remainder of buffer + POP HL ; Get ALV pointer + LD DE,(NDIR0) ; Get first two bytes ALV buffer + LD (HL),E ; Save LSB + INC HL ; Increment pointer + LD (HL),D ; Save MSB + LD HL,(TEMP0) ; Clear number of files on this drive + LD (HL),A ; Clear LSB (A still has 0) + INC HL ; Increment pointer + LD (HL),A ; Clear MSB + +ZDPCH2 EQU $ ;<-- Intercept first scan (ZDS Patch) + CALL SETFCT ; Set file count +INITD2: LD A,0FFH ; Update directory checksum + CALL RDDIR ; Read FCB's from directory + CALL TSTFCT ; Test last FCB + JP Z,SUBEXT ; Return subflg for strict CP/M compat (hfb) + CALL CALDIR ; Calculate entry point FCB + LD A,(HL) ; Get first byte FCB + CP 0E5H ; Test empty directory entry + JR Z,INITD2 ; Yes then get next FCB + CP 021H ; Test time stamp + JR Z,INITD2 ; Yes then get next FCB + +ZDPCH3 EQU $ ;<-- Test for T&D if first time (ZDS Patch) + CALL CKSUB ; Test for submit file + LD C,1 ; Set bit in ALV buffer + CALL FILLBB ; Set bits from FCB in ALV buffer + CALL TSTLF ; Test for last file + CALL NC,SETLF0 ; ..and update the last file count if so + JR INITD2 ; And get next FCB + +; Return Mask for Current Drive in HL + +GETCDM: LD HL,0 ; No drives to Or + +; Set Drive bit in HL + +SDRVB: EX DE,HL ; Copy HL=>DE + LD HL,1 ; Get mask drive "A" + LD A,(DEFDRV) ; Get current drive + OR A ; Test if drive "A" + JR Z,HLORDE ; Yes then done +SDRVB0: ADD HL,HL ; Get next mask + DEC A ; Decrement drive counter + JR NZ,SDRVB0 ; And test if done +HLORDE: LD A,D ; HL=HL or DE + OR H + LD H,A + LD A,E + OR L + LD L,A + RET ; Exit + +SHRHL3: LD B,3 ; Used in a few places + +; Shift HL right logical B bits + +SHRHLB: SRL H + RR L ; Shift HL right one bit (divide by 2) + DJNZ SHRHLB + RET + +; Calculate Sector/Track Directory + +STDIR: LD HL,(FILCNT) ; Get FCB counter directory + IF UNROLL + SRL H + RR L + SRL H ; (net cost: 3) + RR L ; Divide by 4 (inline for speed) + ELSE + LD B,2 + CALL SHRHLB ; Divide by 4 + ENDIF + LD (RECDIR),HL ; Save value (used by checksum) +STDIR2: EX DE,HL ; Copy it to DE +STDIR1: LD HL,0 ; Clear HL + +; Calculate Sector/Track +; Entry: HL,DE=Sector Number (128 byte sector) +; Result Set Track =HL,DE / MAXSEC +; Set Sector =HL,DE MOD MAXSEC + +CALST: LD BC,(MAXSEC) ; Get sectors/track + LD A,17 ; Set up loop counter +CALST0: OR A + SBC HL,BC ; HL > BC? + CCF + JR C,CALST1 ; Yes then jump + ADD HL,BC ; No then restore HL + OR A ; Clear Carry +CALST1: RL E ; Shift result in DE + RL D + DEC A ; Test last bit done + JR Z,CALST2 ; Yes then exit + ADC HL,HL ; Shift next bit in HL + JR CALST0 ; Continue + +CALST2: PUSH HL ; Save sector number + LD HL,(NFTRK) ; Get first track + ADD HL,DE ; Add track number + LD B,H ; Copy it to BC + LD C,L + CALL SETTRK ; CBIOS call Set Track + POP BC ; Restore sector number + LD DE,(TRANS) ; Get translation table address + CALL SECTRN ; CBIOS call sector translation + LD B,H ; Copy result to BC + LD C,L + JP SETSEC ; BIOS call Set Sector + +; Get Disk Map Block Number from FCB (Squeezed by Joe Wright) +; Exit HL=Address FCB +; DE=DM +; BC=Offset in DM +; Zero Flag Set (Z) if DM=0, Else reset (NZ) + +GETDM: LD L,(IX+NXTREC) ; Get record number in L + RL L ; Shift it left once + LD A,(NEXTND) ; Get EXM + AND (IX+FCBEXT) ; And the extent number + LD H,A ; To H + LD A,(NBLOCK) ; Get BSH + LD B,A ; To B + INC B ; +1 + CALL SHRHLB ; Shift HL right B times + LD D,B ; Zero to D + LD A,L ; Result to A + +GETDM4: LD HL,(ARWORD) + LD C,16 ; Add offset 16 to point to DM + ADD HL,BC + LD C,A ; Add entry FCB + ADD HL,BC + LD A,(MAXLEN+1) ; Test 8 bits/16 bits FCB entry + OR A + LD E,(HL) ; Get 8 bit value + JR Z,GETDMX ; ..and exit if 8-bit entries + + ADD HL,BC ; Add twice (16 bit values) + LD E,(HL) ; Get LSB + INC HL ; Increment pointer + LD D,(HL) ; Get MSB + DEC HL ; Decrement pointer +GETDMX: LD A,D ; Check for zero DM value + OR E + RET ; And exit + +; Calculate Sector Number +; Entry: DE=Block Number from FCB + +CALSEC: LD HL,0 ; Clear MSB sector number + LD A,(NBLOCK) ; Get loop counter + LD B,A ; Save it in B + EX DE,HL +CALSC0: ADD HL,HL ; Shift L,D,E + RL E + DJNZ CALSC0 ; B times + EX DE,HL + LD A,(NMASK) ; Get sector mask + AND (IX+NXTREC) ; And with next record + OR E ; Set up LSB sector number + LD E,A + RET ; And exit + +; Check for File Read-Only status, then fall thru to CALDIR + +CKRODI: CALL CHKFRO ; Abort if the file is R/O + ; ..fall thru.. + +; Calculate DIRBUF Entry Point + +CALDIR: LD A,(SECPNT) ; Get sector pointer +CALDIR1: ; New label for DS (crw) + LD HL,(DIRBUF) ; Get start address dirbuf +CALDI0: ADD A,L ; Add L=L+A + LD L,A + RET NC ; No carry exit + INC H ; Increment H + RET ; And exit + +; Init File Count + +SETFCT: LD HL,-1 ; Set up file count + LD (FILCNT),HL ; Save it + RET ; And exit + +; Set Write Protect Disk Command (relocated & compressed hfb) + +CMND28: ; Set read only disk + LD HL,(DSKWP) ; Get disk W/P vector + CALL SDRVB ; Include drive bit + LD (DSKWP),HL ; Save disk W/P vector + LD DE,(NFILES) ; Get max number of files-1 (bumped below) + LD HL,(TEMP0) ; Get pointer to disk parameter block + INC HL ; Correct pointer.. + ; Setlf0 relocated in-line here (hfb) +SETLF0: INC DE ; Increment last file + LD (HL),D ; Save it in TEMP0 + DEC HL + LD (HL),E + RET ; And exit + +; Search using first 15 bytes of FCB, test if found + +SRCT15: CALL SEAR15 ; Search on 15-bytes..(consolidated-hfb) + ; ..fall thru to test presence.. +; Test File Count + +TSTFCT: LD HL,(FILCNT) ; Test file count=0FFFFH + LD A,H ; Get MSB + AND L ; And LSB + INC A ; Test if result=0FFH + RET ; And exit + +; Test Last File + +TSTLF: LD HL,(TEMP0) ; Get pointer to last file + LD DE,(FILCNT) ; Get file counter + LD A,E ; Subtract DE-(HL) + SUB (HL) + INC HL + LD A,D + SBC A,(HL) + RET ; Exit + +; Get Next FCB from Drive +; Entry A=0 Check Checksum, A=0FFH Update Checksum + +RDDIR: LD C,A ; Save checksum flag + LD HL,(FILCNT) ; Get file counter + INC HL ; Increment it + LD (FILCNT),HL ; And save it + LD DE,(NFILES) ; Get maximum number of files + LD A,E ; Is this the last file? + SUB L + LD A,D + SBC A,H + JR C,SETFCT ; ..set file count to 0FFFFH if so + LD A,L ; Get file count LSB + RRCA ; *32 (bm/hfb-to save a byte) + RRCA + RRCA + AND 060H ; Mask it + LD (SECPNT),A ; Save it for later use + RET NZ ; Return if not first FCB sector + PUSH BC ; Save checksum flag + IF ~ZSDOS11 ; (* This was NOT in released package *) + LD A,H ; [1.2] + OR L ; [1.2] First dir entry? + IF ZS + JR NZ,RdDir0 ; [1.2] If not + LD HL,(NCHECK) ; [1.2] Is this a fixed disk? + LD A,H ; [1.2] + OR L ; [1.2] + CALL NZ,HOME ; [1.2] Home if media could change + ELSE ;~Zs + CALL Z,HOME ; [1.2] Home if first dir entry + ENDIF ;Zs + ENDIF ;~Zsdos11 +RdDir0: CALL STDIR ; Calculate sector/track directory + IF ~ZS + CALL READDR ; Read into DIR buffer + +; Check if !!!TIME&.DAT on disk, save temp. result in TDCHEK + + LD HL,(FILCNT) + LD A,H + OR L ; First file? (filcnt = 0) + JR NZ,RDDIR2 ; ..jump if not + LD HL,(DIRBUF) ; Else look for !!!TIME&.DAT + LD B,11 ; Test 11 bytes +RDDIR1: INC HL + LD C,(HL) ; Get Next Char + RES 7,C ; Clear Attricute Bit + ADD A,C ; Add to Checksum + DJNZ RDDIR1 ; Back for more... + SUB TDCKSM ; See it it's !!!TIME&.DAT + LD (TDCHEK),A ; Save result (0 = !!!TIME&.DAT found) +RDDIR2: ; + ELSE + ; READDR subroutine moved in-line here + CALL DMADIR ; Set up DMA directory + CALL READR ; Read a record + CALL STDMA ; ..and set up user's DMA + ENDIF + POP BC ; Restore checksum flag + +; Update/Check Checksum Directory +; Entry C=0 Check Checksum, C=0FFH update Checksum + +CHKDIR: LD HL,(NCHECK) ; Get number of checked records + LD DE,(RECDIR) ; Get current record + XOR A ; Clear carry (bm) + SBC HL,DE ; Test current record + RET Z ; Exit if zero + RET C ; Exit if greater than ncheck + LD HL,(DIRBUF) ; Get dirbuf + CALL CKS127 ; ..and checksum first 127 bytes.. + ADD A,(HL) ; ...then 128th byte (hfb) + LD HL,(CSV) ; Get pointer checksum directory + ADD HL,DE ; Add current record + INC C ; Test checksum flag + JR NZ,CHKDR1 ; 0FFH=> update checksum + LD (HL),A ; Update checksum + RET ; And exit + +CHKDR1: CP (HL) ; Test checksum + RET Z ; Exit if ok + +; Checksum differs, So Disk has changed. Relog it and continue + + LD A,(FLAGS) + BIT 4,A ; Inform user? + LD B,0 ; Disk change error code + LD DE,MDSKCH ; Disk changed message + CALL NZ,ERROR ; Inform user + +; Relog Current Drive after media change detected + + CALL GETCDM ; Get current drive mask in HL + EX DE,HL ; Xfer mask to DE + CALL UNLOG ; Reset login vector for logged drive + CALL RELOG1 ; Do the meat of relogging + ; Caveat emptor: this call is recursive... + CALL SETFCT ; Re-initialize search file count + XOR A ; We only get here by checking.. (bm) + JR RDDIR ; And all checking is done from rddir + +; Read Sector from Drive + +READR: CALL READ ; CBIOS call read sector + JR WRITE0 + +; Write Sector on Drive + +WRITER: CALL WRITE ; CBIOS call write sector +WRITE0: OR A ; Test exit code + RET Z ; Exit if ok + LD B,1 ; Disk I/O error code + LD DE,MBADSC ; Load bad sector message + LD HL,(STBDSC) ; Load bad sector vector + JP (HL) ; ZSDOS error on D: Bad Sector + +; Close File Command (relocated hfb) + +BGPTCH2 EQU $+1 ;<-- BGii patch point + +CMND16: CALL SELDR1 ; Select drive from FCB + +; Close File + +CLOSE: BIT 7,(IX+FCBMOD) ; Test FCB/file modified + RET NZ ; Not then no close required + CALL CHKRO ; Test disk W/P + CALL SRCT15 ; Search file and test present + RET Z ; No then exit with error + CALL CKRODI ; Check file W/P, get directory entry + LD BC,16 ; Offset to DM block + ADD HL,BC ; Add offset + EX DE,HL ; Save DIR PTR in DE + LD HL,(ARWORD) ; Get FCB ptr + ADD HL,BC ; Add offset + EX DE,HL + LD B,C ; Xfer counter + +; Copy FCB (DE) to DIR (HL) if and only if DIR=0 or DIR=FCB + +CLOSE0: INC (HL) + DEC (HL) ; Test DIR for 0 + LD A,(DE) ; Get byte from FCB + JR Z,CLOSE1 ; OK to Copy if 0 + CP (HL) ; Test if same as DIR + JP NZ,RETCFF ; ..if Not, abort Close and return error +CLOSE1: LD (HL),A ; Else save in DIR + INC DE + INC HL + DJNZ CLOSE0 ; Bump pointers and loop until done + LD DE,-20 ; Add -20 to get Extent Number from DIR + ADD HL,DE ; HL contains pointer to extent number + LD A,(IX+FCBEXT) ; Get extent number FCB + CP (HL) ; Compare with extent number directory + JR C,CLOSE3 ; FCB < directory then jump + LD (HL),A ; Save extent number in directory + INC HL ; Get pointer to next record + INC HL + INC HL + LD A,(IX+FCBREC) ; Get next record FCB + LD (HL),A ; Save next record in directory +CLOSE3: CALL CLOSE6 ; Clear Archive Bit and Write FCB + CALL GETDME ; Get Data Module and Extent + IF ~ZSDOS11 ; (* NOT in Release version *) + PUSH BC ;[1.2] Save prior module and Extent + JR Z,CLOSE4 ; ..jump to Stamp if they are both 0 + ELSE ;Zsdos11 (* This was Release version *) + JR Z,CLOSE4 ; ..jump to Stamp if they are both 0 + PUSH BC ; Save prior module and Extent + ENDIF ;~Zsdos11 + LD BC,0 + CALL SETDME ; Set FCB Data Module and Extent to 0 + CALL SRCT15 ; Find proper DIR Entry + IF ~ZSDOS11 + JR Z,JSETDME ; ..Exit if Extent 0 Not Found +CLOSE4: + ELSE ;Zsdos11 + POP BC + JR Z,JSETDME ; ..Exit if Extent 0 Not Found +CLOSE4: PUSH BC + ENDIF ;~Zsdos11 + CALL CLOSE6 ; Clear Archive Bit and Write FCB + LD HL,(STUPDV) ; Get the update routine address + IF ZS + CALL STAMPT ; ..and stamp it + ELSE ;If not Zs (crw) + LD C,10 ; Set Last Modify + CALL JPHL ; ..and Stamp if Enabled + ENDIF ;ZS + IF ~ZSDOS11 +JSETDME: + POP BC ; Get Original Module and Extent Back + ELSE ;Zsdos11 + POP BC ; Get Original Module and Extent Back +JSETDME: + ENDIF ;~Zsdos11 + JP SETDME ; Restore to FCB and Exit + +CLOSE6: CALL CALDIR ; Get directory entry + LD BC,11 ; Point to archive byte + ADD HL,BC + RES 7,(HL) ; Reset archive bit + RES 7,(IX+ARCATT) ; Reset bit in FCB + IF ZSDOS11 + JR WRFCB ; Write FCB to Disk + + IF ~ZS +READDR: CALL DMADIR ; Set up DMA directory + CALL READR ; Read a record + JR STDMA ; ..and set up user's DMA + ENDIF ;NOT Zs + ENDIF ;Zsdos11 + +WRFCB: CALL CALDIR ; Point to dir entry to write + LD A,FCBUSR ; Offset to user byte in FCB + CALL CALDI0 ; ..do the add here + LD (HL),0 ; Prevent writing it to disk + CALL STDIR ; Calculate sector/track directory + LD C,0FFH ; Update checksum directory + CALL CHKDIR +WRITD1: CALL DMADIR ; Set up dma directory (label for DS - crw) + LD C,1 ; Write directory flag + CALL WRITER ; Write record + JR STDMA ; Set up DMA user + + IF ~ZSDOS11 + IF ~ZS +READDR: CALL DMADIR ; Set up DMA directory + CALL READR ; Read a record + JR STDMA ; ..and set up user's DMA + ENDIF ;NOT Zs + ENDIF ;~Zsdos11 + +; Set DMA Address Command + +CMND26: LD (DMA),DE ; Save DMA address + +; Set DMA Address + +STDMA: LD BC,(DMA) ; Get DMA address + JR DMADR0 ; And do BIOS call + +; Set DMA Address Directory + +DMADIR: LD BC,(DIRBUF) ; Get DMA address directory +DMADR0: JP SETDMA ; Cbios call set DMA + +; Get Bit from ALV Buffer +; Entry DE=Block Number +; Exit A =Bit in LSB +; B =Bit Number in A +; HL=Pointer in ALV Buffer + +GETBIT: LD A,E ; Get bit number + AND 7 ; Mask it + INC A ; Add 1 + LD C,A ; Save it + IF UNROLL + SRL D ; Get byte number + RR E ; DE=DE/8 + SRL D + RR E + SRL D + RR E ; ..inline for speed (net cost: 4) + LD B,A ; Re-save bit number for next shift + LD HL,(ALV) ; Get start address ALV buffer + ELSE + EX DE,HL + CALL SHRHL3 ; Divide by 8 + LD B,A ; Re-save bit number for next shift + LD DE,(ALV) ; Get start address ALV buffer + ENDIF ;Unroll + ADD HL,DE ; Add byte number + LD A,(HL) ; Get 8 bits +GETBT0: RLCA ; Get correct bit + DJNZ GETBT0 + LD B,C ; Restore bit number + RET ; And return to caller + +; Set/Reset bit in ALV Buffer +; Entry DE=Block Number +; C =0 Reset Bit, C=1 Set Bit + +SETBIT: PUSH BC ; Save set/reset bit + CALL GETBIT ; Get bit + AND 0FEH ; Mask it + POP DE ; Get set/reset bit + OR E ; Set/reset bit +SETBT0: RRCA ; Rotate bit in correct position + DJNZ SETBT0 + LD (HL),A ; Save 8 bits + RET ; And return to caller + +; Delete File + +DELETE: CALL COMCOD ; Call common code w/VDEL on stack + +; Delete Routine Core (relocated to save space) (hfb) + +VDEL: CALL CKRODI ; Check file W/P, get directory entry + LD (HL),0E5H ; Remove file + INC HL + LD A,(HL) ; Get first char + SUB '$' ; See if submit file + JR NZ,VDEL1 ; If not + LD (SUBFLG),A ; Clear subflg if $*.* erased +VDEL1: INC HL + RES 7,(HL) ; Insure erased files are not public + LD C,0 ; Remove bits ALV buffer + ; ..fall thru and return to caller.. + +; Fill bit buffer from FCB in DIRBUF +; Entry C=0 Reset Bit, C=1 Set Bit + +FILLBB: CALL CALDIR ; Get directory entry + LD DE,16 ; Get offset DM block + ADD HL,DE ; Add offset + LD B,E ; Get block counter +FILLB0: LD E,(HL) ; Get LSB block number + INC HL ; Increment pointer + LD D,0 ; Reset MSB block number + LD A,(MAXLEN+1) ; Test >256 blocks present + OR A + JR Z,FILLB1 ; No then jump + DEC B ; Decrement block counter + LD D,(HL) ; Get correct MSB + INC HL ; Increment pointer +FILLB1: LD A,D ; Test block number + OR E + JR Z,FILLB2 ; Zero then get next block + PUSH HL ; Save pointer + PUSH BC ; Save counter and set/reset bit + LD HL,(MAXLEN) ; Get maximum length ALV buffer + OR A ; Reset carry + SBC HL,DE ; Test DE<=maxlen ALV buffer + CALL NC,SETBIT ; Yes then insert bit + POP BC ; Get counter and set/reset bit + POP HL ; Get pointer +FILLB2: DJNZ FILLB0 ; Repeat for all DM entries + RET ; And return to caller + +; Check File W/P Bit - SEARCH called first + +CHKFRO: CALL CALDIR ; Get directory entry + LD DE,WHLATT ; Offset to R/O bit + ADD HL,DE ; Add offset + LD DE,(WHEEL) ; Get wheel byte address from header + LD A,(DE) ; ..and retrieve the actual byte + AND A ; ..and check the Wheel byte + JR NZ,CHKFR4 ; We have wheel, so allow writes anyway + BIT 7,(HL) ; Else check Wheel attribute + JR NZ,CHKFR2 ; Yes then error +CHKFR4: INC HL ; Check W/P bit (hfb) + BIT 7,(HL) ; Test file W/P + JR NZ,CHKFR2 ; If W/P +CHKFR3: BIT 7,(IX+PSFATT) ; Was file accessed as Public or Path? + RET Z ; If normal access + LD A,(FLAGS) ; Else test for writes allowed + AND 0010B + RET NZ ; Go ahead, writes are allowed +CHKFR2: LD HL,(SFILRO) ; Get pointer to file W/P message + LD B,3 ; File W/P error code + LD DE,MFILRO ; Load file W/P message + JP (HL) ; Display message + + +; Check Drive Write Protect + +BGCKDRO: +CHKRO: CALL CHKRO1 ; Is the disk W/P? + RET NZ ; ..return if disk R/W + LD B,2 ; Else set disk W/P error code + LD DE,MRO ; Load drive W/P message + LD HL,(STRO) ; Get pointer to drive W/P message + JP (HL) ; Display message + +CHKRO1: LD HL,(DSKWP) ; Get the W/P drive vector + CALL SDRVB ; Set the bit for this drive + SBC HL,DE ; See if extra bit added (Cy is clear) + RET + +; Search using first 12 bytes of FCB (hfb) + +SEAR12: LD A,12 + DEFB 21H ; Trash HL and fall through + +; Search using first 15 bytes of FCB + +SEAR15: LD A,15 + +; Search for File Name +; Entry: A = Number of bytes for which to search + +SEARCH: LD (SEARNB),A ; Save number of bytes + LD A,0FFH ; Set exit code to 0FFH (not found) + LD (SEAREX),A + LD (DCOPY),IX ; Copy FCB pointer to RAM (search next) + CALL SETFCT ; Initiate file counter + +; Force directory read with a Call HOME (bh) (Only if Floppys-hfb) + IF ZSDOS11 ; (* Logic moved to RDDIR if NOT Zsdos11 *) + LD HL,(NCHECK) ; Is this a fixed media? + LD A,H + OR L + CALL NZ,HOME ; Invoke CBIOS Home routine if removeable + ENDIF ;~Zsdos11 + +; Search Next File Name + +SEARCN: XOR A ; Check checksum directory + LD H,A + LD L,A + LD (SEARQU),HL ; Clear question mark & public detected flags + RES 7,(IX+PSFATT) ; Reset public/system file flag + CALL RDDIR ; Get FCB from directory + CALL TSTFCT ; Test if past last entry + JR Z,JSEAR8 ; Yes then jump (note carry always clear) + LD DE,(DCOPY) ; Get FCB pointer + LD A,(DE) ; Get first byte + CP 0E5H ; Test if searching empty directory + JR Z,SEARC1 ; Yes then jump + PUSH DE ; Save FCB pointer + CALL TSTLF ; Test last file on this drive + POP DE ; Restore FCB pointer +JSEAR8: JR NC,SEARC8 ; Yes then jump +SEARC1: CALL CALDIR ; Get entry in directory + LD A,(HL) ; Get first byte directory entry + CP 21H ; Test time stamp + JR Z,SEARCN ; Yes then get next directory entry + LD C,0 ; Clear counter + LD A,(SEARNB) ; Get number of bytes to search for + LD B,A ; Save it in counter +SEARC2: LD A,B ; Test if counter is zero + OR A + JR Z,SEARC9 ; Yes then jump + LD A,(DE) ; Get byte from FCB + XOR '?' ; Test if question mark + AND 7FH ; Mask it + JR Z,SEARC6 ; Yes then jump + LD A,C ; Get FCB counter + OR A ; Test first byte + JR NZ,SEARC3 ; No then jump + LD A,(FLAGS) ; Get flag byte + RRA ; Test public file enable + JR NC,SEARC3 ; ..jump if not + INC HL ; Get pointer to Public Bit + INC HL + BIT 7,(HL) ; Test Public Bit directory + DEC HL ; Restore pointer + DEC HL + JR Z,SEARC3 ; No public file then jump + LD A,(DE) ; Get first byte FCB + CP 0E5H ; Test if searching empty directory + JR Z,SEARC3 ; Yes then jump + +; The following 3 lines of code represent a deviation from the description of +; PUBLIC Files as given in DDJ Article by Bridger Mitchell and Derek McKay of +; Plu*Perfect Systems. The PUBLIC Specification states that Public Files will +; NOT be found by any wildcard reference except when a "?" is in the FCB+0 +; byte. The code here relaxes that requirement as follows: If we are in the +; same user area as the public file, then don't report the file as PUBLIC, but +; find it. This has a nasty side effect - it allows erasing of PUBLIC files +; if we are in the same area. However, these files also show up on the direc- +; tory (they wouldn't otherwise), so at least we should know we're blasting +; them. + + XOR (HL) ; Test FCB = Directory Entry + AND 7FH ; Mask it (setting Zero Flag) + JR Z,SEARC5 ; Jump if user is same + LD A,0FFH + LD (SEARPU),A ; Set Public file found + IF UPATH + CALL SETPSF ; Set Public/System file flag + ELSE + SET 7,(IX+PSFATT) ; Set Public/System file flag + ENDIF + JR SEARC5 ; Jump found + +SEARC3: LD A,C ; Get FCB counter + CP 13 ; Is it User Code? + JR Z,SEARC5 ; ..jump if so..don't test + CP 12 ; Is it an Extent Number? + LD A,(DE) ; ..Get byte from FCB + JR Z,SEARC7 ; ..Jump if Extent Number + XOR (HL) ; Is FCB byte = Directory Entry byte? + AND 07FH ; ..Mask it +SEARC4: JR NZ,SEARCN ; ..jump if not same and get next entry +SEARC5: INC DE ; Increment FCB pointer + INC HL ; Increment Directory Entry pointer + INC C ; Increment counter + DEC B ; Decrement counter + JR SEARC2 ; Test next byte + +SEARC6: DEC A ; Set question mark found flag + LD (SEARQU),A + JR SEARC5 ; Jump found + +SEARC7: + XOR (HL) ; Test extent + CALL SEARC7A ; Mask Extent + JR SEARC4 ; ..and test Result + + +SEARC7A: PUSH BC + LD B,A ; Save Extent + LD A,(NEXTND) ; Get extent mask + CPL ; Complement it + AND MAXEXT ; Mask it + AND B ; Mask extent + POP BC ; Restore counters + RET + +SEARC8: CALL SETFCT ; Error set file counter + JP RETCFF ; Set return code to FF and exit + +SEARC9: LD HL,(SEARQU) ; Get question mark and public found flags + LD A,H + AND L + JR NZ,SEARC4 ; Yes then search for next entry + CALL TSTLF ; Test for last file + CALL NC,SETLF0 ; And update if so + LD HL,(RECDIR) ; Set DE return to directory record + LD (DEVAL),HL ; .. for DateStamper simulation + LD A,(FILCNT) ; Get file counter + AND 3 ; Mask it + LD (PEXIT),A ; And set exit code + XOR A ; Clear exit code search + LD (SEAREX),A + RET ; And return to caller + +; The following code is common to DELETE, RENAME, and CSTAT. +; It is coded in a manner that is compatable with the Z280 +; in protected Mode. + +COMCOD: CALL CHKRO ; Check disk W/P + CALL SEAR12 ; Search file +COMCO1: CALL TSTFCT ; Test if file found + POP HL ; Routine addr to HL (in case not found) + RET Z ; Not then exit + PUSH HL ; ..found, so routine back to stack + PUSH HL ; Twice, as RET pops first push + LD HL,COMCO2 + EX (SP),HL ; COMCO2 to stack, routine addr to HL + JP (HL) ; ..branch to routine + +COMCO2: CALL WRFCB ; Write directory buffer on disk + CALL SEARCN ; Search next entry + JR COMCO1 ; And test it + + +; Rename File - Note Wildcard Support + +RENAM: CALL COMCOD ; Go to common code w/VRENAM on stack + +VRENAM: CALL CHKFRO ; Check file W/P + LD HL,(ARWORD) + LD DE,16 ; Offset to new name + ADD HL,DE ; Add offset + EX DE,HL ; Copy HL=>DE + CALL CALDIR ; Get directory entry + INC HL + INC HL + RES 7,(HL) ; Make any renamed file private + DEC HL + DEC HL + LD B,11 ; Set up loop counter +RENAM1: INC HL ; Increment directory pointer + INC DE ; Increment FCB pointer + LD A,(DE) ; Get character from FCB + AND 7FH ; Mask it + CP '?' ; Test if question mark + JR NZ,RENAM2 ; no, then change character on disk + LD A,(HL) ; Else get what's there as there is no change +RENAM2: RLA ; Clear MSB + RL (HL) ; Get MSB from directory + RRA ; And move to FCB + LD (HL),A ; Save in directory + DJNZ RENAM1 ; Loop until done + RET + +; Change Status Bits for File + +CSTAT: CALL COMCOD ; Go to common code w/VCSTAT on stack + +VCSTAT: PUSH IX + POP DE ; FCB pointer in DE + CALL CALDIR ; Get directory entry + LD B,11 ; Set up loop counter +CSTAT1: INC HL ; Increment directory pointer + INC DE ; Increment FCB pointer + LD A,4 ; Are we pointing to Wheel Attribute? + CP B + JR NZ,CSTAT2 ; ..jump if not + PUSH HL + LD HL,(WHEEL) ; Else do we have Wheel privileges? + LD A,(HL) + POP HL + AND A ; ..set flags to show + JR NZ,CSTAT2 ; Jump if we have Wheel + BIT 7,(HL) ; Is file Wheel protected? + JP NZ,CHKFR2 ; ..jump if so +CSTAT2: LD A,(DE) ; Get status bit from FCB + RL (HL) ; Remove MSB of directory + RLA ; Get msb from FCB + RR (HL) ; And move into directory char + DJNZ CSTAT1 ; Loop until done + RET + +; Compute File Size + +FILSZ: LD BC,0 ; Reset file size length + LD D,C + CALL LDRRC ; Save it in FCB+33,34,35 + CALL SEAR12 ; Search file (hfb) +FILSZ0: CALL TSTFCT ; Test if file found + RET Z ; Not then exit + CALL CALDIR ; Get directory entry + EX DE,HL ; Copy to DE + LD HL,15 ; Offset to next record + CALL CALRRC ; Calculate random record count + LD A,D ; Test LSB < (ix+33) + SUB (IX+33) + LD A,C ; Test ISB < (ix+34) + SBC A,(IX+34) + LD A,B ; Test MSB < (ix+35) + SBC A,(IX+35) + CALL NC,LDRRC ; Write new maximum + CALL SEARCN ; Search next file + JR FILSZ0 ; And test it + +; Find File + IF UPATH +FINDF: CALL SRCT15 ; Search file + RET NZ ; Yes then exit + LD A,(FLAGS) + BIT 5,A ; Test if Path enabled + RET Z ; Exit if not + LD HL,(PATH) ; Get Path address + LD A,H ; Test if zero (no path) + OR L + RET Z ; Yes then exit +FINDF0: LD A,(HL) ; Get first entry path name + INC HL ; Increment pointer + OR A ; Test if last entry + JP Z,SEARC8 ; Yes then error exit + AND 7FH ; Mask drive number + CP '$' ; Test if current drive + JR NZ,FINDF1 ; No then jump + LD A,(DRIVE) ; Get current drive + INC A ; Increment drive number +FINDF1: DEC A ; Decrement drive number + PUSH HL ; Save path pointer + CALL SELDK ; Select drive + POP HL ; Restore path pointer + LD A,(HL) ; Get user number + INC HL ; Advance pointer + AND 7FH ; Mask user number + CP '$' ; Test if current user + JR NZ,FINDF2 ; No then jump + LD A,(USER) ; Get current user +FINDF2: AND 1FH ; Mask user number + PUSH HL ; Save path pointer + CALL RESUSR ; Add new user number in FCB+0 and FCB+13 + CALL SRCT15 ; Search file and test if present + POP HL ; Restore path pointer + JR Z,FINDF0 ; No then test next path entry + PUSH HL ; Save path pointer + CALL CALDIR ; Get directory entry + LD DE,10 ; Add offset system bit + ADD HL,DE + BIT 7,(HL) ; Test system file + LD A,(FLAGS) ; Test for relaxed path definition + RLA ; ..by rotating bit.. + RLA ; ..into carry flag + POP HL ; Restore path pointer + JR C,FINDF3 ; If carry, system attrib not required + JR Z,FINDF0 ; No system file then test next path entry +FINDF3: LD A,(DEFDRV) ; Get current drive + INC A ; Increment drive number + LD (FCB0),A ; Save it in exit FCB0 +SETPSF: SET 7,(IX+PSFATT) ; set Public/System file flag + RET ; And return to caller + ENDIF ;Upath + +; Open File Command + +CMND15: CALL SELDRV ; Select drive from FCB + LD (IX+FCBMOD),0 ; Clear data module number + +; Open File + IF UPATH + CALL FINDF ; Find file (use path name) + CALL TSTFCT ; Test file found + ELSE + CALL SRCT15 ; Find file W/O path + ENDIF ;Upath + RET Z ; No then exit +OPENF0: LD A,(IX+PSFATT) ; Get Public/System file bit + PUSH AF ; Save it + LD A,(IX+FCBEXT) ; Get extent number from FCB + PUSH AF ; Save it + CALL CALDIR ; Get directory entry + LD A,(HL) ; Find real user number file is in + OR 80H ; Set user valid flag + PUSH IX ; Save FCB entry + POP DE ; Get in in DE + LD BC,32 ; Number of bytes to move + LDIR ; Move directory to FCB + LD (IX+FCBUSR),A ; And put user byte back + CALL SETB14 ; Set FCB/File Not Modified + LD B,(IX+FCBEXT) ; Get extent number + LD C,(IX+FCBREC) ; Get next record number + POP AF ; Get old extent number + LD (IX+FCBEXT),A ; Save it + CP B ; Compare old and new extent number + JR Z,OPENF1 ; Same then jump + LD C,0 ; Set next record count to 0 + RR C ; Record count to Max (80H) if need new extent +OPENF1: LD (IX+FCBREC),C ; Save next record count + POP AF ; Get Public/System file bit + RL (IX+PSFATT) ; Remove MSB from IX+8 + RLA ; Set new MSB in carry + RR (IX+PSFATT) ; Save Carry in IX+8 + IF ZS + LD HL,(STLAV) ; Get address of last accessed routine + JP STAMPT + ELSE + LD C,5 ; Set access stamp + LD HL,(STLAV) ; Get address of last accessed routine +JPHL: JP (HL) ; ..and Jump to it (or DOTDER) + ENDIF ;Zs + +; Make File Command + +CMND22: CALL SELDRV ; Select drive from FCB + LD (IX+FCBMOD),0 ; Clear data module number + +; Make File + +MAKES: CALL CHKRO ; Check drive W/P + LD HL,(ARWORD) + LD A,(HL) ; Get first byte FCB + PUSH AF ; Save it + LD (HL),0E5H ; Set first byte to empty file + LD A,1 ; Search for 1 byte + CALL SEARCH ; Search empty file + POP AF ; Get first byte FCB + LD (IX+0),A ; Restore it + CALL TSTFCT ; Test empty file found + RET Z ; No then return error + LD HL,(ARWORD) ; Get FCB pointer + CALL CKSUB ; Check if this is a submit file + LD DE,15 ; Prepare offset + ADD HL,DE ; Add it + LD B,17 ; Set loop counter + XOR A +MAKE0: LD (HL),A ; Clear FCB+15 up to FCB+31 + INC HL ; Increment pointer + DJNZ MAKE0 ; And clear all bytes + RES 7,(IX+PSFATT) ; Reset Public/System file bit + RES 7,(IX+ARCATT) ; Reset archive bit if present + CALL CALDIR ; Get directory entry + PUSH IX ; Save FCB entry + POP DE ; Get it in DE + EX DE,HL ; Exchange FCB and directory entry + LD BC,32 ; Number of bytes to move + LDIR ; Move bytes + CALL WRFCB ; Write FCB on disk + CALL SETB14 ; Set file not modified + IF ZS + LD HL,(STCRV) ; Get address of Stamp Create routine + JP STAMPT ; ..and stamp it + ELSE + LD C,0 ; Set Create Stamp + JP STIME ; And exit + ENDIF ;Zs + +; Open Next Extent + +OPENEX: BIT 7,(IX+FCBMOD) ; Test if FCB/File Modified (write) + JR NZ,OPENX2 ; Not then jump + CALL CLOSE ; Close current FCB + LD A,(PEXIT) ; Get exit code + INC A ; Test if error + RET Z ; Yes then exit +OPENX2: CALL CALNEX ; Calculate next extent (LABEL MOVED) + JR C,OPENX3 ; Error then jump + +OPENX0: CALL SRCT15 ; Search for 15-char match & test presence + JR NZ,OPENX5 ; Yes then jump + LD A,(RDWR) ; Test Read/Write flag + OR A ; Test if read + JR Z,OPENX3 ; Yes then error + CALL MAKES ; Make new extent if write + CALL TSTFCT ; Test if succesfull + JR NZ,OPENX6 ; Yes then exit +OPENX3: CALL SETB14 ; Set FCB/File Not Modified +RETCFF: LD A,0FFH ; (hfb/cwc) set exit code +OPENX4: JP SAVEA ; And return to caller + +OPENX5: CALL OPENF0 ; Open file +OPENX6: XOR A ; And clear exit code + JR OPENX4 ; Use same routine + +;==OPENX2: CALL CALNEX ; Calculate next extent +;== JR C,OPENX3 ; Error then jump +;== JR OPENX0 ; Open next extent, FCB contains DU: + +; Calculate Next Extent +; Exit: Carry=1 => Overflow Detected + +CALNEX: CALL GETDME ; Get extent number, data module number + BIT 6,B ; Test error bit random record + SCF ; Set error flag + RET NZ ; ..Error exit if Non-zero + INC C ; Increment extent number + LD A,C ; Get extent number + AND MAXEXT ; Mask it for max extent + LD C,A ; Save it in C +;== JR NZ,SETDME ; If new data module not required + JR NZ,CALNE1 ;== IF NEW DATA MODULE NOT REQUIRED + INC B ; Set next data module + LD A,B ; Get it in A + AND MAXMOD ; Mask it for max module + LD B,A ; Save it in B + SCF ; Set error flag + RET Z ; And return if file overflow +CALNE1: LD (IX+NXTREC),0 ;== ZERO NEXT RECORD COUNT +SETDME: LD (IX+FCBEXT),C ; Save Extent number + LD (IX+FCBMOD),B ; Save Data Module number + IF ZS + AND A ; Clear flag here if ZS + RET + ENDIF ; ..else fall thru on ZD to do same thing + +GETDME: LD C,(IX+FCBEXT) ; Get Extent number + LD B,(IX+FCBMOD) ; Get Data Module number + LD A,C + CALL SEARC7A ; Mask Extent + RES 7,B ; Clear Unmodified Flag + OR B ; Test for Module and Extent = 0 + RET ; ..and return to caller + +; Read Random Record Command + +CMND33: CALL SELDR1 ; Select drive from FCB + +; Read Random Sector + + XOR A ; Set read/write flag + CALL LDFCB ; Load random record in FCB + JR Z,READS ; No error then read sector + RET ; Return error + +; Read Sequential + +CMND20: CALL SELDR1 ; Select drive from FCB + +; Read Sector + +READS: XOR A ; Set Read/Write flag + LD (RDWR),A ; Save it + LD A,(IX+NXTREC) ; Get record counter + CP 80H ; Test if last record this extent +;= JR NC,READS1 ; Yes then open next extent + JR Z,READS1 ;= Yes then open next extent + CP (IX+FCBREC) ; Test if greater then current record + JR C,READS2 ; No then get record +READS0: LD A,1 ; Set end of file flag + JR OPENX4 ; And exit + +READS1: CALL OPNXCK ; Open next extent +READS2: CALL GETDM ; Get block number from DM in FCB + JR Z,READS0 ; Jump if block number=0 to end file + CALL CALSEC ; Calculate Sector Number (128 bytes) + CALL CALST ; Calculate Sector/Track number + CALL READR ; Read data + JP WRITS7 ; Increment elsewhere if necessary + +; Consolidated Routine to Open Extent and check status + +OPNXCK: CALL OPENEX ; Open next extent + LD A,(PEXIT) ; Get exit code + OR A + RET Z ;== IF OPEN OK + POP HL ;== ELSE POP RETURN ADDRESS TO ABORT R/W + JR READS0 ;== AND SET ERROR CODE TO EOF +;== JR NZ,READS0 ; Yes then end of file +;== LD (IX+NXTREC),A ; Clear record counter (jww) +;== RET + +; Write Random Record Command (with and without Zero Fill) + +CMND40: ; (hfb/cwc) +CMND34: CALL SELDR1 ; Select drive from FCB + +; Write Random Sector and Write Random with Zero Fill + + LD A,0FFH ; Set Read/Write flag + CALL LDFCB ; Load FCB from random record + JR Z,WRITES ; No error then write record + RET ; Return error + +; Write Sequential + +CMND21: CALL SELDR1 ; Select drive from FCB + +; Write Sector. Permitted to PUBlic files and those found along Path + +WRITES: LD A,0FFH ; Set read/write flag + LD (RDWR),A ; And save it + +BGPTCH1 EQU $+1 ;<-- Patched location for BGii + + CALL CHKRO ; Check disk W/P + BIT 7,(IX+ROATT) ; Test if file W/P + JR NZ,WRITSA ; Yes then file W/P message + CALL CHKFR3 ; Test W/P if path or Public used + LD HL,(WHEEL) ; Get address of Wheel byte + LD A,(HL) ; Do we have it? + AND A + JR NZ,WRITSB ; Yes - allow write + BIT 7,(IX+WHLATT) ; Else test if Wheel Prot file +WRITSA: JP NZ,CHKFR2 ; Yes then file W/P message +WRITSB: BIT 7,(IX+NXTREC) ; End of this extent? + CALL NZ,OPNXCK ; Open next extent and check status (hfb) + CALL GETDM ; Get block number from FCB + JP NZ,WRITS5 ; Jump to write sector if Block Number <> 0 + PUSH HL ; Save pointer to Block Number + LD A,C ; Test first Block Number in extent + OR A + JR Z,WRITS1 ; Yes then jump + DEC A ; Decrement pointer to Block Number + CALL GETDM4 ; Get previous Block Number + +; Get Free Block from ALV Buffer +; Entry DE=Old Block Number +; Exit DE=New Block Number (0 if No Free Block) +; HL counts Up,DE counts Down + ; GETFRE routine relocated here inline +WRITS1: LD H,D ; Copy old block to HL + LD L,E +GETFR0: LD A,D ; Test down counter is zero + OR E + JR Z,GETFR1 ; Yes then jump + DEC DE ; Decrememt down counter + PUSH HL ; Save up/down counter + PUSH DE + CALL GETBIT ; Get bit from ALV buffer + RRA ; Test if zero + JR NC,GETFR3 ; Yes then found empty block + POP DE ; Get up/down counter + POP HL +GETFR1: LD BC,(MAXLEN) ; Get maximum ALV length-1 in BC + LD A,L ; Is HL >= length ALV-1? + SUB C ; ..do while preserving HL + LD A,H + SBC A,B + JR NC,GETFR2 ; End buffer then jump + INC HL ; Increment up counter + PUSH DE ; Save down/up counter + PUSH HL + EX DE,HL ; Save up counter in DE + CALL GETBIT ; Get bit from ALV buffer + RRA ; Test if zero + JR NC,GETFR3 ; Yes then found empty block + POP HL ; Get down/up counter + POP DE + JR GETFR0 ; And test next block + +GETFR2: LD A,D ; Test if last block tested + OR E + JR NZ,GETFR0 ; No then test next block + JR WRITSG ; Continue with DE=0 + +GETFR3: SCF ; Set block number used + RLA ; Save bit + CALL SETBT0 ; Put bit in ALV buffer + POP DE ; Get correct counter + POP HL ; Restore stack pointer + ; ..continue with (DE=block number) + +WRITSG: POP HL ; Get pointer to Block Number + LD A,D ; Test if blocknumber = 0 + OR E + JR Z,WRITS8 ; Yes then disk full error + RES 7,(IX+FCBMOD) ; Reset FCB/File Modified + LD (HL),E ; Save blocknumber + LD A,(MAXLEN+1) ; Get number of blocks + OR A ; Is it < 256? + JR Z,WRITS2 ; ..Jump if so + INC HL ; Increment to MSB Block Number + LD (HL),D ; ..and save MSB block number +WRITS2: LD C,2 ; Set write new block flag + LD A,(NMASK) ; Get sector mask + AND (IX+NXTREC) ; Mask with record counter + JR Z,WRITSX ; Zero then Ok (at start new record) + LD C,0 ; Else clear new block flag +WRITSX: LD A,(FUNCT) ; Get function number + SUB 40 ; Test if Write RR with zero fill + JR NZ,WRITS6 ; No then jump + PUSH DE ; Save blocknumber + LD HL,(DIRBUF) ; Use directory buffer for zero fill + LD B,128 ; 128 bytes to clear +WRITS3: LD (HL),A ; Clear directory buffer + INC HL ; Increment pointer + DJNZ WRITS3 ; Clear all bytes + CALL CALSEC ; Calculate sector number (128 bytes) + LD A,(NMASK) ; Get sector mask + LD B,A ; Copy it + INC B ; Increment it to get number of writes + CPL ; Complement sector mask + AND E ; Mask sector number + LD E,A ; And save it + LD C,2 ; Set write new block flag +WRITS4: PUSH HL ; Save registers + PUSH DE + PUSH BC + CALL CALST ; Calculate sector/track + CALL DMADIR ; Set DMA directory buffer + POP BC ; Get write new block flag + PUSH BC ; Save it again + CALL WRITER ; Write record on disk + POP BC ; Restore registers + POP DE + POP HL + LD C,0 ; Clear write new block flag + INC E ; Increment sector number + DJNZ WRITS4 ; Write all blocks + CALL STDMA ; Set user DMA address + POP DE ; Get Block Number +WRITS5: LD C,0 ; Clear write new block flag +WRITS6: RES 7,(IX+FCBMOD) ; Reset FCB/File Modified flag + PUSH BC ; Save it + CALL CALSEC ; Calculate sector number (128 bytes) + CALL CALST ; Calculate Sector/Track + POP BC ; Get write new block flag + CALL WRITER ; Write record on disk + LD A,(IX+NXTREC) ; Get record counter + CP (IX+FCBREC) ; Compare with next record + JR C,WRITS7 ; If less then jump + INC A ; Increment record count + LD (IX+FCBREC),A ; Save it on next record position + RES 7,(IX+FCBMOD) ; Reset FCB/File Modified flag +WRITS7: LD A,(FUNCT) ; Get function number + CP 20 ; (hfb) + RET C ; Return if < 20 (hfb) + CP 21+1 ; (hfb) + RET NC ; Return if > 21 (hfb) + INC (IX+NXTREC) ; Increment record count + RET ; And return to caller + +WRITS8: LD A,2 ; Set disk full error + JP SAVEA ; And return to caller + + +; Load FCB for Random Read/Write +; Exit : Zero Flag = 1 No Error +; 0 Error Occured + +LDFCB: LD (RDWR),A ; Save Read/Write flag + LD A,(IX+33) ; Get first byte random record + LD D,A ; Save it in D + RES 7,D ; Reset MSB to get next record + RLA ; Shift MSB in carry + LD A,(IX+34) ; Load next byte random record + RLA ; Shift Carry + PUSH AF ; Save it + AND MAXEXT ; Mask next extent + LD C,A ; Save it in C + POP AF ; Get byte + RLA ; Shift 4 times + RLA + RLA + RLA + AND 0FH ; Mask it + LD B,A ; Save data module number + LD A,(IX+35) ; Get next byte random record + LD E,6 ; Set random record to large flag + CP 4 ; Test random record to large + JR NC,LDFCB8 ; Yes then error + RLCA ; Shift 4 times + RLCA + RLCA + RLCA + ADD A,B ; Add byte + LD B,A ; Save data module number in B + LD (IX+NXTREC),D ; Set next record count + LD D,(IX+FCBMOD) ; Get data module number + BIT 6,D ; Test error random record + JR NZ,LDFCB0 ; Yes then jump + LD A,C ; Get new extent number + CP (IX+FCBEXT) ; Compare with FCB + JR NZ,LDFCB0 ; Not equal then open next extent + LD A,B ; Get new data module number + XOR (IX+FCBMOD) ; Compare with data module number + AND MAXMOD ; Mask it + JR Z,LDFCB6 ; Equal then return +LDFCB0: BIT 7,D ; Test FCB modified (write) + JR NZ,LDFCB1 ; No then jump + PUSH DE ; Save registers + PUSH BC + CALL CLOSE ; Close extent + POP BC ; Restore registers + POP DE + LD E,3 ; Set close error + LD A,(PEXIT) ; Get exit code + INC A + JR Z,LDFCB7 ; Error then exit +LDFCB1: CALL SETDME ; Save Data Module and Extent + CALL SEAR15 ; Search next FCB + LD A,(PEXIT) ; Get error code + INC A + JR NZ,LDFCB5 ; No error then exit + LD A,(RDWR) ; Get read/write flag + LD E,4 ; Set read empty record + INC A + JR NZ,LDFCB7 ; Read then error + CALL MAKES ; Make new FCB + LD E,5 ; Set make error + LD A,(PEXIT) ; Get error code + INC A + JR Z,LDFCB7 ; Error then exit + JR LDFCB6 ; No error exit (zero set) + +LDFCB5: CALL OPENF0 ; Open file +LDFCB6: JP OPENX6 ; Set zero flag and clear error code + +LDFCB7: LD (IX+FCBMOD),0C0H ; Set random record error +LDFCB8: LD A,E ; Get error code + LD (PEXIT),A ; And save it + OR A ; Clear zero flag +SETB14: SET 7,(IX+FCBMOD) ; (hfb) get FCB/File Not Modified + RET ; And return to caller + +; Calculate Random Record +; Entry HL=Offset in FCB +; DE=FCB Pointer +; Exit D=LSB Random Record +; C=ISB Random Record +; B=MSB Random Record + +CALRRC: ADD HL,DE ; Pointer to FCB+15 or FCB+32 + LD A,(HL) ; Get record number + LD HL,12 ; Offset to extent number + ADD HL,DE ; Get pointer to extent byte + LD D,A ; Save record number + LD A,(HL) ; Get extent byte + AND MAXEXT ; Mask it 000eeeee + RL D ; Shift MSB in Carry Cy=R, d=rrrrrrr0 + ADC A,0 ; Add Carry 00xeeeex + RRA ; Shift 1 time (16 bits) 000xeeee + RR D ; D=xrrrrrrr + LD C,A ; Save ISB + INC HL ; Increment to data module number + INC HL + LD A,(HL) ; Get data module number 00mmmmmm + RRCA ; Divide module by 16 + RRCA + RRCA + RRCA + PUSH AF ; Save it mmmm00mm + AND 03H ; Mask for maximum module + LD B,A ; Save it 000000mm + POP AF ; Get LSB + AND 0F0H ; Mask it mmmm0000 + ADD A,C ; Add with ISB mmmxeeee + LD C,A ; Save ISB + RET NC ; No carry then return + INC B ; Increment MSB 000000mm + RET ; And return to caller + ; 000000mm mmmxeeee xrrrrrrr + PAGE + IF ZS +;************************************************************************ +;* U n i v e r s a l T i m e / D a t e S u p p o r t * +;************************************************************************ + +; In order to provide time/date support for as many systems as possible, +; a set of universal routines are used. These routines do not do the +; actual stamping, but provide all the data required to method specific +; programs to perform the needed services. To use the DOS services, the +; external handler needs to tie itself into the Time/Date vector table +; in the ZSDOS configuration area. The Get Stamp, Put Stamp, Stamp Last +; Access, Stamp Create, and Stamp Modify routines receive the following +; parameters in the Z80 registers: +; A = Offset to DIR entry [0,20H,40H,60H] +; BC = Address of ZSDOS WRFCB routine +; DE = Pointer to Directory Buffer +; HL = DMA address +; IX = Pointer to FCB passed to DOS +; The directory buffer contains the dir entry for the FCB passed to DOS, +; A contains the offset. The disk has been tested for R/O on all calls +; except get stamp and is R/W. If a CP/M+ style stamping is used, a simple +; call to the address passed in BC is used to update the disk after adding +; the time as required. This call is ALWAYS required. The routines may +; use AF,BC,DE, and HL without restoring them. Four levels of stack are +; available on the DOS stack for use by the functions. All routines must +; exit with a RET instruction, and A=1 if successful, A=0FFH if error. + +; Get/put Timestamps + +CMD102: +CMD103: CALL SELDRV ; Select DU: from FCB + CALL SRCT15 ; Find the FCB + JR Z,DOTDER ; If not found + LD HL,(GETSTV) ; Get time stamp function address + LD A,(FUNCT) + CP 102 ; Get stamp? + JR Z,DOTDR3 ; Yes + LD HL,(PUTSTV) ; Get address of set stamp routine + ; ..fall thru to common code.. +; Enter here for Stamp Last Access, Stamp Create, Stamp Modify + +STAMPT: PUSH HL + CALL CHKRO1 ; Test for disk W/P but avoid error trap + POP HL + JR Z,DOTDER ; No stamp if disk is W/P + +DOTDR3: CALL GETDME ; Get Data Module and Extent Number + JR NZ,DOTDER ; ..Quit if Not Extent 0 of Module 0 + LD A,(SECPNT) ; Offset to FCB in dirbuf + LD DE,(DIRBUF) ; Dir buffer pointer + LD BC,WRFCB ; Address of WRFCB routine + PUSH HL ; Save function vector + LD HL,(DMA) ; Put DMA in HL + RET ; Then vector to routine + +; Time and Date Routines. Like the date stamping routines, the user must +; supply the actual driver routines for time and date. These routines are +; attached to ZSDOS via the vector table in the configuration area. The +; routines are passed the address to Get/Put the Time and Date in the DE +; and IX registers. The routines may use AF,BC, and D without restor- +; ing them. Four levels of stack are available on the DOS stack for use +; by the the functions. All routines must exit with a RET instruction, +; and A=1 if successful, A=0FFH if error. +; In order to better provide for internal DateStamper, the clock routines +; must save the value at DE+5 when called, and return this value to the +; DOS in the E register. In addition, the HL register must be returned +; as the called DE value +5. +; The Time/Date string consists of 6 packed BCD digits arrayed as: +; Byte 00 01 02 03 04 05 +; YY MM DD HH MM SS + +; Set Time/Date from user-supplied buffer string + +CMD99: LD C,1 ; Set parameter to set time/date + DEFB 21H ; ..and fall thru to GSTD + +; Get Time/Date to string whose address is supplied by the user + +CMD98: LD C,0 ; Set parameter to get time/date +GSTD: LD HL,(GSTIME) ; Get time/date get/set routine address + PUSH HL ; ..to stack for pseudo "Jump" +DOTDER: OR 0FFH ; Save 1 T state while setting flags + RET ; Vector to service routine + ENDIF ;Zs + PAGE + IF ~ZS +;--------------------------------------------------------------------- +; Z D D O S T i m e R o u t i n e s +;--------------------------------------------------------------------- +; STIME - Set file's time and date in !!!TIME&.DAT file +; +; Entry: SECPNT and RECDIR set by search for file. +; BC = 10 - set Modify date/time +; BC = 5 - set Last Access date/time +; BC = 0 - set Create date/time, zero modify & access +; +; Exit : Zero Flag Set (Z) if Time Set in !!!TIME&.DAT file +; Zero Flag Reset (NZ) if error or "No Stamp" attribute Set +; +; Note : Only the first extent's stamp is valid. + +STIME: LD A,(TDCHEK) ; See if !!!TIME&.DAT +RETNZ: OR A ; ..file on disk, clear Carry + RET NZ ; No. (NZ) flags error + + BIT 7,(IX+3) ; Datestamper (tm) "no stamp" bit + RET NZ ; Don't stamp this file + + PUSH BC + CALL GETDME ; See if this is Extent 0 of Module 0 + POP BC + RET NZ ; Quit Now if it isn't + + LD B,A ; Zero B + LD A,(FUNCT) ; Get Current Function + CP 102 ; Is it Get Stamp? + JR Z,STIME0 ; ..jump to skip R/O test if so + CALL CHKRO1 ; Else test for Disk R/O w/o Error Exit + JP Z,DOTDER ; ..and Quit if Error + +STIME0: PUSH BC ; Save 0, 5, or 10 + +; 1. Get disk sector number of file's T&D record, save offset in T&D +; sector for later. + + ; Carry cleared from above + LD A,(SECPNT) ; 0-relative dir. sector offset + ; ..of file FCB (0, 32, 64, or 96) + RRA ; Divide by 2 for !!!TIME&.DAT offset + ; ..a = 0, 16, 32, or 48 + LD HL,(RECDIR) ; 0-relative directory sector of FCB + SRL H ; Divide by 2 to get 0-relative + ; ..sector of T&D file in HL + RR L ; Odd directory sector sets Carry + JR NC,STIME1 + ADD A,64 ; Point to 2nd half of record +STIME1: PUSH AF ; Save pointer for T&D record + PUSH HL ; Save !!!TIME&.DAT file sector + LD HL,(NDIR0) ; Get DIR Alloc Bitmap + LD A,(NMASK) ; Get Block Mask + INC A ; +1 = Number of Records/Block + LD E,A ; Save Records/Block in E + LD D,B ; Extent, B is 0 from above + LD B,16 ; Iterate 16 times +STIME2: ADD HL,HL ; Shift next DIR Alloc bit out to Carry + JR NC,STIME2A ; No Add if No Alloc Bit + EX (SP),HL ; Alloc to Stack, Records into HL + ADD HL,DE ; Add another Alloc worth of records + EX (SP),HL ; Records back to stack, Alloc to HL +STIME2A: DJNZ STIME2 ; Loop until all 16 bits done + POP HL ; Restore !!!TIME&.DATE Record Number + +; 2. Read T&D sector from disk. + + CALL STDIR2 ; Set track and sector of T&D file + CALL READDR ; Read it to DIRBUF + +; 3. Check T&D sector. + + CALL STIME6 ; Check checksum + CP (HL) + JR NZ,TDERR ; Report error + +; 4. Get stamp (GetStp) or set stamp in dirbuf, using offset (tdpnt) + + POP AF ; Get record pointer + CALL CALDIR1 ; Get HL = pointer to stamp in DIRBUF + POP BC ; C = 0, 5, or 10 (offset) + LD A,(FUNCT) + CP 102 ; Get stamp? + RET Z ; Yes, just point with HL + CP 103 ; Set stamp from DMA? + JR Z,STIME4 + + ADD HL,BC ; Add offset (0, 5, 10) + PUSH BC ; Save 0, 5, 10 + CALL CMD98A ; Load 6 bytes from clock to HL + POP BC ; Restore entry parm. + INC A ; 0FFH --> 0 on clock error + JR Z,DOTDER ; ..jump to set NZ status on error + LD (HL),E ; Restore HL+5 (restore only if clock) + LD A,C ; Test entry parameter + OR A ; Set create stamp? + JR NZ,STIME5 ; No, write to disk as is + + LD B,10 ; Yes, +STIME3: LD (HL),A ; Zero the + INC HL ; Access and + DJNZ STIME3 ; Modify dates + JR STIME5 ; And write to disk + +STIME4: LD DE,(DMA) ; Setstp get time from DMA + EX DE,HL ; HL points to DMA + ; DE points to stamp in DIRBUF + LD BC,15 ; Copy 15 bytes to DIRBUF + LDIR + ;..fall thru + +; 5. Reset T&D checksum and write stamped sector to disk. + +STIME5: CALL STIME6 ; Get checksum in A, (HL) = chk byte + LD (HL),A ; Update checksum + CALL WRITD1 ; Write DIRBUF to !!!TIME&.DAT file + XOR A ; Set to (Z), no errors + RET ; Stime done. + +; Don't crash pgm on T&D Err, just return with err + +TDERR: POP HL + POP HL ; Clean up the stack +;= JR GSEXIT ; ..and return error + jr DOTDER ; ..and return error + +; ------------------------------------------------------------------ +; CMND102 - Return file's 15 byte stamp at DMA +; Entry: DE --> FCB of file (wildcards allowed) +; Exit : (DMA) holds 10 byte file stamp +; A = 1 if Ok, Else A = 0FFH if File or Datestamp not found +; DMA contents undefined if error. +; +; CMND103 - Set file's 10 byte stamp from DMA +; Entry: DE --> FCB of file (wildcards allowed) +; (DMA) holds 10 byte file stamp +; Exit : A = 1 if File DateStamp updated (Only first extent is valid) +; A = 0FFH if File/Datestamp not found or "No stamp" attribute set + +CMD102: +CMD103: CALL SELDRV ; Select drive from FCB + CALL SRCT15 ; Search file, test found + JR Z,DOTDER ; ..jump error exit if File Not Found + LD A,(FUNCT) ; Get or set? + CP 103 ; Set? + JR Z,SETSTP ; ..jump if yes + + RES 7,(IX+3) ; Get. clear "no stamp" + CALL STIME ; Point to start of stamp + JR NZ,GSEXIT ; ..Exit w/Error if No Stamping allowed + LD BC,15 ; Load 15 bytes + CALL MV2DMA ; Move data to DMA address + JR GSEXIT + +SETSTP: CALL STIME ; Set from DMA + +GSEXIT: JP Z,READS0 ; Jump to set "1" success status if Ok.. + JP RETCFF ; ..else set 0FFH Error status + +; -------- +; Label for DS version + +CMD98A: EX DE,HL ; Prepare for STIME call + +; Get Time/Date to string whose address is supplied by the user + +CMD98: LD C,0 ; Set parameter to get time/date + DEFB 21H ; ..set for fall thru to GSTD + +; Set Time/Date from User-supplied Buffer string + +CMD99: LD C,1 ; Set parameter to Set Time/Date + +; Clock interface. Clock module must be ZDS DateStamper compatible +; Modified to ZDS DateStamper parameter passing + +GSTD: LD HL,(GSTIME) ; Get time/date get/set routine address + PUSH HL +DOTDER: OR 0FFH ; set error return + RET ; Vector to service routine + +;..... +; Subroutine to Check/Update the !!!TIME&.DAT checksum + +; Entry: DIRBUF points to T&D record +; Exit : A holds checksum +; HL points to checksum byte in record + +STIME6: XOR A ; Clear A + LD HL,(DIRBUF) + ;..fall thru to do CheckSum.. +;**************************************************************** +;* NOTE: This routine must fall thru to the CKS127 routine just * +;* after the ENDIF, so this sequence must not be altered * +;**************************************************************** + +;------------------ End time routines ------------------------ + ENDIF + +; Calculate checksum of 127 bytes addressed by HL. Return with HL +; pointing to the 128th byte. + +CKS127: LD B,127 ; Test 1st 127 bytes +CKSLP: ADD A,(HL) ; Sum all bytes to A + INC HL + DJNZ CKSLP + RET + + PAGE +;************************************************************** +;* Z S D O S H i g h R A M D a t a * +;************************************************************** + +; High RAM area. These locations are not stored by an IOP or +; BackGrounder. + +CODEND: + IF ROM + IF $-ZSDOS > 0E00H + *** ZSDOS TOO BIG !!!!! *** + ENDIF ;$-zsdos + DSEG + ELSE + IF ZS + IF $-ZSDOS > 0DF1H + *** ZSDOS TOO BIG !!!!! *** + ENDIF ;$-zsdos +; ORG ZSDOS+0DF1H ; Set here for Internal Path + FILL ((ZSDOS+0DF1H) - $),055H + ELSE + IF $-ZSDOS > 0DF9H + *** ZDDOS TOO BIG !!!!! *** + ENDIF ;$-zsdos +; ORG ZSDOS+0DF9H + FILL ((ZSDOS+0DF9H) - $),055H + ENDIF ;Zs + ENDIF ;Rom +HIRAM: + IF ZS +IPATH: DEFB 1,0 ; Internal Path = Drive A, User 0 + DEFW 00,00 ; ..two more blank entries + DEFB 0 ; ...and ending Null +TDFVCT: DEFW 00 ; Time and date file vector + ELSE +TDCHEK: DEFB 0 ; used by ZDDOS for T&D present flag + ENDIF ;Zs +LOGIN: DEFW 00 ; Login vector +DSKWP: DEFW 00 ; Disk write protect vector +HDLOG: DEFW 00 ; Fixed disk login vector + + IF ROM +FREEMEM EQU BIOS-CODEND + ELSE +FREEMEM EQU HIRAM-CODEND + ENDIF ;Rom + +; Variables for use with BGii + +BGLOWL EQU BGHIRAM-BGLORAM ; Size of Low RAM save +BGHIL EQU BGRAMTOP-BGHIRAM ; Size of Hi RAM save + + END ; End program + \ No newline at end of file diff --git a/trunk/Source/zsdos.asm b/trunk/Source/zsdos.asm new file mode 100644 index 00000000..0c76166a --- /dev/null +++ b/trunk/Source/zsdos.asm @@ -0,0 +1,39 @@ +; +;================================================================================================== +; WRAPPER FOR ZSDOS/ZDDOS FOR N8VEM PROJECT +; WAYNE WARTHEN - 2011-01-09 +;================================================================================================== +; +; THE FOLLOWING MACROS DO THE HEAVY LIFTING TO MAKE THE ZSDOS SOURCE +; COMPATIBLE WITH TASM +; +#DEFINE EQU .EQU +#DEFINE NAME \; +#DEFINE PAGE .PAGE +#DEFINE CSEG .CSEG +#DEFINE DSEG .DSEG +#DEFINE ORG .ORG +#DEFINE END .END +#DEFINE IF .IF +#DEFINE ELSE .ELSE +#DEFINE ENDIF .ENDIF +#DEFINE DEFB .DB +#DEFINE DEFW .DW +#DEFINE FILL .FILL +; +; ZSDOS USES A .LIB FILE FOR CONFIGURATION. SINCE TASM HAS NO SUPPORT FOR THIS +; WE JUST INCLUDE THE FILE HERE. +; +#DEFINE BLD_ZSDOS11 TRUE ; TRUE BUILDS VER 1.1, FALSE BUILDS VER 1.2 +#DEFINE BLD_ZS TRUE ; TRUE FOR ZSDOS BUILD, FALSE FOR ZDDOS BUILD +#DEFINE BLD_ROM FALSE +#INCLUDE "zsdos.lib" +; +; +; ESTABLISH STARTING ADDRESS FOR ZSDOS +; + .ORG 0D800H +; +; NOW INCLUDE THE MAIN SOURCE +; +#INCLUDE "zsdos-gp.z80" \ No newline at end of file diff --git a/trunk/Source/zsdos.lib b/trunk/Source/zsdos.lib new file mode 100644 index 00000000..a0374525 --- /dev/null +++ b/trunk/Source/zsdos.lib @@ -0,0 +1,185 @@ +; +; WW - CUSTOMIZED FOR N8VEM PROJECT +; + +;..... +; ZSDOS Customization. -HFB, 18 Sept 1987 +; revised 07/17/88 CWC + +FALSE .EQU 0 +TRUE .EQU ~FALSE + +; Set these conditionals before assembly + +;**************************************************************************** +; In the General Public Release version, we have included an equate which +; controls an additional unreleased fix (which only Howard Goldstein found). +; If the following equate is set TRUE, a version 1.1 BDOS will be produced +; which will require no changes to any released utilities. If set to FALSE, +; a version 1.2 BDOS will result, and many support utility libraries and +; overlays will need to be revised to make them function properly. HFB + +;WW - NOW USES BLD_ZSDOS11 TO INHERIT SETTING FROM WRAPPER +ZSDOS11 .EQU BLD_ZSDOS11 ; Set True for Ver 1.1, False for 1.2 + +;**************************************************************************** + +;WW - NOW USES BLD_ZS TO INHERIT SETTING FROM WRAPPER +ZS .EQU BLD_ZS ; Set True for ZSDOS, False for ZDDOS + +;---------- +; Select assembler for ZSDOS. Any modifications to source code must +; support these assemblers at minimum. + +SLR .EQU FALSE ; SLR Z80ASM or SLR180 Assembler, OR ZMAC +ZAS .EQU TRUE ; MITEK/ECHELON ZAS Assembler (3.0 or later) + + IF ZAS + NAME DOS + ENDIF + + IF SLR + .Z80 + NAME ('DOS') + ENDIF + + IF ZAS & ZS + IF ZSDOS11 + .TITLE 'ZSDOS 1.1 - Enhanced CP/M BDOS Replacement' + ELSE ;~Zsdos11 + .TITLE 'ZSDOS 1.2 - Enhanced CP/M BDOS Replacement' + ENDIF ;Zsdos11 + ENDIF + IF ZAS & (~ZS) + IF ZSDOS11 + .TITLE 'ZDDOS 1.1 - Enhanced CP/M BDOS Replacement w/DS' + ELSE ;~Zsdos11 + .TITLE 'ZDDOS 1.2 - Enhanced CP/M BDOS Replacement w/DS' + ENDIF ;Zsdos11 + ENDIF + + IF SLR & ZS + IF ZSDOS11 + TITLE "ZSDOS 1.1 - Enhanced CP/M BDOS Replacement" + ELSE ;~Zsdos11 + TITLE "ZSDOS 1.2 - Enhanced CP/M BDOS Replacement" + ENDIF ;Zsdos11 + ENDIF + IF SLR & (~ZS) + IF ZSDOS11 + TITLE "ZDDOS 1.1 - Enhanced CP/M BDOS Replacement w/DS" + ELSE ;~Zsdos11 + TITLE "ZDDOS 1.2 - Enhanced CP/M BDOS Replacement w/DS" + ENDIF ;Zsdos11 + ENDIF + +;---------- +; P2DOS introduced a search path feature compatible with that used in +; Richard Conn's ZCPR2 and ZCPR3. If a requested file is not located in +; the currently logged Drive/User, the SEARCH routine will sequentially +; scan along the path until either the file is found or the end of the +; path is reached. + + IF ZS +;WW - changed from EQU to #DEFINE to avoid forward reference error in TASM +;PATHAD EQU IPATH ; Set to the desired ZCPR2/3 search path. +#DEFINE PATHAD IPATH + ELSE ; use 0000H to disable path. A short +PATHAD .EQU 00000H ; 3 element internal path is provided + ENDIF ; in ZSDOS. ZDDOS does not use path. + +;---------- +; The WHEEL byte may be sensed from within ZSDOS by setting the following +; address to that of the ZCPR3 WHEEL byte. A value of 0 disables the WHEEL +; byte sensing. + +WHLADR .EQU 00000H ; Set WHEEL byte address (0FDFFH for SB180) + +;---------- +; Some systems, like the Kaypro 4, only recognize changes between single +; and double-sided disks when the system is warm booted; BDOS Function 13 +; (reset disk) will not work. By adding a "hook" to the BIOS of these mach- +; ines and setting RESDSK to TRUE, BDOS functions 13 and 37 will allow changes +; between single and double-sided disks; very handy for disk housekeeping +; utilities such as NSWP, NULU, and cataloging programs. + +; The "hook" is added as follows: Obtain the source to your computer's BIOS. +; Examine the code for WARM BOOT. Somewhere, there should be a call to a rou- +; tine which initializes the disk system after a warm boot, or which detects +; changes between single and double-sided disks. Call this routine DISKINT +; for purposes of discussion. Modify your BIOS's cold boot routine to ini- +; tialize 3 bytes at address SETDSK as "JP DISKINT". The location of SETDSK +; is arbitrary, it may be in your BIOS, or in a reserved spot in CP/M's page 0. + +RESDSK .EQU FALSE + + IF RESDSK +SETDSK .EQU 004BH ; Set to suit your system (bh) + ENDIF ; resdsk (bh) + +;---------- +; The following equate is used to produce separate code and data segments +; for blowing ZSDOS into ROM. Calling BDOS Function 0 will initialize the +; Data Segment to default values. + +ROM .EQU BLD_ROM ; Separate data and code? + +;---------- +; Many ZSDOS features can be controlled while ZSDOS is running by altering +; the FLAG byte. Set the following equate to your desired configuration based +; on your requirements. The individual bit assignments in the FLAG byte are: +; +; Bit - 7 6 5 4 3 2 1 0 +; \ \ \ \ \ \ \ \__Public File Enable (1) / Disable (0) +; \ \ \ \ \ \ \___Public/Path Write Enable (1) / Disable (0) +; \ \ \ \ \ \____Read-Only Enable (1) / Disable (0) +; \ \ \ \ \_____Fast Fixed Disk Relog Enable (1) / Disable (0) +; \ \ \ \______Disk Change Warning Enable (1) / Disable (0) +; \ \ \_______ZCPR2/3 Path Enable (1) / Disable (0) +; \ \________Path without System Enable (1) / Disable (0) +; \_________(Reserved) + +FLGBITS .EQU 01101101B ; PUBLIC On, P/P Write Off, R/O On, + ; Fast Relog On,Disk Change warning Off, + ; Path On, No System path On + +; The operation of Bit 6 represents a deviation from the description of PUBLIC +; Files as given in DDJ Article by Bridger Mitchell and Derek McKay of Plu* +; Perfect Systems. The PUBLIC Specification states that Public Files will NOT +; be found by any wildcard reference except when a "?" is in the FCB+0 byte. +; The code here relaxes that requirement as follows: If we are in the same +; user area as the public file, then don't report the file as PUBLIC, but find +; it. This has a nasty side effect - it allows erasing of PUBLIC files if we +; are in the same area. However, these files also show up on the directory +; (they wouldn't otherwise), so at least we should know we're blasting them. + +;---------- +; Equates for selecting ZSDOS or ZDDOS configurations + +; Since much ZSDOS code must be deleted to embed DateStamper in ZDDOS, the +; following flags do the stripping: +; PICKEY - True = Don't save users' DE register +; CTLREN - True = Add ^R Retype line to cons read, False = No ^R +; UNROLL - True = Inline code for shifts, False = collapse into loops +; UPATH - True = Add User path from OS, False = No OS path search + + IF ZS +CTLREN .EQU TRUE +UNROLL .EQU TRUE +UPATH .EQU TRUE +PICKEY .EQU FALSE + ELSE +CTLREN .EQU FALSE +UNROLL .EQU FALSE +UPATH .EQU FALSE +PICKEY .EQU FALSE + ENDIF + +;---------- +; To Use the Named-COMMON aspect of NZCOM and JETLOADER (tm), the BIOS must +; be referenced from the _BIOS_ name. If operating under this scheme, set +; the ZRL equate to TRUE. With the ZRL equate set to FALSE, a standalone +; .REL file will be produced with no external requirements. + +ZRL .EQU FALSE ; Set True .ZRL file with COMMON for NZCOM, + ; False to produce straight .REL file diff --git a/trunk/Support/Clock/LDTIM_N8.COM b/trunk/Support/Clock/LDTIM_N8.COM new file mode 100644 index 00000000..1ce1dfc7 Binary files /dev/null and b/trunk/Support/Clock/LDTIM_N8.COM differ diff --git a/trunk/Support/Clock/LDTIM_N8VEM.COM b/trunk/Support/Clock/LDTIM_N8VEM.COM new file mode 100644 index 00000000..1b3e2d10 Binary files /dev/null and b/trunk/Support/Clock/LDTIM_N8VEM.COM differ diff --git a/trunk/Support/Clock/LDTIM_SIMH.COM b/trunk/Support/Clock/LDTIM_SIMH.COM new file mode 100644 index 00000000..d2959fae Binary files /dev/null and b/trunk/Support/Clock/LDTIM_SIMH.COM differ diff --git a/trunk/Support/Clock/N8CLK.MAC b/trunk/Support/Clock/N8CLK.MAC new file mode 100644 index 00000000..823f8922 --- /dev/null +++ b/trunk/Support/Clock/N8CLK.MAC @@ -0,0 +1,228 @@ + .Z80 +VERS EQU 03 +; +;RTC_BASE EQU 70H ; RTC PORT ON N8VEM/ZETA +RTC_BASE EQU 88H ; RTC PORT ON N8 +; +RTC_DATA EQU 10000000B ; BIT 7 CONTROLS RTC DATA (I/O) LINE +RTC_CLK EQU 01000000B ; BIT 6 CONTROLS RTC CLOCK LINE, 1 = HIGH +RTC_RD EQU 00100000B ; BIT 5 CONTROLS DATA DIRECTION, 1 = READ +RTC_CE EQU 00010000B ; BIT 4 CONTROLS RTC CE LINE, 1 = HIGH (ENABLED) +; + COMMON /_CLKID/ + +DESCST: DEFW 0000 ; Add label here if a static year byte + ; is used by your clock driver. The + ; label should point to the year byte +; 123456789012345678901234 +CLKNAM: DEFB 'N8 DS1302 Clock ' ; Exactly 24 chars in name + DEFB VERS/10+'0','.',VERS MOD 10 +'0',0 +; +DESCR: DEFB 'DS1302 Real-time Clock Driver for N8 Z180',0 +; + COMMON /_PARM_/ +; +PARBAS: DEFW 0 ; # of parameters (Set to 00 if none) + DEFW 0 ; Pointer to STRS (Set to 00 if none) +; + CSEG +; +;------------------------------------------------------------- +; Z S D O S C L O C K H E A D E R +;------------------------------------------------------------- +; Enter: HL = Address to Put Date/Time string +; Exit : Time moved and counter incremented +; A=1 for OK status on exit +; +; Enter: HL points to a 6-byte buffer to Get/Set time +; Exit : A=1 on Success, A=FFH if error +; HL points to last char in buffer +; E contains original seconds (HL+5) + + JP GETTIM ; Get time + JP WRCLK ; Set time +; +BUFSIZE EQU 7 +BUFRTC: +BUFSEC: DEFB 0 ; Second +BUFMIN: DEFB 0 ; Minute +BUFHR: DEFB 0 ; Hour +BUFDT: DEFB 0 ; Date +BUFMON: DEFB 0 ; Month +BUFDAY: DEFB 0 ; Day +BUFYR: DEFB 0 ; Year +; +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; R e a d T h e C l o c k +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +GETTIM: PUSH HL + LD HL,BUFRTC + CALL CLK_RD + + ; COPY DATE/TIME INTO OUTPUT BUFFER + POP HL + LD A,(BUFYR) + LD (HL),A + INC HL + LD A,(BUFMON) + LD (HL),A + INC HL + LD A,(BUFDT) + LD (HL),A + INC HL + LD A,(BUFHR) + LD (HL),A + INC HL + LD A,(BUFMIN) + LD (HL),A + INC HL + LD A,(BUFSEC) + LD (HL),A + LD E,(HL) + + ; RETURN WITH SUCCESS + XOR A + INC A + RET +; +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; S e t T h e C l o c k +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +WRCLK: LD A,(HL) + LD (BUFYR),A + INC HL + LD A,(HL) + LD (BUFMON),A + INC HL + LD A,(HL) + LD (BUFDT),A + INC HL + LD A,(HL) + LD (BUFHR),A + INC HL + LD A,(HL) + LD (BUFMIN),A + INC HL + LD A,(HL) + LD (BUFSEC),A + + PUSH HL + LD HL,BUFRTC + CALL CLK_WR + POP HL + + ; RETURN WITH SUCCESS + XOR A + INC A + RET +; +; BURST READ CLOCK DATA INTO BUFFER AT HL +; +CLK_RD: + LD C,0BFH ; COMMAND = $BF TO BURST READ CLOCK + CALL RTC_CMD ; SEND COMMAND TO RTC + LD B,BUFSIZE ; B IS LOOP COUNTER +CLK_RD1: + PUSH BC ; PRESERVE BC + CALL RTC_GET ; GET NEXT BYTE + LD (HL),A ; SAVE IN BUFFER + INC HL ; INC BUF POINTER + POP BC ; RESTORE BC + DJNZ CLK_RD1 ; LOOP IF NOT DONE + XOR A ; ALL LINES OFF TO CLEAN UP + OUT (RTC_BASE),A ; WRITE TO RTC PORT + RET +; +; BURST WRITE CLOCK DATA FROM BUFFER AT HL +; +CLK_WR: + LD C,08EH ; COMMAND = $8E TO WRITE CONTROL REGISTER + CALL RTC_CMD ; SEND COMMAND + XOR A ; $00 = UNPROTECT + CALL RTC_PUT ; SEND VALUE TO CONTROL REGISTER +; + LD C,0BEH ; COMMAND = $BE TO BURST WRITE CLOCK + CALL RTC_CMD ; SEND COMMAND TO RTC + LD B,BUFSIZE ; B IS LOOP COUNTER +CLK_WR1: + PUSH BC ; PRESERVE BC + LD A,(HL) ; GET NEXT BYTE TO WRITE + CALL RTC_PUT ; PUT NEXT BYTE + INC HL ; INC BUF POINTER + POP BC ; RESTORE BC + DJNZ CLK_WR1 ; LOOP IF NOT DONE + LD A,80H ; ADD CONTROL REG BYTE, $80 = PROTECT ON + CALL RTC_PUT ; WRITE REQUIRED 8TH BYTE + XOR A ; ALL LINES OFF TO CLEAN UP + OUT (RTC_BASE),A ; WRITE TO RTC PORT + RET +; +; SEND COMMAND IN C TO RTC +; +RTC_CMD: + LD A,RTC_RD ; CE LOW TO RESET RTC + OUT (RTC_BASE),A ; WRITE IT + LD A,C ; LOAD COMMAND + CALL RTC_PUT ; WRITE IT + RET +; +; WRITE BYTE IN A TO THE RTC +; +RTC_PUT: + LD B,8 ; LOOP FOR 8 BITS +RTC_PUT1: + RRCA ; ROTATE NEXT BIT TO SEND INTO BIT 7 + LD C,A ; SAVE WORKING VALUE + AND 10000000B ; ISOLATE THE DATA BIT + OR RTC_CE ; ADD CHIP ENABLE, CLOCK HIGH + OUT (RTC_BASE),A ; WRITE TO PORT WITH CLOCK LOW + XOR RTC_CLK ; TURN CLOCK BACK ON + OUT (RTC_BASE),A ; WRITE TO PORT WITH CLOCK HIGH + LD A,C ; RECOVER WORKING VALUE + DJNZ RTC_PUT1 ; LOOP IF NOT DONE + RET +; +; READ BYTE FROM RTC, RETURN VALUE IN A +; +RTC_GET: + LD C,0 ; INITIALIZE WORKING VALUE TO 0 + LD B,8 ; LOOP FOR 8 BITS +RTC_GET1: + LD A,RTC_RD+RTC_CE ; LOWER CLOCK, CE STAYS HI, READ IS ON + OUT (RTC_BASE),A ; WRITE TO RTC PORT + NOP ; SETTLE + IN A,(RTC_BASE) ; READ THE RTC PORT + AND 00000001B ; ISOLATE THE DATA BIT + OR C ; COMBINE WITH WORKING VALUE + RRCA ; ROTATE FOR NEXT BIT + LD C,A ; SAVE WORKING VALUE + LD A,RTC_CLK+RTC_RD+RTC_CE ; CLOCK BACK TO HIGH NOW + OUT (RTC_BASE),A ; WRITE TO RTC PORT + DJNZ RTC_GET1 ; LOOP IF NOT DONE + LD A,C ; GET RESULT INTO A + RET +; +; +; + COMMON /_POST_/ + RET ; This RETURN MUST be present even if no other + ; code is included in this section + + COMMON /_PRE_/ +; +;--------------------------------------------------------------- +; Read clock and wait for seconds to roll - watchdog protected +; Enter with: DE pointing to relocated clock read routine +; HL pointing to base of high module + +TSTRD: JR TSTRD0 ; Jump around address store + + DEFW TSTRD ; Org location of the code + +TSTRD0: SCF + LD A,1 + RET + + END diff --git a/trunk/Support/Clock/N8CLK.REL b/trunk/Support/Clock/N8CLK.REL new file mode 100644 index 00000000..ad756732 Binary files /dev/null and b/trunk/Support/Clock/N8CLK.REL differ diff --git a/trunk/Support/Clock/N8VEMCLK.MAC b/trunk/Support/Clock/N8VEMCLK.MAC new file mode 100644 index 00000000..daabf6d5 --- /dev/null +++ b/trunk/Support/Clock/N8VEMCLK.MAC @@ -0,0 +1,228 @@ + .Z80 +VERS EQU 03 +; +RTC_BASE EQU 70H ; RTC PORT ON N8VEM/ZETA +;RTC_BASE EQU 88H ; RTC PORT ON N8 +; +RTC_DATA EQU 10000000B ; BIT 7 CONTROLS RTC DATA (I/O) LINE +RTC_CLK EQU 01000000B ; BIT 6 CONTROLS RTC CLOCK LINE, 1 = HIGH +RTC_RD EQU 00100000B ; BIT 5 CONTROLS DATA DIRECTION, 1 = READ +RTC_CE EQU 00010000B ; BIT 4 CONTROLS RTC CE LINE, 1 = HIGH (ENABLED) +; + COMMON /_CLKID/ + +DESCST: DEFW 0000 ; Add label here if a static year byte + ; is used by your clock driver. The + ; label should point to the year byte +; 123456789012345678901234 +CLKNAM: DEFB 'N8VEM DS1302 Clock ' ; Exactly 24 chars in name + DEFB VERS/10+'0','.',VERS MOD 10 +'0',0 +; +DESCR: DEFB 'DS1302 Real-time Clock Driver for N8VEM Z80',0 +; + COMMON /_PARM_/ +; +PARBAS: DEFW 0 ; # of parameters (Set to 00 if none) + DEFW 0 ; Pointer to STRS (Set to 00 if none) +; + CSEG +; +;------------------------------------------------------------- +; Z S D O S C L O C K H E A D E R +;------------------------------------------------------------- +; Enter: HL = Address to Put Date/Time string +; Exit : Time moved and counter incremented +; A=1 for OK status on exit +; +; Enter: HL points to a 6-byte buffer to Get/Set time +; Exit : A=1 on Success, A=FFH if error +; HL points to last char in buffer +; E contains original seconds (HL+5) + + JP GETTIM ; Get time + JP WRCLK ; Set time +; +BUFSIZE EQU 7 +BUFRTC: +BUFSEC: DEFB 0 ; Second +BUFMIN: DEFB 0 ; Minute +BUFHR: DEFB 0 ; Hour +BUFDT: DEFB 0 ; Date +BUFMON: DEFB 0 ; Month +BUFDAY: DEFB 0 ; Day +BUFYR: DEFB 0 ; Year +; +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; R e a d T h e C l o c k +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +GETTIM: PUSH HL + LD HL,BUFRTC + CALL CLK_RD + + ; COPY DATE/TIME INTO OUTPUT BUFFER + POP HL + LD A,(BUFYR) + LD (HL),A + INC HL + LD A,(BUFMON) + LD (HL),A + INC HL + LD A,(BUFDT) + LD (HL),A + INC HL + LD A,(BUFHR) + LD (HL),A + INC HL + LD A,(BUFMIN) + LD (HL),A + INC HL + LD A,(BUFSEC) + LD (HL),A + LD E,(HL) + + ; RETURN WITH SUCCESS + XOR A + INC A + RET +; +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; S e t T h e C l o c k +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; +WRCLK: LD A,(HL) + LD (BUFYR),A + INC HL + LD A,(HL) + LD (BUFMON),A + INC HL + LD A,(HL) + LD (BUFDT),A + INC HL + LD A,(HL) + LD (BUFHR),A + INC HL + LD A,(HL) + LD (BUFMIN),A + INC HL + LD A,(HL) + LD (BUFSEC),A + + PUSH HL + LD HL,BUFRTC + CALL CLK_WR + POP HL + + ; RETURN WITH SUCCESS + XOR A + INC A + RET +; +; BURST READ CLOCK DATA INTO BUFFER AT HL +; +CLK_RD: + LD C,0BFH ; COMMAND = $BF TO BURST READ CLOCK + CALL RTC_CMD ; SEND COMMAND TO RTC + LD B,BUFSIZE ; B IS LOOP COUNTER +CLK_RD1: + PUSH BC ; PRESERVE BC + CALL RTC_GET ; GET NEXT BYTE + LD (HL),A ; SAVE IN BUFFER + INC HL ; INC BUF POINTER + POP BC ; RESTORE BC + DJNZ CLK_RD1 ; LOOP IF NOT DONE + XOR A ; ALL LINES OFF TO CLEAN UP + OUT (RTC_BASE),A ; WRITE TO RTC PORT + RET +; +; BURST WRITE CLOCK DATA FROM BUFFER AT HL +; +CLK_WR: + LD C,08EH ; COMMAND = $8E TO WRITE CONTROL REGISTER + CALL RTC_CMD ; SEND COMMAND + XOR A ; $00 = UNPROTECT + CALL RTC_PUT ; SEND VALUE TO CONTROL REGISTER +; + LD C,0BEH ; COMMAND = $BE TO BURST WRITE CLOCK + CALL RTC_CMD ; SEND COMMAND TO RTC + LD B,BUFSIZE ; B IS LOOP COUNTER +CLK_WR1: + PUSH BC ; PRESERVE BC + LD A,(HL) ; GET NEXT BYTE TO WRITE + CALL RTC_PUT ; PUT NEXT BYTE + INC HL ; INC BUF POINTER + POP BC ; RESTORE BC + DJNZ CLK_WR1 ; LOOP IF NOT DONE + LD A,80H ; ADD CONTROL REG BYTE, $80 = PROTECT ON + CALL RTC_PUT ; WRITE REQUIRED 8TH BYTE + XOR A ; ALL LINES OFF TO CLEAN UP + OUT (RTC_BASE),A ; WRITE TO RTC PORT + RET +; +; SEND COMMAND IN C TO RTC +; +RTC_CMD: + LD A,RTC_RD ; CE LOW TO RESET RTC + OUT (RTC_BASE),A ; WRITE IT + LD A,C ; LOAD COMMAND + CALL RTC_PUT ; WRITE IT + RET +; +; WRITE BYTE IN A TO THE RTC +; +RTC_PUT: + LD B,8 ; LOOP FOR 8 BITS +RTC_PUT1: + RRCA ; ROTATE NEXT BIT TO SEND INTO BIT 7 + LD C,A ; SAVE WORKING VALUE + AND 10000000B ; ISOLATE THE DATA BIT + OR RTC_CE ; ADD CHIP ENABLE, CLOCK HIGH + OUT (RTC_BASE),A ; WRITE TO PORT WITH CLOCK LOW + XOR RTC_CLK ; TURN CLOCK BACK ON + OUT (RTC_BASE),A ; WRITE TO PORT WITH CLOCK HIGH + LD A,C ; RECOVER WORKING VALUE + DJNZ RTC_PUT1 ; LOOP IF NOT DONE + RET +; +; READ BYTE FROM RTC, RETURN VALUE IN A +; +RTC_GET: + LD C,0 ; INITIALIZE WORKING VALUE TO 0 + LD B,8 ; LOOP FOR 8 BITS +RTC_GET1: + LD A,RTC_RD+RTC_CE ; LOWER CLOCK, CE STAYS HI, READ IS ON + OUT (RTC_BASE),A ; WRITE TO RTC PORT + NOP ; SETTLE + IN A,(RTC_BASE) ; READ THE RTC PORT + AND 00000001B ; ISOLATE THE DATA BIT + OR C ; COMBINE WITH WORKING VALUE + RRCA ; ROTATE FOR NEXT BIT + LD C,A ; SAVE WORKING VALUE + LD A,RTC_CLK+RTC_RD+RTC_CE ; CLOCK BACK TO HIGH NOW + OUT (RTC_BASE),A ; WRITE TO RTC PORT + DJNZ RTC_GET1 ; LOOP IF NOT DONE + LD A,C ; GET RESULT INTO A + RET +; +; +; + COMMON /_POST_/ + RET ; This RETURN MUST be present even if no other + ; code is included in this section + + COMMON /_PRE_/ +; +;--------------------------------------------------------------- +; Read clock and wait for seconds to roll - watchdog protected +; Enter with: DE pointing to relocated clock read routine +; HL pointing to base of high module + +TSTRD: JR TSTRD0 ; Jump around address store + + DEFW TSTRD ; Org location of the code + +TSTRD0: SCF + LD A,1 + RET + + END diff --git a/trunk/Support/Clock/N8VEMCLK.REL b/trunk/Support/Clock/N8VEMCLK.REL new file mode 100644 index 00000000..3011f09d Binary files /dev/null and b/trunk/Support/Clock/N8VEMCLK.REL differ diff --git a/trunk/Support/Clock/ReadMe.txt b/trunk/Support/Clock/ReadMe.txt new file mode 100644 index 00000000..0c94e119 --- /dev/null +++ b/trunk/Support/Clock/ReadMe.txt @@ -0,0 +1,5 @@ +This directory contains the source and assembled versions of the ZSystem Clock Drivers for N8VEM & N8. + +The .MAC files can be compiled using M80 with a command line such as "M80 =N8VEMCLK.MAC". + +LDTIM_N8VEM.COM and LDTIM_N8.COM are copies of LDT for N8VEM and N8 respectively. They were constructed useing SETUPZST using the clock drivers included here. They are both setup to load as Resident System Extentions with support for DateStamper style date stamping. \ No newline at end of file diff --git a/trunk/Support/Clock/SIMHCLOK.MAC b/trunk/Support/Clock/SIMHCLOK.MAC new file mode 100644 index 00000000..ecff5b84 --- /dev/null +++ b/trunk/Support/Clock/SIMHCLOK.MAC @@ -0,0 +1,81 @@ +VERS EQU 03 + .Z80 + + COMMON /_CLKID/ + +DESCST: DEFW 0000 ; Add label here if a static year byte + ; is used by your clock driver. The + ; label should point to the year byte +; 123456789012345678901234 +CLKNAM: DEFB 'Altair Z80 SIMH Clock ' ; Exactly 24 chars in name + DEFB VERS/10+'0','.',VERS MOD 10 +'0',0 + +DESCR: DEFB 'This is the Altair Z80 SIMH clock',0 + + + COMMON /_PARM_/ + +PARBAS: DEFW 0 ; # of parameters (Set to 00 if none) + DEFW 0 ; Pointer to STRS (Set to 00 if none) + + CSEG + +;----------------------------------------------------------- +; Z S D O S C L O C K H E A D E R +;----------------------------------------------------------- +; Enter: HL points to a 6-byte buffer to Get/Set time +; Exit : A=1 on Success, A=FFH if error +; HL points to last char in buffer +; E contains original seconds (HL+5) + +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; R e a d T h e C l o c k +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +SIMHPORT EQU 0FEH +READCLOCK EQU 7 +WRITECLOCK EQU 8 +PARBLOCKSIZE EQU 6 + +PRGBAS: JP GETTIM ; Jump to Read Clock + JP WRCLK ; Jump to Set Clock +GETTIM: LD A,READCLOCK + OUT (SIMHPORT),A + LD BC,256*(PARBLOCKSIZE-1)+SIMHPORT ; B := 5, C := 0FEH + INIR + ; bug fixed by Howard Goldstein (via Lee Bradley), 26-Jul-2007 + LD E,(HL) ; Save original seconds in E + INI ; READ SECONDS + DEC HL + LD A,1 ; Set OK status return + RET + +WRCLK: LD A,WRITECLOCK + OUT (SIMHPORT),A + LD A,L + OUT (SIMHPORT),A + LD A,H + OUT (SIMHPORT),A + LD A,1 + RET + + COMMON /_POST_/ + RET ; This RETURN MUST be present even if no other + ; code is included in this section + + COMMON /_PRE_/ + +;--------------------------------------------------------------- +; Read clock and wait for seconds to roll - watchdog protected +; Enter with: DE pointing to relocated clock read routine +; HL pointing to base of high module + +TSTRD: JR TSTRD0 ; Jump around address store + + DEFW TSTRD ; Org location of the code +TSTRD0: SCF + LD A,1 + RET + + END + \ No newline at end of file diff --git a/trunk/Support/Clock/SIMHCLOK.REL b/trunk/Support/Clock/SIMHCLOK.REL new file mode 100644 index 00000000..31e91b38 Binary files /dev/null and b/trunk/Support/Clock/SIMHCLOK.REL differ diff --git a/trunk/Support/ParPortProp/ParPortProp.eeprom b/trunk/Support/ParPortProp/ParPortProp.eeprom new file mode 100644 index 00000000..77349c50 Binary files /dev/null and b/trunk/Support/ParPortProp/ParPortProp.eeprom differ diff --git a/trunk/Support/ParPortProp/Spin/E555_SPKEngine.spin b/trunk/Support/ParPortProp/Spin/E555_SPKEngine.spin new file mode 100644 index 00000000..02e55e87 --- /dev/null +++ b/trunk/Support/ParPortProp/Spin/E555_SPKEngine.spin @@ -0,0 +1 @@ +{{ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // E555 Speaker Engine // // Author: Kwabena W. Agyeman // Updated: 7/27/2010 // Designed For: P8X32A // Version: 1.1 // // Copyright (c) 2010 Kwabena W. Agyeman // See end of file for terms of use. // // Update History: // // v1.0 - Original release - 8/26/2009. // v1.1 - Added support for variable pin assignments - 7/27/2010. // // For each included copy of this object only one spin interpreter should access it at a time. // // Nyamekye, /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Speaker Circuit: // // SpeakerPinNumber --- Speaker Driver (Active High). // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }} PUB speakerFrequency(newFrequency, speakerPinNumber) '' 10 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Changes the speaker frequency using the SPIN interpreter's counter modules. '' // '' // NewFrequency - The new frequency. Between 0 Hz and 80MHz @ 80MHz. -1 to reset the pin and counter modules. '' // SpeakerPinNumber - Pin to use to drive the speaker circuit. Between 0 and 31. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// speakerSetup((newFrequency <> -1), speakerPinNumber) newFrequency := ((newFrequency <# clkfreq) #> 0) result := 1 repeat 32 newFrequency <<= 1 result <-= 1 if(newFrequency => clkfreq) newFrequency -= clkfreq result += 1 frqa := result~ phsb := 0 PUB speakerVolume(newVolume, speakerPinNumber) '' 10 Stack Longs '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// '' // Changes the speaker volume using the SPIN interpreter's counter modules. '' // '' // NewVolume - The new volume. Between 0% and 100%. -1 to reset the pin and counter modules. '' // SpeakerPinNumber - Pin to use to drive the speaker circuit. Between 0 and 31. '' //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// speakerSetup((newVolume <> -1), speakerPinNumber) frqb := (((100 - ((newVolume <# 100) #> 0)) * constant(posx / 50)) | $7) PRI speakerSetup(activeOrInactive, speakerPinNumber) ' 5 Stack Longs speakerPinNumber := ((speakerPinNumber <# 31) #> 0) dira[speakerPinNumber] := activeOrInactive outa[speakerPinNumber] := false ctra := ((constant(%0_0100 << 26) + speakerPinNumber) & activeOrInactive) ctrb := ((constant(%0_0110 << 26) + speakerPinNumber) & activeOrInactive) {{ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TERMS OF USE: MIT License /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, // modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the // Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// }} \ No newline at end of file diff --git a/trunk/Support/ParPortProp/Spin/FullDuplexSerial.spin b/trunk/Support/ParPortProp/Spin/FullDuplexSerial.spin new file mode 100644 index 00000000..b248f963 Binary files /dev/null and b/trunk/Support/ParPortProp/Spin/FullDuplexSerial.spin differ diff --git a/trunk/Support/ParPortProp/Spin/FullDuplexSerialNull.spin b/trunk/Support/ParPortProp/Spin/FullDuplexSerialNull.spin new file mode 100644 index 00000000..7a03e7ab Binary files /dev/null and b/trunk/Support/ParPortProp/Spin/FullDuplexSerialNull.spin differ diff --git a/trunk/Support/ParPortProp/Spin/Keyboard.spin b/trunk/Support/ParPortProp/Spin/Keyboard.spin new file mode 100644 index 00000000..67d8b081 Binary files /dev/null and b/trunk/Support/ParPortProp/Spin/Keyboard.spin differ diff --git a/trunk/Support/ParPortProp/Spin/ParPortProp.spin b/trunk/Support/ParPortProp/Spin/ParPortProp.spin new file mode 100644 index 00000000..f788c6ce Binary files /dev/null and b/trunk/Support/ParPortProp/Spin/ParPortProp.spin differ diff --git a/trunk/Support/ParPortProp/Spin/Parallax Serial Terminal Null.spin b/trunk/Support/ParPortProp/Spin/Parallax Serial Terminal Null.spin new file mode 100644 index 00000000..982e894c Binary files /dev/null and b/trunk/Support/ParPortProp/Spin/Parallax Serial Terminal Null.spin differ diff --git a/trunk/Support/ParPortProp/Spin/Parallax Serial Terminal.spin b/trunk/Support/ParPortProp/Spin/Parallax Serial Terminal.spin new file mode 100644 index 00000000..a525a4be Binary files /dev/null and b/trunk/Support/ParPortProp/Spin/Parallax Serial Terminal.spin differ diff --git a/trunk/Support/ParPortProp/Spin/VGA_1024.spin b/trunk/Support/ParPortProp/Spin/VGA_1024.spin new file mode 100644 index 00000000..624d7331 --- /dev/null +++ b/trunk/Support/ParPortProp/Spin/VGA_1024.spin @@ -0,0 +1,703 @@ +'' VGA_1024.spin +'' +'' MODIFIED BY VINCE BRIEL FOR POCKETERM FEATURES +'' MODIIFED BY JEFF LEDGER / AKA OLDBITCOLLECTOR +'' + +CON + cols = 80 '128 ' number of screen columns + lcols = cols / 4 ' number of long in columns + rows = 40 '64 ' number of screen rows + chars = rows*cols ' number of screen characters + esc = $CB ' keyboard esc char + rowsnow = 36 ' adjusted for split screen effect + maxChars = rowsnow*cols ' adjusted value for split screen effect + lastChar = maxChars / 4 ' last screen position in longs adjusted for split + lastLine = (rowsnow - 1) * cols ' character position of last row + cols1 = 81 ' adjusted value for 80th character + TURQUOISE = $29 + +OBJ + vga : "vga_Hires_Text" + +VAR + byte screen[chars] ' screen character buffer + byte tmpl[cols] ' temporary line buffer + word colors[rows] ' color specs for each screen row (see ColorPtr description above) + byte cursor[6] ' cursor info array (see CursorPtr description above) + long sync, loc, xloc, yloc ' sync used by VGA routine, others are local screen pointers + long kbdreq ' global val of kbdflag + long BR[8] + long Brate + byte inverse + byte invs + byte state ' Current state of state machine + word pos ' Current Position on the screen + word oldpos ' Previous location of cursor before update + word regionTop, regionBot ' Scroll region top/bottom + long arg0 ' First argument of escape sequence + long arg1 ' Second argument of escape sequence + byte lastc ' Last displayed char + word statpos + long vgabasepin + +PUB start(BasePin) | i, char + vgabasepin := BasePin + +''init screen colors to gold on blue + repeat i from 0 to rows - 1 + colors[i] := $08F0 '$2804 (if you want cyan on blue) + +''init cursor attributes + cursor[2] := %110 ' init cursor to underscore with slow blink + BR[0]:=300 + BR[1]:=1200 + BR[2]:=2400 + BR[3]:=4800 + BR[4]:=9600 + BR[5]:=19200 + BR[6]:=38400 + BR[7]:=57600 + BR[8]:=115200 + xloc := cursor[0] := 0 + yloc := cursor[1] := 0 + loc := xloc + yloc*cols + + pos := 0 + regionTop := 0 + regionBot := 35 * cols + state := 0 + statpos := 37 * cols + +PUB vidon + if (!vga.start(vgabasepin, @screen, @colors, @cursor, @sync)) + return false + + waitcnt(clkfreq * 1 + cnt) 'wait 1 second for cogs to start + + +PUB vidoff + vga.stop + +PUB inv(c) + inverse:=c + +PUB color(colorVal) | i + repeat i from 0 to rows - 1 + colors[i] := $0000 | colorVal + +PUB cursorset(c) | i + i:=%000 + if c == 1 + i:= %001 + if c == 2 + i:= %010 + if c == 3 + i:= %011 + if c == 4 + i:= %101 + if c == 5 + i:= %110 + if c == 6 + i:= %111 + if c == 7 + i:= %000 + cursor[2] := i + +PUB bin(value, digits) + +'' Print a binary number, specify number of digits + + repeat while digits > 32 + outc("0") + digits-- + + value <<= 32 - digits + + repeat digits + outc((value <-= 1) & 1 + "0") + + +PUB clrbtm(ColorVal) | i + repeat i from 36 to rows - 1 'was 35 + colors[i] := $0000 + ColorVal + +PUB cls1(c,screencolor,pcport,ascii,CR) | i,x,y + + longfill(@screen[0], $20202020, chars / 4) + + clrbtm(TURQUOISE) + + inverse := 1 + + statprint(36,0, string(" N8VEM ParPortProp | RomWBW v0.92")) + inverse := 0 + statprint(37,0, string(" ")) + statprint(38,0, string(" ")) + statprint(39,0, string(" ")) + + +{{ + x :=xloc + y := yloc + invs := inverse + ''clrbtm(TURQUOISE) + longfill(@screen, $20202020, chars/4) + xloc := 0 + yloc :=0 + loc := xloc + yloc*cols + repeat 80 + outc(32) + xloc := 0 + yloc :=36 + loc := xloc + yloc*cols + inverse := 1 + str(string(" propIO V 0.91 ")) + inverse := 0 + str(string("Baud Rate: ")) + i:= BR[6] + dec(i) + str(string(" ")) + xloc := 18 + loc := xloc + yloc*cols + str(string("Color ")) + str(string("PC Port: ")) + if pcport == 1 + str(string("OFF ")) + if pcport == 0 + str(string("ON ")) + str(string(" Force 7 bit: ")) + if ascii == 0 + str(string("NO ")) + if ascii == 1 + str(string("YES ")) + str(string(" Cursor CR W/LF: ")) + if CR == 1 + str(string("YES")) + if CR == 0 + str(string("NO ")) + outc(13) + outc(10) + + inverse:=1 + xloc := 6 + loc := xloc + yloc*cols + str(string("F1")) + xloc := 19 + loc := xloc + yloc*cols + str(string("F2")) + xloc := 30 + loc := xloc + yloc*cols + str(string("F3")) + xloc := 46 + loc := xloc + yloc*cols + str(string("F4")) + xloc := 58 + loc := xloc + yloc*cols + str(string("F5")) + xloc := 70 + loc := xloc + yloc*cols + str(string("F6")) + inverse := invs + xloc := cursor[0] := x 'right & left was 0 + yloc := cursor[1] := y 'from top was 1 + loc := xloc + yloc*cols +}} + +PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold + + invs := inverse + locold := loc + x := xloc + y := yloc + ''(TURQUOISE) + xloc := 0 + yloc :=36 + loc := xloc + yloc*cols + inverse := 1 + str(string(" propIO V 0.81 ")) + inverse := 0 + xloc := 0 + yloc :=37 + loc := xloc + yloc*cols + str(string("Baud Rate: ")) + i:= BR[6] + dec(i) + str(string(" ")) + xloc := 18 + loc := xloc + yloc*cols + + str(string("Color ")) + str(string("PC Port: ")) + if pcport == 1 + str(string("OFF ")) + if pcport == 0 + str(string("ON ")) + str(string(" Force 7 bit: ")) + if ascii == 0 + str(string("NO ")) + if ascii == 1 + str(string("YES ")) + str(string(" Cursor CR W/LF: ")) + if CR == 1 + str(string("YES")) + if CR == 0 + str(string("NO ")) + xloc := 0 + yloc :=38 + loc := xloc + yloc*cols + inverse:=1 + xloc := 6 + loc := xloc + yloc*cols + str(string("F1")) + xloc := 19 + loc := xloc + yloc*cols + str(string("F2")) + xloc := 30 + loc := xloc + yloc*cols + str(string("F3")) + xloc := 46 + loc := xloc + yloc*cols + str(string("F4")) + xloc := 58 + loc := xloc + yloc*cols + str(string("F5")) + xloc := 70 + loc := xloc + yloc*cols + str(string("F6")) + inverse := invs + xloc := cursor[0] := x + yloc := cursor[1] := y +' loc := xloc + yloc*cols + loc := locold + +PUB dec(value) | i + +'' Print a decimal number + + if value < 0 + -value + outc("-") + + i := 1_000_000_000 + + repeat 10 + if value => i + outc(value/i + "0") + value //= i + result~~ + elseif result or i == 1 + outc("0") + i /= 10 + +PUB hex(value, digits) + +'' Print a hexadecimal number, specify number of digits + + repeat while digits > 8 + outc("0") + digits-- + + value <<= (8 - digits) << 2 + + repeat digits + outc(lookupz((value <-= 4) & $f : "0".."9", "A".."F")) + + +PUB str(string_ptr) + +'' Print a zero terminated string + + repeat strsize(string_ptr) + process_char(byte[string_ptr++]) + +PUB statprint(r, c, str1) | x, ptr + + ptr := r * cols + c + repeat x from 0 to STRSIZE(str1) - 1 + putc(ptr++, BYTE[str1 + x]) + +PUB statnum(r, c, num1) | i, ptr + + ptr := r * cols + c + + if num1 < 0 + -num1 + putc(ptr++,"-") + + i := 1_000_000_000 + + repeat 10 + if num1 => i + putc(ptr++, (num1/i +"0")) + num1 //= i + result~~ + elseif result or i == 1 + putc(ptr++, "0") + i /= 10 + +PUB putc(position, c) + if inverse + c |= $80 + screen[position] := c + +PUB cls + longfill (@screen, $20202020, lastChar) + +PUB fullcls + longfill(@screen, $20202020, 800) + +PUB setInverse(val) + inverse := val + +PUB setInv(c) + if c == 7 + setInverse(1) + else + setInverse(0) + +PUB clEOL(position) | count + count := cols - (position // cols) + bytefill(@screen + position, $20, count) + +PUB clBOL(position) | count + count := position // cols + bytefill(@screen + position - count, $20, count) + +PUB delLine(position) | src, count + position -= position // cols + + src := position + cols + + count := (maxChars - src) / 4 + + if count > 0 + longmove(@screen + position, @screen + src, count) + + longfill(@screen + lastLine, $20202020, lcols) + +PUB clEOS(position) + cleol(position) + position += cols - (position // cols) + repeat while position < maxChars + longfill(@screen + position, $20202020, lcols) + pos += cols + +PUB setCursorPos(position) + cursor[0] := position // cols + cursor[1] := position / cols + +PUB insLine(position) | base, nxt + base := position - (position // cols) + position := lastLine + repeat while position > base + nxt := position - cols + longmove(@screen + position, @screen + nxt, lcols) + position := nxt + clEOL(base) + +PUB insChar(position) | count + count := (cols - (position // cols)) - 1 + bytemove(@tmpl, @screen + position, count) + screen[position] := " " + bytemove(@screen + position + 1, @tmpl, count) + +PUB delChar(position) | count + count := (cols - (position // cols)) - 1 + bytemove(@screen + position, @screen + position + 1, count) + screen[position + count] := " " + +PRI inRegion : answer + answer := (pos => regionTop) AND (pos < regionBot) + +PRI scrollUp + delLine(regionTop) + if regionBot < maxChars + insLine(regionBot) + +PRI scrollDown + if regionBot < maxChars + delLine(regionBot) + insLine(regionTop) + +PRI ansi(c) | x, defVal + + state := 0 + + if (c <> "r") AND (c <> "J") AND (c <> "m") AND (c <> "K") + if arg0 == -1 + arg0 := 1 + if arg1 == -1 + arg1 := 1 + + case c + "@": + repeat while arg0-- > 0 + insChar(pos) + + "b": + repeat while arg0-- > 0 + outc(lastc) + + "d": + if (arg0 < 1) OR (arg0 > rows) + arg0 := rows + pos := ((arg0 - 1) * cols) + (pos // cols) + + "m": + setInv(arg0) + if arg1 <> -1 + setInv(arg1) + + "r": + if arg0 < 1 + arg0 := 1 + elseif arg0 > cols + arg0 := cols + if arg1 < 1 + arg1 := 1 + elseif arg1 > cols + arg1 := cols + if arg1 < arg0 + arg1 := arg0 + + regionTop := (arg0 - 1) * cols + regionBot := arg1 * cols + pos := 0 + + "A": + repeat while arg0-- > 0 + pos -= cols + if pos < 0 + pos += cols + return + + "B": + repeat while arg0-- > 0 + pos += cols + if pos => maxChars + pos -= cols + return + + "C": + repeat while arg0-- > 0 + pos += 1 + if pos => maxChars + pos -= 1 + return + + "D": + repeat while arg0-- > 0 + pos -= 1 + if pos < 0 + pos := 0 + return + + "G": + if (arg0 < 1) OR (arg0 > cols) + arg0 := cols + pos := (pos - (pos // cols)) + (arg0 - 1) + + "H", "f": + if arg0 =< 0 + arg0 := 1 + if arg1 =< 0 + arg1 := 1 + pos := (cols * (arg0 - 1)) + (arg1 - 1) + if pos < 0 + pos := 0 + if pos => maxChars + pos := maxChars - 1 + + "J": + if arg0 == 1 + clBOL(pos) + x := pos - cols + x -= x // cols + repeat while x => 0 + clEOL(x) + x -= cols + return + + if arg0 == 2 + pos := 0 + + clEOL(pos) + x := pos + cols + x -= (x // cols) + repeat while x < maxChars + clEOL(x) + x += cols + + "K": + if arg0 == -1 + clEOL(pos) + elseif arg0 == 1 + clBOL(pos) + else + clEOL(pos - (pos // cols)) + + "L": + if inRegion + repeat while arg0-- > 0 + if regionBot < maxChars + delLine(regionBot) + insLine(pos) + + "M": + if inRegion + repeat while arg0-- > 0 + delLine(pos) + if regionBot < maxChars + insLine(regionBot) + + "P": + repeat while arg0-- + delChar(pos) + +PRI outc(c) + + putc(pos++, lastc := c) + if pos == regionBot + scrollUp + pos -= cols + elseif pos == maxChars + pos := lastLine + +PUB process_char(c) + + case state + + 0: + if c > 127 + c := $20 + + if c => $20 + outc(c) + setCursorPos(pos) + return + + if c == $1B + state := 1 + return + + if c == $0D + pos := pos - (pos // cols) + setCursorPos(pos) + return + + if c == $0A + if inRegion + pos += cols + if pos => regionBot + scrollUp + pos -= cols + else + pos += cols + if pos => maxChars + pos -= cols + setCursorPos(pos) + return + + if c == 9 + pos += (8 - (pos // 8)) + + if pos => maxChars + pos := lastLine + delLine(0) + + setCursorPos(pos) + return + + if c == 8 + if pos > 0 + pos -= 1 + setCursorPos(pos) + return + + 1: + case c + "[": + arg0 := arg1 := -1 + state := 2 + return + + "P": + pos += cols + if pos => maxChars + pos -= cols + + "K": + if pos > 0 + pos -= 1 + + "H": + pos -= cols + if pos < 0 + pos += cols + + "D": + if inRegion + scrollUp + + "M": + if inRegion + scrollDown + + "G": + pos := 0 + + "(": + state := 5 + return + + state := 0 + return + + 2: + if (c => "0") AND (c =< "9") + if arg0 == -1 + arg0 := c - "0" + else + arg0 := (arg0 * 10) + (c - "0") + return + + if c == ";" + state := 3 + return + + ansi(c) + setCursorPos(pos) + return + + 3: + if (c => "0") AND (c =< "9") + if arg1 == -1 + arg1 := c - "0" + else + arg1 := (arg1 * 10) + (c - "0") + return + + if c == ";" + state := 4 + return + + ansi(c) + setCursorPos(pos) + return + + 4: + if (c => "0") AND (c =< "9") + return + + if c == ";" + return + ansi(c) + setCursorPos(pos) + return + + 5: + state := 0 + return + + return \ No newline at end of file diff --git a/trunk/Support/ParPortProp/Spin/VGA_HiRes_Text.spin b/trunk/Support/ParPortProp/Spin/VGA_HiRes_Text.spin new file mode 100644 index 00000000..5b892316 Binary files /dev/null and b/trunk/Support/ParPortProp/Spin/VGA_HiRes_Text.spin differ diff --git a/trunk/Support/ParPortProp/Spin/safe_spi.spin b/trunk/Support/ParPortProp/Spin/safe_spi.spin new file mode 100644 index 00000000..a63cb229 --- /dev/null +++ b/trunk/Support/ParPortProp/Spin/safe_spi.spin @@ -0,0 +1,920 @@ +{{ + SPI interface routines for SD & SDHC & MMC cards + + Jonathan "lonesock" Dummer + version 0.3.0 2009 July 19 + + Using multiblock SPI mode exclusively. + + This is the "SAFE" version...uses + * 1 instruction per bit writes + * 2 instructions per bit reads + + For the fsrw project: + fsrw.sf.net +}} + +CON + ' possible card types + type_MMC = 1 + type_SD = 2 + type_SDHC = 3 + + ' Error codes + ERR_CARD_NOT_RESET = -1 + ERR_3v3_NOT_SUPPORTED = -2 + ERR_OCR_FAILED = -3 + ERR_BLOCK_NOT_LONG_ALIGNED = -4 + '... + ' These errors are for the assembly engine...they are negated inside, and need to be <= 511 + ERR_ASM_NO_READ_TOKEN = 100 + ERR_ASM_BLOCK_NOT_WRITTEN = 101 + ' NOTE: errors -128 to -255 are reserved for reporting R1 response errors + '... + ERR_SPI_ENGINE_NOT_RUNNING = -999 + ERR_CARD_BUSY_TIMEOUT = -1000 + + ' SDHC/SD/MMC command set for SPI + CMD0 = $40+0 ' GO_IDLE_STATE + CMD1 = $40+1 ' SEND_OP_COND (MMC) + ACMD41 = $C0+41 ' SEND_OP_COND (SDC) + CMD8 = $40+8 ' SEND_IF_COND + CMD9 = $40+9 ' SEND_CSD + CMD10 = $40+10 ' SEND_CID + CMD12 = $40+12 ' STOP_TRANSMISSION + CMD13 = $40+13 ' SEND_STATUS + ACMD13 = $C0+13 ' SD_STATUS (SDC) + CMD16 = $40+16 ' SET_BLOCKLEN + CMD17 = $40+17 ' READ_SINGLE_BLOCK + CMD18 = $40+18 ' READ_MULTIPLE_BLOCK + CMD23 = $40+23 ' SET_BLOCK_COUNT (MMC) + ACMD23 = $C0+23 ' SET_WR_BLK_ERASE_COUNT (SDC) + CMD24 = $40+24 ' WRITE_BLOCK + CMD25 = $40+25 ' WRITE_MULTIPLE_BLOCK + CMD55 = $40+55 ' APP_CMD + CMD58 = $40+58 ' READ_OCR + CMD59 = $40+59 ' CRC_ON_OFF + + ' buffer size for my debug cmd log + 'LOG_SIZE = 256<<1 + +{ +VAR + long SPI_engine_cog + ' these are used for interfacing with the assembly engine | temporary initialization usage + long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask + long SPI_block_index ' which 512-byte block to read/write | cnt at init + long SPI_buffer_address ' where to get/put the data in Hub RAM | unused +'} +DAT +'' I'm placing these variables in a DAT section to make this driver a singleton. +'' If for some reason you really need more than one driver (e.g. if you have more +'' than a single SD socket), move these back into VAR. +SPI_engine_cog long 0 +' these are used for interfacing with the assembly engine | temporary initialization usage +SPI_command long 0 ' "t", "r", "w", 0 =>done, <0 => error | unused +SPI_block_index long 0 ' which 512-byte block to read/write | cnt at init +SPI_buffer_address long 0 ' where to get/put the data in Hub RAM | unused + +{ +VAR + ' for debug ONLY + byte log_cmd_resp[LOG_SIZE+1] +PUB get_log_pointer + return @log_cmd_resp +'} + +PUB start( basepin ) +{{ + This is a compatibility wrapper, and requires that the pins be + both consecutive, and in the order DO CLK DI CS. +}} + return start_explicit( basepin, basepin+1, basepin+2, basepin+3 ) + +PUB readblock( block_index, buffer_address ) + if SPI_engine_cog == 0 + abort ERR_SPI_ENGINE_NOT_RUNNING + if (buffer_address & 3) + abort ERR_BLOCK_NOT_LONG_ALIGNED + SPI_block_index := block_index + SPI_buffer_address := buffer_address + SPI_command := "r" + repeat while SPI_command == "r" + if SPI_command < 0 + abort SPI_command + +PUB writeblock( block_index, buffer_address ) + if SPI_engine_cog == 0 + abort ERR_SPI_ENGINE_NOT_RUNNING + if (buffer_address & 3) + abort ERR_BLOCK_NOT_LONG_ALIGNED + SPI_block_index := block_index + SPI_buffer_address := buffer_address + SPI_command := "w" + repeat while SPI_command == "w" + if SPI_command < 0 + abort SPI_command + +PUB get_seconds + if SPI_engine_cog == 0 + abort ERR_SPI_ENGINE_NOT_RUNNING + SPI_command := "t" + repeat while SPI_command == "t" + ' secods are in SPI_block_index, remainder is in SPI_buffer_address + return SPI_block_index + +PUB get_milliseconds : ms + if SPI_engine_cog == 0 + abort ERR_SPI_ENGINE_NOT_RUNNING + SPI_command := "t" + repeat while SPI_command == "t" + ' secods are in SPI_block_index, remainder is in SPI_buffer_address + ms := SPI_block_index * 1000 + ms += SPI_buffer_address * 1000 / clkfreq + +PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i +{{ + Do all of the card initialization in SPIN, then hand off the pin + information to the assembly cog for hot SPI block R/W action! +}} + ' Start from scratch + stop + ' clear my log buffer + { + bytefill( @log_cmd_resp, 0, LOG_SIZE+1 ) + dbg_ptr := @log_cmd_resp + dbg_end := dbg_ptr + LOG_SIZE + '} + ' wait ~4 milliseconds + waitcnt( 500 + (clkfreq>>8) + cnt ) + ' (start with cog variables, _BEFORE_ loading the cog) + pinDO := DO + maskDO := |< DO + pinCLK := CLK + pinDI := DI + maskDI := |< DI + maskCS := |< CS + adrShift := 9 ' block = 512 * index, and 512 = 1<<9 + ' pass the output pin mask via the command register + maskAll := maskCS | (| 74 clocks + outa |= maskAll + repeat 4096 + outa[CLK]~~ + outa[CLK]~ + ' time-hack + SPI_block_index := cnt + ' reset the card + tmp~ + repeat i from 0 to 9 + if tmp <> 1 + tmp := send_cmd_slow( CMD0, 0, $95 ) + if (tmp & 4) + ' the card said CMD0 ("go idle") was invalid, so we're possibly stuck in read or write mode + if i & 1 + ' exit multiblock read mode + repeat 4 + read_32_slow ' these extra clocks are required for some MMC cards + send_slow( $FD, 8 ) ' stop token + read_32_slow + repeat while read_slow <> $FF + else + ' exit multiblock read mode + send_cmd_slow( CMD12, 0, $61 ) + if tmp <> 1 + ' the reset command failed! + crash( ERR_CARD_NOT_RESET ) + ' Is this a SD type 2 card? + if send_cmd_slow( CMD8, $1AA, $87 ) == 1 + ' Type2 SD, check to see if it's a SDHC card + tmp := read_32_slow + ' check the supported voltage + if (tmp & $1FF) <> $1AA + crash( ERR_3v3_NOT_SUPPORTED ) + ' try to initialize the type 2 card with the High Capacity bit + repeat while send_cmd_slow( ACMD41, |<30, $77 ) + ' the card is initialized, let's read back the High Capacity bit + if send_cmd_slow( CMD58, 0, $FD ) <> 0 + crash( ERR_OCR_FAILED ) + ' get back the data + tmp := read_32_slow + ' check the bit + if tmp & |<30 + card_type := type_SDHC + adrShift := 0 + else + card_type := type_SD + else + ' Either a type 1 SD card, or it's MMC, try SD 1st + if send_cmd_slow( ACMD41, 0, $E5 ) < 2 + ' this is a type 1 SD card (1 means busy, 0 means done initializing) + card_type := type_SD + repeat while send_cmd_slow( ACMD41, 0, $E5 ) + else + ' mark that it's MMC, and try to initialize + card_type := type_MMC + repeat while send_cmd_slow( CMD1, 0, $F9 ) + ' some SD or MMC cards may have the wrong block size, set it here + send_cmd_slow( CMD16, 512, $15 ) + ' card is mounted, make sure the CRC is turned off + send_cmd_slow( CMD59, 0, $91 ) + ' check the status + 'send_cmd_slow( CMD13, 0, $0D ) + ' done with the SPI bus for now + outa |= maskCS + ' set my counter modes for super fast SPI operation + ' writing: NCO single-ended mode, output on DI + writeMode := (%00100 << 26) | (DI << 0) + ' reading + 'readMode := (%11000 << 26) | (DO << 0) | (CLK << 9) + ' clock + 'clockLineMode := (%00110 << 26) | (CLK << 0) ' DUTY, 25% duty cycle + ' clock + clockLineMode := (%00100 << 26) | (CLK << 0) ' NCO, 50% duty cycle + ' how many bytes (8 clocks, >>3) fit into 1/2 of a second (>>1), 4 clocks per instruction (>>2)? + N_in8_500ms := clkfreq >> constant(1+2+3) + ' how long should we wait before auto-exiting any multiblock mode? + idle_limit := 125 ' ms, NEVER make this > 1000 + idle_limit := clkfreq / (1000 / idle_limit) ' convert to counts + ' Hand off control to the assembly engine's cog + bufAdr := @SPI_buffer_address + sdAdr := @SPI_block_index + SPI_command := 0 ' just make sure it's not 1 + ' start my driver cog and wait till I hear back that it's done + SPI_engine_cog := cognew( @SPI_engine_entry, @SPI_command ) + 1 + if( SPI_engine_cog == 0 ) + crash( ERR_SPI_ENGINE_NOT_RUNNING ) + repeat while SPI_command <> -1 + ' and we no longer need to control any pins from here + dira &= !maskAll + ' the return variable is card_type + +PUB release +{{ + I do not want to abort if the cog is not + running, as this is called from stop, which + is called from start/ [8^) +}} + if SPI_engine_cog + SPI_command := "z" + repeat while SPI_command == "z" + +PUB stop +{{ + kill the assembly driver cog. +}} + release + if SPI_engine_cog + cogstop( SPI_engine_cog~ - 1 ) + +PRI crash( abort_code ) +{{ + In case of Bad Things(TM) happening, + exit as gracefully as possible. +}} + ' and we no longer need to control any pins from here + dira &= !maskAll + ' and report our error + abort abort_code + +PRI send_cmd_slow( cmd, val, crc ) : reply | time_stamp +{{ + Send down a command and return the reply. + Note: slow is an understatement! + Note: this uses the assembly DAT variables for pin IDs, + which means that if you run this multiple times (say for + multiple SD cards), these values will change for each one. + But this is OK as all of these functions will be called + during the initialization only, before the PASM engine is + running. +}} + ' if this is an application specific command, handle it + if (cmd & $80) + ' ACMD is the command sequense of CMD55-CMD + cmd &= $7F + reply := send_cmd_slow( CMD55, 0, $65 ) + if (reply > 1) + return reply + ' the CS line needs to go low during this operation + outa |= maskCS + outa &= !maskCS + ' give the card a few cocks to finish whatever it was doing + read_32_slow + ' send the command byte + send_slow( cmd, 8 ) + ' send the value long + send_slow( val, 32 ) + ' send the CRC byte + send_slow( crc, 8 ) + ' is this a CMD12?, if so, stuff byte + if cmd == CMD12 + read_slow + ' read back the response (spec declares 1-8 reads max for SD, MMC is 0-8) + time_stamp := 9 + repeat + reply := read_slow + while( reply & $80 ) and ( time_stamp-- ) + ' done, and 'reply' is already pre-loaded + { + if dbg_ptr < (dbg_end-1) + byte[dbg_ptr++] := cmd + byte[dbg_ptr++] := reply + if (cmd&63) == 13 + ' get the second byte + byte[dbg_ptr++] := cmd + byte[dbg_ptr++] := read_slow + '} + +PRI send_slow( value, bits_to_send ) + value ><= bits_to_send + repeat bits_to_send + outa[pinCLK]~ + outa[pinDI] := value + value >>= 1 + outa[pinCLK]~~ + +PRI read_32_slow : r + repeat 4 + r <<= 8 + r |= read_slow + +PRI read_slow : r +{{ + Read back 8 bits from the card +}} + ' we need the DI line high so a read can occur + outa[pinDI]~~ + ' get 8 bits (remember, r is initialized to 0 by SPIN) + repeat 8 + outa[pinCLK]~ + outa[pinCLK]~~ + r += r + ina[pinDO] + ' error check + if( (cnt - SPI_block_index) > (clkfreq << 2) ) + crash( ERR_CARD_BUSY_TIMEOUT ) + +DAT +{{ + This is the assembly engine for doing fast block + reads and writes. This is *ALL* it does! +}} +ORG 0 +SPI_engine_entry + ' Counter A drives data out + mov ctra,writeMode + ' Counter B will always drive my clock line + mov ctrb,clockLineMode + ' set our output pins to match the pin mask + mov dira,maskAll + ' handshake that we now control the pins + neg user_request,#1 + wrlong user_request,par + ' start my seconds' counter here + mov last_time,cnt + +waiting_for_command + ' update my seconds counter, but also track the idle + ' time so we can to release the card after timeout. + call #handle_time + ' read the command, and make sure it's from the user (> 0) + rdlong user_request,par + cmps user_request,#0 wz,wc +if_be jmp #waiting_for_command + ' handle our card based commands + cmp user_request,#"r" wz +if_z jmp #read_ahead + cmp user_request,#"w" wz +if_z jmp #write_behind + cmp user_request,#"z" wz +if_z jmp #release_card + ' time requests are handled differently + cmp user_request,#"t" wz ' time +if_z wrlong seconds,sdAdr ' seconds goes into the SD index register +if_z wrlong dtime,bufAdr ' the remainder goes into the buffer address register + ' in all other cases, clear the user's request + mov user_request,#0 + wrlong user_request,par + jmp #waiting_for_command + + +release_card + mov user_cmd,#"z" ' request a release + neg lastIndexPlus,#1 ' reset the last block index + neg user_idx,#1 ' and make this match it + call #handle_command + mov user_request,user_cmd + wrlong user_request,par + jmp #waiting_for_command + +read_ahead + rdlong user_idx,sdAdr + ' if the correct block is not already loaded, load it + mov tmp1,user_idx + add tmp1,#1 + cmp tmp1,lastIndexPlus wz +if_z cmp lastCommand,#"r" wz +if_z jmp #:get_on_with_it + mov user_cmd,#"r" + call #handle_command +:get_on_with_it + ' copy the data up into Hub RAM + movi transfer_long,#%000010_000 'set to wrlong + call #hub_cog_transfer + ' signify that the data is ready, Spin can continue + mov user_request,user_cmd + wrlong user_request,par + ' request the next block + mov user_cmd,#"r" + add user_idx,#1 + call #handle_command + ' done + jmp #waiting_for_command + +write_behind + rdlong user_idx,sdAdr + ' copy data in from Hub RAM + movi transfer_long,#%000010_001 'set to rdlong + call #hub_cog_transfer + ' signify that we have the data, Spin can continue + mov user_request,user_cmd + wrlong user_request,par + ' write out the block + mov user_cmd,#"w" + call #handle_command + ' done + jmp #waiting_for_command + +{{ + Set user_cmd and user_idx before calling this +}} +handle_command + ' Can we stay in the old mode? (address = old_address+1) && (old mode == new_mode) + cmp lastIndexPlus,user_idx wz +if_z cmp user_cmd,lastCommand wz +if_z jmp #:execute_block_command + ' we fell through, must exit the old mode! (except if the old mode was "release") + cmp lastCommand,#"w" wz +if_z call #stop_mb_write + cmp lastCommand,#"r" wz +if_z call #stop_mb_read + ' and start up the new mode! + cmp user_cmd,#"w" wz +if_z call #start_mb_write + cmp user_cmd,#"r" wz +if_z call #start_mb_read + cmp user_cmd,#"z" wz +if_z call #release_DO +:execute_block_command + ' track the (new) last index and command + mov lastIndexPlus,user_idx + add lastIndexPlus,#1 + mov lastCommand,user_cmd + ' do the block read or write or terminate! + cmp user_cmd,#"w" wz +if_z call #write_single_block + cmp user_cmd,#"r" wz +if_z call #read_single_block + cmp user_cmd,#"z" wz +if_z mov user_cmd,#0 + ' done +handle_command_ret + ret + +{=== these PASM functions get me in and out of multiblock mode ===} +release_DO + ' we're already out of multiblock mode, so + ' deselect the card and send out some clocks + or outa,maskCS + call #in8 + call #in8 + ' if you are using pull-up resistors, and need all + ' lines tristated, then uncomment the following line. + ' for Cluso99 + 'mov dira,#0 +release_DO_ret + ret + +start_mb_read + movi block_cmd,#CMD18<<1 + call #send_SPI_command_fast +start_mb_read_ret + ret + +stop_mb_read + movi block_cmd,#CMD12<<1 + call #send_SPI_command_fast + call #busy_fast +stop_mb_read_ret + ret + +start_mb_write + movi block_cmd,#CMD25<<1 + call #send_SPI_command_fast +start_mb_write_ret + ret + +stop_mb_write + call #busy_fast + ' only some cards need these extra clocks + mov tmp1,#16 +:loopity + call #in8 + djnz tmp1,#:loopity + ' done with hack + movi phsa,#$FD<<1 + call #out8 + call #in8 ' stuff byte + call #busy_fast +stop_mb_write_ret + ret + +send_SPI_command_fast + ' make sure we have control of the output lines + mov dira,maskAll + ' make sure the CS line transitions low + or outa,maskCS + andn outa,maskCS + ' 8 clocks + call #in8 + ' send the data + mov phsa,block_cmd ' do which ever block command this is (already in the top 8 bits) + call #out8 ' write the byte + mov phsa,user_idx ' read in the desired block index + shl phsa,adrShift ' this will multiply by 512 (bytes/sector) for MMC and SD + call #out8 ' move out the 1st MSB ' + rol phsa,#1 + call #out8 ' move out the 1st MSB ' + rol phsa,#1 + call #out8 ' move out the 1st MSB ' + rol phsa,#1 + call #out8 ' move out the 1st MSB ' + ' bogus CRC value + call #in8 ' in8 looks like out8 with $FF + ' CMD12 requires a stuff byte + shr block_cmd,#24 + cmp block_cmd,#CMD12 wz +if_z call #in8 ' 8 clocks + ' get the response + mov tmp1,#9 +:cmd_response + call #in8 + test readback,#$80 wc,wz +if_c djnz tmp1,#:cmd_response +if_nz neg user_cmd,readback + ' done +send_SPI_command_fast_ret + ret + + +busy_fast + mov tmp1,N_in8_500ms +:still_busy + call #in8 + cmp readback,#$FF wz +if_nz djnz tmp1,#:still_busy +busy_fast_ret + ret + + +out8 + andn outa,maskDI + 'movi phsb,#%11_0000000 + mov phsb,#0 + movi frqb,#%01_0000000 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + mov frqb,#0 + ' don't shift out the final bit...already sent, but be aware + ' of this when sending consecutive bytes (send_cmd, for e.g.) +out8_ret + ret + +{ +in8 + or outa,maskDI + mov ctra,readMode + ' Start my clock + mov frqa,#1<<7 + mov phsa,#0 + movi phsb,#%11_0000000 + movi frqb,#%01_0000000 + ' keep reading in my value, one bit at a time! (Kuneko - "Wh) + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + mov frqb,#0 ' stop the clock + mov readback,phsa + mov frqa,#0 + mov ctra,writeMode +in8_ret + ret +} +in8 + neg phsa,#1' DI high + mov readback,#0 + ' set up my clock, and start it + movi phsb,#%011_000000 + movi frqb,#%001_000000 + ' keep reading in my value + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + mov frqb,#0 ' stop the clock + rcl readback,#1 + mov phsa,#0 'DI low +in8_ret + ret + + +' this is called more frequently than 1 Hz, and +' is only called when the user command is 0. +handle_time + mov tmp1,cnt ' get the current timestamp + add idle_time,tmp1 ' add the current time to my idle time counter + sub idle_time,last_time ' subtract the last time from my idle counter (hence delta) + add dtime,tmp1 ' add to my accumulator, + sub dtime,last_time ' and subtract the old (adding delta) + mov last_time,tmp1 ' update my "last timestamp" + rdlong tmp1,#0 ' what is the clock frequency? + cmpsub dtime,tmp1 wc ' if I have more than a second in my accumulator + addx seconds,#0 ' then add it to "seconds" + ' this part is to auto-release the card after a timeout + cmp idle_time,idle_limit wz,wc +if_b jmp #handle_time_ret ' don't clear if we haven't hit the limit + mov user_cmd,#"z" ' we can't overdo it, the command handler makes sure + neg lastIndexPlus,#1 ' reset the last block index + neg user_idx,#1 ' and make this match it + call #handle_command ' release the card, but don't mess with the user's request register +handle_time_ret + ret + +hub_cog_transfer +' setup for all 4 passes + mov ctrb,clockXferMode + mov frqb,#1 + rdlong buf_ptr,bufAdr + mov ops_left,#4 + movd transfer_long,#speed_buf +four_transfer_passes + ' sync to the Hub RAM access + rdlong tmp1,tmp1 + ' how many long to move on this pass? (512 bytes / 4)longs / 4 passes + mov tmp1,#(512 / 4 / 4) + ' get my starting address right (phsb is incremented 1 per clock, so 16 each Hub access) + mov phsb,buf_ptr + ' write the longs, stride 4...low 2 bits of phsb are ignored +transfer_long + rdlong 0-0,phsb + add transfer_long,incDest4 + djnz tmp1,#transfer_long + ' go back to where I started, but advanced 1 long + sub transfer_long,decDestNminus1 + ' offset my Hub pointer by one long per pass + add buf_ptr,#4 + ' do all 4 passes + djnz ops_left,#four_transfer_passes + ' restore the counter mode + mov frqb,#0 + mov phsb,#0 + mov ctrb,clockLineMode +hub_cog_transfer_ret + ret + + +read_single_block + ' where am I sending the data? + movd :store_read_long,#speed_buf + mov ops_left,#128 + ' wait until the card is ready + mov tmp1,N_in8_500ms +:get_resp + call #in8 + cmp readback,#$FE wz +if_nz djnz tmp1,#:get_resp +if_nz neg user_cmd,#ERR_ASM_NO_READ_TOKEN +if_nz jmp #read_single_block_ret + ' set DI high + neg phsa,#1 + ' read the data + mov ops_left,#128 +:read_loop + mov tmp1,#4 + movi phsb,#%011_000000 +:in_byte + ' Start my clock + movi frqb,#%001_000000 + ' keep reading in my value, BACKWARDS! (Brilliant idea by Tom Rokicki!) + test maskDO,ina wc + rcl readback,#8 + test maskDO,ina wc + muxc readback,#2 + test maskDO,ina wc + muxc readback,#4 + test maskDO,ina wc + muxc readback,#8 + test maskDO,ina wc + muxc readback,#16 + test maskDO,ina wc + muxc readback,#32 + test maskDO,ina wc + muxc readback,#64 + test maskDO,ina wc + mov frqb,#0 ' stop the clock + muxc readback,#128 + ' go back for more + djnz tmp1,#:in_byte + ' make it...NOT backwards [8^) + rev readback,#0 +:store_read_long + mov 0-0,readback ' due to some counter weirdness, we need this mov + add :store_read_long,const512 + djnz ops_left,#:read_loop + + ' set DI low + mov phsa,#0 + + ' now read 2 trailing bytes (CRC) + call #in8 ' out8 is 2x faster than in8 + call #in8 ' and I'm not using the CRC anyway + ' give an extra 8 clocks in case we pause for a long time + call #in8 ' in8 looks like out8($FF) + + ' all done successfully + mov idle_time,#0 + mov user_cmd,#0 +read_single_block_ret + ret + +write_single_block + ' where am I getting the data? (all 512 bytes / 128 longs of it?) + movs :write_loop,#speed_buf + ' read in 512 bytes (128 longs) from Hub RAM and write it to the card + mov ops_left,#128 + ' just hold your horses + call #busy_fast + ' $FC for multiblock, $FE for single block + movi phsa,#$FC<<1 + call #out8 + mov phsb,#0 ' make sure my clock accumulator is right + 'movi phsb,#%11_0000000 +:write_loop + ' read 4 bytes + mov phsa,speed_buf + add :write_loop,#1 + ' a long in LE order is DCBA + rol phsa,#24 ' move A7 into position, so I can do the swizzled version + movi frqb,#%010000000 ' start the clock (remember A7 is already in place) + rol phsa,#1 ' A7 is going out, at the end of this instr, A6 is in place + rol phsa,#1 ' A5 + rol phsa,#1 ' A4 + rol phsa,#1 ' A3 + rol phsa,#1 ' A2 + rol phsa,#1 ' A1 + rol phsa,#1 ' A0 + rol phsa,#17 ' B7 + rol phsa,#1 ' B6 + rol phsa,#1 ' B5 + rol phsa,#1 ' B4 + rol phsa,#1 ' B3 + rol phsa,#1 ' B2 + rol phsa,#1 ' B1 + rol phsa,#1 ' B0 + rol phsa,#17 ' C7 + rol phsa,#1 ' C6 + rol phsa,#1 ' C5 + rol phsa,#1 ' C4 + rol phsa,#1 ' C3 + rol phsa,#1 ' C2 + rol phsa,#1 ' C1 + rol phsa,#1 ' C0 + rol phsa,#17 ' D7 + rol phsa,#1 ' D6 + rol phsa,#1 ' D5 + rol phsa,#1 ' D4 + rol phsa,#1 ' D3 + rol phsa,#1 ' D2 + rol phsa,#1 ' D1 + rol phsa,#1 ' D0 will be in place _after_ this instruction + mov frqb,#0 ' shuts the clock off, _after_ this instruction + djnz ops_left,#:write_loop + ' write out my two (bogus, using $FF) CRC bytes + call #in8 + call #in8 + ' now read response (I need this response, so can't spoof using out8) + call #in8 + and readback,#$1F + cmp readback,#5 wz +if_z mov user_cmd,#0 ' great +if_nz neg user_cmd,#ERR_ASM_BLOCK_NOT_WRITTEN ' oops + ' send out another 8 clocks + call #in8 + ' all done + mov idle_time,#0 +write_single_block_ret + ret + + +{=== Assembly Interface Variables ===} +pinDO long 0 ' pin is controlled by a counter +pinCLK long 0 ' pin is controlled by a counter +pinDI long 0 ' pin is controlled by a counter +maskDO long 0 ' mask for reading the DO line from the card +maskDI long 0 ' mask for setting the pin high while reading +maskCS long 0 ' mask = (1< 32 + outc("0") + digits-- + + value <<= 32 - digits + + repeat digits + outc((value <-= 1) & 1 + "0") + + +PUB clrbtm(ColorVal) | i + repeat i from 36 to rows - 1 'was 35 + colors[i] := $0000 + ColorVal + +PUB cls1(c,screencolor,pcport,ascii,CR) | i,x,y + + longfill(@screen[0], $20202020, chars / 4) + + clrbtm(TURQUOISE) + + inverse := 1 + + statprint(36,0, string(" N8VEM ParPortProp | RomWBW v0.92")) + inverse := 0 + statprint(37,0, string(" ")) + statprint(38,0, string(" ")) + statprint(39,0, string(" ")) + + +{{ + x :=xloc + y := yloc + invs := inverse + ''clrbtm(TURQUOISE) + longfill(@screen, $20202020, chars/4) + xloc := 0 + yloc :=0 + loc := xloc + yloc*cols + repeat 80 + outc(32) + xloc := 0 + yloc :=36 + loc := xloc + yloc*cols + inverse := 1 + str(string(" propIO V 0.91 ")) + inverse := 0 + str(string("Baud Rate: ")) + i:= BR[6] + dec(i) + str(string(" ")) + xloc := 18 + loc := xloc + yloc*cols + str(string("Color ")) + str(string("PC Port: ")) + if pcport == 1 + str(string("OFF ")) + if pcport == 0 + str(string("ON ")) + str(string(" Force 7 bit: ")) + if ascii == 0 + str(string("NO ")) + if ascii == 1 + str(string("YES ")) + str(string(" Cursor CR W/LF: ")) + if CR == 1 + str(string("YES")) + if CR == 0 + str(string("NO ")) + outc(13) + outc(10) + + inverse:=1 + xloc := 6 + loc := xloc + yloc*cols + str(string("F1")) + xloc := 19 + loc := xloc + yloc*cols + str(string("F2")) + xloc := 30 + loc := xloc + yloc*cols + str(string("F3")) + xloc := 46 + loc := xloc + yloc*cols + str(string("F4")) + xloc := 58 + loc := xloc + yloc*cols + str(string("F5")) + xloc := 70 + loc := xloc + yloc*cols + str(string("F6")) + inverse := invs + xloc := cursor[0] := x 'right & left was 0 + yloc := cursor[1] := y 'from top was 1 + loc := xloc + yloc*cols +}} + +PUB clsupdate(c,screencolor,PCPORT,ascii,CR) | i,x,y,locold + + invs := inverse + locold := loc + x := xloc + y := yloc + ''(TURQUOISE) + xloc := 0 + yloc :=36 + loc := xloc + yloc*cols + inverse := 1 + str(string(" propIO V 0.81 ")) + inverse := 0 + xloc := 0 + yloc :=37 + loc := xloc + yloc*cols + str(string("Baud Rate: ")) + i:= BR[6] + dec(i) + str(string(" ")) + xloc := 18 + loc := xloc + yloc*cols + + str(string("Color ")) + str(string("PC Port: ")) + if pcport == 1 + str(string("OFF ")) + if pcport == 0 + str(string("ON ")) + str(string(" Force 7 bit: ")) + if ascii == 0 + str(string("NO ")) + if ascii == 1 + str(string("YES ")) + str(string(" Cursor CR W/LF: ")) + if CR == 1 + str(string("YES")) + if CR == 0 + str(string("NO ")) + xloc := 0 + yloc :=38 + loc := xloc + yloc*cols + inverse:=1 + xloc := 6 + loc := xloc + yloc*cols + str(string("F1")) + xloc := 19 + loc := xloc + yloc*cols + str(string("F2")) + xloc := 30 + loc := xloc + yloc*cols + str(string("F3")) + xloc := 46 + loc := xloc + yloc*cols + str(string("F4")) + xloc := 58 + loc := xloc + yloc*cols + str(string("F5")) + xloc := 70 + loc := xloc + yloc*cols + str(string("F6")) + inverse := invs + xloc := cursor[0] := x + yloc := cursor[1] := y +' loc := xloc + yloc*cols + loc := locold + +PUB dec(value) | i + +'' Print a decimal number + + if value < 0 + -value + outc("-") + + i := 1_000_000_000 + + repeat 10 + if value => i + outc(value/i + "0") + value //= i + result~~ + elseif result or i == 1 + outc("0") + i /= 10 + +PUB hex(value, digits) + +'' Print a hexadecimal number, specify number of digits + + repeat while digits > 8 + outc("0") + digits-- + + value <<= (8 - digits) << 2 + + repeat digits + outc(lookupz((value <-= 4) & $f : "0".."9", "A".."F")) + + +PUB str(string_ptr) + +'' Print a zero terminated string + + repeat strsize(string_ptr) + process_char(byte[string_ptr++]) + +PUB statprint(r, c, str1) | x, ptr + + ptr := r * cols + c + repeat x from 0 to STRSIZE(str1) - 1 + putc(ptr++, BYTE[str1 + x]) + +PUB statnum(r, c, num1) | i, ptr + + ptr := r * cols + c + + if num1 < 0 + -num1 + putc(ptr++,"-") + + i := 1_000_000_000 + + repeat 10 + if num1 => i + putc(ptr++, (num1/i +"0")) + num1 //= i + result~~ + elseif result or i == 1 + putc(ptr++, "0") + i /= 10 + +PUB putc(position, c) + if inverse + c |= $80 + screen[position] := c + +PUB cls + longfill (@screen, $20202020, lastChar) + +PUB fullcls + longfill(@screen, $20202020, 800) + +PUB setInverse(val) + inverse := val + +PUB setInv(c) + if c == 7 + setInverse(1) + else + setInverse(0) + +PUB clEOL(position) | count + count := cols - (position // cols) + bytefill(@screen + position, $20, count) + +PUB clBOL(position) | count + count := position // cols + bytefill(@screen + position - count, $20, count) + +PUB delLine(position) | src, count + position -= position // cols + + src := position + cols + + count := (maxChars - src) / 4 + + if count > 0 + longmove(@screen + position, @screen + src, count) + + longfill(@screen + lastLine, $20202020, lcols) + +PUB clEOS(position) + cleol(position) + position += cols - (position // cols) + repeat while position < maxChars + longfill(@screen + position, $20202020, lcols) + pos += cols + +PUB setCursorPos(position) + cursor[0] := position // cols + cursor[1] := position / cols + +PUB insLine(position) | base, nxt + base := position - (position // cols) + position := lastLine + repeat while position > base + nxt := position - cols + longmove(@screen + position, @screen + nxt, lcols) + position := nxt + clEOL(base) + +PUB insChar(position) | count + count := (cols - (position // cols)) - 1 + bytemove(@tmpl, @screen + position, count) + screen[position] := " " + bytemove(@screen + position + 1, @tmpl, count) + +PUB delChar(position) | count + count := (cols - (position // cols)) - 1 + bytemove(@screen + position, @screen + position + 1, count) + screen[position + count] := " " + +PRI inRegion : answer + answer := (pos => regionTop) AND (pos < regionBot) + +PRI scrollUp + delLine(regionTop) + if regionBot < maxChars + insLine(regionBot) + +PRI scrollDown + if regionBot < maxChars + delLine(regionBot) + insLine(regionTop) + +PRI ansi(c) | x, defVal + + state := 0 + + if (c <> "r") AND (c <> "J") AND (c <> "m") AND (c <> "K") + if arg0 == -1 + arg0 := 1 + if arg1 == -1 + arg1 := 1 + + case c + "@": + repeat while arg0-- > 0 + insChar(pos) + + "b": + repeat while arg0-- > 0 + outc(lastc) + + "d": + if (arg0 < 1) OR (arg0 > rows) + arg0 := rows + pos := ((arg0 - 1) * cols) + (pos // cols) + + "m": + setInv(arg0) + if arg1 <> -1 + setInv(arg1) + + "r": + if arg0 < 1 + arg0 := 1 + elseif arg0 > cols + arg0 := cols + if arg1 < 1 + arg1 := 1 + elseif arg1 > cols + arg1 := cols + if arg1 < arg0 + arg1 := arg0 + + regionTop := (arg0 - 1) * cols + regionBot := arg1 * cols + pos := 0 + + "A": + repeat while arg0-- > 0 + pos -= cols + if pos < 0 + pos += cols + return + + "B": + repeat while arg0-- > 0 + pos += cols + if pos => maxChars + pos -= cols + return + + "C": + repeat while arg0-- > 0 + pos += 1 + if pos => maxChars + pos -= 1 + return + + "D": + repeat while arg0-- > 0 + pos -= 1 + if pos < 0 + pos := 0 + return + + "G": + if (arg0 < 1) OR (arg0 > cols) + arg0 := cols + pos := (pos - (pos // cols)) + (arg0 - 1) + + "H", "f": + if arg0 =< 0 + arg0 := 1 + if arg1 =< 0 + arg1 := 1 + pos := (cols * (arg0 - 1)) + (arg1 - 1) + if pos < 0 + pos := 0 + if pos => maxChars + pos := maxChars - 1 + + "J": + if arg0 == 1 + clBOL(pos) + x := pos - cols + x -= x // cols + repeat while x => 0 + clEOL(x) + x -= cols + return + + if arg0 == 2 + pos := 0 + + clEOL(pos) + x := pos + cols + x -= (x // cols) + repeat while x < maxChars + clEOL(x) + x += cols + + "K": + if arg0 == -1 + clEOL(pos) + elseif arg0 == 1 + clBOL(pos) + else + clEOL(pos - (pos // cols)) + + "L": + if inRegion + repeat while arg0-- > 0 + if regionBot < maxChars + delLine(regionBot) + insLine(pos) + + "M": + if inRegion + repeat while arg0-- > 0 + delLine(pos) + if regionBot < maxChars + insLine(regionBot) + + "P": + repeat while arg0-- + delChar(pos) + +PRI outc(c) + + putc(pos++, lastc := c) + if pos == regionBot + scrollUp + pos -= cols + elseif pos == maxChars + pos := lastLine + +PUB process_char(c) + + case state + + 0: + if c > 127 + c := $20 + + if c => $20 + outc(c) + setCursorPos(pos) + return + + if c == $1B + state := 1 + return + + if c == $0D + pos := pos - (pos // cols) + setCursorPos(pos) + return + + if c == $0A + if inRegion + pos += cols + if pos => regionBot + scrollUp + pos -= cols + else + pos += cols + if pos => maxChars + pos -= cols + setCursorPos(pos) + return + + if c == 9 + pos += (8 - (pos // 8)) + + if pos => maxChars + pos := lastLine + delLine(0) + + setCursorPos(pos) + return + + if c == 8 + if pos > 0 + pos -= 1 + setCursorPos(pos) + return + + 1: + case c + "[": + arg0 := arg1 := -1 + state := 2 + return + + "P": + pos += cols + if pos => maxChars + pos -= cols + + "K": + if pos > 0 + pos -= 1 + + "H": + pos -= cols + if pos < 0 + pos += cols + + "D": + if inRegion + scrollUp + + "M": + if inRegion + scrollDown + + "G": + pos := 0 + + "(": + state := 5 + return + + state := 0 + return + + 2: + if (c => "0") AND (c =< "9") + if arg0 == -1 + arg0 := c - "0" + else + arg0 := (arg0 * 10) + (c - "0") + return + + if c == ";" + state := 3 + return + + ansi(c) + setCursorPos(pos) + return + + 3: + if (c => "0") AND (c =< "9") + if arg1 == -1 + arg1 := c - "0" + else + arg1 := (arg1 * 10) + (c - "0") + return + + if c == ";" + state := 4 + return + + ansi(c) + setCursorPos(pos) + return + + 4: + if (c => "0") AND (c =< "9") + return + + if c == ";" + return + ansi(c) + setCursorPos(pos) + return + + 5: + state := 0 + return + + return \ No newline at end of file diff --git a/trunk/Support/PropIO/Spin/VGA_HiRes_Text.spin b/trunk/Support/PropIO/Spin/VGA_HiRes_Text.spin new file mode 100644 index 00000000..5b892316 Binary files /dev/null and b/trunk/Support/PropIO/Spin/VGA_HiRes_Text.spin differ diff --git a/trunk/Support/PropIO/Spin/safe_spi.spin b/trunk/Support/PropIO/Spin/safe_spi.spin new file mode 100644 index 00000000..a63cb229 --- /dev/null +++ b/trunk/Support/PropIO/Spin/safe_spi.spin @@ -0,0 +1,920 @@ +{{ + SPI interface routines for SD & SDHC & MMC cards + + Jonathan "lonesock" Dummer + version 0.3.0 2009 July 19 + + Using multiblock SPI mode exclusively. + + This is the "SAFE" version...uses + * 1 instruction per bit writes + * 2 instructions per bit reads + + For the fsrw project: + fsrw.sf.net +}} + +CON + ' possible card types + type_MMC = 1 + type_SD = 2 + type_SDHC = 3 + + ' Error codes + ERR_CARD_NOT_RESET = -1 + ERR_3v3_NOT_SUPPORTED = -2 + ERR_OCR_FAILED = -3 + ERR_BLOCK_NOT_LONG_ALIGNED = -4 + '... + ' These errors are for the assembly engine...they are negated inside, and need to be <= 511 + ERR_ASM_NO_READ_TOKEN = 100 + ERR_ASM_BLOCK_NOT_WRITTEN = 101 + ' NOTE: errors -128 to -255 are reserved for reporting R1 response errors + '... + ERR_SPI_ENGINE_NOT_RUNNING = -999 + ERR_CARD_BUSY_TIMEOUT = -1000 + + ' SDHC/SD/MMC command set for SPI + CMD0 = $40+0 ' GO_IDLE_STATE + CMD1 = $40+1 ' SEND_OP_COND (MMC) + ACMD41 = $C0+41 ' SEND_OP_COND (SDC) + CMD8 = $40+8 ' SEND_IF_COND + CMD9 = $40+9 ' SEND_CSD + CMD10 = $40+10 ' SEND_CID + CMD12 = $40+12 ' STOP_TRANSMISSION + CMD13 = $40+13 ' SEND_STATUS + ACMD13 = $C0+13 ' SD_STATUS (SDC) + CMD16 = $40+16 ' SET_BLOCKLEN + CMD17 = $40+17 ' READ_SINGLE_BLOCK + CMD18 = $40+18 ' READ_MULTIPLE_BLOCK + CMD23 = $40+23 ' SET_BLOCK_COUNT (MMC) + ACMD23 = $C0+23 ' SET_WR_BLK_ERASE_COUNT (SDC) + CMD24 = $40+24 ' WRITE_BLOCK + CMD25 = $40+25 ' WRITE_MULTIPLE_BLOCK + CMD55 = $40+55 ' APP_CMD + CMD58 = $40+58 ' READ_OCR + CMD59 = $40+59 ' CRC_ON_OFF + + ' buffer size for my debug cmd log + 'LOG_SIZE = 256<<1 + +{ +VAR + long SPI_engine_cog + ' these are used for interfacing with the assembly engine | temporary initialization usage + long SPI_command ' "t", "r", "w", 0 =>done, <0 => error | pin mask + long SPI_block_index ' which 512-byte block to read/write | cnt at init + long SPI_buffer_address ' where to get/put the data in Hub RAM | unused +'} +DAT +'' I'm placing these variables in a DAT section to make this driver a singleton. +'' If for some reason you really need more than one driver (e.g. if you have more +'' than a single SD socket), move these back into VAR. +SPI_engine_cog long 0 +' these are used for interfacing with the assembly engine | temporary initialization usage +SPI_command long 0 ' "t", "r", "w", 0 =>done, <0 => error | unused +SPI_block_index long 0 ' which 512-byte block to read/write | cnt at init +SPI_buffer_address long 0 ' where to get/put the data in Hub RAM | unused + +{ +VAR + ' for debug ONLY + byte log_cmd_resp[LOG_SIZE+1] +PUB get_log_pointer + return @log_cmd_resp +'} + +PUB start( basepin ) +{{ + This is a compatibility wrapper, and requires that the pins be + both consecutive, and in the order DO CLK DI CS. +}} + return start_explicit( basepin, basepin+1, basepin+2, basepin+3 ) + +PUB readblock( block_index, buffer_address ) + if SPI_engine_cog == 0 + abort ERR_SPI_ENGINE_NOT_RUNNING + if (buffer_address & 3) + abort ERR_BLOCK_NOT_LONG_ALIGNED + SPI_block_index := block_index + SPI_buffer_address := buffer_address + SPI_command := "r" + repeat while SPI_command == "r" + if SPI_command < 0 + abort SPI_command + +PUB writeblock( block_index, buffer_address ) + if SPI_engine_cog == 0 + abort ERR_SPI_ENGINE_NOT_RUNNING + if (buffer_address & 3) + abort ERR_BLOCK_NOT_LONG_ALIGNED + SPI_block_index := block_index + SPI_buffer_address := buffer_address + SPI_command := "w" + repeat while SPI_command == "w" + if SPI_command < 0 + abort SPI_command + +PUB get_seconds + if SPI_engine_cog == 0 + abort ERR_SPI_ENGINE_NOT_RUNNING + SPI_command := "t" + repeat while SPI_command == "t" + ' secods are in SPI_block_index, remainder is in SPI_buffer_address + return SPI_block_index + +PUB get_milliseconds : ms + if SPI_engine_cog == 0 + abort ERR_SPI_ENGINE_NOT_RUNNING + SPI_command := "t" + repeat while SPI_command == "t" + ' secods are in SPI_block_index, remainder is in SPI_buffer_address + ms := SPI_block_index * 1000 + ms += SPI_buffer_address * 1000 / clkfreq + +PUB start_explicit( DO, CLK, DI, CS ) : card_type | tmp, i +{{ + Do all of the card initialization in SPIN, then hand off the pin + information to the assembly cog for hot SPI block R/W action! +}} + ' Start from scratch + stop + ' clear my log buffer + { + bytefill( @log_cmd_resp, 0, LOG_SIZE+1 ) + dbg_ptr := @log_cmd_resp + dbg_end := dbg_ptr + LOG_SIZE + '} + ' wait ~4 milliseconds + waitcnt( 500 + (clkfreq>>8) + cnt ) + ' (start with cog variables, _BEFORE_ loading the cog) + pinDO := DO + maskDO := |< DO + pinCLK := CLK + pinDI := DI + maskDI := |< DI + maskCS := |< CS + adrShift := 9 ' block = 512 * index, and 512 = 1<<9 + ' pass the output pin mask via the command register + maskAll := maskCS | (| 74 clocks + outa |= maskAll + repeat 4096 + outa[CLK]~~ + outa[CLK]~ + ' time-hack + SPI_block_index := cnt + ' reset the card + tmp~ + repeat i from 0 to 9 + if tmp <> 1 + tmp := send_cmd_slow( CMD0, 0, $95 ) + if (tmp & 4) + ' the card said CMD0 ("go idle") was invalid, so we're possibly stuck in read or write mode + if i & 1 + ' exit multiblock read mode + repeat 4 + read_32_slow ' these extra clocks are required for some MMC cards + send_slow( $FD, 8 ) ' stop token + read_32_slow + repeat while read_slow <> $FF + else + ' exit multiblock read mode + send_cmd_slow( CMD12, 0, $61 ) + if tmp <> 1 + ' the reset command failed! + crash( ERR_CARD_NOT_RESET ) + ' Is this a SD type 2 card? + if send_cmd_slow( CMD8, $1AA, $87 ) == 1 + ' Type2 SD, check to see if it's a SDHC card + tmp := read_32_slow + ' check the supported voltage + if (tmp & $1FF) <> $1AA + crash( ERR_3v3_NOT_SUPPORTED ) + ' try to initialize the type 2 card with the High Capacity bit + repeat while send_cmd_slow( ACMD41, |<30, $77 ) + ' the card is initialized, let's read back the High Capacity bit + if send_cmd_slow( CMD58, 0, $FD ) <> 0 + crash( ERR_OCR_FAILED ) + ' get back the data + tmp := read_32_slow + ' check the bit + if tmp & |<30 + card_type := type_SDHC + adrShift := 0 + else + card_type := type_SD + else + ' Either a type 1 SD card, or it's MMC, try SD 1st + if send_cmd_slow( ACMD41, 0, $E5 ) < 2 + ' this is a type 1 SD card (1 means busy, 0 means done initializing) + card_type := type_SD + repeat while send_cmd_slow( ACMD41, 0, $E5 ) + else + ' mark that it's MMC, and try to initialize + card_type := type_MMC + repeat while send_cmd_slow( CMD1, 0, $F9 ) + ' some SD or MMC cards may have the wrong block size, set it here + send_cmd_slow( CMD16, 512, $15 ) + ' card is mounted, make sure the CRC is turned off + send_cmd_slow( CMD59, 0, $91 ) + ' check the status + 'send_cmd_slow( CMD13, 0, $0D ) + ' done with the SPI bus for now + outa |= maskCS + ' set my counter modes for super fast SPI operation + ' writing: NCO single-ended mode, output on DI + writeMode := (%00100 << 26) | (DI << 0) + ' reading + 'readMode := (%11000 << 26) | (DO << 0) | (CLK << 9) + ' clock + 'clockLineMode := (%00110 << 26) | (CLK << 0) ' DUTY, 25% duty cycle + ' clock + clockLineMode := (%00100 << 26) | (CLK << 0) ' NCO, 50% duty cycle + ' how many bytes (8 clocks, >>3) fit into 1/2 of a second (>>1), 4 clocks per instruction (>>2)? + N_in8_500ms := clkfreq >> constant(1+2+3) + ' how long should we wait before auto-exiting any multiblock mode? + idle_limit := 125 ' ms, NEVER make this > 1000 + idle_limit := clkfreq / (1000 / idle_limit) ' convert to counts + ' Hand off control to the assembly engine's cog + bufAdr := @SPI_buffer_address + sdAdr := @SPI_block_index + SPI_command := 0 ' just make sure it's not 1 + ' start my driver cog and wait till I hear back that it's done + SPI_engine_cog := cognew( @SPI_engine_entry, @SPI_command ) + 1 + if( SPI_engine_cog == 0 ) + crash( ERR_SPI_ENGINE_NOT_RUNNING ) + repeat while SPI_command <> -1 + ' and we no longer need to control any pins from here + dira &= !maskAll + ' the return variable is card_type + +PUB release +{{ + I do not want to abort if the cog is not + running, as this is called from stop, which + is called from start/ [8^) +}} + if SPI_engine_cog + SPI_command := "z" + repeat while SPI_command == "z" + +PUB stop +{{ + kill the assembly driver cog. +}} + release + if SPI_engine_cog + cogstop( SPI_engine_cog~ - 1 ) + +PRI crash( abort_code ) +{{ + In case of Bad Things(TM) happening, + exit as gracefully as possible. +}} + ' and we no longer need to control any pins from here + dira &= !maskAll + ' and report our error + abort abort_code + +PRI send_cmd_slow( cmd, val, crc ) : reply | time_stamp +{{ + Send down a command and return the reply. + Note: slow is an understatement! + Note: this uses the assembly DAT variables for pin IDs, + which means that if you run this multiple times (say for + multiple SD cards), these values will change for each one. + But this is OK as all of these functions will be called + during the initialization only, before the PASM engine is + running. +}} + ' if this is an application specific command, handle it + if (cmd & $80) + ' ACMD is the command sequense of CMD55-CMD + cmd &= $7F + reply := send_cmd_slow( CMD55, 0, $65 ) + if (reply > 1) + return reply + ' the CS line needs to go low during this operation + outa |= maskCS + outa &= !maskCS + ' give the card a few cocks to finish whatever it was doing + read_32_slow + ' send the command byte + send_slow( cmd, 8 ) + ' send the value long + send_slow( val, 32 ) + ' send the CRC byte + send_slow( crc, 8 ) + ' is this a CMD12?, if so, stuff byte + if cmd == CMD12 + read_slow + ' read back the response (spec declares 1-8 reads max for SD, MMC is 0-8) + time_stamp := 9 + repeat + reply := read_slow + while( reply & $80 ) and ( time_stamp-- ) + ' done, and 'reply' is already pre-loaded + { + if dbg_ptr < (dbg_end-1) + byte[dbg_ptr++] := cmd + byte[dbg_ptr++] := reply + if (cmd&63) == 13 + ' get the second byte + byte[dbg_ptr++] := cmd + byte[dbg_ptr++] := read_slow + '} + +PRI send_slow( value, bits_to_send ) + value ><= bits_to_send + repeat bits_to_send + outa[pinCLK]~ + outa[pinDI] := value + value >>= 1 + outa[pinCLK]~~ + +PRI read_32_slow : r + repeat 4 + r <<= 8 + r |= read_slow + +PRI read_slow : r +{{ + Read back 8 bits from the card +}} + ' we need the DI line high so a read can occur + outa[pinDI]~~ + ' get 8 bits (remember, r is initialized to 0 by SPIN) + repeat 8 + outa[pinCLK]~ + outa[pinCLK]~~ + r += r + ina[pinDO] + ' error check + if( (cnt - SPI_block_index) > (clkfreq << 2) ) + crash( ERR_CARD_BUSY_TIMEOUT ) + +DAT +{{ + This is the assembly engine for doing fast block + reads and writes. This is *ALL* it does! +}} +ORG 0 +SPI_engine_entry + ' Counter A drives data out + mov ctra,writeMode + ' Counter B will always drive my clock line + mov ctrb,clockLineMode + ' set our output pins to match the pin mask + mov dira,maskAll + ' handshake that we now control the pins + neg user_request,#1 + wrlong user_request,par + ' start my seconds' counter here + mov last_time,cnt + +waiting_for_command + ' update my seconds counter, but also track the idle + ' time so we can to release the card after timeout. + call #handle_time + ' read the command, and make sure it's from the user (> 0) + rdlong user_request,par + cmps user_request,#0 wz,wc +if_be jmp #waiting_for_command + ' handle our card based commands + cmp user_request,#"r" wz +if_z jmp #read_ahead + cmp user_request,#"w" wz +if_z jmp #write_behind + cmp user_request,#"z" wz +if_z jmp #release_card + ' time requests are handled differently + cmp user_request,#"t" wz ' time +if_z wrlong seconds,sdAdr ' seconds goes into the SD index register +if_z wrlong dtime,bufAdr ' the remainder goes into the buffer address register + ' in all other cases, clear the user's request + mov user_request,#0 + wrlong user_request,par + jmp #waiting_for_command + + +release_card + mov user_cmd,#"z" ' request a release + neg lastIndexPlus,#1 ' reset the last block index + neg user_idx,#1 ' and make this match it + call #handle_command + mov user_request,user_cmd + wrlong user_request,par + jmp #waiting_for_command + +read_ahead + rdlong user_idx,sdAdr + ' if the correct block is not already loaded, load it + mov tmp1,user_idx + add tmp1,#1 + cmp tmp1,lastIndexPlus wz +if_z cmp lastCommand,#"r" wz +if_z jmp #:get_on_with_it + mov user_cmd,#"r" + call #handle_command +:get_on_with_it + ' copy the data up into Hub RAM + movi transfer_long,#%000010_000 'set to wrlong + call #hub_cog_transfer + ' signify that the data is ready, Spin can continue + mov user_request,user_cmd + wrlong user_request,par + ' request the next block + mov user_cmd,#"r" + add user_idx,#1 + call #handle_command + ' done + jmp #waiting_for_command + +write_behind + rdlong user_idx,sdAdr + ' copy data in from Hub RAM + movi transfer_long,#%000010_001 'set to rdlong + call #hub_cog_transfer + ' signify that we have the data, Spin can continue + mov user_request,user_cmd + wrlong user_request,par + ' write out the block + mov user_cmd,#"w" + call #handle_command + ' done + jmp #waiting_for_command + +{{ + Set user_cmd and user_idx before calling this +}} +handle_command + ' Can we stay in the old mode? (address = old_address+1) && (old mode == new_mode) + cmp lastIndexPlus,user_idx wz +if_z cmp user_cmd,lastCommand wz +if_z jmp #:execute_block_command + ' we fell through, must exit the old mode! (except if the old mode was "release") + cmp lastCommand,#"w" wz +if_z call #stop_mb_write + cmp lastCommand,#"r" wz +if_z call #stop_mb_read + ' and start up the new mode! + cmp user_cmd,#"w" wz +if_z call #start_mb_write + cmp user_cmd,#"r" wz +if_z call #start_mb_read + cmp user_cmd,#"z" wz +if_z call #release_DO +:execute_block_command + ' track the (new) last index and command + mov lastIndexPlus,user_idx + add lastIndexPlus,#1 + mov lastCommand,user_cmd + ' do the block read or write or terminate! + cmp user_cmd,#"w" wz +if_z call #write_single_block + cmp user_cmd,#"r" wz +if_z call #read_single_block + cmp user_cmd,#"z" wz +if_z mov user_cmd,#0 + ' done +handle_command_ret + ret + +{=== these PASM functions get me in and out of multiblock mode ===} +release_DO + ' we're already out of multiblock mode, so + ' deselect the card and send out some clocks + or outa,maskCS + call #in8 + call #in8 + ' if you are using pull-up resistors, and need all + ' lines tristated, then uncomment the following line. + ' for Cluso99 + 'mov dira,#0 +release_DO_ret + ret + +start_mb_read + movi block_cmd,#CMD18<<1 + call #send_SPI_command_fast +start_mb_read_ret + ret + +stop_mb_read + movi block_cmd,#CMD12<<1 + call #send_SPI_command_fast + call #busy_fast +stop_mb_read_ret + ret + +start_mb_write + movi block_cmd,#CMD25<<1 + call #send_SPI_command_fast +start_mb_write_ret + ret + +stop_mb_write + call #busy_fast + ' only some cards need these extra clocks + mov tmp1,#16 +:loopity + call #in8 + djnz tmp1,#:loopity + ' done with hack + movi phsa,#$FD<<1 + call #out8 + call #in8 ' stuff byte + call #busy_fast +stop_mb_write_ret + ret + +send_SPI_command_fast + ' make sure we have control of the output lines + mov dira,maskAll + ' make sure the CS line transitions low + or outa,maskCS + andn outa,maskCS + ' 8 clocks + call #in8 + ' send the data + mov phsa,block_cmd ' do which ever block command this is (already in the top 8 bits) + call #out8 ' write the byte + mov phsa,user_idx ' read in the desired block index + shl phsa,adrShift ' this will multiply by 512 (bytes/sector) for MMC and SD + call #out8 ' move out the 1st MSB ' + rol phsa,#1 + call #out8 ' move out the 1st MSB ' + rol phsa,#1 + call #out8 ' move out the 1st MSB ' + rol phsa,#1 + call #out8 ' move out the 1st MSB ' + ' bogus CRC value + call #in8 ' in8 looks like out8 with $FF + ' CMD12 requires a stuff byte + shr block_cmd,#24 + cmp block_cmd,#CMD12 wz +if_z call #in8 ' 8 clocks + ' get the response + mov tmp1,#9 +:cmd_response + call #in8 + test readback,#$80 wc,wz +if_c djnz tmp1,#:cmd_response +if_nz neg user_cmd,readback + ' done +send_SPI_command_fast_ret + ret + + +busy_fast + mov tmp1,N_in8_500ms +:still_busy + call #in8 + cmp readback,#$FF wz +if_nz djnz tmp1,#:still_busy +busy_fast_ret + ret + + +out8 + andn outa,maskDI + 'movi phsb,#%11_0000000 + mov phsb,#0 + movi frqb,#%01_0000000 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + rol phsa,#1 + mov frqb,#0 + ' don't shift out the final bit...already sent, but be aware + ' of this when sending consecutive bytes (send_cmd, for e.g.) +out8_ret + ret + +{ +in8 + or outa,maskDI + mov ctra,readMode + ' Start my clock + mov frqa,#1<<7 + mov phsa,#0 + movi phsb,#%11_0000000 + movi frqb,#%01_0000000 + ' keep reading in my value, one bit at a time! (Kuneko - "Wh) + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + shr frqa,#1 + mov frqb,#0 ' stop the clock + mov readback,phsa + mov frqa,#0 + mov ctra,writeMode +in8_ret + ret +} +in8 + neg phsa,#1' DI high + mov readback,#0 + ' set up my clock, and start it + movi phsb,#%011_000000 + movi frqb,#%001_000000 + ' keep reading in my value + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + rcl readback,#1 + test maskDO,ina wc + mov frqb,#0 ' stop the clock + rcl readback,#1 + mov phsa,#0 'DI low +in8_ret + ret + + +' this is called more frequently than 1 Hz, and +' is only called when the user command is 0. +handle_time + mov tmp1,cnt ' get the current timestamp + add idle_time,tmp1 ' add the current time to my idle time counter + sub idle_time,last_time ' subtract the last time from my idle counter (hence delta) + add dtime,tmp1 ' add to my accumulator, + sub dtime,last_time ' and subtract the old (adding delta) + mov last_time,tmp1 ' update my "last timestamp" + rdlong tmp1,#0 ' what is the clock frequency? + cmpsub dtime,tmp1 wc ' if I have more than a second in my accumulator + addx seconds,#0 ' then add it to "seconds" + ' this part is to auto-release the card after a timeout + cmp idle_time,idle_limit wz,wc +if_b jmp #handle_time_ret ' don't clear if we haven't hit the limit + mov user_cmd,#"z" ' we can't overdo it, the command handler makes sure + neg lastIndexPlus,#1 ' reset the last block index + neg user_idx,#1 ' and make this match it + call #handle_command ' release the card, but don't mess with the user's request register +handle_time_ret + ret + +hub_cog_transfer +' setup for all 4 passes + mov ctrb,clockXferMode + mov frqb,#1 + rdlong buf_ptr,bufAdr + mov ops_left,#4 + movd transfer_long,#speed_buf +four_transfer_passes + ' sync to the Hub RAM access + rdlong tmp1,tmp1 + ' how many long to move on this pass? (512 bytes / 4)longs / 4 passes + mov tmp1,#(512 / 4 / 4) + ' get my starting address right (phsb is incremented 1 per clock, so 16 each Hub access) + mov phsb,buf_ptr + ' write the longs, stride 4...low 2 bits of phsb are ignored +transfer_long + rdlong 0-0,phsb + add transfer_long,incDest4 + djnz tmp1,#transfer_long + ' go back to where I started, but advanced 1 long + sub transfer_long,decDestNminus1 + ' offset my Hub pointer by one long per pass + add buf_ptr,#4 + ' do all 4 passes + djnz ops_left,#four_transfer_passes + ' restore the counter mode + mov frqb,#0 + mov phsb,#0 + mov ctrb,clockLineMode +hub_cog_transfer_ret + ret + + +read_single_block + ' where am I sending the data? + movd :store_read_long,#speed_buf + mov ops_left,#128 + ' wait until the card is ready + mov tmp1,N_in8_500ms +:get_resp + call #in8 + cmp readback,#$FE wz +if_nz djnz tmp1,#:get_resp +if_nz neg user_cmd,#ERR_ASM_NO_READ_TOKEN +if_nz jmp #read_single_block_ret + ' set DI high + neg phsa,#1 + ' read the data + mov ops_left,#128 +:read_loop + mov tmp1,#4 + movi phsb,#%011_000000 +:in_byte + ' Start my clock + movi frqb,#%001_000000 + ' keep reading in my value, BACKWARDS! (Brilliant idea by Tom Rokicki!) + test maskDO,ina wc + rcl readback,#8 + test maskDO,ina wc + muxc readback,#2 + test maskDO,ina wc + muxc readback,#4 + test maskDO,ina wc + muxc readback,#8 + test maskDO,ina wc + muxc readback,#16 + test maskDO,ina wc + muxc readback,#32 + test maskDO,ina wc + muxc readback,#64 + test maskDO,ina wc + mov frqb,#0 ' stop the clock + muxc readback,#128 + ' go back for more + djnz tmp1,#:in_byte + ' make it...NOT backwards [8^) + rev readback,#0 +:store_read_long + mov 0-0,readback ' due to some counter weirdness, we need this mov + add :store_read_long,const512 + djnz ops_left,#:read_loop + + ' set DI low + mov phsa,#0 + + ' now read 2 trailing bytes (CRC) + call #in8 ' out8 is 2x faster than in8 + call #in8 ' and I'm not using the CRC anyway + ' give an extra 8 clocks in case we pause for a long time + call #in8 ' in8 looks like out8($FF) + + ' all done successfully + mov idle_time,#0 + mov user_cmd,#0 +read_single_block_ret + ret + +write_single_block + ' where am I getting the data? (all 512 bytes / 128 longs of it?) + movs :write_loop,#speed_buf + ' read in 512 bytes (128 longs) from Hub RAM and write it to the card + mov ops_left,#128 + ' just hold your horses + call #busy_fast + ' $FC for multiblock, $FE for single block + movi phsa,#$FC<<1 + call #out8 + mov phsb,#0 ' make sure my clock accumulator is right + 'movi phsb,#%11_0000000 +:write_loop + ' read 4 bytes + mov phsa,speed_buf + add :write_loop,#1 + ' a long in LE order is DCBA + rol phsa,#24 ' move A7 into position, so I can do the swizzled version + movi frqb,#%010000000 ' start the clock (remember A7 is already in place) + rol phsa,#1 ' A7 is going out, at the end of this instr, A6 is in place + rol phsa,#1 ' A5 + rol phsa,#1 ' A4 + rol phsa,#1 ' A3 + rol phsa,#1 ' A2 + rol phsa,#1 ' A1 + rol phsa,#1 ' A0 + rol phsa,#17 ' B7 + rol phsa,#1 ' B6 + rol phsa,#1 ' B5 + rol phsa,#1 ' B4 + rol phsa,#1 ' B3 + rol phsa,#1 ' B2 + rol phsa,#1 ' B1 + rol phsa,#1 ' B0 + rol phsa,#17 ' C7 + rol phsa,#1 ' C6 + rol phsa,#1 ' C5 + rol phsa,#1 ' C4 + rol phsa,#1 ' C3 + rol phsa,#1 ' C2 + rol phsa,#1 ' C1 + rol phsa,#1 ' C0 + rol phsa,#17 ' D7 + rol phsa,#1 ' D6 + rol phsa,#1 ' D5 + rol phsa,#1 ' D4 + rol phsa,#1 ' D3 + rol phsa,#1 ' D2 + rol phsa,#1 ' D1 + rol phsa,#1 ' D0 will be in place _after_ this instruction + mov frqb,#0 ' shuts the clock off, _after_ this instruction + djnz ops_left,#:write_loop + ' write out my two (bogus, using $FF) CRC bytes + call #in8 + call #in8 + ' now read response (I need this response, so can't spoof using out8) + call #in8 + and readback,#$1F + cmp readback,#5 wz +if_z mov user_cmd,#0 ' great +if_nz neg user_cmd,#ERR_ASM_BLOCK_NOT_WRITTEN ' oops + ' send out another 8 clocks + call #in8 + ' all done + mov idle_time,#0 +write_single_block_ret + ret + + +{=== Assembly Interface Variables ===} +pinDO long 0 ' pin is controlled by a counter +pinCLK long 0 ' pin is controlled by a counter +pinDI long 0 ' pin is controlled by a counter +maskDO long 0 ' mask for reading the DO line from the card +maskDI long 0 ' mask for setting the pin high while reading +maskCS long 0 ' mask = (1< + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/trunk/Support/ZSDOS/NZCOMPAT.HEX b/trunk/Support/ZSDOS/NZCOMPAT.HEX new file mode 100644 index 00000000..e0caa8e0 --- /dev/null +++ b/trunk/Support/ZSDOS/NZCOMPAT.HEX @@ -0,0 +1,11 @@ +:10028000FE01281FFE032803FEFFC0CDD802C8CD03 +:10029000BF02C021030011000113131A1B1B0947E1 +:1002A0000E03E9CDD802C8CDBF02C0210900094E16 +:1002B000234678B12804606918F501FCFF18D7605F +:1002C00069210F000911D502C506031ABE200423B7 +:1002D0001310F8C1C9504348110101211700194EEC +:1002E000234604EB7E23666FAFED42D0210000A7CA +:0102F000C944 +:00000001FF +8' 23 6 INC HL + 538 01A9' 10 \ No newline at end of file diff --git a/trunk/Support/ZSDOS/PUTBG.COM b/trunk/Support/ZSDOS/PUTBG.COM new file mode 100644 index 00000000..970e2d8a Binary files /dev/null and b/trunk/Support/ZSDOS/PUTBG.COM differ diff --git a/trunk/Support/ZSDOS/PUTDS.COM b/trunk/Support/ZSDOS/PUTDS.COM new file mode 100644 index 00000000..c0ceba64 Binary files /dev/null and b/trunk/Support/ZSDOS/PUTDS.COM differ diff --git a/trunk/Support/ZSDOS/README.1ST b/trunk/Support/ZSDOS/README.1ST new file mode 100644 index 00000000..e56c7f46 --- /dev/null +++ b/trunk/Support/ZSDOS/README.1ST @@ -0,0 +1,30 @@ +README.1ST -- Last-minute news for ZSDOS Distribution Disk. + +12/3/88 + +COPY.UPD updates information about COPY.COM. Please mark +your user manual with the changes. + +User 1 contains files for Apple ][ CP/M systems. + +ZSDOS is published by: + +Plu*Perfect Systems +410 23rd St. +Santa Monica CA 90402 +(213)-393-6105 (evenings) +messages may be left on Ladera Z-Node: +(213)-670-9465 (300/1200/2400) + +and is also available from: + +Sage Microsystems East +1435 Centre St. +Newton MA 02159 +(617)965-3552 (9am-1130pm) +(617)965-7259 (300/1200/2400 bps) password: DDT + + +BGii corresponds most closely to these ZCPR34 options: + +full \ No newline at end of file diff --git a/trunk/Support/ZSDOS/README.2ND b/trunk/Support/ZSDOS/README.2ND new file mode 100644 index 00000000..d3c4332f --- /dev/null +++ b/trunk/Support/ZSDOS/README.2ND @@ -0,0 +1,165 @@ +GETTINÇ STARTED. + + The natural human inclination is to start using products +before wading through the instructions. We understand that and +have developed some rather simple steps to provide initial ZSDOS +capabilities rather painlessly. This will provide the inducement +to read the appropriate sections of the manual for a complete +customized installation. Merely follow the steps listed here, +then read the manual at your liesure to learn how to tailor the +ZSDOS system to you particular needs and desires. These instruc +tions cite the relevant paragraphs in the manual in case a more +detailed description is desired. + +1 LOADINÇ THĊ DOS These steps are written around the full- +featured ZSDOS version of the Operating System to demonstrate all +of the power, and provide procedures for systems already using +either type of Time Stamping supported by ZSDOS. It is recom +mended that these steps be followed initially, followed by a +later installation with ZDDOS if either a minimal memory configu +ration is desired, or only DateStamper-type File Stamping is +desired. The differences between ZSDOS and ZDDOS are briefly +described in Section 1 of the manual. + + A. DO YOU OPERATE UNDER NZ-COM? (3.1.2) + If No, Go To Step B. + If Yes, + + Rename ZSDOS.ZRL to NZDOS.ZRL and replace your + existing NZDOS.ZRL with this new file. Reinstall + NZCOM and load the system. + + Go to Step 2. + + B. DO YOU HAVE Plu*Perfect Systems' JETLDR? (3.1.3) + If No, Go To Step C. + If Yes, + + Type: + JETLDR ZSDOS.ZRL + + Go to Step 2. + + C. ARE YOU USING AN SB-180/FX-180 with XBIOS? (3.1.4) + If No, Go To Step D. + If Yes, + + Enter SYSBLD with your current system model. + Select Menu 1.1, and change the DOS name to + ZSDOS.ZRL. Exit SYSBLD, and "XBOOT" the new image. + + Go to Step 2. + + D. YOU ARE INSTALLING TO A BOOTABLE SYSTEM IMAGE. (3.1.1) + + (1) Create a system image file with MOVCPM, MOVZSYS or + whatever facility you computer uses (ONEAC ON! + image is already in this form). Save the moved + system image to a disk file remembering the name. + + + (2) Call the ZSDOS Installation tool in absolute mode + (3.1.1.1) with: + INSTALOS /A + Read in the image created above, and select option + 2 to replace the DOS. Load the ZSDOS.ZRL file and + answer 'N' (No) to the prompt asking whether to + configure default options. Select menu option 4 to + exit the program and save the new image. + + (3) Install the new image on your system boot tracks + with the SYSGEN utility provided with your computer. + WARNING: PERFORM THIS STEP ON A WORKING DISK, NOT A + MASTER DISK. Reboot your system from this disk and + you will be operating under ZSDOS. + + +2. You should have completed installation of one of the forms in +step 1 at this point, and have ZSDOS up and running. To see what +Time Stamps can do for your system, two files have been pre- +configured on the distribution disk. LDTIMD.COM is an RSX form +of DateStamper with the Relative clock. LDTIMP.COM is an RSX form +of P2DOS stamping also with the Relative clock. If you are +unfamiliar with the two methods, a brief comparison is: + + Stamp Method Advantages Disadvantages + ------------ ---------- ------------- + DateStamper(tm) Wide acceptance Slight Time penalty + Uses Only 1 Dir Stamp file can be + entry erased + Offers Last Access + stamp + + P2DOS (CP/M Plus) Fast Uses 1/4 of Dir + Entries + +If you do NOT want Date/Time Stamp or clock support, go to +Step 3, otherwise activate one of the two programs by entering +either LDTIMD or LDTIMP (see LDTIM, 3.2.3). Then Set the clock +using TD.COM (4.6). + +To see the effect of stamping, prepare a disk for stamping with +PUTDS.COM (3.2.4) if you selected LDTIMD, or INITDIR.COM (3.2.5) +if you selected LDTIMP. Copy or edit some files and note the +effect with ZXD (4.11). You will probably want to tailor the +stamping to your system clock or other parameters now, so please +read Section 3 of the manual for details. + + +3. FINAL TOUCHES. After you have completed whichever of the above +steps you elected, we recommend highly that you read at least +Sections 1 and 2 of the manual to learn the power that ZSDOS can +bring to 8-bit computers. Learn to use the tools provided with +the ZSDOS distribution package to customize the Operating System +to your own requirements and desires. All tools listed below +operate equally well under ZSDOS and ZDDOS unless specifically +noted. Briefly, the tools are: + + + COPY - Copy single or groups of files between disk drives +and/or user areas preserving date/time stamps (Modification of +ZCPR tool MCOPY). (4.1) + + DATSWEEP (ZDDOS or ZSDOS with DateStamper only) - +Plu*Perfect's full-featured screen-oriented disk and file utility +(4.2). + + FILEATTR - Display/Set attributes of individual or groups of +files. (4.3) + + FILEDATE (ZDDOS or ZSDOS with DateStamper only) - Full fea +tured Disk directory lister that permits elaborate selective +listing based on DateStamper-style Date/Time files. (4.4) + + INITDIR - Initialize a disk directory for P2DOS (CP/M Plus) +type Date/Time Stamping. (3.2.5) + + PUTDS - Initialize a disk for DateStamper type Date/Time +Stamping (licensed Plu*Perfect utility). (3.2.4) + + RELOG - Resets Hard Disk Login vectors. Primarily for use +in more elaborate Hard Disk systems which swap logical Hard +Drives, or use removeable-media, but are defined as Fixed Drives. +(4.5) + + TD - Display/Set an installed clock via ZSDOS/ZDDOS. (4.6) + + ZCAL - Display a brief calendar of current or any desired +month. (4.7) + + ZCNFG - Configuration utility to set defaults, such as US or +European date displays, in COPY, FILEATTR, FILEDATE, TD, and ZXD. + + ZPATH (ZSDOS only) - Permits setting the Internal DOS path +as well as a ZCPR3 path (Modification of ZCPR tool PATH). (4.9) + + ZSCONFIG - Basic configuration program for both ZSDOS and +ZDDOS. Operates in both interactive and command-line driven +modes wih the latter being ideal for customizing the System from +a STARTUP file under ZCPR3 environments. Options vary between +ZSDOS and ZDDOS. (4.10) + + ZXD - Directory lister for DateStamper and/or P2DOS (CP/M +Plus) Date/Time stamping methods (Extensive modification of ZCPR +tool XD III). (4.11) + \ No newline at end of file diff --git a/trunk/Support/ZSDOS/RELOG.COM b/trunk/Support/ZSDOS/RELOG.COM new file mode 100644 index 00000000..13ffc62e Binary files /dev/null and b/trunk/Support/ZSDOS/RELOG.COM differ diff --git a/trunk/Support/ZSDOS/SETTERM.COM b/trunk/Support/ZSDOS/SETTERM.COM new file mode 100644 index 00000000..eca19bf9 Binary files /dev/null and b/trunk/Support/ZSDOS/SETTERM.COM differ diff --git a/trunk/Support/ZSDOS/SETUPZST.COM b/trunk/Support/ZSDOS/SETUPZST.COM new file mode 100644 index 00000000..35e4b589 Binary files /dev/null and b/trunk/Support/ZSDOS/SETUPZST.COM differ diff --git a/trunk/Support/ZSDOS/STAMPS.DAT b/trunk/Support/ZSDOS/STAMPS.DAT new file mode 100644 index 00000000..23cd9bd7 Binary files /dev/null and b/trunk/Support/ZSDOS/STAMPS.DAT differ diff --git a/trunk/Support/ZSDOS/TD.CFG b/trunk/Support/ZSDOS/TD.CFG new file mode 100644 index 00000000..ab44bab9 Binary files /dev/null and b/trunk/Support/ZSDOS/TD.CFG differ diff --git a/trunk/Support/ZSDOS/TD.COM b/trunk/Support/ZSDOS/TD.COM new file mode 100644 index 00000000..552aba67 Binary files /dev/null and b/trunk/Support/ZSDOS/TD.COM differ diff --git a/trunk/Support/ZSDOS/TERMBASE.DAT b/trunk/Support/ZSDOS/TERMBASE.DAT new file mode 100644 index 00000000..358d61c0 Binary files /dev/null and b/trunk/Support/ZSDOS/TERMBASE.DAT differ diff --git a/trunk/Support/ZSDOS/TESTCLOK.COM b/trunk/Support/ZSDOS/TESTCLOK.COM new file mode 100644 index 00000000..d547e2b8 Binary files /dev/null and b/trunk/Support/ZSDOS/TESTCLOK.COM differ diff --git a/trunk/Support/ZSDOS/USERCLOK.TEM b/trunk/Support/ZSDOS/USERCLOK.TEM new file mode 100644 index 00000000..619215d5 --- /dev/null +++ b/trunk/Support/ZSDOS/USERCLOK.TEM @@ -0,0 +1,185 @@ + TITLE "Clock module name - (REL clock name here)" + SUBTTL "Description of Clock Module" +;================================================================ +; Place brief description and machine clock I/O parameters here +; along with any version and date data +;================================================================ + +VERS EQU 01 + .Z80 + NAME CCLOK ; Change this to no more than 6-char + ; name for the REL driver module + + MACLIB CLOCK.LIB ; Some useful equates are here + +; This first section contains identification information for the driver +; The information is not placed in the clock driver code section, but are +; located in a different area located by the _CLKID Named Common directive. + + COMMON /_CLKID/ + +DESCST: DEFW 0000 ; Add label here if a static year byte + ; is used by your clock driver. The + ; label should point to the year byte + +CLKNAM: DEFB 'Myclock ' ; Exactly 24 chars in name + DEFB VERS/10+'0','.',VERS MOD 10 +'0',0 + +DESCR: DEFB ' This description may be longer than the brief',CR,LF + DEFB ' name string above, and must be null-terminated',0 + + IF [$-DESCST] > 256 + OVER2 ; This must be less than or equal to 256 bytes + ENDIF + + PAGE + SUBTTL "Configurable Clock Hardware Parameters" +;--------------------------------------------------------------------- +; This section contains any configurable parameters needed for the +; clock driver. They must be structured in the manner shown in order +; for the loader to properly match and set the values. +; The values in this section are not loaded in the same code section +; as the actual driver code, but are located in another base referenced +; by the _PARM_ Named Common directive. + + COMMON /_PARM_/ + +PARBAS: DEFW NPARAMS ; # of parameters (Set to 00 if none) + DEFW STRS ; Pointer to STRS (Set to 00 if none) +NP0: +XYR EQU $+1 + DEFB BYTE ; EXAMPLE! - This shows a byte value + DEFW 88H ; " - ..and default value in Set + +XPORT EQU $+1 + DEFB WORD ; EXAMPLE! - This shows a 16-bit value + DEFW 0F013H ; " - ..and default value in Set + +NPARAMS EQU ($-NP0)/3 + +STRS: DEFB 'Default Year',0 ; EXAMPLE! - Text prompt for XYR + DEFB 'Default Port',0 ; EXAMPLE! - Text prompt for XPORT + + PAGE + SUBTTL "Clock Code - SB180 HeartBeat" +;------------------------------------------------------------------ +; This section should contain the actual Clock Driver code, and all +; entries here are located in the CSEG, or Code Segment. + + CSEG + +; Add any needed equates here if they are not included in CLOCK.LIB + +TIMOFF EQU 36H ; EXAMPLE! - Bios offset for clock ptr + +;----------------------------------------------------------- +; Z S D O S C L O C K H E A D E R +;----------------------------------------------------------- +; Enter: HL points to a 6-byte buffer to Get/Set time +; Exit : A=1 on Success, A=FFH if error +; HL points to last char in buffer +; NOTE: If clock Set is not included, comment these two jumps +; out to save a few bytes. The loader, SETUPZST, uses +; these two jumps to recognize a full ZSDOS clock and +; modify the interface code. + +PRGBAS: JP GETTIM ; Jump to Read Clock + JP WRCLK ; Jump to Set Clock + +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; R e a d T h e C l o c k +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; Clock READ code starts here. + +GETTIM: ; The work of reading the clock + ; goes here. Values needing to be set + ; during installation are referenced as: +;YPORT1 EQU $+1 +; LD BC,0000 ; EXAMPLE! - this will set a 16-bit value +; ; in the configuration process +;YYR EQU $+1 ; EXAMPLE! - This will set an 8-bit value +; LD A,00 ; in the configuration process + +; ... Place the meat of the driver in this section ... + +OKRET: LD A,01 ; Set OK status return + RET + +ERRET: OR 0FFH ; Set Error code if needed + RET + +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; S e t T h e C l o c k +;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - +; Clock Set code placed here if needed. If Clock Setting +; is not being added, comment out this section to save a +; byte of code. + +WRCLK: + RET + + PAGE + SUBTTL "Run-Time Configuration of Ports and Masks" +;------------------------------------------------------------- +; This code installs configurable items into the clock module +; Enter with DE pointing to the physical base address of the +; relocatable module. DE MUST BE USED TO SET VALUES IN +; THE CSEG PORTION OF CODE! +; NOTE: Code in this section is not added to the actual clock +; driver, but placed in a different area referenced to +; the common base _POST_. + + COMMON /_POST_/ + +; Values in the _PARM_, _POST_ and _PRE_ sections may be loaded +; and saved directly, since their addresses are constant from +; linkage through execution. Setting or reading values in the +; CSEG must be indirect based on the value in the DE register +; pair. The following examples show how to access the various +; sections. +; +; LD A,(XYR) ; EXAMPLE - Get byte from _PARM_ directly +; LD HL,YYR ; " - Begin offset into CSEG indirectly +; ADD HL,DE ; " - HL now addresses relocated loc'n +; LD (HL),A ; " - ..so value can be stored +; +; Likewise, 16-bit values must be accessed indirectly, and may use +; the BC register pair as transfer storage. +; +; LD BC,(XPORT) ; EXAMPLE - Get word from _PARM_ directly +; LD HL,YPORT1 ; " - Begin offset into CSEG indirectly +; ADD HL,DE ; " - HL now addresses relocated loc'n +; LD (HL),C ; " - ..so value can be saved.. +; INC HL ; " - ...a byte.. +; LD (HL),B ; " - ....at a time.. +; +; LD (YPORT2),BC ; EXAMPLE - Values can be stored directly into +; " - other sections such as _PRE_ + + RET ; This RETURN MUST be present even if no other + ; code is included in this section + + + PAGE + SUBTTL "Pre-Execution Clock Checks (Check for ticking)" +;---------------------------------------------------------------- +; This module is executed just prior to installing the module to +; insure that a valid clock is present +; Enter with DE pointing to base of relocated clock code segment + + COMMON /_PRE_/ + +; Optional final setup of the clock module may go here. Examples of such +; code would be installation-dependant items such as physical RAM location +; for the driver module. If any code is added here, the DE register pair +; MUST be preserved to properly inter PRECLOCK code (If included). + +;YPORT2 EQU $+1 ; EXAMPLE - just to show accessing method +; LD BC,0000 ; " - ..from _POST_ code. + + INCLUDE PRECLOCK.LIB ; This section of code merely calls the + ; clock and waits an arbitrary period of + ; time (>> 1 second) to see if the time + ; changes. It returns an error if not. + END + \ No newline at end of file diff --git a/trunk/Support/ZSDOS/ZCAL.COM b/trunk/Support/ZSDOS/ZCAL.COM new file mode 100644 index 00000000..a5add241 Binary files /dev/null and b/trunk/Support/ZSDOS/ZCAL.COM differ diff --git a/trunk/Support/ZSDOS/ZCNFG.COM b/trunk/Support/ZSDOS/ZCNFG.COM new file mode 100644 index 00000000..ae423dc5 Binary files /dev/null and b/trunk/Support/ZSDOS/ZCNFG.COM differ diff --git a/trunk/Support/ZSDOS/ZCNFG24.CFG b/trunk/Support/ZSDOS/ZCNFG24.CFG new file mode 100644 index 00000000..1bfe49bf Binary files /dev/null and b/trunk/Support/ZSDOS/ZCNFG24.CFG differ diff --git a/trunk/Support/ZSDOS/ZDDOS.HEX b/trunk/Support/ZSDOS/ZDDOS.HEX new file mode 100644 index 00000000..aaa41d74 --- /dev/null +++ b/trunk/Support/ZSDOS/ZDDOS.HEX @@ -0,0 +1,254 @@ +:0A0A0600C39BE423E723E723E72363 +:100A1000E7000000006DEBF12CF12CF12CF1EBF173 +:100A2000EBF1EBF10000000000000000000080008E +:100A300000000000000000000000000000000000B6 +:100A400000000000000000000000000000000000A6 +:100A50000000000000000000000000000000000096 +:100A60000000005A44444F5320312E3120436F7010 +:100A70007972696768742028632920313938372CE6 +:100A800038382020432E572E436F7472696C6C20C7 +:100A90002620482E462E426F776572AF476F672239 +:100AA0004CE4224EE4ED7361E4319BE4DDE5D5DDF9 +:100AB000E1DD225DE4DD225FE421BDE7E579324B33 +:100AC000E4FE0C380DFE31380DFE62D8FE68D0D63B +:100AD000314F2185E8E521E2E409097E23666F4B69 +:100AE0007BE9A1E750E53BE615F212F20FF25AE579 +:100AF00091E58EE5ACE695E58EE699E8E1E752E909 +:100B000042EE8FEB38E85FE86FE846EF87EF8DEE57 +:100B10007AE8C0E882E824ECBCE8D8EAB4E891E8D6 +:100B2000C4E8D3E83CEF7CEFDFE8E7E8F1E788E8EA +:100B3000B8E87CEF88E888E888E888E8CFE888E8C3 +:100B4000C8E8B0E8E2F1E5F18CE889E8B8F1B8F17D +:100B5000CD75E5D8E5CD3BE6E1C91C28141C280677 +:100B60001C2812C30CF23A29E4B73E01CC06F2A7C6 +:100B7000C9CD66E5C82129E47E3600B7CC09F2FE6E +:100B80000DC8FE0AC8FE09C8FE08C8FE20C9320307 +:100B9000003A0300C93A26E43227E413AF1213D512 +:100BA000CD75E5D1219FE5E52A5DE44E23FE0D28B4 +:100BB00074FE0A2870FE7F2804FE0820367EA7C82F +:100BC0001B35D54623EB2126E44E237E2B770418D4 +:100BD000051ACD6AE61310F979964771D1D50E083A +:100BE000C5CD0CF20E20CD0CF23E08CD3BE6C11077 +:100BF000EDD1C9FE152804FE18200AAFB6C8E5CD10 +:100C0000C0E5E118F6FE1020072128E47E2F77C901 +:100C100012E5CD2AE6E1347EB9280A3D1A13C0FE5A +:100C200003C0C3A1E7E13E0D1811FE20300DFE09FF +:100C3000280DF53E5ECD4EE6F1C640FE09200F3E82 +:100C400020CD4EE63A26E4E60720F43E09C9C5D594 +:100C50004FC5CD8EE6C1C5CD0CF2C1C53A28E4B76B +:100C6000C40FF2C179D1C12126E434FE7F2815FEDC +:100C700020D0FE092811FE08280A34FE0A2805FEA5 +:100C80000DC036023535C93E0786E6F877C9CD6610 +:100C9000E5C8CD75E5FE13200ACD09F2FE0320EE6E +:100CA000C3A1E73229E43E01C91120E71AFE24C896 +:100CB00013CD3BE618F6016400CDC4E60E0ACDC4A0 +:100CC000E601010116FF149130FC81F57AB0280786 +:100CD000477AC630CD54E5F1C94368616E676564F3 +:100CE0002442616420536563746F72244E6F204404 +:100CF000726976652446696C6520572F50245A44E2 +:100D0000444F53206572726F72206F6E20240D0A5B +:100D100043616C6C3A2024202046696C653A20249B +:100D20000D0A243A5CE44F0F385CC5D5CDA9E61115 +:100D3000FEE6CDACE63A2BE4C641CD3BE61114E726 +:100D4000CDACE6D1CDACE6110EE7CDACE63A4BE446 +:100D5000CDB6E63A4EE4A72829C1C5DDE53A4BE415 +:100D6000FE132004CDC6EAE31117E7CDACE6E10699 +:100D70000B233E03B83E2ECC54E57EE67FCD54E5F2 +:100D800010EFCDA9E6C13E0490200D212CE47E2B6E +:100D9000BE2805C5CD59E9C1CB4920183E01903088 +:100DA00005AF325CE4C7CD71E5A720FACD75E5FE4D +:100DB00003C018ED7867A7C82EFF224CE43A4EE432 +:100DC000B7280C3A2DE4DD77003A2CE4CD59E9ED53 +:100DD0007B61E4DD2A99E42A4CE4ED5B5FE47D4429 +:100DE000C9218000222EE4CD28ECAF322BE411FF84 +:100DF000FFCD27E83A15E4CB57200621FCF1CD3092 +:100E0000E83A4BE4FE0D21FEF1C430E83A2BE4F55C +:100E1000000000F1CD59E93A57E41869237E2BD63A +:100E200024C03D3257E4C97B2F5F7A2F5721FAF156 +:100E30007BA677237AA677C9CDF7E8DD7E00D63F7B +:100E4000280DDD7E0EFE3F2804DD360E003E0FCD60 +:100E5000DDEC2A34E4018000ED5B2EE4EDB0C9DD69 +:100E60002A58E4DD225DE4CDF7E8CDF4EC18E3CDBB +:100E7000F7E8CD57EC3A5AE4180BCDF7E8CDC2EDC0 +:100E800018F33A2BE4324CE4C93215E43A15E4186D +:100E9000F4CDF7E8CDEDED18DC212200FE44202B47 +:100EA0003A25E4A728256311E1F1ED535FE4181B0F +:100EB000211144DD2AFCF1DD2AFEF1DD2A3AE4DDD0 +:100EC0002AFAF1DD2A36E4DD2A2EE4224CE4C93286 +:100ED0005CE4C9212AE43C7E28AB7BE61F77C9CDC0 +:100EE00005E9CD16EE188E212000CD07F1DD722127 +:100EF000DD7122DD7023C93A5CE4A720082A5DE495 +:100F0000010D0009773EFF324EE43A2BE45F2A5D83 +:100F1000E47E322DE4FE3F2839DDE5DD2A5DE4E69E +:100F20000FE528025E1DCD52E9E1DD7E0DCB7F206D +:100F3000073A2AE41802DDE5DD2A5DE4E61FDD77E5 +:100F400000F680DD770DDDE1C92A0BE4060411EC23 +:100F5000E6E93A2BE4322CE47B2AFAF1E60F47C4A7 +:100F600039EAEB212BE4CB432802BEC877D54FCD1D +:100F70001BF27CB528D31130E4010200EDB022321F +:100F8000E40E06091134E40E08EDB02A36E40E0F23 +:100F9000EDB0D1CB43C0CD1FEAEB2AFAF1CD30EA58 +:100FA00022FAF13A15E4CB5F282A2A47E47CB54FB0 +:100FB0002AFEF17BA56F7AA4B53EFF28013C47B11C +:100FC000C8AF676FB0280A79B720092AFEF1CD3083 +:100FD000EA22FEF12A41E4CD37EA444D2A3AE4E51B +:100FE000545D13AF77EDB0E1ED5B45E47323722AF6 +:100FF00032E4772377CDD1EA3EFFCD05EBCDF1EAA0 +:10100000CA17E8CDC6EA7EFEE528EDFE2128E9CD27 +:101010001CE80E01CD6DECCDF8EAD4E9EA18D9212F +:101020000000EB2101003A2BE4B72804293D20FC05 +:101030007AB4677BB56FC90603CB3CCB1D10FAC9E8 +:101040002A54E40602CD39EA2252E4EB210000EDF5 +:101050004B3CE43E11B7ED423F380209B7CB13CB0E +:10106000123D2804ED6A18EDE52A49E419444DCDF6 +:101070001EF2C1ED5B30E4CD30F2444DC321F2DD10 +:101080006E20CB153A40E4DDA60C673A3EE44704F7 +:10109000CD39EA507D2A5DE40E10094F093A42E449 +:1010A000B75E2805095E23562B7AB3C92100003AA2 +:1010B0003EE447EB29CB1310FBEB3A3FE4DDA620DF +:1010C000B35FC9CD96EC3A56E42A34E4856FD02458 +:1010D000C921FFFF2254E4C92AFCF1CD22EA22FCF7 +:1010E000F1ED5B43E42A32E42313722B73C9CDDBA9 +:1010F000EC2A54E47CA53CC92A32E4ED5B54E47B41 +:1011000096237A9EC94F2A54E4232254E4ED5B438C +:10111000E47B957A9C38BA7D0F0F0FE6603256E477 +:10112000C0C5CD40EACD00EC2A54E47CB520112A9C +:1011300034E4060B234ECBB98110F9D69132F9F184 +:10114000C12A47E4ED5B52E4AFED52C8D82A34E43B +:10115000CDF2F1862A38E4190C200277C9BEC83ACC +:1011600015E4CB67060011D9E6C423E7CD1FEAEBEF +:10117000CD27E8CD0CE8CDD1EAAF1889CD27F218FC +:1011800003CD2AF2B7C8060111E1E62A09E4E9CD48 +:1011900005E9DDCB0E7EC0CDC2ECCDEEEAC8CDC3F5 +:1011A000EA01100009EB2A5DE409EB4134351A2805 +:1011B00004BEC204EF77132310F211ECFF19DD7E99 +:1011C0000CBE380877232323DD7E0F77CDF1EBCDDE +:1011D0002EEF280DC5010000CD28EFCDEEEAC12885 +:1011E0000DC5CDF1EB2A1CE40E0ACD8CEEC1C3284F +:1011F000EFCDC6EA010B0009CBBEDDCB0BBE180854 +:10120000CD2EECCD7CEB1820CDC6EA3E0DCDCCEA40 +:101210003600CD40EA0EFFCD41EBCD2EEC0E01CDD8 +:1012200081EB1804ED532EE4ED4B2EE41804ED4B46 +:1012300034E4C324F27BE6073C4FEBCD37EA47EDBD +:101240005B3AE4197E0710FD41C9C5CD35ECE6FED9 +:10125000D1B30F10FD77C9CDA8EDCDC3EA36E52394 +:101260007ED62420033257E423CBBE0E00CDC6EA3F +:1012700011100019435E2316003A42E4B728030513 +:1012800056237AB3280DE5C52A41E4B7ED52D44A76 +:10129000ECC1E110E0C9CDC6EA11080019ED5B13FD +:1012A000E41AA72004CB7E201023CB7E200BDDCBBD +:1012B000077EC83A15E4E602C02A0FE4060311F5DA +:1012C000E6E9CDCFECC0060211FAE62A0DE4E92AE0 +:1012D000FCF1CD22EAED52C93E0C213E0F325BE417 +:1012E0003EFF325AE4DD2258E4CDD1EA2A47E47CBD +:1012F000B5C418F2AF676F2250E4DDCB07BECD0551 +:10130000EBCDF1EA280EED5B58E41AFEE52807D58F +:10131000CDF8EAD1306CCDC6EA7EFE2128D60E008B +:101320003A5BE44778B728601AEE3FE67F283C79BD +:10133000B720233A15E41F301D2323CB7E2B2B2807 +:10134000151AFEE52810AEE67F281A3EFF3251E45A +:10135000DDCB07FE180F79FE0D280AFE0C1A2811A6 +:10136000AEE67F208F13230C0518B93D3250E418E8 +:10137000F4AECD77ED18ECC5473A40E42FE61FA058 +:10138000C1C9CDD1EAC304EF2A50E47CA520D4CD55 +:10139000F8EAD4E9EA2A52E4225FE43A54E4E603A4 +:1013A000324CE4AF325AE4C9CDC2ECCDD8ECCDF129 +:1013B000EAE1C8E5E521BAEDE3E9CD08ECCDF4ECCE +:1013C00018ECCDA8EDCD96EC2A5DE411100019EBD8 +:1013D000CDC6EA2323CBBE2B2B060B23131AE67FA5 +:1013E000FE3F20017E17CB161F7710EFC9CDA8ED69 +:1013F000DDE5D1CDC6EA060B23133E04B8200EE589 +:101400002A13E47EE1A72005CB7EC2B9EC1ACB16E5 +:1014100017CB1E10E3C901000051CDEDE8CDD8EC8B +:10142000CDF1EAC8CDC6EAEB210F00CD07F17ADD98 +:10143000962179DD9E2278DD9E23D4EDE8CDF4EC73 +:1014400018DECDF7E8DD360E00CDEEEAC8DD7E070A +:10145000F5DD7E0CF5CDC6EA7EF680DDE5D1012016 +:1014600000EDB0DD770DCD02F1DD460CDD4E0FF164 +:10147000DD770CB828040E00CB19DD710FF1DDCB40 +:10148000071617DDCB071E0E052A18E4E9CDF7E88D +:10149000DD360E00CDC2EC2A5DE47EF536E53E0178 +:1014A000CDDDECF1DD7700CDF1EAC82A5DE4CD1C9D +:1014B000E8110F00190611AF772310FCDDCB07BE32 +:1014C000DDCB0BBECDC6EADDE5D1EB012000EDB0F2 +:1014D000CD08ECCD02F10E00C32CF1DDCB0E7E2049 +:1014E00008CD92EB3A4CE43CC8CD0FEF3813CDEE6B +:1014F000EA20163A4FE4B72808CD94EECDF1EA2061 +:101500000BCD02F13EFFC385E8CD4DEEAF18F7CD10 +:101510002EEFCB7037C00C79E61F4F20070478E61A +:101520003F4737C8DD362000DD710CDD700EDD4E23 +:101530000CDD460E79CD77EDCBB8B0C9CD05E9AF5E +:10154000CD7EF02804C9CD05E9AF324FE4DD7E2021 +:10155000FE802809DDBE0F38073E0118A9CD71EFC6 +:10156000CD7FEA28F4CDACEACD4FEACD7CEBC36C5D +:10157000F0CDDBEE3A4CE4B7C8E118DDCD05E93E2D +:10158000FFCD7EF02804C9CD05E93EFF324FE4CD02 +:10159000C2ECDDCB097E200ECDAEEC2A13E47EA793 +:1015A0002007DDCB087EC2B9ECDDCB207EC471EF15 +:1015B000CD7FEAC24BF0E579B728043DCD95EA62CC +:1015C0006B7AB3280B1BE5D5CD35EC1F3020D1E16C +:1015D000ED4B41E47D917C98300E23D5E5EBCD3584 +:1015E000EC1F300AE1D118D97AB320D51807371784 +:1015F000CD52ECD1E1E17AB3287FDDCB0EBE733A58 +:1016000042E4B7280223720E023A3FE4DDA6202806 +:10161000020E003A4BE4D6282033D52A34E4068063 +:10162000772310FCCDACEA3A3FE447042FA35F0ECA +:1016300002E5D5C5CD4FEACD2EECC1C5CD81EBC1BC +:10164000D1E10E001C10EACD28ECD10E00DDCB0E4E +:10165000BEC5CDACEACD4FEAC1CD81EBDD7E20DD4C +:10166000BE0F38083CDD770FDDCB0EBE3A4BE4FEF3 +:1016700014D8FE16D0DD3420C93E02C385E8324FAF +:10168000E4DD7E2157CBBA17DD7E2217F5E61F4F2A +:10169000F117171717E60F47DD7E231E06FE0430ED +:1016A0005C070707078047DD7220DD560ECB7220EE +:1016B0000E79DDBE0C200878DDAE0EE63F2837CB74 +:1016C0007A200FD5C5CD92EBC1D11E033A4CE43C34 +:1016D0002827CD28EFCDDBEC3A4CE43C20153A4FDF +:1016E000E41E043C2013CD94EE1E053A4CE43C2845 +:1016F000081803CD4DEEC30CEFDD360EC07B324C27 +:10170000E4B7DDCB0EFEC9197E210C0019577EE629 +:101710001FCB12CE001FCB1A4F23237E0F0F0F0FAC +:10172000F5E60347F1E6F0814FD004C93AF9F1B785 +:10173000C0DDCB037EC0C5CD2EEFC1C0473A4BE420 +:10174000FE662806CDCFECCAEBF1C53A56E41F2A57 +:1017500052E4CB3CCB1D3002C640F5E52A45E43AC5 +:101760003FE43C5F500610293003E319E310F8E131 +:10177000CD4BEACD00ECCDEEF1BE2038F1CDC9EA7B +:10178000C13A4BE4FE66C8FE67281609C5CDE1F1F3 +:10179000C13C28577379B72012060A772310FC182A +:1017A0000AED5B2EE4EB010F00EDB0CDEEF177CD4D +:1017B0001AECAFC9E1E11833CDF7E8CDEEEA282BFA +:1017C0003A4BE4FE672811DDCB03BECD2CF1200B94 +:1017D000010F00CD58E81803CD2CF1CA59EFC3040E +:1017E000EFEB0E00210E012A16E4E5F6FFC9AF2A41 +:1017F00034E4067F862310FCC900000000000000CE +:10322000005581AA0A000000000000000000000014 +:10323000000000001209100901001001A8AAAAAAA2 +:10324000AAAAAAAAAAAAAAAAAAAA8400204188402D +:103250000000800444040000000110000821000068 +:103260000208100010008000480010420402000014 +:1032700000001108240808080100400000000000B8 +:10328000000000002040929044922480402400825C +:103290001020400010410090204844224022482045 +:1032A0000949400220800004000012084412929054 +:1032B0009048480004224044442422001210008216 +:1032C00000121140000108080008910822000201C4 +:1032D00041200091241004000020494200088290FF +:1032E000240042120001000084040400000842424D +:1032F00040208480000002102009402491000944ED +:103300000011018090040280888044000249244119 +:10331000082402120101100000400224901009004C +:1033200024841012820812200420001280800008D9 +:103330000004010101002008112412801049080234 +:103340000902040104002000008000000040100871 +:103350009004922444248190900404000080200072 +:10336000041000904420009010088000000100002C +:10337000008840020422010040002404480821483B +:1033800008090200000080400411008084244940A4 +:1033900008420224008124400004080001000400C7 +:1033A0000208202040024042000290080040002015 +:1033B0000100000000000000804090040121200175 +:1033C00001000000004000824022024002002481EF +:1033D00008800000102002240420202401020200A2 +:0000000000 + \ No newline at end of file diff --git a/trunk/Support/ZSDOS/ZDDOS.ZRL b/trunk/Support/ZSDOS/ZDDOS.ZRL new file mode 100644 index 00000000..800f2a33 Binary files /dev/null and b/trunk/Support/ZSDOS/ZDDOS.ZRL differ diff --git a/trunk/Support/ZSDOS/ZPATH.COM b/trunk/Support/ZSDOS/ZPATH.COM new file mode 100644 index 00000000..5c0aa503 Binary files /dev/null and b/trunk/Support/ZSDOS/ZPATH.COM differ diff --git a/trunk/Support/ZSDOS/ZSCONFIG.COM b/trunk/Support/ZSDOS/ZSCONFIG.COM new file mode 100644 index 00000000..2cc26074 Binary files /dev/null and b/trunk/Support/ZSDOS/ZSCONFIG.COM differ diff --git a/trunk/Support/ZSDOS/ZSDOS.HEX b/trunk/Support/ZSDOS/ZSDOS.HEX new file mode 100644 index 00000000..7b32bc49 --- /dev/null +++ b/trunk/Support/ZSDOS/ZSDOS.HEX @@ -0,0 +1,254 @@ +:0A0A0600C39BE44CE74CE74CE74CBF +:100A1000E7F1F100006DDDF1DDF1DDF1DDF1DDF19A +:100A2000DDF1DDF1000000000000000000008000AA +:100A300000000000000000000000000000000000B6 +:100A400000000000000000000000000000000000A6 +:100A50000000000000000000000000000000000096 +:100A60000000005A53444F5320312E3120436F7001 +:100A70007972696768742028632920313938372CE6 +:100A800038382020432E572E436F7472696C6C20C7 +:100A90002620482E462E426F776572AF476F672239 +:100AA0004CE4224EE4ED7361E4319BE4DDE5D5DDF9 +:100AB000E1DD225DE4DD225FE421E6E7E579324B0A +:100AC000E4FE0C380DFE31380DFE62D8FE68D0D63B +:100AD000314F21BBE8E521E2E409097E23666F4B33 +:100AE0007BE9CAE750E564E615F212F20FF25AE527 +:100AF00091E58EE5D5E695E5B7E6CFE80AE87AE92F +:100B0000B4EEA8EB6EE895E8A5E8BEEFFFEF02EFC4 +:100B1000B0E8E8E8B8E833ECE4E803EBDCE8C7E881 +:100B2000ECE8FBE8B4EFF4EF07E90FE91AE8BEE8F8 +:100B3000E0E8F4EFBEE8BEE8BEE8BEE8F7E8BEE8ED +:100B4000F0E8D8E8D7F1D4F1C2E8BFE8A4F1A4F105 +:100B5000CD75E5D8E5CD64E6E1C91C28141C28064E +:100B60001C2812C30CF23A29E4B73E01CC06F2A7C6 +:100B7000C9CD66E5C82129E47E3600B7CC09F2FE6E +:100B80000DC8FE0AC8FE09C8FE08C8FE20C9320307 +:100B9000003A0300C93A26E43227E413AF1213D512 +:100BA000CD75E5D1219FE5E52A5DE44E23FE0D28B4 +:100BB00002FE0ACA4EE6FE7F2804FE0820367EA703 +:100BC000C81B35D54623EB2126E44E237E2B770424 +:100BD00018051ACD93E61310F979964771D1D50E01 +:100BE00008C5CD0CF20E20CD0CF23E08CD64E6C156 +:100BF00010EDD1C9FE152804FE18200AAFB6C8E5CD +:100C0000CDC1E5E118F6FE122024E5CDD2E621267D +:100C1000E4360023463E20041803CD64E610FBE1D1 +:100C20004623EB0418051ACD53E61310F9C9FE103C +:100C300020072128E47E2F77C912E5CD53E6E13461 +:100C40007EB9280A3D1A13C0FE03C0C3CAE7E13EBD +:100C50000D1811FE20300DFE09280DF53E5ECD77F2 +:100C6000E6F1C640FE09200F3E20CD77E63A26E4A5 +:100C7000E60720F43E09C9C5D54FC5CDB7E6C1C5C5 +:100C8000CD0CF2C1C53A28E4B7C40FF2C179D1C185 +:100C90002126E434FE7F2815FE20D0FE092811FE0F +:100CA00008280A34FE0A2805FE0DC036023535C96B +:100CB0003E0786E6F877C9CD66E5C8CD75E5FE1333 +:100CC000200ACD09F2FE0320EEC3CAE73229E43E32 +:100CD00001C91149E71AFE24C813CD64E618F601CC +:100CE0006400CDEDE60E0ACDEDE601010116FF141C +:100CF0009130FC81F57AB02807477AC630CD54E5AB +:100D0000F1C94368616E676564244261642053657C +:100D100063746F72244E6F2044726976652446694D +:100D20006C6520572F50245A53444F5320657272DC +:100D30006F72206F6E20240D0A43616C6C3A202480 +:100D4000202046696C653A20240D0A243A5CE44F61 +:100D50000F385CC5D5CDD2E61127E7CDD5E63A2BC5 +:100D6000E4C641CD64E6113DE7CDD5E6D1CDD5E66B +:100D70001137E7CDD5E63A4BE4CDDFE63A4EE4A7AE +:100D80002829C1C5DDE53A4BE4FE132004CDF1EA84 +:100D9000E31140E7CDD5E6E1060B233E03B83E2E36 +:100DA000CC54E57EE67FCD54E510EFCDD2E6C13ED2 +:100DB0000490200D212CE47E2BBE2805C5CD81E9B1 +:100DC000C1CB4920183E01903005AF325CE4C7CD5D +:100DD00071E5A720FACD75E5FE03C018ED7867A789 +:100DE000C82EFF224CE43A4EE4B7280C3A2DE4DD3D +:100DF00077003A2CE4CD81E9ED7B61E4DD2A99E4CA +:100E00002A4CE4ED5B5FE47D44C9218000222EE49E +:100E1000CD37ECAF322BE411FFFFCD5DE83A15E49E +:100E2000CB57200621FCF1CD66E83A4BE4FE0D21BC +:100E3000FEF1C466E82AFEF1CD58EAEB21F8F1CDC7 +:100E400066E83A2BE4F5000000F1CD81E93A57E479 +:100E50001869237E2BD624C03D3257E4C97B2F5F0F +:100E60007A2F5721FAF17BA677237AA677C9CD1F6F +:100E7000E9DD7E00D63F280DDD7E0EFE3F2804DD35 +:100E8000360E003E0FCDF3EC2A34E4018000ED5B1A +:100E90002EE4EDB0C9DD2A58E4DD225DE4CD1FE982 +:100EA000CD0AED18E3CD1FE9CD6DEC3A5AE4180BED +:100EB000CD1FE9CDD7ED18F33A2BE4324CE4C9321B +:100EC00015E43A15E418F4CD1FE9CD02EE18DC2143 +:100ED0002200ED535FE4181B211153DD2AFCF1DDE4 +:100EE0002AFEF1DD2A3AE4DD2AFAF1DD2A36E4DDD4 +:100EF0002A2EE4224CE4C9325CE4C9212AE43C7E77 +:100F000028B97BE61F77C9CD2DE9CD2BEE189C21A2 +:100F10002000CD7FF1DD7221DD7122DD7023C93A21 +:100F20005CE4A720082A5DE4010D0009773EFF324A +:100F30004EE43A2BE45F2A5DE47E322DE4FE3F2846 +:100F400039DDE5DD2A5DE4E60FE528025E1DCD7A98 +:100F5000E9E1DD7E0DCB7F20073A2AE41802DDE5CA +:100F6000DD2A5DE4E61FDD7700F680DD770DDDE14B +:100F7000C92A0BE406041115E7E93A2BE4322CE404 +:100F80007B2AFAF1E60F47C461EAEB212BE4CB435D +:100F90002802BEC877D54FCD1BF27CB528D31130BF +:100FA000E4010200EDB02232E40E06091134E40E31 +:100FB00008EDB02A36E40E0FEDB0D1CB43C0CD47DB +:100FC000EAEB2AFAF1CD58EA22FAF13A15E4CB5FBE +:100FD000282A2A47E47CB54F2AFEF17BA56F7AA424 +:100FE000B53EFF28013C47B1C8AF676FB0280A790A +:100FF000B720092AFEF1CD58EA22FEF12A41E4CDBC +:101000005FEA444D2A3AE4E5545D13AF77EDB0E171 +:10101000ED5B45E47323722A32E4772377CDFCEA53 +:101020003EFFCD30EBCD1CEBCA4DE8CDF1EA7EFEA4 +:10103000E528EDFE2128E9CD52E80E01CD83ECCD67 +:1010400023EBD414EB18D9210000EB2101003A2B3B +:10105000E4B72804293D20FC7AB4677BB56FC90644 +:1010600003CB3CCB1D10FAC92A54E4CB3CCB1DCB9F +:101070003CCB1D2252E4EB210000ED4B3CE43E1141 +:10108000B7ED423F380209B7CB13CB123D2804ED30 +:101090006A18EDE52A49E419444DCD1EF2C1ED5B15 +:1010A00030E4CD30F2444DC321F2DD6E20CB153A51 +:1010B00040E4DDA60C673A3EE44704CD61EA507D8A +:1010C0002A5DE40E10094F093A42E4B75E2805098B +:1010D0005E23562B7AB3C92100003A3EE447EB2940 +:1010E000CB1310FBEB3A3FE4DDA620B35FC9CDACD8 +:1010F000EC3A56E42A34E4856FD024C921FFFF225C +:1011000054E4C92AFCF1CD4AEA22FCF1ED5B43E448 +:101110002A32E42313722B73C9CDF1EC2A54E47CF8 +:10112000A53CC92A32E4ED5B54E47B96237A9EC940 +:101130004F2A54E4232254E4ED5B43E47B957A9CEC +:1011400038BA7D0F0F0FE6603256E4C0C5CD68EAAD +:10115000CD3DECCD95EBCD37ECC12A47E4ED5B52AC +:10116000E4AFED52C8D82A34E4CDE0F1862A38E461 +:10117000190C200277C9BEC83A15E4CB67060011E6 +:1011800002E7C44CE7CD47EAEBCD5DE8CD35E8CDCD +:10119000FCEAAF189BCD27F21803CD2AF2B7C80698 +:1011A00001110AE72A09E4E9CD2DE9DDCB0E7EC065 +:1011B000CDD8ECCD19EBC8CDEEEA01100009EB2A31 +:1011C0005DE409EB4134351A2804BEC27AEF771387 +:1011D0002310F211ECFF19DD7E0CBE3808772323B3 +:1011E00023DD7E0F77CD08ECCDA6EF280DC50100DD +:1011F00000CD9EEFCD19EBC1280BC5CD08EC2A1C04 +:10120000E4CDB9F1C1C39EEFCDF1EA010B0009CBEA +:10121000BEDDCB0BBE1800CDF1EA3E0DCDF7EA36B0 +:1012200000CD68EA0EFFCD5AEBCD3DEC0E01CD9A14 +:10123000EB1804ED532EE4ED4B2EE41804ED4B3483 +:10124000E4C324F27BE6073C4FCB3ACB1BCB3ACB33 +:101250001BCB3ACB1B472A3AE4197E0710FD41C944 +:10126000C5CD44ECE6FED1B30F10FD77C9CDBDED81 +:10127000CDEEEA36E5237ED62420033257E423CB95 +:10128000BE0E00CDF1EA11100019435E2316003A9C +:1012900042E4B728030556237AB3280DE5C52A4151 +:1012A000E4B7ED52D460ECC1E110E0C9CDF1EA1130 +:1012B000080019ED5B13E41AA72004CB7E2010234D +:1012C000CB7E200BDDCB077EC83A15E4E602C02AB0 +:1012D0000FE40603111EE7E9CDE5ECC00602112379 +:1012E000E72A0DE4E92AFCF1CD4AEAED52C93E0CA9 +:1012F000213E0F325BE43EFF325AE4DD2258E4CD5A +:10130000FCEA2A47E47CB5C418F2AF676F2250E4C8 +:10131000DDCB07BECD30EBCD1CEB280EED5B58E4EA +:101320001AFEE52807D5CD23EBD1306BCDF1EA7E4F +:10133000FE2128D60E003A5BE44778B7285F1AEE04 +:101340003FE67F283B79B720223A15E41F301C2363 +:1013500023CB7E2B2B28141AFEE5280FAEE67F2820 +:10136000193EFF3251E4CDAFEE180F79FE0D280A79 +:10137000FE0C1A2811AEE67F209013230C0518BA34 +:101380003D3250E418F4AECD8CED18ECC5473A4030 +:10139000E42FE61FA0C1C9CDFCEAC37AEF2A50E4CE +:1013A0007CA520D4CD23EBD414EB2A52E4225FE4B5 +:1013B0003A54E4E603324CE4AF325AE4C9CDD8ECF7 +:1013C000CDEEECCD1CEBE1C8E5E521CFEDE3E9CDB9 +:1013D00017ECCD0AED18ECCDBDEDCDACEC2A5DE4FB +:1013E00011100019EBCDF1EA2323CBBE2B2B060BFA +:1013F00023131AE67FFE3F20017E17CB161F7710BE +:10140000EFC9CDBDEDDDE5D1CDF1EA060B23133EED +:1014100004B8200EE52A13E47EE1A72005CB7EC2A6 +:10142000CFEC1ACB1617CB1E10E3C901000051CD2B +:1014300015E9CDEEECCD1CEBC8CDF1EAEB210F00A8 +:10144000CD7FF17ADD962179DD9E2278DD9E23D451 +:1014500015E9CD0AED18DECD19EBC03A15E4CB6FD6 +:10146000C82A11E47CB5C87E23B7CA97EDE67FFE93 +:101470002420043A2CE43C3DE5CD81E9E17E23E6DD +:101480007FFE2420033A2AE4E61FE5CD5EE9CD196C +:10149000EBE128D3E5CDF1EA110A0019CB7E3A152C +:1014A000E41717E1380228BF3A2BE43C322DE4DD83 +:1014B000CB07FEC9CD1FE9DD360E00CD57EECD1CA2 +:1014C000EBC8DD7E07F5DD7E0CF5CDF1EA7EF6801A +:1014D000DDE5D1012000EDB0DD770DCD7AF1DD46FF +:1014E0000CDD4E0FF1DD770CB828040E00CB19DDB2 +:1014F000710FF1DDCB071617DDCB071E2A18E4C3E9 +:10150000B9F1CD1FE9DD360E00CDD8EC2A5DE47EC1 +:10151000F536E53E01CDF3ECF1DD7700CD1CEBC8EF +:101520002A5DE4CD52E8110F00190611AF772310A0 +:10153000FCDDCB07BEDDCB0BBECDF1EADDE5D1EBAB +:10154000012000EDB0CD17ECCD7AF12A1AE4C3B931 +:10155000F1DDCB0E7E2008CDABEB3A4CE43CC8CDA0 +:1015600085EF3813CD19EB20163A4FE4B72808CD94 +:1015700009EFCD1CEB200BCD7AF13EFFC3BBE8CDCC +:10158000C2EEAF18F7CDA6EFCB7037C00C79E61FCF +:101590004F20070478E63F4737C8DD362000DD716D +:1015A0000CDD700EA7C9DD4E0CDD460E79CD8CED3D +:1015B000CBB8B0C9CD2DE9AFCDF6F02804C9CD2DFB +:1015C000E9AF324FE4DD7E20FE802809DDBE0F3812 +:1015D000073E0118A7CDE9EFCDAAEA28F4CDD7EA56 +:1015E000CD7AEACD95EBC3E4F0CD51EF3A4CE4B7B8 +:1015F000C8E118DDCD2DE93EFFCDF6F02804C9CDB8 +:101600002DE93EFF324FE4CDD8ECDDCB097E200E34 +:10161000CDC4EC2A13E47EA72007DDCB087EC2CF21 +:10162000ECDDCB207EC4E9EFCDAAEAC2C3F0E579B8 +:10163000B728043DCDC0EA626B7AB3280B1BE5D511 +:10164000CD44EC1F3020D1E1ED4B41E47D917C98FD +:10165000300E23D5E5EBCD44EC1F300AE1D118D98B +:101660007AB320D518073717CD68ECD1E1E17AB30A +:10167000287FDDCB0EBE733A42E4B7280223720EF8 +:10168000023A3FE4DDA62028020E003A4BE4D628B9 +:101690002033D52A34E40680772310FCCDD7EA3AEC +:1016A0003FE447042FA35F0E02E5D5C5CD7AEACD0E +:1016B0003DECC1C5CD9AEBC1D1E10E001C10EACDC5 +:1016C00037ECD10E00DDCB0EBEC5CDD7EACD7AEA20 +:1016D000C1CD9AEBDD7E20DDBE0F38083CDD770FF3 +:1016E000DDCB0EBE3A4BE4FE14D8FE16D0DD34201E +:1016F000C93E02C3BBE8324FE4DD7E2157CBBA17A7 +:10170000DD7E2217F5E61F4FF117171717E60F4773 +:10171000DD7E231E06FE04305C070707078047DDD9 +:101720007220DD560ECB72200E79DDBE0C200878BB +:10173000DDAE0EE63F2837CB7A200FD5C5CDABEB1B +:10174000C1D11E033A4CE43C2827CD9EEFCDF1ECED +:101750003A4CE43C20153A4FE41E043C2013CD09DA +:10176000EF1E053A4CE43C28081803CDC2EEC382B4 +:10177000EFDD360EC07B324CE4B7DDCB0EFEC9196F +:101780007E210C0019577EE61FCB12CE001FCB1A0C +:101790004F23237E0F0F0F0FF5E60347F1E6F0818D +:1017A0004FD004C9CD1FE9CD19EB28312A1EE43AE8 +:1017B0004BE4FE66280A2A20E4E5CDE5ECE1281D8D +:1017C000CDA6EF20183A56E4ED5B34E40117ECE5C2 +:1017D0002A2EE4C90E01210E002A16E4E5F6FFC9FF +:1017E000067F862310FCC9000000000000000000F6 +:1017F00000010000000000000000000000000000E8 +:10322000005585AA0A000000000000000000000010 +:10323000000000001209100901001001A8AAAAAAA2 +:10324000AAAAAAAAAAAAAAAAAAAA8400204188402D +:10325000000080044404200000022000104200000E +:103260000420011000021020002000000190002026 +:103270008408040000000022104810101002008092 +:103280000000000000000000004080242189244943 +:103290000081480004214080002082002041908865 +:1032A0004480449040129244129000082000010093 +:1032B00080040291842424241212204044442422B5 +:1032C000001210008200121140000108080008914D +:1032D000082200020141200091241004000020492E +:1032E00042000882902400421200010000042020C5 +:1032F0000000401012020221040400108000490066 +:1033000022890448200288080084241101890004CD +:1033100092488210480424020220000080044820C1 +:1033200089040042080941040900000108800420C2 +:10333000200002004140400000084204890420446B +:1033400012824082004100010008000020010000BC +:10335000080201924092848824101292800000009A +:1033600010048000020092080400122208102008B5 +:103370008020810001444020011000200000004016 +:1033800012488040240000088024011242081242A2 +:10339000820000000080400411008084244940081D +:1033A00042022400812440000408000100040002BD +:1033B0000820204002404200029008004000200106 +:1033C0000000000000000080409004012120010165 +:1033D0000000000040420211844804080000000080 +:0000000000 + \ No newline at end of file diff --git a/trunk/Support/ZSDOS/ZSDOS.ZRL b/trunk/Support/ZSDOS/ZSDOS.ZRL new file mode 100644 index 00000000..e43d1b0a Binary files /dev/null and b/trunk/Support/ZSDOS/ZSDOS.ZRL differ diff --git a/trunk/Support/ZSDOS/ZSVSTAMP.CIM b/trunk/Support/ZSDOS/ZSVSTAMP.CIM new file mode 100644 index 00000000..4756dfac Binary files /dev/null and b/trunk/Support/ZSDOS/ZSVSTAMP.CIM differ diff --git a/trunk/Support/ZSDOS/ZSVSTAMP.COM b/trunk/Support/ZSDOS/ZSVSTAMP.COM new file mode 100644 index 00000000..026d5d7a Binary files /dev/null and b/trunk/Support/ZSDOS/ZSVSTAMP.COM differ diff --git a/trunk/Support/ZSDOS/ZSVSTAMP.DOC b/trunk/Support/ZSDOS/ZSVSTAMP.DOC new file mode 100644 index 00000000..2a8a7c1e --- /dev/null +++ b/trunk/Support/ZSDOS/ZSVSTAMP.DOC @@ -0,0 +1,118 @@ + ZSVSTAMP USAGE NOTES + + + +1.0 INTRODUCTION + + ZSVSTAMP is a utility program that saves the create +date/time stamp of a given file in memory. At a later time, +ZSVSTAMP can restore the create stamp to a file. This can be +useful when modifying a file with an editor that actually creates +a new copy of the file rather than modifying it in place. +ZSVSTAMP allows the original creation date of the document to be +retained. + + In order to support all types of date stamping under ZSDOS, +ZSVSTAMP uses the get/set stamp functions of ZSDOS (or ZDDOS) and +thus may only be run under these operating systems. It also +requires ZCPR3 with multiple command line, external FCB and +message buffer. If an attempt is made to run ZSVSTAMP on a +system that does not meet these requirements, the program will +abort with an error message. + + + +2.0 OPERATION + + ZSVSTAMP has two modes of operation -- Manual and Automatic. + + + +2.1 Automatic Mode + + This mode is the most commonly used. It is extremely well +suited for use in alias scripts and can make the whole process of +saving and restoring date stamps virtually transparent to the +user. The syntax is: + + ZSVSTAMP approg [ufn] + +where "approg" is the program, such as an editor, that you wish +to run and "ufn" is an unambiguous file name to be modified by +"approg." When a command of this type is given, ZSVSTAMP saves +"ufn"'s creation date in protected memory. It then causes +"approg" to be run, and when "approg" finishes, ZSVSTAMP is +automatically run again to restore the original create stamp to +"ufn." If "ufn" does not exist, or if the disk does not support +date stamping, ZSVSTAMP displays a warning message and +immediately passes control to "approg" without attempting to save +a stamp. In this situation, ZSVSTAMP is not rerun when "approg" +completes execution. + + Some editors allow a syntax such as + + EDIT oldfile newfile + +When ZSVSTAMP is invoked with more than one parameter following +the application name, no stamps are saved or restored. This +feature can be disabled if desired, (see the section on +customization). + + + +2.2 Manual Mode + + Manual mode can be used to save or restore a file's create +stamp. The syntax is: + + ZSVSTAMP ufn /G or /S + +to Get or Save a file's create stamp, or: + + ZSVSTAMP ufn /P or /R + +to Put or Restore a saved stamp back onto a file. + + + +3.0 CUSTOMIZING ZSVSTAMP + +There are five configuration flags located near the beginning of +the program. Each flag is preceeded by an ASCII string to help +identify its function. These flags may be patched to customize +ZSVSTAMP as desired. + + The first four flags determine whether or not various +warning messages can be displayed when ZSVSTAMP is being run in +Automatic Mode. Setting a flag to 0 disables its associated +message; any other value enables the message. The flags are +labeled "NOSTMP," "NOFILE," "READERR," and "UPDTERR," and they +affect the "Disk has no time/date stamps," "File not found," +"Can't read time/date stamp," and "Can't update time/date stamp" +messages respectively. The program is distributed with all four +messages enabled. Please note that these flags have no effect in +Manual Mode where error messages are always enabled. + + The fifth and final configuration flag is labeled +"REPLALWS." It determines what ZSVSTAMP will do when more than +one parameter follows the application name in an Automatic Mode +command. If the byte following the "REPLALWS" label equals 0, +ZSVSTAMP checks to see if there is more than one parameter +following the application program name. If there is, ZSVSTAMP +simply exits to the application without saving or updating any +stamps. (This is the default setting in the distributed +version.) If the "REPLALWS" flag is non-zero, no such check is +made. + + + +4.0 CONTACTING THE AUTHOR + + Howard Goldstein may be contacted at: + + Newton Centre Z-Node, (Z-Node 3): 617/965-7259 + + Ladera Z-Node, (Z-Node 2): 213/670-9465 + + Home phone, (voice): 203/787-1918 + \ No newline at end of file diff --git a/trunk/Support/ZSDOS/ZXD.CFG b/trunk/Support/ZSDOS/ZXD.CFG new file mode 100644 index 00000000..f202ae59 Binary files /dev/null and b/trunk/Support/ZSDOS/ZXD.CFG differ diff --git a/trunk/Support/ZSDOS/ZXD.COM b/trunk/Support/ZSDOS/ZXD.COM new file mode 100644 index 00000000..20395673 Binary files /dev/null and b/trunk/Support/ZSDOS/ZXD.COM differ diff --git a/trunk/Support/vdu.rom b/trunk/Support/vdu.rom new file mode 100644 index 00000000..6452286c Binary files /dev/null and b/trunk/Support/vdu.rom differ diff --git a/trunk/Tools/Win32 Disk Imager.exe b/trunk/Tools/Win32 Disk Imager.exe new file mode 100644 index 00000000..bff00365 Binary files /dev/null and b/trunk/Tools/Win32 Disk Imager.exe differ diff --git a/trunk/Tools/cpmtools/cpmchattr.exe b/trunk/Tools/cpmtools/cpmchattr.exe new file mode 100644 index 00000000..79d9d6d6 Binary files /dev/null and b/trunk/Tools/cpmtools/cpmchattr.exe differ diff --git a/trunk/Tools/cpmtools/cpmchmod.exe b/trunk/Tools/cpmtools/cpmchmod.exe new file mode 100644 index 00000000..8f657dca Binary files /dev/null and b/trunk/Tools/cpmtools/cpmchmod.exe differ diff --git a/trunk/Tools/cpmtools/cpmcp.exe b/trunk/Tools/cpmtools/cpmcp.exe new file mode 100644 index 00000000..600e4529 Binary files /dev/null and b/trunk/Tools/cpmtools/cpmcp.exe differ diff --git a/trunk/Tools/cpmtools/cpmls.exe b/trunk/Tools/cpmtools/cpmls.exe new file mode 100644 index 00000000..eeecf540 Binary files /dev/null and b/trunk/Tools/cpmtools/cpmls.exe differ diff --git a/trunk/Tools/cpmtools/cpmrm.exe b/trunk/Tools/cpmtools/cpmrm.exe new file mode 100644 index 00000000..a61e7022 Binary files /dev/null and b/trunk/Tools/cpmtools/cpmrm.exe differ diff --git a/trunk/Tools/cpmtools/cygncurses-8.dll b/trunk/Tools/cpmtools/cygncurses-8.dll new file mode 100644 index 00000000..4a2c5328 Binary files /dev/null and b/trunk/Tools/cpmtools/cygncurses-8.dll differ diff --git a/trunk/Tools/cpmtools/cygwin1.dll b/trunk/Tools/cpmtools/cygwin1.dll new file mode 100644 index 00000000..37e6d8da Binary files /dev/null and b/trunk/Tools/cpmtools/cygwin1.dll differ diff --git a/trunk/Tools/cpmtools/diskdefs b/trunk/Tools/cpmtools/diskdefs new file mode 100644 index 00000000..2e1f5725 --- /dev/null +++ b/trunk/Tools/cpmtools/diskdefs @@ -0,0 +1,341 @@ +diskdef ibm-3740 + seclen 128 + tracks 77 + sectrk 26 + blocksize 1024 + maxdir 64 + skew 6 + boottrk 2 + os p2dos +end + +diskdef 4mb-hd + seclen 128 + tracks 1024 + sectrk 32 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 0 + os p2dos +end + +diskdef pcw + seclen 512 + tracks 40 + sectrk 9 + blocksize 1024 + maxdir 64 + skew 1 + boottrk 1 + os 3 +end + +diskdef pc1.2m + seclen 512 + tracks 80 + # this format uses 15 sectors per track, but 30 per cylinder + sectrk 30 + blocksize 4096 + maxdir 256 + skew 1 + boottrk 0 + os 3 +end + +# CP/M 86 on 1.44MB floppies +diskdef cpm86-144feat + seclen 512 + tracks 160 + sectrk 18 + blocksize 4096 + maxdir 256 + skew 1 + boottrk 2 + os 3 +end + +diskdef cf2dd + seclen 512 + tracks 160 + sectrk 9 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 1 + os 3 +end + +#amstrad: values are read from super block (special name hardcoded) + +# Royal alphatronic +# setfdprm /dev/fd1 dd ssize=256 cyl=40 sect=16 head=2 +diskdef alpha + seclen 256 + tracks 40 + sectrk 32 + blocksize 2048 + maxdir 128 + skew 1 + boottrk 2 + os 2.2 +end + +# Apple II CP/M skew o Apple II DOS 3.3 skew +diskdef apple-do + seclen 256 + tracks 35 + sectrk 16 + blocksize 1024 + maxdir 64 + skew 0 + boottrk 3 + os 2.2 +end + +# Apple II CP/M skew o Apple II PRODOS skew +diskdef apple-po + seclen 256 + tracks 35 + sectrk 16 + blocksize 1024 + maxdir 64 + skew 0 + boottrk 3 + os 2.2 +end + +# MYZ80 hard drive (only works with libdsk, because it has a 256-byte header) +diskdef myz80 + seclen 1024 + tracks 64 + sectrk 128 + blocksize 4096 + maxdir 1024 + skew 1 + boottrk 0 + os 3 +end + +# Despite being Amstrad formats, CPC System and CPC Data don't have an Amstrad +# superblock. You'll need to use libdsk to access them because the Linux +# and Windows kernel drivers won't touch them. +diskdef cpcsys + seclen 512 + tracks 40 + sectrk 9 + blocksize 1024 + maxdir 64 + skew 1 + boottrk 2 + os 3 +end +diskdef cpcdata + seclen 512 + tracks 40 + sectrk 9 + blocksize 1024 + maxdir 64 + skew 1 + boottrk 0 + os 3 +end + +# after being read in with no sector skew. +diskdef nigdos + seclen 512 + # NigDos double sided disk format, 42 tracks * 2 sides + tracks 84 + sectrk 10 + blocksize 2048 + maxdir 128 + skew 1 + boottrk 0 + # this format wastes half of the directory entry + logicalextents 1 + os 3 +end + +diskdef epsqx10 + seclen 512 + tracks 40 + sectrk 20 + blocksize 2048 + maxdir 128 + skew 0 + boottrk 2 + os 2.2 +end + +diskdef ibm-8ss + seclen 512 + tracks 40 + sectrk 8 + blocksize 1024 + maxdir 64 + skew 0 + boottrk 1 + os 2.2 +end + +diskdef ibm-8ds + seclen 512 + tracks 40 + sectrk 8 + blocksize 1024 + maxdir 64 + skew 0 + boottrk 1 + os 2.2 +end + +diskdef electroglas + seclen 512 + tracks 80 + sectrk 10 + blocksize 2048 + maxdir 256 + skew 0 + boottrk 1 + os 3 +end + +# IBM CP/M-86 +# setfdprm /dev/fd1 sect=8 dtr=1 hd ssize=512 tpi=48 head=1 +diskdef ibmpc-514ss + seclen 512 + tracks 40 + sectrk 8 + blocksize 1024 + maxdir 64 + skew 1 + boottrk 1 + os 2.2 +end + +# IBM CP/M-86 +# setfdprm /dev/fd1 sect=8 dtr=1 hd ssize=512 tpi=48 +diskdef ibmpc-514ds + seclen 512 + tracks 80 + sectrk 8 + blocksize 2048 + maxdir 64 + skew 0 + boottrk 2 + os 2.2 +end + +diskdef p112 + seclen 512 + tracks 160 + sectrk 18 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 2 + os 3 +end + +diskdef p112-old + seclen 512 + tracks 160 + sectrk 18 + blocksize 2048 + maxdir 128 + skew 1 + boottrk 1 + os 3 +end + +diskdef kpii + seclen 512 + tracks 40 + sectrk 10 + blocksize 1024 + maxdir 32 + skew 0 + boottrk 1 + os 2.2 +end + +# setfdprm /dev/fd0 dd sect=10 +diskdef interak + seclen 512 + tracks 80 + sectrk 20 + blocksize 4096 + maxdir 256 + skew 1 + boottrk 2 + os 2.2 +end + +# For 512KB ROM, less 32K for system image +diskdef rom512KB + seclen 128 + tracks 14 + sectrk 256 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 0 + os 2.2 +end + +# For 1024KB ROM, less 32K for system image +diskdef rom1024KB + seclen 128 + tracks 30 + sectrk 256 + blocksize 2048 + maxdir 256 + skew 1 + boottrk 0 + os 2.2 +end + +# For N8VEM mass storage (4 raw partitions) +diskdef hd0 + seclen 512 + tracks 65 + sectrk 256 + blocksize 4096 + maxdir 512 + skew 1 + boottrk 1 + os 2.2 +end + +diskdef hd1 + seclen 512 + tracks 130 + sectrk 256 + blocksize 4096 + maxdir 512 + skew 1 + boottrk 66 + os 2.2 +end + +diskdef hd2 + seclen 512 + tracks 195 + sectrk 256 + blocksize 4096 + maxdir 512 + skew 1 + boottrk 131 + os 2.2 +end + +diskdef hd3 + seclen 512 + tracks 260 + sectrk 256 + blocksize 4096 + maxdir 512 + skew 1 + boottrk 196 + os 2.2 +end diff --git a/trunk/Tools/cpmtools/docs/README.win32.cygwin.txt b/trunk/Tools/cpmtools/docs/README.win32.cygwin.txt new file mode 100644 index 00000000..868e1e8c --- /dev/null +++ b/trunk/Tools/cpmtools/docs/README.win32.cygwin.txt @@ -0,0 +1,518 @@ +README.win32.cygwin.txt +----------------------- + +Building cpmtools-2.9 in Windows XP using: + +- cpmtools http://www.moria.de/~michael/cpmtools/ +- cygwin and the ncurses library - http://www.cygwin.com/ + +"The experts will always complain about shorter documents that do do not +provide enough details to confuse the rest of us, and longer documents that +do not omit enough details to confuse the rest of us. No documentation is +needed for people of that calibre." + +- Bill Buckels, November 2008 + +This document is provided in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. In particular, Bill Buckels has no warranty obligations +or liability resulting from its use in any way whatsoever. If you don't agree +then don't read it. + +Introduction +------------ + +This document is intended as a general guideline. An annotated summary is +provided directly below especially for expert users followed by annotated +details. + +Please review the other documentation and source code that comes with +cpmtools for more information about cpmtools. Please review the cygwin +documentation for more information about cygwin. + +At time of this writing, I have used the latest versions of the packages +listed above to build the latest version of cpmtools in its entirety. I have +documented the steps I followed below. + +Although there are probably other environments and compilers that can build +cpmtools for Windows I have not been successful in using the other several I +tried. Using a complete cygwin installation I had no problems and I had +cpmtools built in moments after I had cygwin installed and the cpmtools +source in place as documented below. + +Intended Audience +----------------- + +This document takes two tracks for installing cpmtools binary executables +after they have been built in cygwin: + +1. End users who will run cpmtools from within the cygwin shell. This +includes unix users who do not want to use the native Windows command line. + +2. End users who will run cpmtools from the native Windows command line. The +average Windows user does not have cygwin, and probably won't want to install +cygwin or learn a unix-like shell to use cpmtools. + +The consideration here is where cpmtools looks for its CP/M disk format +definitions file (diskdefs) when not in a unix-like environment like cygwin +and this consideration will affect the way you build cpmtools since this path +is hardcoded into the binary executables. + +My hope is that this document will help address the needs of both types of +Windows end users and those who wish to provide cpmtools to them. + +Summary +------- + +- Install cygwin with ncurses. +- Download cpmtools-2.9.tar.tar to your cygwin home directory. +- Start cygwin from the shortcut on the Windows desktop. + +- Enter the following commands: + +tar -xvf cpmtools.tar.tar +cd cpmtools-2.9 +./configure --with-diskdefs=/usr/local/share/diskdefs +make +mkdir /usr/local/share +mkdir /usr/local/share/man +mkdir /usr/local/share/man/man1 +mkdir /usr/local/share/man/man5 +make install + +Assumptions +----------- + +The above builds cpmtools under cygwin for end users who will use cpmtools in +the cygwin shell and who will use the default installation. + +I am assuming in this summary that all has gone well and that anyone who +deviates from what I have done or who has customized their cygwin +installation will be able to troubleshoot their own problems, + +I therefore make the following related assumptions in this summary: + +- That compiler related programs and libraries required to build cpmtools +under cygwin (including ncurses) are installed. + +- That you wish to download into and work under your home directory. You may +also consider whether a better place to download is in /usr/local/src and +whether you should install in the binaries in /opt/cpmtools/ and things of +that nature. + +Default Format +-------------- + +You can change the default format to accomodate the special needs of your +users so they don't need to type their favorite format. The following line +can be entered to configure for an apple-do default format: + +./configure --with-defformat="apple-do" --with-diskdefs=/usr/local/share/diskdefs + +Native Windows Installation +--------------------------- + +If you wish to distribute your binaries to Windows end users who will not +have the cygwin shell and who will use the Windows command line, you have 2 +options: + +1. Require your users to always work in the same directory as diskdefs. + +- or - + +2. Hardcode the default diskdefs path into your binary executables and +require your users to always use the expected directory for diskdefs. + +The following line shows how to configure for an apple-do default format and +to set the default diskdefs path in a mannner that is acceptable to Windows +to a relative path from the root of the current drive: + +./configure --with-defformat="apple-do" --with-diskdefs=/cpmtools/diskdefs + +Cross-Cygwin Binary Installation +-------------------------------- + +You can still use the binaries built as above and installed using "make +install" in cygwin if you add the following line to /etc/fstab (assuming your +cygdrive is the Windows C:drive): + +c:\cygwin\usr\local\share /cpmtools + +Making a Zip Installation for Native Windows Users +-------------------------------------------------- + +If your target is the Windows user who does not have cygwin you can do the +following in cygwin in your build directory to create a zip file that will +contain the cpmtools binary executables: + +- mkdir cpmtools +- cp *.exe cpmtools/. +- cp diskdefs cpmtools/. +- cp /bin/cygwin1.dll cpmtools/. +- cp /bin/cygncurses-8.dll cpmtools/. +- zip -R cpmtools/*.* + +Making Documentation for Native Windows Users +--------------------------------------------- + +If you wish to provide the cpmtools manual pages in html format you can use +man2html to generate your html in ugly format and redirect to a file and edit +by hand. Here's an example: + +man2html -r cpm.5 > cpm.html + +If you wish to avoid html and provide the cpmtools manual pages in text +format you can use troff to generate your text in ugly format and redirect to +a file and edit by hand. Here's an example: + +troff -a cpm.5 > cpm.txt + +This concludes the summary. + +Details, Alternatives, and Other Fluff +-------------------------------------- + +1.cygwin +-------- + +Cygwin gave me a complete and free environment to both configure and build +cpmtools in its entirety. + +I installed cygwin from http://www.cygwin.com/ in its entirety which included +the ncurses library and when prompted to select a download site I chose +ftp://mirrors.kernel.org/sourceware/cygwin/ + +The site you pick will depend on your own preference and how much of cygwin +you decide to install will be up to you. I have a good Internet connection +and a large hard disk so installing ALL of cygwin was no problem for me. +Those who don't may wish to attempt an incremental installation which I +personally found to be annoying and tedious. + +It is not necessary to install ALL cygwin options. Another alternative is to +take the minimalistic approach and just install the compiler related +programs and libraries required to build cpmtools (including ncurses). If you +have missed something you will still be able to select additional components +via Cygwin Setup. + +By default cygwin installs into c:\cygwin and puts a shortcut on the Windows +desktop. By default the cygwin shell starts in your cygwin home directory +under c:\cygwin\home\. I used the cygwin default paths for my installation of +cygwin. + +2. cpmtoools +------------ + +I then downloaded Download cpmtools-2.9 from +http://www.moria.de/~michael/cpmtools/ +and used WinRAR to extract cpmtools-2.9 to +C:\cygwin\home\bbuckels\cpmtools-2.9\ + +I have noted in the summary that tar can be used. Use whatever you are +comfortable with to handle things from unix of a tarball nature. + +3. Building +----------- + +3.1. I started cygwin by clicking on the cygwin shortcut on my desktop which +placed me into my cygwin home directory in the cygwin shell. + +3.2 Now in the cygwin shell, I changed to the cpmtools directory by typing +the following and pressing the [Enter] key: + +cd cpmtools-2.9 + + +3.3 Running the configure script +-------------------------------- + +Before making cpmtools, the configure script must be run to create the +cpmtools makefile and the config.h header file required by cpmtools. + +I ran the configure script with two options; to set the default format for +cpmtools to Apple II DOS 3.3 disk images and to tell cpmtools where to find +the diskdefs format definitions file (which is required to run cpmtools. See +far below.) + +3.3.2 Building for use in the cygwin shell +------------------------------------------ + +If I was building for use in the cygwin shell and I was using the default +paths used by "make install" noted far below, to be certain that my diskdefs +file would be found and to set my default format to "apple-do" I would type +the following and press the [Enter] key: + +./configure --with-defformat="apple-do" --with-diskdefs=/usr/local/share/diskdefs + +3.3.1 Building for the Native Windows command line +--------------------------------------------------- + +To set the default format to "apple-do" and to provide a relative path for +native Windows to my diskefs file which I would later copy to C:\cpmtools\ , +I typed the following and pressed the [Enter] key: + +./configure --with-defformat="apple-do" --with-diskdefs=/cpmtools/diskdefs + +Note: Windows paths are typed into the Windows native command line with +backslashes in the MS- DOS tradition. Historically the forward slash used by +unix as a path separator was used as a switch character in MS-DOS utilities +and this has carried forward with the commands that come with Windows. But in +a program, local Windows paths can be used with forward slashes instead and +they still work. Backslashes will cause problems for configure so use forward +slashes. + +3.4. The configure script created my cpmtools makefile and config.h with the +options I chose. I then ran make by typing the following and pressing the +[Enter] Key. + +make + +This concludes the first part of the details section of this document and I +have covered the basic steps that I followed to build cpmtools. What you do +will likely be a close variation. + +4. Installing +------------- + +4.1 Some of this is also noted in the summary. Also keep in mind that if +cpmtools is used outside of cygwin access to the documentation which is in +the form of unix-style man pages will not be available unless reformatted to +a media type that Windows users are familiar with. + +4.1.1 Installing for the cygwin shell +----------------------------------- + +You can review the summary and the cpmtools INSTALL document for more +information on unix-like installations. Installation of cpmtools for use in +the cygwin shell follows those conventions. + +If installing cpmtools to be used in cygwin using the cpmtools defaults and +assuming the directories below don't already exist, you will need to manually +create the following directories using the mkdir command as follows: + +mkdir /usr/local/share +mkdir /usr/local/share/man +mkdir /usr/local/share/man/man1 +mkdir /usr/local/share/man/man5 + +This is because the manual pages (man pages) will not be installed if you +don't. If you install the man pages, then when you need help on cpmtools in +cygwin, you can just enter "man cpmls" or "man cpmchmod", etc. + +After you make the directories above enter the following command: + +make install + +Assuming all has gone well, cpmtools is now part of your cygwin installation +and can be used wherever you work in cygwin. + +4.1.2 Installing for Use Outside Cygwin +--------------------------------------- + +Please also read the summary. + +The requirements of my installation were to create a directory structure for +a binary executable version of cpmtools targetted at Apple II disk image +users that would run at the native Windows cmd prompt. I offer the following +for general reference. The cygwin paths are based on my installation of +cygwin and are presented using conventional windows pathname notation. + +4.1.2.1 Dll's +------------- + +Two dll's from the c:\cygwin\bin\ directory were required: + +cygwin1.dll +cygncurses-8.dll + +Regardless of installation, for this cygwin and this ncurses version access +to these dll's will be required by this version of the cpmtools excecutables. + +4.2 Manually Placing Files for Use Outside Cygwin +------------------------------------------------- + +I did my installation by hand. + +My executables were created in c:\cygwin\home\bbuckels\cpmtools-2.9\ (my +cygwin home directory) which is also where the diskdefs file was. + +I used Windows Explorer to manually do the following: + +4.2.1 create c:\cpmtools\ directory. +4.2.2 copy all 8 exes into c:\cpmtools\ +4.2.3 copy both dll's listed above into c:\cpmtools\ +4.2.4 copy diskdefs into c:\cpmtools\ + +This gave me my directory structure and files for testing and distribution. + +I also placed an Apple II CP/M disk image called EXMPLCPM.dsk in c:\cpmtools\ +as a test target. + + +5. Additional Notes +------------------- + +5.1 diskdefs - CP/M disk format definitions +-------------------------------------------- + +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available CP/M +formats and their names. For Apple II CP/M 80 users the disk image formats +apple-do and apple-po are available. + +The possible locations where cpmtools first looks for the diskdefs file: + +- Can vary depending on the preferences of the person who builds the cpmtools +binaries (executables) from the source code. + +- The location is also installation dependent and the diskdefs file may also +have been renamed (but we hope not). + +If it's not found the current (work) directory is then searched for a file +called diskdefs. + +On a unix-like system, a ${prefix}/share/ style path like /usr/local/share/ +is a possible place that cpmtools could be made to first look for diskdefs. + +In a Win32 system sometimes unix-like shells like cygwin are used to run +cpmtools instead of Windows cmd. For those installations unix-like +conventions probably should apply. + +For cpmtools installations targetted at the average Windows user who does not +have a unix-like shell and uses the Windows cmd prompt to run cpmtools there +is no standard shared place that cpmtools can be made to first look for +diskdefs. Pathed File names like \cpm\diskdefs or even c:\cpmtools\diskdefs +are possible. + +5.2 Difficulties in using the Windows File System +--------------------------------------------------- + +This is not a troubleshooting guide. Unless you wish to find-out for yourself +as I did just how many problems you can face with all of this, or you are +really an expert, please do yourself a favour and try to stay within what I +am suggesting as standard or alternative ways of building cpmtools. + +Missing libaries and compiler tools can be solved by trial and error and +reading the cygwin and cpmtools documentation. + +There are however some things about path names and file names that you need +to be aware of, some of which I have mentioned throughout this document and +some which I deliberately did not mention yet, like avoiding absolute paths +and drive letters. + +If you use a drive letter like C: when hardcoding a path to diskdefs you are +making several assumptions: + +First off, you are assuming that your build of cpmtools will only be run from +within Windows cmd shell on the local drive C:, (not from a bash-like shell +like cygwin which doesn't support drive letters the same way Windows cmd and +Windows itself does), and that diskdefs will not be on another drive, and +that drive C: exists in the first place, and that diskdefs is not on a +Windows network either unless drive C:,X:,Y:,Z:,etc is a mapped network +drive. It is questionable whether cpmtools build process for diskdefs pathing +supports UNC pathing anyway. I couldn't get \\ to work since the first slash +disappears in the configure script and the second slash becomes an escape +sequence for the next letter. + +Relative pathing will work and if you want to use conventions like +/cpmtools-2.9/diskedefs this will work. Environments like ${USERPROFILE} +aren't a good idea even if I could have got them to work since they are not +portable for several reasons and I will say no more on this except I +recommend that any path that you decide to use for diskdefs will only be +almost portable between shells if off the root directory and contains forward +slashes and no drive letters or colons. + +I hope what I have said proved less confusing to read than to write if you +have bothered to read it. If you are not confused yet read further. + +- Since cpmtools has special meanings for A: and B: as command line targets +it probably isn't a good idea to use these drives especially. + +- Some programmers and users have no difficulty in shifts between unix-like +and Windows pathing. Some will be familiar with how colons are used on +systems like Mac OSX. I think the only point to be made here is to consider +your target audience and all the things you can anticipate going wrong with +interoperability of all of this, (cpmtools being a set of command line +tools), and build cpmtools accordingly for the needs of you or your users, +then test what you have built with all this in mind. + +5.3 Testing your build of cpmtools +---------------------------------- + +To test what you have built I suggest you start with cpmls and cpmcp and an +apple disk image or equivalent. + +John Elliot said "If you have appropriate rights, the CPMTOOLS should be able +to access the floppy drive by using "A:" or "B:" as the name of the disc +image.". I say don't bother mucking with your physical disk drive unless you +have a physical CP/M disk of a format supported by cpmtools safely in the +drive. + +Get an apple CP/M disk image and use it for testing is what I suggest. The +following examples assume you have an Apple II DOS 3.3 order disk image +called EXMPLCPM.dsk for testing. + +To list the files: + +cpmls -f apple-do EXMPLCPM.dsk + +The following example shows how to copy a file from an Apple II DOS 3.3 order +cpm disk image to the current directory: + +cpmcp -f apple-do EXMPLCPM.dsk bhead.c 0:bhead.c + +The following example shows how to copy a file to an Apple II DOS 3.3 order +cpm disk image from the current directory: + +cpmcp -f apple-do EXMPLCPM.dsk 0:bhead.c bhead.c + +To test the other utilities in cpmtools like cpmrm, cpmchattr, cpmchmod, +fsck.cpm and fsed.cpm, review the appropriate manpages for usage. + +Those are simple tests as well using an apple-do format disk image. For +mkfs.cpm I will leave it to those more capable than I to decide what to do +there. Compared to them I am merely dangerous. + +Acknowledgements and Stuff +-------------------------- + +Michael Haardt - for cpmtools in the first place and for his tireless and +ongoing efforts in supporting cpmtools in the second. + +John Elliot - for bringing cpmtools to Windows. + +My focus is on Windows XP (and other Windows) users and making this available +to them. At this point in time my focus is also on Apple II Z80 Softcard +users. Thankfully Michael Haardt has considered Apple II disk images in +cpmtools. My focus is also on the Aztec C Z80 MS-DOS cross-compiler which +creates Apple II CP/M programs in Windows XP. + +Between Michael and John, with cpmtools I can now easily get these onto an +Apple disk image and transfer the disk image over to my real Apple II which +has a Z80 softcard clone using my Microdrive with a CF card and make a real +CP/M disk from the image with DISKMAKER.8 or DSK2FILE then run my Aztec C +CP/M programs using the real thing. I can also use the emulator that came +with Apple II Oasis to run the disk image. + +Apparently nothing is missing from cpmtools for Windows XP that is available +on cpmtools for unix-like systems and I am thankful for that. Hopefully you +will be too. + +I would also like to acknowledge the following individuals from the +comp.os.cpm and apple2.sys usenet newsgroups who gave their experience, +thoughts and encouragement during my adventure with all of this and in no +particular order: + +David Schmidt - for cygwin feedback. +Udo Munk - for cygwin feedback. +Peter Dassow - for cygwin feedback. +Stevo Tarkin - for msys feedback. +Volker Pohlers - for msys and pdcurses feedback. +Rolf Harmann - for linux feedback. +Richard Brady - who may or may not know watfor:) + +If I missed anyone, I thank them too. I am somewhat new to some of this and +needed all the help I received. cygwin is now my friend. + +Bill Buckels +bbuckels@mts.net +November 2008 \ No newline at end of file diff --git a/trunk/Tools/cpmtools/docs/cpm.htm b/trunk/Tools/cpmtools/docs/cpm.htm new file mode 100644 index 00000000..d4a165f6 --- /dev/null +++ b/trunk/Tools/cpmtools/docs/cpm.htm @@ -0,0 +1,357 @@ +CPM - CP/M disk and file system format + + + +

CPM

+Section: File formats (5)
+Updated: June 16, 2008

+ +Index   +Return to Main Contents   +Disclaimer  


+ +  +NAME cpm - CP/M disk and file system format.

+ +  +DESCRIPTION

+ +  +Characteristic sizes - Each CP/M disk format is described by the following specific sizes: +
+ +
+ +Sector size in bytes +
+ +Number of tracks +
+ +Number of sectors +
+ +Block size +
+ +Number of directory entries +
+ +Logical sector skew +
+ +Number of reserved system tracks +

+
+ +A block is the smallest allocatable storage unit. CP/M supports block +sizes of 1024, 2048, 4096, 8192 and 16384 bytes. Unfortunately, this +format specification is not stored on the disk and there are lots of +formats. Accessing a block is performed by accessing its sectors, which +are stored with the given software skew. +

+ +  +Device areas - A CP/M disk contains three areas:
+ +
+ +System tracks (optional) +
+ +Directory +
+ +Data +

+
+ +The system tracks store the boot loader and CP/M itself. In order to save +disk space, there are non-bootable formats which omit those system tracks. +The term disk capacity always excludes the space for system tracks. +Note that there is no bitmap or list for free blocks. When accessing a +drive for the first time, CP/M builds this bitmap in core from the directory. +

+ +  +Directory entries - The directory is a sequence of directory entries (also called extents), +which contain 32 bytes of the following structure:
+
+ +St F0 F1 F2 F3 F4 F5 F6 F7 E0 E1 E2 Xl Bc Xh Rc
+
+ +Al   Al Al Al Al Al Al Al Al Al Al Al Al Al AlAl
+
+
+ + +St is the status; possible values are:
+
+ +0-15: used for file, status is the user number +
+ +16-31: used for file, status is the user number (P2DOS) +or used for password extent (CP/M 3 or higher) +
+ +32: disc label +
+ +33: time stamp (P2DOS) +
+ +0xE5: unused +

+
+ +F0-E2 are the file name and its extension. They may consist of +any printable 7 bit ASCII character but: < > . , ; : = ? * [ ]. +The file name must not be empty, the extension may be empty. Both are +padded with blanks. The highest bit of each character of the file name +and extension is used as attribute. The attributes have the following +meaning:
+ + +
+F0: requires set wheel byte (Backgrounder II) +
+ +F1: public file (P2DOS, ZSDOS), forground-only command (Backgrounder II) +
+ +F2: date stamp (ZSDOS), background-only commands (Backgrounder II) +
+ +F7: wheel protect (ZSDOS) +
+ +E0: read-only +
+ +E1: system file +
+ +E2: archived +

+
+ +Public files (visible under each user number) are not supported by CP/M +2.2, but there is a patch and some free CP/M clones support them without +any patches. +

+ +The wheel byte is (by default) the memory location at 0x4b. If it is +zero, only non-privileged commands may be executed. + +

+ + +Xl and Xh store the extent number. A file may use more than +one directory entry, if it contains more blocks than an extent can hold. +In this case, more extents are allocated and each of them is numbered +sequentially with an extent number. If a physical extent stores more than +16k, it is considered to contain multiple logical extents, each pointing +to 16k data, and the extent number of the last used logical extent +is stored. Note: Some formats decided to always store only one logical +extent in a physical extent, thus wasting extent space. CP/M 2.2 allows +512 extents per file, CP/M 3 and higher allow up to 2048. Bit 5-7 of +Xl are 0, bit 0-4 store the lower bits of the extent number. Bit 6 +and 7 of Xh are 0, bit 0-5 store the higher bits of the extent number. + +

+ + +Rc and Bc determine the length of the data used by this extent. The +physical extent is divided into logical extents, each of them being 16k +in size (a physical extent must hold at least one logical extent, e.g. a +blocksize of 1024 byte with two-byte block pointers is not allowed). +Rc stores the number of 128 byte records of the last used logical extent. +Bc stores the number of bytes in the last used record. The value 0 means +128 for backward compatibility with CP/M 2.2, which did not support Bc. + +

+ + +Al stores block pointers. If the disk capacity is less than 256 blocks, +Al is interpreted as 16 byte-values, otherwise as 8 double-byte-values. +A block pointer of 0 marks a hole in the file. If a hole +covers the range of a full extent, the extent will not be allocated. In particular, +the first extent of a file does not neccessarily have extent number 0. +A file may not share blocks with other files, as its blocks would be freed +if the other files is erased without a following disk system reset. CP/M returns +EOF when it reaches a hole, whereas UNIX returns zero-value bytes, which makes +holes invisible. +

+ +  +Time stamps - P2DOS and CP/M Plus support time stamps, which are stored in each fourth +directory entry. +

+This entry contains the time stamps for +the extents using the previous three directory entries. Note that you +really have time stamps for each extent, no matter if it is the first +extent of a file or not. The structure of time stamp entries is:
+ +
+ +1 byte status 0x21 +
+ +8 bytes time stamp for third-last directory entry +
+ +2 bytes unused +
+ +8 bytes time stamp for second-last directory entry +
+ +2 bytes unused +
+ +8 bytes time stamp for last directory entry +

+
+ +A time stamp consists of two dates: Creation and modification date (the +latter being recorded when the file is closed). CP/M Plus further +allows optionally to record the access instead of creation date as first +time stamp.
+ +
+2 bytes (little-endian) days starting with 1 at 01-01-1978 +
+ +1 byte hour in BCD format +
+ +1 byte minute in BCD format +

+
+ + +  +Disc labels - CP/M Plus supports disc labels, which are stored in an arbitrary directory +entry. +

+The structure of disc labels is:
+ +
+1 byte status 0x20 +
+ +F0-E2 are the disc label +
+ +1 byte mode: bit 7 activates password protection, bit 6 causes time stamps on +access, but 5 causes time stamps on modifications, bit 4 causes time stamps on +creation and bit 0 is set when a label exists. Bit 4 and 6 are exclusively set. +
+ +1 byte password decode byte: To decode the password, xor this byte with the password +bytes in reverse order. To encode a password, add its characters to get the +decode byte. +
+ +2 reserved bytes +
+ +8 password bytes +
+ +4 bytes label creation time stamp +
+ +4 bytes label modification time stamp +

+
+ + +  +Passwords - CP/M Plus supports passwords, which are stored in an arbitrary directory entry. +

+ +The structure of these entries is:
+ +
+ +1 byte status (user number plus 16) +
+ +F0-E2 are the file name and its extension. +
+ +1 byte password mode: bit 7 means password required for reading, bit 6 for writing +and bit 5 for deleting. +
+ +1 byte password decode byte: To decode the password, xor this byte with the password +bytes in reverse order. To encode a password, add its characters to get the +decode byte. +
+ +2 reserved bytes +
+ +8 password bytes +

+
+ + + +  +SEE ALSO

+ +mkfs.cpm(1), + +fsck.cpm(1), + +fsed.cpm(1), + +cpmls(1) + + +

+ +
+ Index
+
+
NAME cpm - CP/M disk and file system format
+
DESCRIPTION
+
+
Characteristic sizes
+
Device areas
+
Directory entries
+
Time stamps
+
Disc labels
+
Passwords
+
+
SEE ALSO
+
+
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ diff --git a/trunk/Tools/cpmtools/docs/cpmchattr.htm b/trunk/Tools/cpmtools/docs/cpmchattr.htm new file mode 100644 index 00000000..f1a98984 --- /dev/null +++ b/trunk/Tools/cpmtools/docs/cpmchattr.htm @@ -0,0 +1,256 @@ +CPMCHATTR - change file attributes on CP/M files + + +

CPMCHATTR

+Section: User commands (1)
+Updated: June 16, 2008

+ +Index   +Return to Main Contents   +Disclaimer  


+ + +  +NAME cpmchattr - change file attributes on CP/M files.

+ + +  +SYNOPSIS

+ + +cpmchattr + +[-f + +format] + +image + +attrib + +file-pattern + +... + +

+ +Note: Wildcards like *.com should be preceded with the user number +using a pattern like 0:*.com. +
+
+ + +  +DESCRIPTION

+ +Cpmchattr changes the file attributes for files on CP/M disks. +
+
+ + +  +OPTIONS

+ +
+ +
-f
+ +Use the given CP/M disk format instead of the default format. +

+For Apple II CP/M 80 users the cpmchattr command may have no practical +effect. Try +cpmchmod instead for setting read only +attributes. +

+ +
attrib Set the file attributes as given.
+ +
+
+ +  +FILE ATTRIBUTES - The file attribute string can contain the characters +1,2,3,4,s,a,N and M.

+ +The meanings of these are: + +
+
1-4
+ +
+The CP/M "user attributes" F1-F4. CP/M does not assign any +meaning to these attributes, though MP/M does. +
+ +
s
+ +
+The file is a system file. This attribute can also be set by +cpmchmod(1). + +
a
+ +
+The file has been backed up. +
N
+ +
+Reset all attributes to zero. So the string "N1r" resets all attributes and +then sets F1 and Read-Only. +
M
+ +
+Attributes after an M are unset rather than set. The string "12M34" sets +atttributes F1 and F2, and unsets F3 and F4. +

+
+ +  +RETURN VALUE - Upon successful completion, exit code 0 is returned.

+ +This will likely only be of interest to programmers. In a Win32 system the +exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +ERRORS - Any errors are indicated by exit code 1.

+ +This will likely only be of interest to programmers. In a Win32 system the +exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +FILES - diskdefs - CP/M disk format definitions

+ +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available CP/M +formats and their names. For Apple II CP/M 80 users the disk +image formats apple-do and apple-po are available. +

+For Apple II CP/M 80 users the cpmchattr command may have no +practical effect. Try +cpmchmod instead for setting read only +attributes. +

+The possible locations where cpmtools first looks for the diskdefs file: +
+
+- Can vary depending on the preferences of the person who builds the +cpmtools binaries (executables) from the source code. +

+- The location is also installation dependent and the diskdefs file +may also have been renamed. +
+
+If it's not found the current (work) directory is then searched for a +file called diskdefs. +
+
+On a unix-like system, a ${prefix}/share/ style path +like /usr/local/share/ is a possible place that cpmtools will first +look for diskdefs. +
+
+In a Win32 system sometimes unix-like shells like cygwin +are used to run cpmtools instead of Windows cmd. For those installations +unix-like conventions probably apply. +
+
+For cpmtools installations targetted at the average +Windows user who does not have a unix-like shell and uses the Windows cmd +prompt to run cpmtools there is no standard shared place that cpmtools will first +look for diskdefs. Pathed File names like \cpm\diskdefs or +even c:\cpmtools\diskdefs are possible. +
+
+ +  +AUTHORS +
+
+This program is copyright 1997-2008 Michael Haardt <michael@moria.de> and +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +

+ + +This program is free software; you can redistribute it and/or modify +it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +

+ +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+ +You should have received a copy of the GNU General Public License along +with this program. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+ + +  +SEE ALSO

+ +cmpls(1), + +cpmchmod(1), + +cpm(5) + +

+ +
+ + Index +
+
+ +
+
NAME cpmchattr - change file attributes on CP/M files.
+
SYNOPSIS
+
DESCRIPTION
+
+
OPTIONS
+
FILE ATTRIBUTES
+
RETURN VALUE
+
ERRORS
+
FILES
+
+
AUTHORS
+
SEE ALSO
+
+ +
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ + diff --git a/trunk/Tools/cpmtools/docs/cpmchmod.htm b/trunk/Tools/cpmtools/docs/cpmchmod.htm new file mode 100644 index 00000000..72f1c48e --- /dev/null +++ b/trunk/Tools/cpmtools/docs/cpmchmod.htm @@ -0,0 +1,251 @@ +CPMCHMOD - change file mode on CP/M files + + +

CPMCHMOD

+Section: User commands (1)
+Updated: June 16, 2008

+ +Index   +Return to Main Contents   +Disclaimer  


+ +  +NAME cpmchmod - change file mode on CP/M files.

+ +  +SYNOPSIS

+ +cpmchmod + +[-f + +format] + +image + +mode + +file-pattern + +... + +

+ +Note: Wildcards like *.com should be preceded with the user number +using a pattern like 0:*.com. +
+
+ +  +DESCRIPTION

+ +Cpmchmod changes the file mode for files on CP/M disks. +
+
+ +  +OPTIONS

+ +
+ +
-f
+ +Use the given CP/M disk format instead of the default format. +

+ + +
mode Octal file mode, as used in the unix command chmod.
+ +
+Numeric (Octal) file mode: +
+
+From one to four octal digits. Any omitted digits are assumed to be leading zeros. +
+
+chmod Examples: +
+
+chmod 400 file - Read by owner
+chmod 040 file - Read by group
+chmod 004 file - Read by world +
+
+chmod 200 file - Write by owner
+chmod 020 file - Write by group
+chmod 002 file - Write by world +
+
+chmod 100 file - execute by owner
+chmod 010 file - execute by group
+chmod 001 file - execute by world +
+
+To combine these, just add the numbers together: +
+
+chmod 444 file - Allow read permission to owner and group and world
+chmod 777 file - Allow everyone to read, write, and execute file +
+
+
+cmpchmod Examples: +
+
+The following example shows how to change a file on an Apple II DOS 3.3 +order cpm disk image to read only: +
+
+cpmchmod -f apple-do exmplcpm.dsk 444 bhead.c +
+
+The following example shows how to change a file on an Apple II DOS 3.3 +order cpm disk image to read/write: +
+
+cpmchmod -f apple-do exmplcpm.dsk 666 bhead.c +
+
+ +  +RETURN VALUE - Upon successful completion, exit code 0 is returned.

+ +This will likely only be of interest to programmers. In a Win32 system the +exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +ERRORS - Any errors are indicated by exit code 1.

+ +This will likely only be of interest to programmers. In a Win32 system the +exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +FILES - diskdefs - CP/M disk format definitions

+ +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available CP/M +formats and their names. For Apple II CP/M 80 users the disk +image formats apple-do and apple-po are available. +

+The possible locations where cpmtools first looks for the diskdefs file: +
+
+- Can vary depending on the preferences of the person who builds the +cpmtools binaries (executables) from the source code. +

+- The location is also installation dependent and the diskdefs file +may also have been renamed. +
+
+If it's not found the current (work) directory is then searched for a +file called diskdefs. +
+
+On a unix-like system, a ${prefix}/share/ style path +like /usr/local/share/ is a possible place that cpmtools will first +look for diskdefs. +
+
+In a Win32 system sometimes unix-like shells like cygwin +are used to run cpmtools instead of Windows cmd. For those installations +unix-like conventions probably apply. +
+
+For cpmtools installations targetted at the average +Windows user who does not have a unix-like shell and uses the Windows cmd +prompt to run cpmtools there is no standard shared place that cpmtools will first +look for diskdefs. Pathed File names like \cpm\diskdefs or +even c:\cpmtools\diskdefs are possible. +
+
+ +  +AUTHORS +
+
+This program is copyright 1997-2008 Michael Haardt <michael@moria.de> and +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +

+ + +This program is free software; you can redistribute it and/or modify +it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +

+ +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+ +You should have received a copy of the GNU General Public License along +with this program. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+ +  +SEE ALSO

+ +cmpls(1), + +cpm(5) + +

+ + +
+ + Index +
+
+ +
+
NAME cpmchmod - change file mode on CP/M files.
+
SYNOPSIS
+
DESCRIPTION
+
+
OPTIONS
+
RETURN VALUE
+
ERRORS
+
FILES
+
+
AUTHORS
+
SEE ALSO
+
+ + +
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ + diff --git a/trunk/Tools/cpmtools/docs/cpmcp.htm b/trunk/Tools/cpmtools/docs/cpmcp.htm new file mode 100644 index 00000000..9d9b676f --- /dev/null +++ b/trunk/Tools/cpmtools/docs/cpmcp.htm @@ -0,0 +1,290 @@ +CPMCP - copy files from and to CP/M disks + + +

CPMCP

+Section: User commands (1)
+Updated: June 16, 2008

+ +Index   +Return to Main Contents   +Disclaimer  


+ +  +NAME cpmcp - copy files from and to CP/M disks.

+ + +  +SYNOPSIS

+ +cpmcp + +[-f + +format] + +[-p] + +[-t] + +image + +user:file file +
+
+ +cpmcp + +[-f + +format] + +[-p] + +[-t] + +image + +user:file ... directory +
+
+ +cpmcp + +[-f + +format] + +[-p] + +[-t] + +image + +file user:file +
+
+ +cpmcp + +[-f + +format] + +[-p] + +[-t] + +image + +file ... user: + +

+ +  +DESCRIPTION

+ +Cpmcp copies one or more files to or from a CP/M disk. +
+
+ + +When copying multiple files, the last argument must be a drive or directory. +The drive letter does not matter because the device is specified by the +image, it is only used to specify which direction you want to copy. The user +number is specified after the drive letter, if omitted user 0 is used. +

+ +You can use * and ? as "wildcards" in CP/M file names, +which have the same meaning in unix-like shells, and also on the MS-DOS +and Windows command lines for file name patterns. + +
+
+ +  +OPTIONS

+ +
+ +
-f
+ +Use the given CP/M disk format instead of the default format. +

+For Apple II CP/M 80 +users the disk image formats apple-do and apple-po are available. These +are DOS3.3 order and ProDOS order disk image formats respectively, and must always be specified +using the form -f apple-do or -f apple-po. +

+ +
-p
+Preserve time stamps when copying files from CP/M to UNIX (not +implemented for copying the other way so far). +
+
+ + +
-t
+Convert text files between CP/M and UNIX conventions. +
+ +
+ +Examples: +
+
+The following example shows how to copy a file from an Apple II DOS 3.3 order cpm disk image +to the current directory: +
+
+cpmcp -f apple-do exmplcpm.dsk bhead.c 0:bhead.c +
+
+The following example shows how to copy a file to an Apple II DOS 3.3 order cpm disk image +from the current directory: +
+
+cpmcp -f apple-do exmplcpm.dsk 0:bhead.c bhead.c +
+
+ +  +RETURN VALUE - Upon successful completion, exit code 0 is returned.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +ERRORS - Any errors are indicated by exit code 1.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +FILES - diskdefs - CP/M disk format definitions

+ +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available +CP/M formats and their names. For Apple II CP/M 80 users the disk +image formats apple-do and apple-po are available. +

+The possible locations where cpmtools first looks for the diskdefs file: +
+
+- Can vary depending on the preferences of the person who builds the +cpmtools binaries (executables) from the source code. +

+- The location is also installation dependent and the diskdefs file +may also have been renamed. +
+
+If it's not found the current (work) directory is then searched for a +file called diskdefs. +
+
+On a unix-like system, a ${prefix}/share/ style path +like /usr/local/share/ is a possible place that cpmtools will first +look for diskdefs. +
+
+In a Win32 system sometimes unix-like shells like cygwin +are used to run cpmtools instead of Windows cmd. For those installations +unix-like conventions probably apply. +
+
+For cpmtools installations targetted at the average +Windows user who does not have a unix-like shell and uses the Windows cmd +prompt to run cpmtools there is no standard shared place that cpmtools will first +look for diskdefs. Pathed File names like \cpm\diskdefs or +even c:\cpmtools\diskdefs are possible. +
+
+ + +  +AUTHORS +
+
+This program is copyright 1997-2008 Michael Haardt <michael@moria.de>. +The Windows port is +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +

+ + +This program is free software; you can redistribute it and/or modify +it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +

+ +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+ +You should have received a copy of the GNU General Public License along +with this program. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+ +  +SEE ALSO

+ +cmpls(1), + +cpm(5) + +

+ +
+ + Index +
+
+ +
+
NAME cpmcp - copy files from and to CP/M disks.
+
SYNOPSIS
+
DESCRIPTION
+
+
OPTIONS
+
RETURN VALUE
+
ERRORS
+
FILES
+
+
AUTHORS
+
SEE ALSO
+
+ +
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ diff --git a/trunk/Tools/cpmtools/docs/cpmls.htm b/trunk/Tools/cpmtools/docs/cpmls.htm new file mode 100644 index 00000000..0617ea24 --- /dev/null +++ b/trunk/Tools/cpmtools/docs/cpmls.htm @@ -0,0 +1,235 @@ +CPMLS - list sorted contents of directory + + +

CPMLS

+Section: User commands (1)
+Updated: June 16, 2008

+ +Index   +Return to Main Contents   +Disclaimer  


+ + +  +NAME cpmls - list sorted contents of directory

+ +  +SYNOPSIS

+ + +cpmls + +[-d|-D|-F|-A|-l[-c][-i]] + +[-f + +format] + +image + +[file-pattern...] +

+ +  +DESCRIPTION

+ +Cpmls lists the sorted contents of the directory. +
+
+ +  +OPTIONS

+ +
+ +
-f
+ +Use the given CP/M disk format instead of the default format. +

+For Apple II CP/M 80 +users the disk image formats apple-do and apple-po are available. These +are DOS3.3 order and ProDOS order disk image formats respectively, and must always be specified +using the form -f apple-do or -f apple-po. +

+ +
-d
+Old CP/M 2.2 dir output. +

+ +
-D
+P2DOS 2.3 ddir-like output. +

+ +
-F
+CP/M 3.x dir output. +

+ +
-A
+E2fs lsattr-like output. +

+ +
-l
+Long UNIX-style directory listing including size, time stamp and user number. +

+ +
-c
+Output the creation time, not the modification time. +

+ +
-i
+Print index number of each file. +
+
+ +Example: +
+
+The following example shows how to list the files on an Apple II DOS 3.3 +order cpm disk image using a unix-like output: +
+
+cpmls -f apple-do -l exmplcpm.dsk +
+
+ +  +RETURN VALUE - Upon successful completion, exit code 0 is returned.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +ERRORS - Any errors are indicated by exit code 1.

+ +This will likely only be of interest to programmers. In a Win32 system the +exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +FILES - diskdefs - CP/M disk format definitions

+ +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available +CP/M formats and their names. For Apple II CP/M 80 users the disk +image formats apple-do and apple-po are available. +

+The possible locations where cpmtools first looks for the diskdefs file: +
+
+- Can vary depending on the preferences of the person who builds the +cpmtools binaries (executables) from the source code. +

+- The location is also installation dependent and the diskdefs file +may also have been renamed. +
+
+If it's not found the current (work) directory is then searched for a +file called diskdefs. +
+
+On a unix-like system, a ${prefix}/share/ style path +like /usr/local/share/ is a possible place that cpmtools will first +look for diskdefs. +
+
+In a Win32 system sometimes unix-like shells like cygwin +are used to run cpmtools instead of Windows cmd. For those installations +unix-like conventions probably apply. +
+
+For cpmtools installations targetted at the average +Windows user who does not have a unix-like shell and uses the Windows cmd +prompt to run cpmtools there is no standard shared place that cpmtools will first +look for diskdefs. Pathed File names like \cpm\diskdefs or +even c:\cpmtools\diskdefs are possible. +
+
+ +  +AUTHORS +
+
+This program is copyright 1997-2008 Michael Haardt <michael@moria.de>. +The Windows port is +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +

+ + +This program is free software; you can redistribute it and/or modify +it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +

+ +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+ +You should have received a copy of the GNU General Public License along +with this program. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+ +  +SEE ALSO

+ +cpmcp(1), + +cpm(5) + +

+ + +
+ + Index +
+
+ +
+
NAME cpmls - list sorted contents of directory.
+
SYNOPSIS
+
DESCRIPTION
+
+
OPTIONS
+
RETURN VALUE
+
ERRORS
+
FILES
+
+
AUTHORS
+
SEE ALSO
+
+ +
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ diff --git a/trunk/Tools/cpmtools/docs/cpmrm.htm b/trunk/Tools/cpmtools/docs/cpmrm.htm new file mode 100644 index 00000000..86bff425 --- /dev/null +++ b/trunk/Tools/cpmtools/docs/cpmrm.htm @@ -0,0 +1,203 @@ +CPMRM - remove files on CP/M disks + + +

CPMRM

+Section: User commands (1)
+Updated: June 16, 2008

+ +
Index   +Return to Main Contents   +Disclaimer  


+ + +  +NAME cpmrm - remove files on CP/M disks.

+ +  +SYNOPSIS

+ + +cpmrm + +[-f + +format] + +image + +file-pattern + +... +

+ +  +DESCRIPTION

+ +Cpmrm removes files from CP/M disks. +
+
+ +  +OPTIONS

+ +
+ +
-f
+ +Use the given CP/M disk format instead of the default format. +

+For Apple II CP/M 80 +users the disk image formats apple-do and apple-po are available. These +are DOS3.3 order and ProDOS order disk image formats respectively, and must always be specified +using the form -f apple-do or -f apple-po. +
+
+
+Example: +
+
+The following example shows how to remove a file on an Apple II DOS 3.3 +order cpm disk image: +
+
+cpmrm -f apple-do exmplcpm.dsk 0:bhead.c +
+
+  +RETURN VALUE - Upon successful completion, exit code 0 is returned.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +ERRORS - Any errors are indicated by exit code 1.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +FILES - diskdefs - CP/M disk format definitions

+ +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available +CP/M formats and their names. For Apple II CP/M 80 users the disk +image formats apple-do and apple-po are available. +

+The possible locations where cpmtools first looks for the diskdefs file: +
+
+- Can vary depending on the preferences of the person who builds the +cpmtools binaries (executables) from the source code. +

+- The location is also installation dependent and the diskdefs file +may also have been renamed. +
+
+If it's not found the current (work) directory is then searched for a +file called diskdefs. +
+
+On a unix-like system, a ${prefix}/share/ style path +like /usr/local/share/ is a possible place that cpmtools will first +look for diskdefs. +
+
+In a Win32 system sometimes unix-like shells like cygwin +are used to run cpmtools instead of Windows cmd. For those installations +unix-like conventions probably apply. +
+
+For cpmtools installations targetted at the average +Windows user who does not have a unix-like shell and uses the Windows cmd +prompt to run cpmtools there is no standard shared place that cpmtools will first +look for diskdefs. Pathed File names like \cpm\diskdefs or +even c:\cpmtools\diskdefs are possible. +
+
+ +  +AUTHORS +
+
+This program is copyright 1997-2008 Michael Haardt <michael@moria.de>. +The Windows port is +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +

+ + +This program is free software; you can redistribute it and/or modify +it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +

+ +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+ +You should have received a copy of the GNU General Public License along +with this program. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+ +  +SEE ALSO

+ +cpm(5) + +

+ +
+ + Index +
+
+ +
+
NAME cpmrm - remove files on CP/M disks.
+
SYNOPSIS
+
DESCRIPTION
+
+
OPTIONS
+
RETURN VALUE
+
ERRORS
+
FILES
+
+
AUTHORS
+
SEE ALSO
+
+ +
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ diff --git a/trunk/Tools/cpmtools/docs/fsck.cpm.htm b/trunk/Tools/cpmtools/docs/fsck.cpm.htm new file mode 100644 index 00000000..32cf3075 --- /dev/null +++ b/trunk/Tools/cpmtools/docs/fsck.cpm.htm @@ -0,0 +1,228 @@ +FSCK.CPM - check a CP/M file system + + +

FSCK.CPM

+Section: User commands (1)
+Updated: June 16, 2008

+ +Index   +Return to Main Contents   +Disclaimer  


+ + +  +NAME fsck.cpm - check a CP/M file system.

+ +  +SYNOPSIS

+ +fsck.cpm + +[-f + +format] + +[-n] + +image + +

+ + +  +DESCRIPTION

+ +Fsck.cpm is used to check and repair a CP/M file system. +
+
+After reading the directory, it makes two passes. The first pass checks +extent fields for range and format violations (bad status, extent number, +last record byte count, file name, extension, block number, record count, +size of .COM files, time stamp format, invalid password characters, invalid +time stamp mode). The second pass checks extent connectivity (multiple +allocated blocks and duplicate directory entries). +
+
+fsck.cpm can not yet repair all errors. +
+
+ +  +OPTIONS

+ +
+ +
-f
+ +Use the given CP/M disk format instead of the default format. +

+For Apple II CP/M 80 +users the disk image formats apple-do and apple-po are available. These +are DOS3.3 order and ProDOS order disk image formats respectively, and must always be specified +using the form -f apple-do or -f apple-po. +

+ + +
-n
+Open the file system read-only and do not repair any errors. +
+
+
+ +  +RETURN VALUE - Upon successful completion, exit code 0 is returned.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +ERRORS - Any errors are indicated by exit code 1.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +FILES - diskdefs - CP/M disk format definitions

+ +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available +CP/M formats and their names. For Apple II CP/M 80 users the disk +image formats apple-do and apple-po are available. +

+The possible locations where cpmtools first looks for the diskdefs file: +
+
+- Can vary depending on the preferences of the person who builds the +cpmtools binaries (executables) from the source code. +

+- The location is also installation dependent and the diskdefs file +may also have been renamed. +
+
+If it's not found the current (work) directory is then searched for a +file called diskdefs. +
+
+On a unix-like system, a ${prefix}/share/ style path +like /usr/local/share/ is a possible place that cpmtools will first +look for diskdefs. +
+
+In a Win32 system sometimes unix-like shells like cygwin +are used to run cpmtools instead of Windows cmd. For those installations +unix-like conventions probably apply. +
+
+For cpmtools installations targetted at the average +Windows user who does not have a unix-like shell and uses the Windows cmd +prompt to run cpmtools there is no standard shared place that cpmtools will first +look for diskdefs. Pathed File names like \cpm\diskdefs or +even c:\cpmtools\diskdefs are possible. +
+
+ + +  +DIAGNOSTICS - image: used/total files (n.n% non-contiguos), used/total blocks +
+
+No inconsistencies could be found. The number of used files actually +is the number of used extents. Since a file may use more than +one extent, this may be greater than the actual number of files, but a +correct measure would not reflect how many files could still be created +at most. A file is considered fragmented, if sequential data blocks +pointed to by the same extent do not have sequential block numbers. +The number of used blocks includes the blocks used for system tracks +and the directory. +
+
+ +  +AUTHORS +
+
+This program is copyright 1997-2008 Michael Haardt <michael@moria.de>. +The Windows port is +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +

+ + +This program is free software; you can redistribute it and/or modify +it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +

+ +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+ +You should have received a copy of the GNU General Public License along +with this program. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+ +  +SEE ALSO

+ +mkfs.cpm(1), + +cpm(5) + +

+ +
+ + Index +
+
+ +
+
NAME fsck.cpm - check a CP/M file system.
+
SYNOPSIS
+
DESCRIPTION
+
+
OPTIONS
+
RETURN VALUE
+
ERRORS
+
FILES
+
DIAGNOSTICS
+
+
AUTHORS
+
SEE ALSO
+
+ +
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ diff --git a/trunk/Tools/cpmtools/docs/fsed.cpm.htm b/trunk/Tools/cpmtools/docs/fsed.cpm.htm new file mode 100644 index 00000000..2ea7a0ea --- /dev/null +++ b/trunk/Tools/cpmtools/docs/fsed.cpm.htm @@ -0,0 +1,202 @@ +FSED.CPM - edit a CP/M file system + + +

FSED.CPM

+Section: User commands (1)
+Updated: June 16, 2008

+ +Index   +Return to Main Contents   +Disclaimer  


+ + +  +NAME fsed.cpm - edit a CP/M file system.

+ +  +SYNOPSIS

+ +fsed.cpm + +[-f + +format] + +image + +
+
+ + +  +DESCRIPTION

+ +Fsed.cpm edits a CP/M file system on an image file or device. +
+
+It knows about the system, directory and data area, using sector skew on +the last two. Directory entries are decoded. The interactive usage is +self-explanatory, provided you are familiar with programming tools like +hexadecimal editors. If you are not then you should work with this program +and familiarize yourself with its usage. +
+
+  +OPTIONS

+ +
+ +
-f
+ +Use the given CP/M disk format instead of the default format. +

+For Apple II CP/M 80 +users the disk image formats apple-do and apple-po are available. These +are DOS3.3 order and ProDOS order disk image formats respectively, and must always be specified +using the form -f apple-do or -f apple-po. +

+
+ +  +RETURN VALUE - Upon successful completion, exit code 0 is returned.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +ERRORS - Any errors are indicated by exit code 1.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +FILES - diskdefs - CP/M disk format definitions

+ +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available +CP/M formats and their names. For Apple II CP/M 80 users the disk +image formats apple-do and apple-po are available. +

+The possible locations where cpmtools first looks for the diskdefs file: +
+
+- Can vary depending on the preferences of the person who builds the +cpmtools binaries (executables) from the source code. +

+- The location is also installation dependent and the diskdefs file +may also have been renamed. +
+
+If it's not found the current (work) directory is then searched for a +file called diskdefs. +
+
+On a unix-like system, a ${prefix}/share/ style path +like /usr/local/share/ is a possible place that cpmtools will first +look for diskdefs. +
+
+In a Win32 system sometimes unix-like shells like cygwin +are used to run cpmtools instead of Windows cmd. For those installations +unix-like conventions probably apply. +
+
+For cpmtools installations targetted at the average +Windows user who does not have a unix-like shell and uses the Windows cmd +prompt to run cpmtools there is no standard shared place that cpmtools will first +look for diskdefs. Pathed File names like \cpm\diskdefs or +even c:\cpmtools\diskdefs are possible. +
+
+ +  +AUTHORS +
+
+This program is copyright 1997-2008 Michael Haardt <michael@moria.de>. +The Windows port is +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +

+ +This program is free software; you can redistribute it and/or modify +it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +

+ +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+ +You should have received a copy of the GNU General Public License along +with this program. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+ +  +SEE ALSO

+ +mkfs.cpm(1), + +mkfs.cpm(1), + +cpmls(1), + +cpm(5) + +

+ +
+ + Index +
+
+ +
+
NAME fsed.cpm - edit a CP/M file system.
+
SYNOPSIS
+
DESCRIPTION
+
+
OPTIONS
+
RETURN VALUE
+
ERRORS
+
FILES
+
+
AUTHORS
+
SEE ALSO
+
+ +
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ diff --git a/trunk/Tools/cpmtools/docs/index.htm b/trunk/Tools/cpmtools/docs/index.htm new file mode 100644 index 00000000..5b257dda --- /dev/null +++ b/trunk/Tools/cpmtools/docs/index.htm @@ -0,0 +1,253 @@ +Cpmtools 2.9 Executables for Windows Users + + + +

+

+Welcome to the Wonderfully Ancient World of CP/M
+Cpmtools 2.9 Executables for Windows Users
+
+ + +
+Introduction +
+
+ +Cpmtools is a suite of command line utilities which allow access to +CP/M file systems. It is available on many platforms. This document +is targetted at the use of the cpmtools Win32 executables at +the Windows command prompt by Windows users who know how to use +command line utilities and disk images +and who may not wish to create cpmtools executables from +source code... just to use them. + +
+
+Cpmtools is copyright 1997-2008 Michael Haardt <michael@moria.de> and +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +
+
+<< Back to Top +
+
+
+Licence +
+
+Cpmtools is free software; you can redistribute it and/or modify it +under the terms of +the GNU General Public License as +published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Cpmtools is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+You should receive a copy of +the GNU General Public License along +with cpmtools. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+<< Back to Top +
+
+
+Downloads +
+
+The source for the latest version of cpmtools is available as +a GNU zipped tape archive from: +
+
+ +http://www.moria.de/~michael/cpmtools/ + +
+
+The cpmtools source used in cygwin to build both the Windows binary (Executable) versions of +cpmtools 2.9 noted below is available from the +www.cpm8680.com Website in a zip file format: +
+
+ +http://www.cpm8680.com/cpmtools/cpmtools-2.9.zip + +
+
+For Windows Users who do not wish to make working programs from source code, a compiled +Native Win32 Binary (Executable) version of cpmtools 2.9 is available from the +www.cpm8680.com Website in a zip file format: +
+
+ +http://www.cpm8680.com/cpmtools/cpmtools-2.9-Win32.zip + +
+
+Just unzip with pathnames intact to the root of your local drive (usually C:) +and open-up a cmd prompt in the \cpmtools directory (Windows XP and Vista users +can click-on the cpmtools XP Shortcut) +and you should be good to go. The document you are reading and the program description documents +that it links to are included in the Windows zip file. To use them just click-on them from Windows explorer and +in the \cpmtools\docs directory and +they will load into your favorite web browser. +
+
+ +The distribution noted above has the following customizations: +
+
+The default disk image format is apple-do. This means that if you are working +with Apple II DOS 3.3 order disk images you never need to include the -f apple-do +format option when typing in your command line. +
+
+The diskdefs file is called \cpmtools\diskdefs. This has been hardcoded +into the executables. This means that you can add the \cpmtools directory +to your PATH and the disk and disk image format definitions file will be found. +Users of earlier versions of Windows than XP that support Win32 will need to open a command +prompt and run \cpmtools\cpmtools.bat to set their PATH. +
+
+A Windows XP Shortcut has been added for Windows XP Users. This should +also work in Windows Vista. This means that Windows XP and Vista users can just +click on this shortcut in Windows Explorer or the Shortcut can be copied to +the desktop. +
+
+
+<< Back to Top +
+
+For cygwin Users who do not wish to make working programs from source code, a compiled +cygwin 5 Binary (Executable) version of cpmtools 2.9 is available from the +www.cpm8680.com Website in a zip file format: +
+
+ +http://www.cpm8680.com/cpmtools/cpmtools-2.9-cygwin.zip + +
+
+Outside cygwin just unzip with pathnames intact to the root of the drive that the cygwin +version 5 directory is installed on (\cygwin is assumed). If you are doing this inside cygwin +using zip and cygwin is installed on C:, then cd \cygdrive\c before un-zipping. +
+
+The cygwin installation comes complete with the manpages but not the html manual. +It overlays your cygwin installation so review the zip before installing. +
+
+ +The distribution noted above has the following customization: +
+
+The default disk image format is apple-do. This means that if you are working +with Apple II DOS 3.3 order disk images you never need to include the -f apple-do +format option when typing in your command line. +
+
+Other than that, it is what you would get if you built from scratch then installed +using "make install". If you wish to know more you should download +the source as well. +
+
+
+<< Back to Top +
+
+
+CP/M Resources +
+
+Aztec C CP/M compilers for +making programs in Windows, MS-DOS, and CP/M that will run in CP/M are available +from the Aztec C Museum Website for Fair Use and for +free by hobbyists and enthusiasts. These are no longer commercially available and are offered +with the permission of the Copyright holder. +
+
+The Aztec C Museum Website is only one of many free +CP/M resources on the Internet too numerous to mention that can be used in conjunction with +cpmtools. Some of these include: +
+ +<< Back to Top +
+
+
+Caveat Emptor +
+
+This document was written and formatted by hand by Bill Buckels. Its +contents are either part of cpmtools or provide additional information about using cmptools. It is targetted primarily +at Windows users but most of it applies to all users of cpmtools. +
+
+It is provided in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. In particular, Bill Buckels has no warranty +obligations or liability resulting from its use in any way whatsoever. If you don't +agree then don't read it. +
+ diff --git a/trunk/Tools/cpmtools/docs/mkfs.cpm.htm b/trunk/Tools/cpmtools/docs/mkfs.cpm.htm new file mode 100644 index 00000000..35b2066c --- /dev/null +++ b/trunk/Tools/cpmtools/docs/mkfs.cpm.htm @@ -0,0 +1,215 @@ +MKFS.CPM - make a CP/M file system + + +

MKFS.CPM

+Section: User commands (1)
+Updated: June 16, 2008

+ +Index   +Return to Main Contents   +Disclaimer  


+ +  +NAME mkfs.cpm - make a CP/M file system.

+ +  +SYNOPSIS

+ +mkfs.cpm + +[-f + +format] + +[-b + +boot] + +[-L + +label] + +image + +
+
+ +  +DESCRIPTION

+ +Mkfs.cpm makes a CP/M file system on an image file or device. +
+
+ +  +OPTIONS

+ +
+ +
-f
+ +Use the given CP/M disk format instead of the default format. +

+For Apple II CP/M 80 +users the disk image formats apple-do and apple-po are available. These +are DOS3.3 order and ProDOS order disk image formats respectively, and must always be specified +using the form -f apple-do or -f apple-po. +

+ +
-b bootblock
+ +
+Write the contents of the file bootblock to the system tracks +instead of filling them with 0xe5. This option can be used up to four +times. The file contents (typically boot block, CCP, BDOS and BIOS) +are written to sequential sectors, padding with 0xe5 if needed. +
+
+ +
-L label
+
+Label the file system. This is only supported by CP/M Plus. +

+
+ +  +RETURN VALUE - Upon successful completion, exit code 0 is returned.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +ERRORS - Any errors are indicated by exit code 1.

+ +This will likely only be of interest to programmers. In a Win32 system +the exit code can be trapped in a batch file as an "ERRORLEVEL" or as a +return value when run from another Win32 console program written in a +language like C. +

+ +  +FILES - diskdefs - CP/M disk format definitions

+ +The diskdefs file is a plain ascii text file that serves as a database of +disk and disk image format definitions. It can be reviewed for available +CP/M formats and their names. For Apple II CP/M 80 users the disk +image formats apple-do and apple-po are available. +

+The possible locations where cpmtools first looks for the diskdefs file: +
+
+- Can vary depending on the preferences of the person who builds the +cpmtools binaries (executables) from the source code. +

+- The location is also installation dependent and the diskdefs file +may also have been renamed. +
+
+If it's not found the current (work) directory is then searched for a +file called diskdefs. +
+
+On a unix-like system, a ${prefix}/share/ style path +like /usr/local/share/ is a possible place that cpmtools will first +look for diskdefs. +
+
+In a Win32 system sometimes unix-like shells like cygwin +are used to run cpmtools instead of Windows cmd. For those installations +unix-like conventions probably apply. +
+
+For cpmtools installations targetted at the average +Windows user who does not have a unix-like shell and uses the Windows cmd +prompt to run cpmtools there is no standard shared place that cpmtools will first +look for diskdefs. Pathed File names like \cpm\diskdefs or +even c:\cpmtools\diskdefs are possible. +
+
+ + +  +AUTHORS +
+
+This program is copyright 1997-2008 Michael Haardt <michael@moria.de>. +The Windows port is +copyright 2000, 2001 John Elliott <jce@seasip.demon.co.uk>. +

+ + +This program is free software; you can redistribute it and/or modify +it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +

+ +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +

+ +You should have received a copy of the GNU General Public License along +with this program. If not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +

+ +  +SEE ALSO

+ +cpmls(1), + +cpm(5) + +

+ +
+ + Index +
+
+ +
+
NAME mkfs.cpm - make a CP/M file system.
+
SYNOPSIS
+
DESCRIPTION
+
+
OPTIONS
+
RETURN VALUE
+
ERRORS
+
FILES
+
+
AUTHORS
+
SEE ALSO
+
+ +
+Gradus ad Parnassum +
+
+An ugly version of this document was initially created by man2html on November 14, 2008 +using the cpmtools version 2.8 manual pages +then edited and reformatted by hand by Bill Buckels. +
+
+Caveat Emptor +
+
+The contents of this document +are either part of cpmtools or provide additional information about using cmptools. +You can redistribute it under the terms of +the GNU General Public License as +published by the Free Software Foundation; either version 3 of the License, or (at your +option) any later version. +
+
+Bill Buckels has no warranty +obligations or liability resulting from this document's use in any way whatsoever. If you don't +agree then don't read it. +
+ diff --git a/trunk/Tools/cpmtools/fsck.cpm.exe b/trunk/Tools/cpmtools/fsck.cpm.exe new file mode 100644 index 00000000..1fc22022 Binary files /dev/null and b/trunk/Tools/cpmtools/fsck.cpm.exe differ diff --git a/trunk/Tools/cpmtools/fsed.cpm.exe b/trunk/Tools/cpmtools/fsed.cpm.exe new file mode 100644 index 00000000..149a75e2 Binary files /dev/null and b/trunk/Tools/cpmtools/fsed.cpm.exe differ diff --git a/trunk/Tools/cpmtools/mkfs.cpm.exe b/trunk/Tools/cpmtools/mkfs.cpm.exe new file mode 100644 index 00000000..eadcbd70 Binary files /dev/null and b/trunk/Tools/cpmtools/mkfs.cpm.exe differ diff --git a/trunk/Tools/gcc/libiconv-2.dll b/trunk/Tools/gcc/libiconv-2.dll new file mode 100644 index 00000000..049244df Binary files /dev/null and b/trunk/Tools/gcc/libiconv-2.dll differ diff --git a/trunk/Tools/gcc/libintl-8.dll b/trunk/Tools/gcc/libintl-8.dll new file mode 100644 index 00000000..c7e10441 Binary files /dev/null and b/trunk/Tools/gcc/libintl-8.dll differ diff --git a/trunk/Tools/gcc/mingw32-make.exe b/trunk/Tools/gcc/mingw32-make.exe new file mode 100644 index 00000000..0a5ce27b Binary files /dev/null and b/trunk/Tools/gcc/mingw32-make.exe differ diff --git a/trunk/Tools/rawwritewin/COPYING b/trunk/Tools/rawwritewin/COPYING new file mode 100644 index 00000000..5b6e7c66 --- /dev/null +++ b/trunk/Tools/rawwritewin/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/trunk/Tools/rawwritewin/changes.txt b/trunk/Tools/rawwritewin/changes.txt new file mode 100644 index 00000000..c7c769eb --- /dev/null +++ b/trunk/Tools/rawwritewin/changes.txt @@ -0,0 +1,18 @@ +Version 0.6 +Remove load time requirement for wininet.dll. +Add extra read to Win9X to settle floppy disk into the drive +Add absolute path to dll load to prevent conflict under ME +Packed the exe with UPX +Created auto install script + +Version 0.5 +Command line parameters +Better error messages +Autoupdate +Auto download missing dll + +Version 0.4 +Number of copies to write +NT does not always show floppy drives +Better error message when diskio.dll not found + diff --git a/trunk/Tools/rawwritewin/diskio.dll b/trunk/Tools/rawwritewin/diskio.dll new file mode 100644 index 00000000..1c6a7f0c Binary files /dev/null and b/trunk/Tools/rawwritewin/diskio.dll differ diff --git a/trunk/Tools/rawwritewin/rawwritewin.exe b/trunk/Tools/rawwritewin/rawwritewin.exe new file mode 100644 index 00000000..822dfe19 Binary files /dev/null and b/trunk/Tools/rawwritewin/rawwritewin.exe differ diff --git a/trunk/Tools/rawwritewin/readme.txt b/trunk/Tools/rawwritewin/readme.txt new file mode 100644 index 00000000..42fad30c --- /dev/null +++ b/trunk/Tools/rawwritewin/readme.txt @@ -0,0 +1,5 @@ +RawWrite for Windows +==================== +95, 98, ME, NT, 2K, XP + +Under 95, 98 & ME you need diskio.dll. It must be in the same directory as rawwritewin.exe \ No newline at end of file diff --git a/trunk/Tools/tasm32/8051.H b/trunk/Tools/tasm32/8051.H new file mode 100644 index 00000000..d5131ba9 --- /dev/null +++ b/trunk/Tools/tasm32/8051.H @@ -0,0 +1,162 @@ +;************************************************************* +;* TASM 8051/8052/80154 SFR BIT/BYTE MNEMONIC EQUATES LIST * +;************************************************************* + +P0 .equ 080H ;Port 0 +SP .equ 081H ;Stack pointer +DPL .equ 082H +DPH .equ 083H +PCON .equ 087H +TCON .equ 088H +TMOD .equ 089H +TL0 .equ 08AH +TL1 .equ 08BH +TH0 .equ 08CH +TH1 .equ 08DH +P1 .equ 090H ;Port 1 +SCON .equ 098H +SBUF .equ 099H +P2 .equ 0A0H ;Port 2 +IE .equ 0A8H +P3 .equ 0B0H ;Port 3 +IP .equ 0B8H +T2CON .equ 0C8H ;8052, 80154 only +RCAP2L .equ 0CAH ;8052, 80154 only +RCAP2H .equ 0CBH ;8052, 80154 only +TL2 .equ 0CCH ;8052, 80154 only +TH2 .equ 0CDH ;8052, 80154 only +PSW .equ 0D0H +ACC .equ 0E0H ;Accumulator +B .equ 0F0H ;Secondary Accumulator +IOCON .equ 0F8H ;80154 only + +;PORT 0 BITS +P0.0 .equ 080H ;Port 0 bit 0 +P0.1 .equ 081H ;Port 0 bit 1 +P0.2 .equ 082H ;Port 0 bit 2 +P0.3 .equ 083H ;Port 0 bit 3 +P0.4 .equ 084H ;Port 0 bit 4 +P0.5 .equ 085H ;Port 0 bit 5 +P0.6 .equ 086H ;Port 0 bit 6 +P0.7 .equ 087H ;Port 0 bit 7 + +;PORT 1 BITS +P1.0 .equ 090H ;Port 1 bit 0 +P1.1 .equ 091H ;Port 1 bit 1 +P1.2 .equ 092H ;Port 1 bit 2 +P1.3 .equ 093H ;Port 1 bit 3 +P1.4 .equ 094H ;Port 1 bit 4 +P1.5 .equ 095H ;Port 1 bit 5 +P1.6 .equ 096H ;Port 1 bit 6 +P1.7 .equ 097H ;Port 1 bit 7 + +;PORT 2 BITS +P2.0 .equ 0A0H ;Port 2 bit 0 +P2.1 .equ 0A1H ;Port 2 bit 1 +P2.2 .equ 0A2H ;Port 2 bit 2 +P2.3 .equ 0A3H ;Port 2 bit 3 +P2.4 .equ 0A4H ;Port 2 bit 4 +P2.5 .equ 0A5H ;Port 2 bit 5 +P2.6 .equ 0A6H ;Port 2 bit 6 +P2.7 .equ 0A7H ;Port 2 bit 7 + +;PORT 3 BITS +P3.0 .equ 0B0H ;Port 3 bit 0 +P3.1 .equ 0B1H ;Port 3 bit 1 +P3.2 .equ 0B2H ;Port 3 bit 2 +P3.3 .equ 0B3H ;Port 3 bit 3 +P3.4 .equ 0B4H ;Port 3 bit 4 +P3.5 .equ 0B5H ;Port 3 bit 5 +P3.6 .equ 0B6H ;Port 3 bit 6 +P3.7 .equ 0B7H ;Port 3 bit 7 + +;ACCUMULATOR BITS +ACC.0 .equ 0E0H ;Acc bit 0 +ACC.1 .equ 0E1H ;Acc bit 1 +ACC.2 .equ 0E2H ;Acc bit 2 +ACC.3 .equ 0E3H ;Acc bit 3 +ACC.4 .equ 0E4H ;Acc bit 4 +ACC.5 .equ 0E5H ;Acc bit 5 +ACC.6 .equ 0E6H ;Acc bit 6 +ACC.7 .equ 0E7H ;Acc bit 7 + +;B REGISTER BITS +B.0 .equ 0F0H ;Breg bit 0 +B.1 .equ 0F1H ;Breg bit 1 +B.2 .equ 0F2H ;Breg bit 2 +B.3 .equ 0F3H ;Breg bit 3 +B.4 .equ 0F4H ;Breg bit 4 +B.5 .equ 0F5H ;Breg bit 5 +B.6 .equ 0F6H ;Breg bit 6 +B.7 .equ 0F7H ;Breg bit 7 + +;PSW REGISTER BITS +P .equ 0D0H ;Parity flag +F1 .equ 0D1H ;User flag 1 +OV .equ 0D2H ;Overflow flag +RS0 .equ 0D3H ;Register bank select 1 +RS1 .equ 0D4H ;Register bank select 0 +F0 .equ 0D5H ;User flag 0 +AC .equ 0D6H ;Auxiliary carry flag +CY .equ 0D7H ;Carry flag + +;TCON REGISTER BITS +IT0 .equ 088H ;Intr 0 type control +IE0 .equ 089H ;Intr 0 edge flag +IT1 .equ 08AH ;Intr 1 type control +IE1 .equ 08BH ;Intr 1 edge flag +TR0 .equ 08CH ;Timer 0 run +TF0 .equ 08DH ;Timer 0 overflow +TR1 .equ 08EH ;Timer 1 run +TF1 .equ 08FH ;Timer 1 overflow + +;SCON REGISTER BITS +RI .equ 098H ;RX Intr flag +TI .equ 099H ;TX Intr flag +RB8 .equ 09AH ;RX 9th bit +TB8 .equ 09BH ;TX 9th bit +REN .equ 09CH ;Enable RX flag +SM2 .equ 09DH ;8/9 bit select flag +SM1 .equ 09EH ;Serial mode bit 1 +SM0 .equ 09FH ;Serial mode bit 0 + +;IE REGISTER BITS +EX0 .equ 0A8H ;External intr 0 +ET0 .equ 0A9H ;Timer 0 intr +EX1 .equ 0AAH ;External intr 1 +ET1 .equ 0ABH ;Timer 1 intr +ES .equ 0ACH ;Serial port intr +ET2 .equ 0ADH ;Timer 2 intr +;Reserved 0AEH Reserved +EA .equ 0AFH ;Global intr enable + +;IP REGISTER BITS +PX0 .equ 0B8H ;Priority level-External intr 0 +PT0 .equ 0B9H ;Priority level-Timer 0 intr +PX1 .equ 0BAH ;Priority level-External intr 1 +PT1 .equ 0BBH ;Priority level-Timer 1 intr +PS .equ 0BCH ;Priority level-Serial port intr +PT2 .equ 0BDH ;Priority level-Timer 2 intr +;Reserved 0BEH Reserved +PCT .equ 0BFH ;Global priority level + +;IOCON REGISTER BITS 80154 ONLY +ALF .equ 0F8H ;Power down port condition +P1HZ .equ 0F9H ;Port 1 control +P2HZ .equ 0FAH ;Port 2 control +P3HZ .equ 0FBH ;Port 3 control +IZC .equ 0FCH ;Pullup select +SERR .equ 0FDH ;Serial reception error +T32 .equ 0FEH ;32 bit timer config +WDT .equ 0FFH ;Watchdog config + +;T2CON REGISTER BITS 8052/80154 ONLY +CP/RL2 .equ 0C8H ;Timer 2 capture/reload flag +C/T2 .equ 0C9H ;Timer 2 timer/counter select +TR2 .equ 0CAH ;Timer 2 start/stop +EXEN2 .equ 0CBH ;Timer 2 external enable +TCLK .equ 0CCH ;TX clock flag +RCLK .equ 0CDH ;RX clock flag +EXF2 .equ 0CEH ;Timer 2 external flag +TF2 .equ 0CFH ;Timer 2 overflow + diff --git a/trunk/Tools/tasm32/COPYRIGH.TXT b/trunk/Tools/tasm32/COPYRIGH.TXT new file mode 100644 index 00000000..cac66938 --- /dev/null +++ b/trunk/Tools/tasm32/COPYRIGH.TXT @@ -0,0 +1,62 @@ +The Telemark Assembler Copyright Notification + +The files on this disk are: +Copyright 1985-1993 by Speech Technology Incorporated, all rights reserved. +Copyright 1998,1999,2001 by Thomas N. Anderson , all rights reserved. + +The following files on this disk may be freely copied and shared with others: + +TASM.EXE - TASM Assembler, executable +TASM48.TAB - 8048 Instruction definition table +TASM51.TAB - 8051 Instruction definition table +TASM65.TAB - 6502 Instruction definition table +TASM85.TAB - 8085 Instruction definition table +TASM80.TAB - Z80 Instruction definition table +TASM05.TAB - 6805 Instruction definition table +TASM68.TAB - 6800/6801/68HC11 Instruction definition table +TASM3210.TAB - TMS32010 Instruction definition table +TASM3225.TAB - TMS32025 Instruction definition table +TASM70.TAB - TMS7000 Instruction definition table +TASMMAN.HTM - TASM Documentation (HTML) +TASMTABS.HTM - TASM Documentation on individual tables (HTML) +TEST*.ASM - TASM test cases (one for each table) +TESTTABS.BAT - Batch script to execute the test cases +8051.H - Useful register definitions for the 8051 +MOTO.H - Useful directive definitions for Motorola compatibility +README.TXT - Brief Explanation of Disk contents +COPYRIGH.TXT - Copyright notice +ORDERFRM.TXT - Registration Form +ORDERFRM.HTM - Registration Form (HTML) +RELNOTES.TXT - Release notes. + +Although you may freely copy the above files, TASM is not 'free' or +'public domain'. It is copyrighted material which can be copied and +evaluated by people without registration, but those that use it on a +regular basis must register (see the ORDERFRM.TXT or ORDERFRM.HTM files). + +The following files are to be copied only with the following +restrictions: The owner of this software may make as many copies of +the following as is deemed necessary as long as no possibility exists +for the software (or derivitive products) to be in use on more than +one machine at a time. Or, if a site license has been purchased, the +software can only be used on machines at that site. + + TASM.C + TASMMAIN.C + MACRO.C + PARSE.C + STR.C + LOOKUP.C + WRTOBJ.C + FNAME.C + WRTOBJ.C + ERRLOG.C + TASM.H + + + Thomas N. Anderson + Squak Valley Software + 837 Front Street South + Issaquah, WA 98027 + + email: andersontn@acm.org diff --git a/trunk/Tools/tasm32/MOTO.H b/trunk/Tools/tasm32/MOTO.H new file mode 100644 index 00000000..26e52282 --- /dev/null +++ b/trunk/Tools/tasm32/MOTO.H @@ -0,0 +1,20 @@ +; A few handy defines to make TASM more like typcial +; motorola syntax + +.MSFIRST ; Most Significant byte first + +#define EQU .EQU +#define ORG .ORG +#define RMB .BLOCK +#define FCB .BYTE +#define FCC .TEXT +#define FDB .WORD + +#define equ .EQU +#define org .ORG +#define rmb .BLOCK +#define fcb .BYTE +#define fcc .TEXT +#define fdb .WORD + + diff --git a/trunk/Tools/tasm32/ORDERFRM.HTM b/trunk/Tools/tasm32/ORDERFRM.HTM new file mode 100644 index 00000000..77af8f75 --- /dev/null +++ b/trunk/Tools/tasm32/ORDERFRM.HTM @@ -0,0 +1,82 @@ + + + +Telemark Cross Assembler (TASM) Order Form + +

TASM Order Form

+

To order TASM, print this page, fill in the details and mail to SVS at:

+

Squak Valley Software
837 Front Street South
Issaquah, WA 98027
USA

+

TASM registration provides the user:

+
    +
  • Most Recent TASM Distribution Disk (includes tables for all supported +processor families)
  • +
  • TASM Source code (in C)
  • +
  • Bound TASM Manual
  • +
  • Telephone Support
  • +
  • Knowledge that they are supporting the development of useful but +inexpensive software
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Item DescriptionUnit PriceAmount Extended
TASM 3.2 Registration $40______________________
TASM 3.2 Site Registration$90______________________
TASM 3.2 Update for registered users$10______________________
Subtotal______________________
Tax (Washington State residents add 8.6%)______________________
Billing Fee (for orders not accompanied by payment)$10______________________
Foreign postage and handling$10______________________
Total______________________
+
    +
  • All payments must be in US funds drawn on a US bank (No credit card +payments)
  • +
  • Orders outside North America please add the indicated foreign postage and +handling.
  • +
  • Purchase orders allowed from North America only (all others must be +prepaid).
+

Ship To:

+ + + + + + + + + + + + + + + +
Name____________________________________
Company ___________________________________
Street Address____________________________________
City, State/Province, Postal Code____________________________________
Country ____________________________________
diff --git a/trunk/Tools/tasm32/ORDERFRM.TXT b/trunk/Tools/tasm32/ORDERFRM.TXT new file mode 100644 index 00000000..d5282a5a --- /dev/null +++ b/trunk/Tools/tasm32/ORDERFRM.TXT @@ -0,0 +1,55 @@ +ORDERING INFORMATION (TASM Version 3.2) + +TASM is distributed as shareware. The shareware portion of the +product may be freely copied and used for evaluation purposes. Use +of TASM beyond a reasonable evaluation period requires registration. +Registered users receive the following benefits: + + 1. The recent version of TASM. + 2. TASM source code (in C). + 3. Bound TASM manual. + 4. Telephone support. + 5. Knowledge that they are supporting the development of + useful but inexpensive software. + +DESCRIPTION UNIT PRICE PRICE +-------------------------------------------------------------------- + +TASM Registration (TASM disk, manual, & source) $40.00 _______ + +TASM Site Registration (for sites with multiple 90.00 _______ + users. Includes same materials as above.) + +TASM User's Manual (included above) 10.00 _______ + +TASM update for registered users 10.00 _______ + (latest disk (with source), and manual) + +Subtotal _______ + +Tax (Washington state residents add 8.6%) _______ + +Billing fee (for orders not accompanied by check) 10.00 _______ + +Foreign postage (outside North America) add $10.00 _______ + (Foreign orders must be in US funds drawn on a US bank) + +TOTAL (post paid) _______ + + +Which processors are of primary interest to you? __________________ +(This is for our information only. You will +receive all current TASM tables). + +Shipping Address: + +______________________________________________ + +______________________________________________ + +______________________________________________ + +Send check or money order (no credit cards) to: Squak Valley Software + 837 Front Street South + Issaquah, WA 98027 + diff --git a/trunk/Tools/tasm32/README.1ST b/trunk/Tools/tasm32/README.1ST new file mode 100644 index 00000000..7bb8208e --- /dev/null +++ b/trunk/Tools/tasm32/README.1ST @@ -0,0 +1,18 @@ +This is the registered distribution disk for TASM - the Telemark Assembler. +The files on the disk are: + +Readme.1st - This file +Tasm32.zip - TASM distribution archive, Version 3.2 + +To extract the archive use pkunzip or pkzip for windows and extract +into the desired directory for TASM. + +See the README.TXT file after extraction. +See the BUILD.TXT file for notes on building from the source archive. + + Thomas N. Anderson + Squak Valley Software + 837 Front Street South + Issaquah, WA 98027 + andersontn@acm.org + diff --git a/trunk/Tools/tasm32/README.TXT b/trunk/Tools/tasm32/README.TXT new file mode 100644 index 00000000..07555f5e --- /dev/null +++ b/trunk/Tools/tasm32/README.TXT @@ -0,0 +1,46 @@ +This is the shareware distribution disk for TASM - a table driven +assembler. The files on the disk include: + +TASM.EXE - TASM Assembler, executable +TASM48.TAB - 8048 Instruction definition table +TASM51.TAB - 8051 Instruction definition table +TASM65.TAB - 6502 Instruction definition table +TASM85.TAB - 8085 Instruction definition table +TASM80.TAB - Z80 Instruction definition table +TASM05.TAB - 6805 Instruction definition table +TASM3210.TAB - TMS32010 Instruction definition table +TASM3225.TAB - TMS32025 Instruction definition table +TASM68.TAB - 6800/6801 Instruction definition table +TASM70.TAB - TMS7000 Instruction definition table +TASM96.TAB - 8096 Instruction definition table +TEST*.ASM - TASM test files (one for each table). +TESTTABS.BAT - Batch script to execute TASM for each test case. +8051.H - Useful register definitions for the 8051 +MOTO.H - Useful directive definitions for Motorola compatibility +TASMMAN.HTM - TASM User's Manual (HTML) +TASMTABS.HTM - TASM Table Description Manual (HTML) +README.TXT - Brief Explanation of Disk contents +COPYRIGH.TXT - Copyright notice +ORDERFRM.TXT - Order Form (plain text) +ORDERFRM.HTM - Order Form (HTML) + +For a brief discription of how to run TASM, execute TASM with no command +line parameters. + +If you find TASM useful, why not register? Unregistered use of TASM +beyond a 30 day evaluation period is a violation of the license. +For the $40.00 registration fee you get: + + 1. Latest version of TASM. + 2. Source code (in C). + 3. Bound Manual. + 4. email support. + +To register, use the form on the disk (ORDERFRM.TXT), or just send +$40.00 check or money order to: + + Thomas N. Anderson + Squak Valley Software + 837 Front Street South + Issaquah, WA 98027 + andersontn@acm.org diff --git a/trunk/Tools/tasm32/RELNOTES.TXT b/trunk/Tools/tasm32/RELNOTES.TXT new file mode 100644 index 00000000..24ae4f97 --- /dev/null +++ b/trunk/Tools/tasm32/RELNOTES.TXT @@ -0,0 +1,213 @@ +TASM RELEASE NOTES [September 2001] + +RELEASE DATE/VERSION DESCRIPTION +----------------------------------------------------------------------- +10/01/85 Version 2.0 First version with external table def files. + +01/01/86 Version 2.1 Added '*=' and '=' directives as + alternatives to .ORG and .EQU (for + more complete MOS Technology compatibility). + Enhanced parsing algorithm so it can + deal with more than one variable expression. + Added -d option + +02/14/86 Version 2.2 Modified so instruction set definition + tables don't need to be compiled in. + Added 8051 tables. + Increased the number of labels allowed. + +03/31/87 Version 2.3 Fixed bug that prevented location 0xffff + from being used and written to object file. + Most changes in wrtobj() and pr_hextab(). + +05/01/87 Version 2.4 Added multiple byte opcode support. + Added shift/or operation capability to + args from instruction set definition table. + Converted to MS C version 3.0 + Added hashing to instruction set table + lookups to speed up. + +11/01/87 Version 2.5 Added DB and DW directives. + Added escape capability in TEXT strings. + Fixed inst_lookup function to treat the + multiple wild card case a little better + Added 8080/8085 and Z80 tables. + Added sorting on label table. + Increased size of read buffer. + Speed enhancements. + Added DEFCONT (macro continuation) directive. + Converted to Microsoft C 5.0 compiler. + Added 6805 table (and related modops). + Added Z80 bit modop. + Minor speed up. + Fixed bug that enters infinite loop + when a macro invocation has no closing paren. + Added some three arg MODOPs. + +8/15/88 Version 2.6.1 Added CODES/NOCODES directives + Fixed bug preventing directives in multiple + statement lines. + 2.6.2 Added COMB_NIBBLE and COMB_NIBBLE_SWAP MODOPS + +2/1/89 Version 2.7 Removed ad hoc heap and now use malloc() + Added MSFIRST and LSFIRST directives. + Added EXPORT directive. + Added symbol table file (-s flag). + Added NSEG/CSEG/BSEG/DSEG/XSEG directives + and the SYM/AVSYM directives to support + the Avocet avsim51 simulator. + Added support for TMS320. + Added -r flag to set read buffer size. + Converted expression evaluation from + signed 16 bit to signed 32 bit (enabling + apparent ability to use signed or unsigned + 16 bit values). + +4/20/89 Version 2.7.1 Return 0x20000 for undefined labels so that + (label+x) type stuff won't confuse zero + page addressing. + Added duplicate label error message on pass 1. + +6/20/89 Version 2.7.2 Improved macro expansion capability. + No expansion in comments. + Context sensitive identifiers. + Revised exit codes. + +6/27/89 Version 2.7.3 Added -a flag for strict error checking: + (1) No outer parens around expressions. + (2) Error message if unused argbytes remain + (3) Duplicate labels + Fixed so ']' can terminate expressions. + Removed parse() from tasm.c + +8/19/89 Version 2.7.4 Added Motorola hex object format. + Fixed bug that complained when \ immediately + followed a opcode with no args. + Slightly improved error reporting (Errorbuf). + +10/31/89 Version 2.7.5 Added TMS7000 support. + Fixed argv[] bug (only dimensioned to 10 in pass1. + +12/23/89 Version 2.7.6 Improved handling of % (modulo vs binary + prefix ambiguity). + Fixed list so lines with more than + 6 bytes go on second line. + +03/04/90 Version 2.7.7 Fixed bug that left off 2 bytes if ORG + went backwards and all 64K was used. + Added a command line option to ignore + case on labels. + Added a couple MODOP rules for TMS9900. + Allow double quoted text strings for BYTE. + +04/15/90 Version 2.7.8 Fixed expression evaluator bug (paren popping) + and changed expression evaluator to a more + conventional left to right evaluation order. + Added TURBOC ifdef's (from Lance Jump). + +08/20/90 Version 2.8 Primarily a documentation update. + Added error check for AJMP/ACALL off of + current 2K block (8051). + +10/15/90 Version 2.8.1 Minor speed up in label searching. + Fixed word addressing for TMS320 + Version 2.8.2 Local labels. + More label table format options (long form + suppress local labels). + +11/30/90 Version 2.8.3 Turbo C conversion. + DS directive added. + +12/27/90 Version 2.8.4 Added COMMENTCHAR directive to change the + comment indicator in the first column. + This was done to support the assembly + files from the small C compiler (sc11) + for the 68CH11. + +02/14/91 Version 2.8.5 Added LOCALLABELCHAR directive to + override the default "_" as the + prefix for local labels. + +03/18/91 Version 2.8.6 Added some MODOPs in support of TMS320C25 + +04/20/91 Version 2.8.7 Fixed sign extend bug in CSWAP modop. + Increased MAXLABS to 10000 for big version. + +05/05/91 Version 2.8.8 Fixed pointer bug in debug output in sort_labels(). + +05/20/91 Version 2.9 TMS320C25 table along with some MODOP enhancements + for it. + TASMTABS.DOC updated (but not TASM.DOC) + +08/09/91 Version 2.9.1 Nested conditionals. + +04/01/92 Version 2.9.2 Fixed long label clobber problem in + find_label() and save_label. Syntax + errors could result in a comment line + after an instruction being lumped together + with a label resulting in a long label. + The label functions were not testing for + labels that exceed the specified size. + Added CHK directive. + Added REL3 MODOD to support uPD75xxx. + Delinting and more ANSIfication. + Modifications due to feedback from B Provo: + Added FILL directive. + Allow multiple labels for EXPORT directive. + Allow address with END directive. + TASM.DOC update + +11/25/92 Version 2.9.3 Improved error reporting for mismatched quotes. + Disallow the single quote character constants. + Convert to BCC++ 3.1 + Provide filename,linenum on all error messages. + Modify format of error messages for compatibility + with the Brief editor. + Added ECHO directive to send output to console. + Performance improvements in macro processing. + "Type Safe" conversion (compatible with C++). + Improved error reporting for imbalanced ifdefs. + + +01/29/93 Version 2.9.4 Added rules for 8096 (I1,I2,I3,I4,I5,I6). + Generate error message on forward reference + in EQUate statements. + Eliminated -a option for enabling the detection + of branches of 2K page for 8051. This + is now built into the table. + Allow white space in double quotes for BYTE + directive. This previously worked for TEXT, + but not BYTE. + Fixed defect with Z80 4 byte indexed instructions. + Fixed macro defect. If the macro definition has + args but the invocation does not some garbage + gets expanded into the source line. + Z80 OTDR opcode was incorrect. + Z80 IN0/OUT0/INA instructions did not require + the parens around the args. + Some experimental support for windows verson of TASM. + +10/24/93 Version 3.0 Documentation update. TASM.DOC, TASMTABS.DOC + and RELNOTES.DOC updated, but the functionality + remains unchanged from version 2.9.4. + +06/16/94 Version 3.0.1 Multiple macros on the same line. + Fixed problem with -c with >8000h bytes used goes bonkers + Corrected word addressing problem for BLOCK/DS directives. + Allow escaped quotes in TEXT strings. + +11/30/97 Version 3.1 LINUX support. + Protect mode version (tasmp) with better memory + management (more labels allowed, etc.) + Added an 8096 table. + Added Logical NOT unary operator. + Added an object file format with word address + +09/01/01 version 3.2 Increased LINESIZ to 512 to enable use of longer macros. + Eliminated -r command line option (to set + read buffer size - Now obsolete.) + Improved list() function to put a max of + six bytes per line to avoid problems with + directives that generate large blocks of + object code (i.e. .FILL). + Built as a 32 bit version using MS C++ 6.0 diff --git a/trunk/Tools/tasm32/TASM.EXE b/trunk/Tools/tasm32/TASM.EXE new file mode 100644 index 00000000..f7c733cc Binary files /dev/null and b/trunk/Tools/tasm32/TASM.EXE differ diff --git a/trunk/Tools/tasm32/TASM05.TAB b/trunk/Tools/tasm32/TASM05.TAB new file mode 100644 index 00000000..61e2972c --- /dev/null +++ b/trunk/Tools/tasm32/TASM05.TAB @@ -0,0 +1,215 @@ +"TASM 6805 Assembler. " +/*************************************************************************** +/* $Id +/*************************************************************************** +/* This is the instruction set definition table for the 6805 version of TASM. +/* Thomas N. Anderson, Speech Technology Incorported, April 1988. +/* +/*INSTR ARGS OPCODE BYTES MOD CLASS SHIFT OR */ +/*-------------------------------------------*/ + +ADC #* A9 2 NOP 1 +ADC ,X F9 1 NOP 1 +ADC *,X D9 3 MZERO 1 +ADC * C9 3 MZERO 1 + +ADD #* AB 2 NOP 1 +ADD ,X FB 1 NOP 1 +ADD *,X DB 3 MZERO 1 +ADD * CB 3 MZERO 1 + +AND #* A4 2 NOP 1 +AND ,X F4 1 NOP 1 +AND *,X D4 3 MZERO 1 +AND * C4 3 MZERO 1 + +ASLA "" 48 1 NOP 1 +ASLX "" 58 1 NOP 1 +ASL ,X 78 1 NOP 1 +ASL *,X 68 2 NOP 1 +ASL * 38 2 NOP 1 + +ASRA "" 47 1 NOP 1 +ASRX "" 57 1 NOP 1 +ASR ,X 77 1 NOP 1 +ASR *,X 67 2 NOP 1 +ASR * 37 2 NOP 1 + +BCC * 24 2 R1 1 +BCLR *,* 11 2 MBIT 1 +BCS * 25 2 R1 1 +BEQ * 27 2 R1 1 +BHCC * 28 2 R1 1 +BHCS * 29 2 R1 1 +BHI * 22 2 R1 1 +BHS * 24 2 R1 1 +BIH * 2F 2 R1 1 +BIL * 2E 2 R1 1 + +BIT #* A5 2 NOP 1 +BIT ,X F5 1 NOP 1 +BIT *,X D5 3 MZERO 1 +BIT * C5 3 MZERO 1 + +BLO * 25 2 R1 1 +BLS * 23 2 R1 1 +BMC * 2C 2 R1 1 +BMI * 2B 2 R1 1 +BMS * 2D 2 R1 1 +BNE * 26 2 R1 1 +BPL * 2A 2 R1 1 +BRA * 20 2 R1 1 + +BRCLR *,*,* 01 3 MBIT 1 +BRN * 21 2 R1 1 +BRSET *,*,* 00 3 MBIT 1 +BSET *,* 10 2 MBIT 1 +BSR * AD 2 R1 1 + +CLC "" 98 1 NOP 1 +CLI "" 9A 1 NOP 1 + +CLRA "" 4F 1 NOP 1 +CLRX "" 5F 1 NOP 1 +CLR ,X 7F 1 NOP 1 +CLR *,X 6F 2 NOP 1 +CLR * 3F 2 NOP 1 + +CMP #* A1 2 NOP 1 +CMP ,X F1 1 NOP 1 +CMP *,X D1 3 MZERO 1 +CMP * C1 3 MZERO 1 + +CMPX #* A3 2 NOP 1 /* equivalent to CPX */ +CMPX ,X F3 1 NOP 1 +CMPX *,X D3 3 MZERO 1 +CMPX * C3 3 MZERO 1 + +COMA "" 43 1 NOP 1 +COMX "" 53 1 NOP 1 +COM ,X 73 1 NOP 1 +COM *,X 63 2 NOP 1 +COM * 33 2 NOP 1 + +CPX #* A3 2 NOP 1 +CPX ,X F3 1 NOP 1 +CPX *,X D3 3 MZERO 1 +CPX * C3 3 MZERO 1 + +DECA "" 4A 1 NOP 1 +DECX "" 5A 1 NOP 1 +DEX "" 5A 1 NOP 1 +DEC ,X 7A 1 NOP 1 +DEC *,X 6A 2 NOP 1 +DEC * 3A 2 NOP 1 + +EOR #* A8 2 NOP 1 +EOR ,X F8 1 NOP 1 +EOR *,X D8 3 MZERO 1 +EOR * C8 3 MZERO 1 + +INCA "" 4C 1 NOP 1 +INCX "" 5C 1 NOP 1 +INX "" 5C 1 NOP 1 +INC ,X 7C 1 NOP 1 +INC *,X 6C 2 NOP 1 +INC * 3C 2 NOP 1 + +JMP ,X FC 1 NOP 1 +JMP *,X DC 3 MZERO 1 +JMP * CC 3 MZERO 1 + +JSR ,X FD 1 NOP 1 +JSR *,X DD 3 MZERO 1 +JSR * CD 3 MZERO 1 + +LDA #* A6 2 NOP 1 +LDA ,X F6 1 NOP 1 +LDA *,X D6 3 MZERO 1 +LDA * C6 3 MZERO 1 + +LDX #* AE 2 NOP 1 +LDX ,X FE 1 NOP 1 +LDX *,X DE 3 MZERO 1 +LDX * CE 3 MZERO 1 + +LSLA "" 48 1 NOP 1 +LSLX "" 58 1 NOP 1 +LSL ,X 78 1 NOP 1 +LSL *,X 68 2 NOP 1 +LSL * 38 2 NOP 1 + +LSRA "" 44 1 NOP 1 +LSRX "" 54 1 NOP 1 +LSR ,X 74 1 NOP 1 +LSR *,X 64 2 NOP 1 +LSR * 34 2 NOP 1 + +MUL "" 42 1 NOP 4 /* HC05C4 only */ + +NEGA "" 40 1 NOP 1 +NEGX "" 50 1 NOP 1 +NEG ,X 70 1 NOP 1 +NEG *,X 60 2 NOP 1 +NEG * 30 2 NOP 1 + +NOP "" 9D 1 NOP 1 + +ORA #* AA 2 NOP 1 +ORA ,X FA 1 NOP 1 +ORA *,X DA 3 MZERO 1 +ORA * CA 3 MZERO 1 + +ROLA "" 49 1 NOP 1 +ROLX "" 59 1 NOP 1 +ROL ,X 79 1 NOP 1 +ROL *,X 69 2 NOP 1 +ROL * 39 2 NOP 1 + +RORA "" 46 1 NOP 1 +RORX "" 56 1 NOP 1 +ROR ,X 76 1 NOP 1 +ROR *,X 66 2 NOP 1 +ROR * 36 2 NOP 1 + +RSP "" 9C 1 NOP 1 +RTI "" 80 1 NOP 1 +RTS "" 81 1 NOP 1 + +SBC #* A2 2 NOP 1 +SBC ,X F2 1 NOP 1 +SBC *,X D2 3 MZERO 1 +SBC * C2 3 MZERO 1 + +SEC "" 99 1 NOP 1 +SEI "" 9B 1 NOP 1 + +STA ,X F7 1 NOP 1 +STA *,X D7 3 MZERO 1 +STA * C7 3 MZERO 1 + +STOP "" 8E 1 NOP 2 /* M146805 CMOS only */ + +STX ,X FF 1 NOP 1 +STX *,X DF 3 MZERO 1 +STX * CF 3 MZERO 1 + +SUB #* A0 2 NOP 1 +SUB ,X F0 1 NOP 1 +SUB *,X D0 3 MZERO 1 +SUB * C0 3 MZERO 1 + +SWI "" 83 1 NOP 1 + +TAX "" 97 1 NOP 1 + +TSTA "" 4D 1 NOP 1 +TSTX "" 5D 1 NOP 1 +TST ,X 7D 1 NOP 1 +TST *,X 6D 2 NOP 1 +TST * 3D 2 NOP 1 + +TXA "" 9F 1 NOP 1 + +WAIT "" 8F 1 NOP 2 /* M146805 CMOS only */ + diff --git a/trunk/Tools/tasm32/TASM180.TAB b/trunk/Tools/tasm32/TASM180.TAB new file mode 100644 index 00000000..03affd9a --- /dev/null +++ b/trunk/Tools/tasm32/TASM180.TAB @@ -0,0 +1,594 @@ +"TASM Z180 Assembler. " +/**************************************************************************** +/* $Id: tasm80.tab 1.2 1998/02/28 14:31:22 toma Exp $ +/**************************************************************************** +/* This is the instruction set definition table +/* for the Z80 version of TASM. +/* Thomas N. Anderson, Speech Technology Incorporated +/* This table authored and submitted by Carl A. Wall, VE3APY. +/* +/* Class bits assigned as follows: +/* Bit-0 = Z80 (base instruction set) +/* Bit-1 = HD64180 (extended instructions) +/* See TASM manual for info on table structure. +/* +/*INSTR ARGS OP BYTES RULE CLASS SHIFT OR */ +/*-------------------------------------------*/ + +ADC A,(HL) 8E 1 NOP 1 +ADC A,(IX*) 8EDD 3 ZIX 1 +ADC A,(IY*) 8EFD 3 ZIX 1 +ADC A,A 8F 1 NOP 1 +ADC A,B 88 1 NOP 1 +ADC A,C 89 1 NOP 1 +ADC A,D 8A 1 NOP 1 +ADC A,E 8B 1 NOP 1 +ADC A,H 8C 1 NOP 1 +ADC A,L 8D 1 NOP 1 +ADC A,* CE 2 NOP 1 +ADC HL,BC 4AED 2 NOP 1 +ADC HL,DE 5AED 2 NOP 1 +ADC HL,HL 6AED 2 NOP 1 +ADC HL,SP 7AED 2 NOP 1 + +ADD A,(HL) 86 1 NOP 1 +ADD A,(IX*) 86DD 3 ZIX 1 +ADD A,(IY*) 86FD 3 ZIX 1 +ADD A,A 87 1 NOP 1 +ADD A,B 80 1 NOP 1 +ADD A,C 81 1 NOP 1 +ADD A,D 82 1 NOP 1 +ADD A,E 83 1 NOP 1 +ADD A,H 84 1 NOP 1 +ADD A,L 85 1 NOP 1 +ADD A,* C6 2 NOP 1 +ADD HL,BC 09 1 NOP 1 +ADD HL,DE 19 1 NOP 1 +ADD HL,HL 29 1 NOP 1 +ADD HL,SP 39 1 NOP 1 +ADD IX,BC 09DD 2 NOP 1 +ADD IX,DE 19DD 2 NOP 1 +ADD IX,IX 29DD 2 NOP 1 +ADD IX,SP 39DD 2 NOP 1 +ADD IY,BC 09FD 2 NOP 1 +ADD IY,DE 19FD 2 NOP 1 +ADD IY,IY 29FD 2 NOP 1 +ADD IY,SP 39FD 2 NOP 1 + +AND (HL) A6 1 NOP 1 +AND (IX*) A6DD 3 ZIX 1 +AND (IY*) A6FD 3 ZIX 1 +AND A A7 1 NOP 1 +AND B A0 1 NOP 1 +AND C A1 1 NOP 1 +AND D A2 1 NOP 1 +AND E A3 1 NOP 1 +AND H A4 1 NOP 1 +AND L A5 1 NOP 1 +AND * E6 2 NOP 1 + +BIT *,(HL) 46CB 2 ZBIT 1 +BIT *,(IX*) CBDD 4 ZBIT 1 0 4600 +BIT *,(IY*) CBFD 4 ZBIT 1 0 4600 +BIT *,A 47CB 2 ZBIT 1 +BIT *,B 40CB 2 ZBIT 1 +BIT *,C 41CB 2 ZBIT 1 +BIT *,D 42CB 2 ZBIT 1 +BIT *,E 43CB 2 ZBIT 1 +BIT *,H 44CB 2 ZBIT 1 +BIT *,L 45CB 2 ZBIT 1 + +CALL C,* DC 3 NOP 1 +CALL M,* FC 3 NOP 1 +CALL NC,* D4 3 NOP 1 +CALL NZ,* C4 3 NOP 1 +CALL P,* F4 3 NOP 1 +CALL PE,* EC 3 NOP 1 +CALL PO,* E4 3 NOP 1 +CALL Z,* CC 3 NOP 1 +CALL * CD 3 NOP 1 + +CCF "" 3F 1 NOP 1 + +CP (HL) BE 1 NOP 1 +CP (IX*) BEDD 3 ZIX 1 +CP (IY*) BEFD 3 ZIX 1 +CP A BF 1 NOP 1 +CP B B8 1 NOP 1 +CP C B9 1 NOP 1 +CP D BA 1 NOP 1 +CP E BB 1 NOP 1 +CP H BC 1 NOP 1 +CP L BD 1 NOP 1 +CP * FE 2 NOP 1 +CPD "" A9ED 2 NOP 1 +CPDR "" B9ED 2 NOP 1 +CPIR "" B1ED 2 NOP 1 +CPI "" A1ED 2 NOP 1 +CPL "" 2F 1 NOP 1 + +DAA "" 27 1 NOP 1 + +DEC (HL) 35 1 NOP 1 +DEC (IX*) 35DD 3 ZIX 1 +DEC (IY*) 35FD 3 ZIX 1 +DEC A 3D 1 NOP 1 +DEC B 05 1 NOP 1 +DEC BC 0B 1 NOP 1 +DEC C 0D 1 NOP 1 +DEC D 15 1 NOP 1 +DEC DE 1B 1 NOP 1 +DEC E 1D 1 NOP 1 +DEC H 25 1 NOP 1 +DEC HL 2B 1 NOP 1 +DEC IX 2BDD 2 NOP 1 +DEC IY 2BFD 2 NOP 1 +DEC L 2D 1 NOP 1 +DEC SP 3B 1 NOP 1 +DI "" F3 1 NOP 1 +DJNZ * 10 2 R1 1 + +EI "" FB 1 NOP 1 +EX (SP),HL E3 1 NOP 1 +EX (SP),IX E3DD 2 NOP 1 +EX (SP),IY E3FD 2 NOP 1 +EX AF,AF' 08 1 NOP 1 +EX DE,HL EB 1 NOP 1 +EXX "" D9 1 NOP 1 +HALT "" 76 1 NOP 1 + +IM 0 46ED 2 NOP 1 +IM 1 56ED 2 NOP 1 +IM 2 5EED 2 NOP 1 + +/* Alternate form of above +IM0 46ED 2 NOP 1 +IM1 56ED 2 NOP 1 +IM2 5EED 2 NOP 1 + +IN A,(C) 78ED 2 NOP 1 +IN B,(C) 40ED 2 NOP 1 +IN C,(C) 48ED 2 NOP 1 +IN D,(C) 50ED 2 NOP 1 +IN E,(C) 58ED 2 NOP 1 +IN H,(C) 60ED 2 NOP 1 +IN L,(C) 68ED 2 NOP 1 + +IN A,(*) DB 2 NOP 1 + +IN0 A,(*) 38ED 3 NOP 1 +IN0 B,(*) 00ED 3 NOP 1 +IN0 C,(*) 08ED 3 NOP 1 +IN0 D,(*) 10ED 3 NOP 1 +IN0 E,(*) 18ED 3 NOP 1 +IN0 H,(*) 20ED 3 NOP 1 +IN0 L,(*) 28ED 3 NOP 1 + +INC (HL) 34 1 NOP 1 +INC (IX*) 34DD 3 ZIX 1 +INC (IY*) 34FD 3 ZIX 1 +INC A 3C 1 NOP 1 +INC B 04 1 NOP 1 +INC BC 03 1 NOP 1 +INC C 0C 1 NOP 1 +INC D 14 1 NOP 1 +INC DE 13 1 NOP 1 +INC E 1C 1 NOP 1 +INC H 24 1 NOP 1 +INC HL 23 1 NOP 1 +INC IX 23DD 2 NOP 1 +INC IY 23FD 2 NOP 1 +INC L 2C 1 NOP 1 +INC SP 33 1 NOP 1 + + +IND "" AAED 2 NOP 1 +INDR "" BAED 2 NOP 1 +INI "" A2ED 2 NOP 1 +INIR "" B2ED 2 NOP 1 + +JP (HL) E9 1 NOP 1 +JP (IX) E9DD 2 NOP 1 +JP (IY) E9FD 2 NOP 1 +JP C,* DA 3 NOP 1 +JP M,* FA 3 NOP 1 +JP NC,* D2 3 NOP 1 +JP NZ,* C2 3 NOP 1 +JP P,* F2 3 NOP 1 +JP PE,* EA 3 NOP 1 +JP PO,* E2 3 NOP 1 +JP Z,* CA 3 NOP 1 +JP * C3 3 NOP 1 + +JR C,* 38 2 R1 1 +JR NC,* 30 2 R1 1 +JR NZ,* 20 2 R1 1 +JR Z,* 28 2 R1 1 +JR * 18 2 R1 1 + +LD (BC),A 02 1 NOP 1 +LD (DE),A 12 1 NOP 1 +LD (HL),A 77 1 NOP 1 +LD (HL),B 70 1 NOP 1 +LD (HL),C 71 1 NOP 1 +LD (HL),D 72 1 NOP 1 +LD (HL),E 73 1 NOP 1 +LD (HL),H 74 1 NOP 1 +LD (HL),L 75 1 NOP 1 +LD (HL),* 36 2 NOP 1 +LD (IX*),A 77DD 3 ZIX 1 +LD (IX*),B 70DD 3 ZIX 1 +LD (IX*),C 71DD 3 ZIX 1 +LD (IX*),D 72DD 3 ZIX 1 +LD (IX*),E 73DD 3 ZIX 1 +LD (IX*),H 74DD 3 ZIX 1 +LD (IX*),L 75DD 3 ZIX 1 +LD (IX*),* 36DD 4 ZIX 1 +LD (IY*),A 77FD 3 ZIX 1 +LD (IY*),B 70FD 3 ZIX 1 +LD (IY*),C 71FD 3 ZIX 1 +LD (IY*),D 72FD 3 ZIX 1 +LD (IY*),E 73FD 3 ZIX 1 +LD (IY*),H 74FD 3 ZIX 1 +LD (IY*),L 75FD 3 ZIX 1 +LD (IY*),* 36FD 4 ZIX 1 +LD (*),A 32 3 NOP 1 +LD (*),BC 43ED 4 NOP 1 +LD (*),DE 53ED 4 NOP 1 +LD (*),HL 22 3 NOP 1 +LD (*),IX 22DD 4 NOP 1 +LD (*),IY 22FD 4 NOP 1 +LD (*),SP 73ED 4 NOP 1 +LD A,(BC) 0A 1 NOP 1 +LD A,(DE) 1A 1 NOP 1 +LD A,(HL) 7E 1 NOP 1 +LD A,(IX*) 7EDD 3 ZIX 1 +LD A,(IY*) 7EFD 3 ZIX 1 +LD A,A 7F 1 NOP 1 +LD A,B 78 1 NOP 1 +LD A,C 79 1 NOP 1 +LD A,D 7A 1 NOP 1 +LD A,E 7B 1 NOP 1 +LD A,H 7C 1 NOP 1 +LD A,I 57ED 2 NOP 1 +LD A,L 7D 1 NOP 1 +LD A,R 5FED 2 NOP 1 +LD A,(*) 3A 3 NOP 1 +LD A,* 3E 2 NOP 1 +LD B,(HL) 46 1 NOP 1 +LD B,(IX*) 46DD 3 ZIX 1 +LD B,(IY*) 46FD 3 ZIX 1 +LD B,A 47 1 NOP 1 +LD B,B 40 1 NOP 1 +LD B,C 41 1 NOP 1 +LD B,D 42 1 NOP 1 +LD B,E 43 1 NOP 1 +LD B,H 44 1 NOP 1 +LD B,L 45 1 NOP 1 +LD B,* 06 2 NOP 1 +LD BC,(*) 4BED 4 NOP 1 +LD BC,* 01 3 NOP 1 +LD C,(HL) 4E 1 NOP 1 +LD C,(IX*) 4EDD 3 ZIX 1 +LD C,(IY*) 4EFD 3 ZIX 1 +LD C,A 4F 1 NOP 1 +LD C,B 48 1 NOP 1 +LD C,C 49 1 NOP 1 +LD C,D 4A 1 NOP 1 +LD C,E 4B 1 NOP 1 +LD C,H 4C 1 NOP 1 +LD C,L 4D 1 NOP 1 +LD C,* 0E 2 NOP 1 +LD D,(HL) 56 1 NOP 1 +LD D,(IX*) 56DD 3 ZIX 1 +LD D,(IY*) 56FD 3 ZIX 1 +LD D,A 57 1 NOP 1 +LD D,B 50 1 NOP 1 +LD D,C 51 1 NOP 1 +LD D,D 52 1 NOP 1 +LD D,E 53 1 NOP 1 +LD D,H 54 1 NOP 1 +LD D,L 55 1 NOP 1 +LD D,* 16 2 NOP 1 +LD DE,(*) 5BED 4 NOP 1 +LD DE,* 11 3 NOP 1 +LD E,(HL) 5E 1 NOP 1 +LD E,(IX*) 5EDD 3 ZIX 1 +LD E,(IY*) 5EFD 3 ZIX 1 +LD E,A 5F 1 NOP 1 +LD E,B 58 1 NOP 1 +LD E,C 59 1 NOP 1 +LD E,D 5A 1 NOP 1 +LD E,E 5B 1 NOP 1 +LD E,H 5C 1 NOP 1 +LD E,L 5D 1 NOP 1 +LD E,* 1E 2 NOP 1 +LD H,(HL) 66 1 NOP 1 +LD H,(IX*) 66DD 3 ZIX 1 +LD H,(IY*) 66FD 3 ZIX 1 +LD H,A 67 1 NOP 1 +LD H,B 60 1 NOP 1 +LD H,C 61 1 NOP 1 +LD H,D 62 1 NOP 1 +LD H,E 63 1 NOP 1 +LD H,H 64 1 NOP 1 +LD H,L 65 1 NOP 1 +LD H,* 26 2 NOP 1 +LD HL,(*) 2A 3 NOP 1 +LD HL,* 21 3 NOP 1 +LD I,A 47ED 2 NOP 1 +LD IX,(*) 2ADD 4 NOP 1 +LD IX,* 21DD 4 NOP 1 +LD IY,(*) 2AFD 4 NOP 1 +LD IY,* 21FD 4 NOP 1 +LD L,(HL) 6E 1 NOP 1 +LD L,(IX*) 6EDD 3 ZIX 1 +LD L,(IY*) 6EFD 3 ZIX 1 +LD L,A 6F 1 NOP 1 +LD L,B 68 1 NOP 1 +LD L,C 69 1 NOP 1 +LD L,D 6A 1 NOP 1 +LD L,E 6B 1 NOP 1 +LD L,H 6C 1 NOP 1 +LD L,L 6D 1 NOP 1 +LD L,* 2E 2 NOP 1 +LD R,A 4FED 2 NOP 1 +LD SP,(*) 7BED 4 NOP 1 +LD SP,HL F9 1 NOP 1 +LD SP,IX F9DD 2 NOP 1 +LD SP,IY F9FD 2 NOP 1 +LD SP,* 31 3 NOP 1 +LDD "" A8ED 2 NOP 1 +LDDR "" B8ED 2 NOP 1 +LDI "" A0ED 2 NOP 1 +LDIR "" B0ED 2 NOP 1 +NEG "" 44ED 2 NOP 1 +NOP "" 00 1 NOP 1 + +MLT BC 4CED 2 NOP 1 +MLT DE 5CED 2 NOP 1 +MLT HL 6CED 2 NOP 1 +MLT SP 7CED 2 NOP 1 + +OR (HL) B6 1 NOP 1 +OR (IX*) B6DD 3 ZIX 1 +OR (IY*) B6FD 3 ZIX 1 +OR A B7 1 NOP 1 +OR B B0 1 NOP 1 +OR C B1 1 NOP 1 +OR D B2 1 NOP 1 +OR E B3 1 NOP 1 +OR H B4 1 NOP 1 +OR L B5 1 NOP 1 +OR * F6 2 NOP 1 + +OTDM "" 8BED 2 NOP 1 +OTDMR "" 9BED 2 NOP 1 +OTDR "" BBED 2 NOP 1 +OTIM "" 83ED 2 NOP 1 +OTIMR "" 93ED 2 NOP 1 +OTIR "" B3ED 2 NOP 1 + +OUT (C),A 79ED 2 NOP 1 +OUT (C),B 41ED 2 NOP 1 +OUT (C),C 49ED 2 NOP 1 +OUT (C),D 51ED 2 NOP 1 +OUT (C),E 59ED 2 NOP 1 +OUT (C),H 61ED 2 NOP 1 +OUT (C),L 69ED 2 NOP 1 +OUT (*),A D3 2 NOP 1 + +OUT0 (*),A 39ED 3 NOP 1 +OUT0 (*),B 01ED 3 NOP 1 +OUT0 (*),C 09ED 3 NOP 1 +OUT0 (*),D 11ED 3 NOP 1 +OUT0 (*),E 19ED 3 NOP 1 +OUT0 (*),H 21ED 3 NOP 1 +OUT0 (*),L 29ED 3 NOP 1 + +OUTD "" ABED 2 NOP 1 +OUTI "" A3ED 2 NOP 1 + +POP AF F1 1 NOP 1 +POP BC C1 1 NOP 1 +POP DE D1 1 NOP 1 +POP HL E1 1 NOP 1 +POP IX E1DD 2 NOP 1 +POP IY E1FD 2 NOP 1 + +PUSH AF F5 1 NOP 1 +PUSH BC C5 1 NOP 1 +PUSH DE D5 1 NOP 1 +PUSH HL E5 1 NOP 1 +PUSH IX E5DD 2 NOP 1 +PUSH IY E5FD 2 NOP 1 + +RES *,(HL) 86CB 2 ZBIT 1 +RES *,(IX*) CBDD 4 ZBIT 1 0 8600 +RES *,(IY*) CBFD 4 ZBIT 1 0 8600 +RES *,A 87CB 2 ZBIT 1 +RES *,B 80CB 2 ZBIT 1 +RES *,C 81CB 2 ZBIT 1 +RES *,D 82CB 2 ZBIT 1 +RES *,E 83CB 2 ZBIT 1 +RES *,H 84CB 2 ZBIT 1 +RES *,L 85CB 2 ZBIT 1 + +RET "" C9 1 NOP 1 +RET C D8 1 NOP 1 +RET M F8 1 NOP 1 +RET NC D0 1 NOP 1 +RET NZ C0 1 NOP 1 +RET P F0 1 NOP 1 +RET PE E8 1 NOP 1 +RET PO E0 1 NOP 1 +RET Z C8 1 NOP 1 +RETI "" 4DED 2 NOP 1 +RETN "" 45ED 2 NOP 1 + +RL (HL) 16CB 2 NOP 1 +RL (IX*) CBDD 4 ZIX 1 0 1600 +RL (IY*) CBFD 4 ZIX 1 0 1600 +RL A 17CB 2 NOP 1 +RL B 10CB 2 NOP 1 +RL C 11CB 2 NOP 1 +RL D 12CB 2 NOP 1 +RL E 13CB 2 NOP 1 +RL H 14CB 2 NOP 1 +RL L 15CB 2 NOP 1 +RLA "" 17 1 NOP 1 + +RLC (HL) 06CB 2 NOP 1 +RLC (IX*) CBDD 4 ZIX 1 0 0600 +RLC (IY*) CBFD 4 ZIX 1 0 0600 +RLC A 07CB 2 NOP 1 +RLC B 00CB 2 NOP 1 +RLC C 01CB 2 NOP 1 +RLC D 02CB 2 NOP 1 +RLC E 03CB 2 NOP 1 +RLC H 04CB 2 NOP 1 +RLC L 05CB 2 NOP 1 +RLCA "" 07 1 NOP 1 +RLD "" 6FED 2 NOP 1 + +RR (HL) 1ECB 2 NOP 1 +RR (IX*) CBDD 4 ZIX 1 0 1E00 +RR (IY*) CBFD 4 ZIX 1 0 1E00 +RR A 1FCB 2 NOP 1 +RR B 18CB 2 NOP 1 +RR C 19CB 2 NOP 1 +RR D 1ACB 2 NOP 1 +RR E 1BCB 2 NOP 1 +RR H 1CCB 2 NOP 1 +RR L 1DCB 2 NOP 1 +RRA "" 1F 1 NOP 1 +RRC (HL) 0ECB 2 NOP 1 +RRC (IX*) CBDD 4 ZIX 1 0 0E00 +RRC (IY*) CBFD 4 ZIX 1 0 0E00 +RRC A 0FCB 2 NOP 1 +RRC B 08CB 2 NOP 1 +RRC C 09CB 2 NOP 1 +RRC D 0ACB 2 NOP 1 +RRC E 0BCB 2 NOP 1 +RRC H 0CCB 2 NOP 1 +RRC L 0DCB 2 NOP 1 +RRCA "" 0F 1 NOP 1 +RRD "" 67ED 2 NOP 1 + +RST 00H C7 1 NOP 1 +RST 08H CF 1 NOP 1 +RST 10H D7 1 NOP 1 +RST 18H DF 1 NOP 1 +RST 20H E7 1 NOP 1 +RST 28H EF 1 NOP 1 +RST 30H F7 1 NOP 1 +RST 38H FF 1 NOP 1 + +/* Alternate form of above +RST 00 C7 1 NOP 1 +RST 08 CF 1 NOP 1 +RST 10 D7 1 NOP 1 +RST 18 DF 1 NOP 1 +RST 20 E7 1 NOP 1 +RST 28 EF 1 NOP 1 +RST 30 F7 1 NOP 1 +RST 38 FF 1 NOP 1 + +SBC A,(HL) 9E 1 NOP 1 +SBC A,(IX*) 9EDD 3 ZIX 1 +SBC A,(IY*) 9EFD 3 ZIX 1 +SBC A,A 9F 1 NOP 1 +SBC A,B 98 1 NOP 1 +SBC A,C 99 1 NOP 1 +SBC A,D 9A 1 NOP 1 +SBC A,E 9B 1 NOP 1 +SBC A,H 9C 1 NOP 1 +SBC A,L 9D 1 NOP 1 +SBC HL,BC 42ED 2 NOP 1 +SBC HL,DE 52ED 2 NOP 1 +SBC HL,HL 62ED 2 NOP 1 +SBC HL,SP 72ED 2 NOP 1 +SBC A,* DE 2 NOP 1 +SCF "" 37 1 NOP 1 + +SET *,(HL) C6CB 2 ZBIT 1 +SET *,(IX*) CBDD 4 ZBIT 1 0 C600 +SET *,(IY*) CBFD 4 ZBIT 1 0 C600 +SET *,A C7CB 2 ZBIT 1 +SET *,B C0CB 2 ZBIT 1 +SET *,C C1CB 2 ZBIT 1 +SET *,D C2CB 2 ZBIT 1 +SET *,E C3CB 2 ZBIT 1 +SET *,H C4CB 2 ZBIT 1 +SET *,L C5CB 2 ZBIT 1 + +SLA (HL) 26CB 2 NOP 1 +SLA (IX*) CBDD 4 ZIX 1 0 2600 +SLA (IY*) CBFD 4 ZIX 1 0 2600 +SLA A 27CB 2 NOP 1 +SLA B 20CB 2 NOP 1 +SLA C 21CB 2 NOP 1 +SLA D 22CB 2 NOP 1 +SLA E 23CB 2 NOP 1 +SLA H 24CB 2 NOP 1 +SLA L 25CB 2 NOP 1 + +SLP "" 76ED 2 NOP 1 + +SRA (HL) 2ECB 2 NOP 1 +SRA (IX*) CBDD 4 ZIX 1 0 2E00 +SRA (IY*) CBFD 4 ZIX 1 0 2E00 +SRA A 2FCB 2 NOP 1 +SRA B 28CB 2 NOP 1 +SRA C 29CB 2 NOP 1 +SRA D 2ACB 2 NOP 1 +SRA E 2BCB 2 NOP 1 +SRA H 2CCB 2 NOP 1 +SRA L 2DCB 2 NOP 1 + +SRL (HL) 3ECB 2 NOP 1 +SRL (IX*) CBDD 4 ZIX 1 0 3E00 +SRL (IY*) CBFD 4 ZIX 1 0 3E00 +SRL A 3FCB 2 NOP 1 +SRL B 38CB 2 NOP 1 +SRL C 39CB 2 NOP 1 +SRL D 3ACB 2 NOP 1 +SRL E 3BCB 2 NOP 1 +SRL H 3CCB 2 NOP 1 +SRL L 3DCB 2 NOP 1 + +SUB (HL) 96 1 NOP 1 +SUB (IX*) 96DD 3 ZIX 1 +SUB (IY*) 96FD 3 ZIX 1 +SUB A 97 1 NOP 1 +SUB B 90 1 NOP 1 +SUB C 91 1 NOP 1 +SUB D 92 1 NOP 1 +SUB E 93 1 NOP 1 +SUB H 94 1 NOP 1 +SUB L 95 1 NOP 1 +SUB * D6 2 NOP 1 + +TST A 3CED 2 NOP 1 +TST B 04ED 2 NOP 1 +TST C 0CED 2 NOP 1 +TST D 14ED 2 NOP 1 +TST E 1CED 2 NOP 1 +TST H 24ED 2 NOP 1 +TST L 2CED 2 NOP 1 +TST (HL) 34ED 2 NOP 1 +TST * 64ED 3 NOP 1 + +TSTIO * 74ED 3 NOP 1 + +XOR (HL) AE 1 NOP 1 +XOR (IX*) AEDD 3 ZIX 1 +XOR (IY*) AEFD 3 ZIX 1 +XOR A AF 1 NOP 1 +XOR B A8 1 NOP 1 +XOR C A9 1 NOP 1 +XOR D AA 1 NOP 1 +XOR E AB 1 NOP 1 +XOR H AC 1 NOP 1 +XOR L AD 1 NOP 1 +XOR * EE 2 NOP 1 diff --git a/trunk/Tools/tasm32/TASM3210.TAB b/trunk/Tools/tasm32/TASM3210.TAB new file mode 100644 index 00000000..88dbddd5 --- /dev/null +++ b/trunk/Tools/tasm32/TASM3210.TAB @@ -0,0 +1,205 @@ +"TASM TMS32010 Assembler." +/**************************************************************************** +/* $Id: tasm3210.tab 1.1 1993/07/31 01:12:40 toma Exp $ +/**************************************************************************** +/* This is the instruction set definition table +/* for the TMS32010 version of TASM. +/* Thomas N. Anderson, Speech Technology Incorporated +/* +/* See TASM manual for info on table structure. +/* +/*INSTR ARGS OPCODE BYTES MOD CLASS SHIFT MASK */ +/*-------------------------------------------*/ + +/* Generate opcodes high byte first */ +.MSFIRST +/* Don't use '*' as the wild card since it is used for indirect addressing */ +/* In this table '@' is the wild card indicating where expression may appear*/ +.ALTWILD +/* Use word addressing (not byte addressing) +.WORDADDRS +/* All shift/and stuff applies to opcodes, not args +.NOARGSHIFT + +.REGSET *+ A0 1 +.REGSET *- 90 1 +.REGSET * 80 1 + +ABS "" 7F88 2 NOP 1 + +ADD !,@,@ 0000 2 T1 1 8 0F00 +ADD !,@ 0008 2 T1 1 8 0F00 +ADD ! 0008 2 NOP 1 +ADD @,@ 0000 2 TDMA 1 8 0F00 +ADD @ 0000 2 T1 1 0 007F + +ADDH !,@ 6000 2 T1 1 0 01 +ADDH ! 6008 2 NOP 1 +ADDH @ 6000 2 T1 1 0 007F + +ADDS !,@ 6100 2 T1 1 0 01 +ADDS ! 6108 2 NOP 1 +ADDS @ 6100 2 T1 1 0 007F + +AND !,@ 7900 2 T1 1 0 01 +AND ! 7908 2 NOP 1 +AND @ 7900 2 T1 1 0 7F + +APAC "" 7F8F 2 NOP 1 +B @ F900 4 SWAP 1 +BANZ @ F400 4 SWAP 1 +BGEZ @ FD00 4 SWAP 1 +BGZ @ FC00 4 SWAP 1 +BIOZ @ F600 4 SWAP 1 +BLEZ @ FB00 4 SWAP 1 +BLZ @ FA00 4 SWAP 1 +BNZ @ FE00 4 SWAP 1 +BV @ F500 4 SWAP 1 +BZ @ FF00 4 SWAP 1 +CALA "" 7F8C 2 NOP 1 +CALL @ F800 4 SWAP 1 +DINT "" 7F81 2 NOP 1 + +DMOV !,@ 6900 2 T1 1 0 01 +DMOV ! 6908 2 NOP 1 +DMOV @ 6900 2 T1 1 0 007F + +EINT "" 7F82 2 NOP 1 + +IN !,@,@ 4000 2 T1 1 8 0700 +IN !,@ 4008 2 T1 1 8 0700 +IN @,@ 4000 2 TDMA 1 8 0700 + +LAC !,@,@ 2000 2 T1 1 8 0F00 +LAC !,@ 2008 2 T1 1 8 0F00 +LAC ! 2008 2 NOP 1 +LAC @,@ 2000 2 TDMA 1 8 0F00 +LAC @ 2000 2 T1 1 0 007F + +LACK @ 7E00 2 T1 1 0 00FF + +LAR @,!,@ 3800 2 TAR 1 0 0001 +LAR @,! 3808 2 TAR 1 0 0001 +LAR @,@ 3800 2 TAR 1 0 007F + +LARK @,@ 7000 2 TAR 1 0 00FF +LARP @ 6880 2 T1 1 0 0001 + +LDP !,@ 6F00 2 T1 1 0 01 +LDP ! 6F08 2 NOP 1 +LDP @ 6F00 2 T1 1 0 007F + +LDPK @ 6E00 2 T1 1 0 01 + +LST !,@ 7B00 2 T1 1 0 01 +LST ! 7B08 2 NOP 1 +LST @ 7B00 2 T1 1 0 007F + +LT !,@ 6A00 2 T1 1 0 01 +LT ! 6A08 2 NOP 1 +LT @ 6A00 2 T1 1 0 007F + +LTA !,@ 6C00 2 T1 1 0 01 +LTA ! 6C08 2 NOP 1 +LTA @ 6C00 2 T1 1 0 007F + +LTD !,@ 6B00 2 T1 1 0 01 +LTD ! 6B08 2 NOP 1 +LTD @ 6B00 2 T1 1 0 007F + +MAR !,@ 6800 2 T1 1 0 01 +MAR ! 6808 2 NOP 1 +MAR @ 6800 2 T1 1 0 007F + +MPY !,@ 6D00 2 T1 1 0 01 +MPY ! 6D08 2 NOP 1 +MPY @ 6D00 2 T1 1 0 007F + +MPYK @ 8000 2 T1 1 0 1FFF + +NOP "" 7F80 2 NOP 1 + +OR !,@ 7A00 2 T1 1 0 01 +OR ! 7A08 2 NOP 1 +OR @ 7A00 2 T1 1 0 007F + +OUT !,@,@ 4800 2 T1 1 8 0700 +OUT !,@ 4808 2 T1 1 8 0700 +OUT @,@ 4800 2 TDMA 1 8 0700 + +PAC "" 7F8E 2 NOP 1 +POP "" 7F9D 2 NOP 1 +PUSH "" 7F9C 2 NOP 1 +RET "" 7F8D 2 NOP 1 +ROVM "" 7F8A 2 NOP 1 + +/* shift count for SACH can only be 0,1, or 4. The mask allows */ +/* 0,1,4, or 5. Let the user beware */ +SACH !,@,@ 5800 2 T1 1 8 0500 +SACH !,@ 5808 2 T1 1 8 0500 +SACH ! 5808 2 NOP 1 +SACH @,@ 5800 2 TDMA 1 8 0500 +SACH @ 5800 2 T1 1 0 007F + +/* The data book shows a shift field for SACL but states it must be 0. +/* The previous version of this table left the shift field out +/* for simplicity, but here I have put it back for compatibility. +/* The AND mask is set to zero in this case so a error message +/* will result from non-zero shifts. +SACL !,@,@ 5000 2 T1 1 8 0000 +SACL !,@ 5008 2 T1 1 8 0000 +SACL ! 5008 2 NOP 1 +SACL @,@ 5000 2 TDMA 1 8 0000 +SACL @ 5000 2 T1 1 0 007F + +SAR @,!,@ 3000 2 TAR 1 0 0001 +SAR @,! 3008 2 TAR 1 0 0001 +SAR @,@ 3000 2 TAR 1 0 007F + +SOVM "" 7F8B 2 NOP 1 +SPAC "" 7F90 2 NOP 1 + +SST !,@ 7C00 2 T1 1 0 0001 +SST ! 7C08 2 NOP 1 +SST @ 7C00 2 T1 1 0 007F + +SUB !,@,@ 1000 2 T1 1 8 0F00 +SUB !,@ 1008 2 T1 1 8 0F00 +SUB ! 1008 2 NOP 1 +SUB @,@ 1000 2 TDMA 1 8 0F00 +SUB @ 1000 2 T1 1 0 007F + +SUBC !,@ 6400 2 T1 1 0 01 +SUBC ! 6408 2 NOP 1 +SUBC @ 6400 2 T1 1 0 007F + +SUBH !,@ 6200 2 T1 1 0 01 +SUBH ! 6208 2 NOP 1 +SUBH @ 6200 2 T1 1 0 007F + +SUBS !,@ 6300 2 T1 1 0 01 +SUBS ! 6308 2 NOP 1 +SUBS @ 6300 2 T1 1 0 007F + +TBLR !,@ 6700 2 T1 1 0 01 +TBLR ! 6708 2 NOP 1 +TBLR @ 6700 2 T1 1 0 007F + +TBLW !,@ 7D00 2 T1 1 0 01 +TBLW ! 7D08 2 NOP 1 +TBLW @ 7D00 2 T1 1 0 007F + +XOR !,@ 7800 2 T1 1 0 01 +XOR ! 7808 2 NOP 1 +XOR @ 7800 2 T1 1 0 007F + +ZAC "" 7F89 2 NOP 1 + +ZALH !,@ 6500 2 T1 1 0 01 +ZALH ! 6508 2 NOP 1 +ZALH @ 6500 2 T1 1 0 007F + +ZALS !,@ 6600 2 T1 1 0 01 +ZALS ! 6608 2 NOP 1 +ZALS @ 6600 2 T1 1 0 007F + diff --git a/trunk/Tools/tasm32/TASM3225.TAB b/trunk/Tools/tasm32/TASM3225.TAB new file mode 100644 index 00000000..6535309a --- /dev/null +++ b/trunk/Tools/tasm32/TASM3225.TAB @@ -0,0 +1,456 @@ +"TASM TMS32025 Assembler." +/**************************************************************************** +/* $Id: tasm3225.tab 1.2 1997/09/28 22:16:44 toma Exp $ +/**************************************************************************** +/* This is the instruction set definition table +/* for the TMS32025 version of TASM. +/* Bob Stricklin +/* +/* See TASM manual for info on table structure. +/* +/*INSTR ARGS OPCODE BYTES MOD CLASS SHIFT MASK */ +/*-------------------------------------------*/ + +/* Generate opcodes high byte first */ +.MSFIRST +/* Don't use '*' as the wild card since it is used for indirect addressing */ +/* In this table '@' is the wild card indicating where expression may appear*/ +.ALTWILD +.WORDADDRS +.NOARGSHIFT + +/* Addressing mode definitions. +/* Value gets OR'd in to the opcode if the +/* addressing mode is recognized +/* Note: no special classes are defined, so if this +/* table is used for TMS32020, invalid instructions +/* will not result in errors (no BR0+/- addressing mode (for example) +/* The ! character can match any of the patterns in the REGSET: +.REGSET *BR0+ F0 1 +.REGSET *BR0- C0 1 +.REGSET *0+ E0 1 +.REGSET *0- D0 1 +.REGSET *+ A0 1 +.REGSET *- 90 1 +.REGSET * 80 1 + + + + +ABS "" CE1B 2 NOP 1 + +ADD !,@,@ 0088 2 T1 1 8 0F00 +ADD !,@ 0080 2 T1 1 8 0F00 +ADD ! 0080 2 NOP 1 +ADD @,@ 0000 2 TDMA 1 8 0F00 +ADD @ 0000 2 T1 1 0 007F + +ADDC !,@ 4388 2 T1 1 0 0007 +ADDC ! 4380 2 NOP 1 +ADDC @ 4300 2 T1 1 0 007F + +ADDH !,@ 4888 2 T1 1 0 0007 +ADDH ! 4880 2 NOP 1 +ADDH @ 4800 2 T1 1 0 007F + +ADDK @ CC00 2 T1 1 0 00FF ;8 bit constant + +ADDS !,@ 4988 2 T1 1 0 0007 +ADDS ! 4980 2 NOP 1 +ADDS @ 4900 2 T1 1 0 007F + +ADDT !,@ 4A88 2 T1 1 0 0007 +ADDT ! 4A80 2 NOP 1 +ADDT @ 4A00 2 T1 1 0 007F + +ADLK @,@ D002 4 TLK 1 8 0F00 +ADLK @ D002 4 TLK 1 + +ADRK @ 7E00 2 T1 1 0 00FF ;8 bit constant + +AND !,@ 4E88 2 T1 1 0 0007 +AND ! 4E80 2 NOP 1 +AND @ 4E00 2 T1 1 0 007F + +ANDK @,@ D004 4 TLK 1 8 0F00 +ANDK @ D004 4 TLK 1 + +APAC "" CE15 2 NOP 1 + +B @,!,@ FF88 4 TLK 1 0 07 +B @,! FF80 4 SWAP 1 +B @ FF80 4 SWAP 1 + +BACC "" CE25 2 NOP 1 + +BANZ @,!,@ FB88 4 TLK 1 0 07 +BANZ @,! FB80 4 SWAP 1 +BANZ @ FB90 4 SWAP 1 ; Default to the equivalent of + ; BANZ loop,*- (as per spec) for + ; TMS32010 compatibility. + +BBNZ @,!,@ F988 4 TLK 1 0 07 +BBNZ @,! F980 4 SWAP 1 +BBNZ @ F980 4 SWAP 1 + +BBZ @,!,@ F888 4 TLK 1 0 07 +BBZ @,! F880 4 SWAP 1 +BBZ @ F880 4 SWAP 1 + +BC @,!,@ 5E88 4 TLK 1 0 07 +BC @,! 5E80 4 SWAP 1 +BC @ 5E80 4 SWAP 1 + +BGEZ @,!,@ F488 4 TLK 1 0 07 +BGEZ @,! F480 4 SWAP 1 +BGEZ @ F480 4 SWAP 1 + +BGZ @,!,@ F188 4 TLK 1 0 07 +BGZ @,! F180 4 SWAP 1 +BGZ @ F180 4 SWAP 1 + +BIOZ @,!,@ FA88 4 TLK 1 0 07 +BIOZ @,! FA80 4 SWAP 1 +BIOZ @ FA80 4 SWAP 1 + +BIT !,@,@ 9088 2 T1 1 8 0F00 ;8 bit shift +BIT !,@ 9080 2 T1 1 8 0F00 +BIT @,@ 9000 2 TDMA 1 8 0F00 + +BITT !,@ 5788 2 T1 1 0 07 +BITT ! 5780 2 T1 1 +BITT @ 5700 2 T1 1 0 7F + +BLEZ @,!,@ F288 4 TLK 1 0 07 +BLEZ @,! F280 4 SWAP 1 +BLEZ @ F280 4 SWAP 1 + +BLKD @,!,@ FD88 4 TLK 1 0 07 +BLKD @,! FD80 4 TLK 1 0 07 +BLKD @,@ FD00 4 TLK 1 0 FF + +BLKP @,!,@ FC88 4 TLK 1 0 07 +BLKP @,! FC80 4 TLK 1 0 07 +BLKP @,@ FC00 4 TLK 1 0 FF + +BLZ @,!,@ F388 4 TLK 1 0 07 +BLZ @,! F380 4 SWAP 1 +BLZ @ F380 4 SWAP 1 + +BNC @,!,@ 5F88 4 TLK 1 0 07 +BNC @,! 5F80 4 SWAP 1 +BNC @ 5F80 4 SWAP 1 + +BNV @,!,@ F788 4 TLK 1 0 07 +BNV @,! F780 4 SWAP 1 +BNV @ F780 4 SWAP 1 + +BNZ @,!,@ F588 4 TLK 1 0 07 +BNZ @,! F580 4 SWAP 1 +BNZ @ F580 4 SWAP 1 + +BV @,!,@ F088 4 TLK 1 0 07 +BV @,! F080 4 SWAP 1 +BV @ F080 4 SWAP 1 + +BZ @,!,@ F688 4 TLK 1 0 07 +BZ @,! F680 4 SWAP 1 +BZ @ F680 4 SWAP 1 + +CALA "" CE24 2 NOP 1 + +CALL @,!,@ FE88 4 TLK 1 0 07 +CALL @,! FE80 4 SWAP 1 +CALL @ FE80 4 SWAP 1 + +CMPL "" CE27 2 NOP 1 + +CMPR @ CE50 2 T1 1 0 03 ;2 BIT CONTANT + +CNFD "" CE04 2 NOP 1 + +CNFP "" CE05 2 NOP 1 + +CONF "" CE3C 2 T1 4 0 03 ; c26 ONLY + +DINT "" CE01 2 NOP 1 + +DMOV !,@ 5688 2 T1 1 0 07 +DMOV ! 5680 2 NOP 1 +DMOV @ 5600 2 T1 1 0 007F + +EINT "" CE00 2 NOP 1 + +FORT @ CE0E 2 T1 1 0 01 + +IDLE "" CE1F 2 NOP 1 + +IN !,@,@ 8088 2 T1 1 8 0F00 +IN !,@ 8080 2 T1 1 8 0F00 +IN @,@ 8000 2 TDMA 1 8 0F00 + +LAC !,@,@ 2088 2 T1 1 8 0F00 +LAC !,@ 2080 2 T1 1 8 0F00 +LAC ! 2080 2 NOP 1 +LAC @,@ 2000 2 TDMA 1 8 0F00 +LAC @ 2000 2 T1 1 0 007F + +LACK @ CA00 2 T1 1 0 00FF ;tested for -25 + +LACT !,@ 4288 2 T1 1 0 07 +LACT ! 4280 2 NOP 1 +LACT @ 4200 2 T1 1 0 007F + +LALK @,@ D001 4 TLK 1 8 0F00 +LALK @ D001 4 TLK 1 + +LAR @,!,@ 3088 2 TAR 1 0 07 +LAR @,! 3080 2 TAR 1 0 07 +LAR @,@ 3000 2 TAR 1 0 7F + +LARK @,@ C000 2 TAR 1 0 00FF +LARP @ 5588 2 T1 1 0 0007 + +LDP !,@ 5288 2 T1 1 0 07 +LDP ! 5280 2 NOP 1 +LDP @ 5200 2 T1 1 0 007F + +LDPK @ C800 2 T1 1 0 01FF ;9 bit constant + +LPH !,@ 5388 2 T1 1 0 07 +LPH ! 5380 2 NOP 1 +LPH @ 5300 2 T1 1 0 7F + +LRLK @,@ D000 4 T5 1 8 0700 ;, + +LST !,@ 5088 2 T1 1 0 07 +LST ! 5080 2 NOP 1 +LST @ 5000 2 T1 1 0 7F + +LST1 !,@ 5188 2 T1 1 0 07 +LST1 ! 5180 2 NOP 1 +LST1 @ 5100 2 T1 1 0 7F + +LT !,@ 3C88 2 T1 1 0 07 +LT ! 3C80 2 NOP 1 +LT @ 3C00 2 T1 1 0 7F + +LTA !,@ 3D88 2 T1 1 0 07 +LTA ! 3D80 2 NOP 1 +LTA @ 3D00 2 T1 1 0 7F + +LTD !,@ 3F88 2 T1 1 0 07 +LTD ! 3F80 2 NOP 1 +LTD @ 3F00 2 T1 1 0 7F + +LTP !,@ 3E88 2 T1 1 0 07 +LTP ! 3E80 2 NOP 1 +LTP @ 3E00 2 T1 1 0 7F + +LTS !,@ 5B88 2 T1 1 0 07 +LTS ! 5B80 2 NOP 1 +LTS @ 5B00 2 T1 1 0 7F + +MAC @,!,@ 5D88 4 TLK 1 0 07 +MAC @,! 5D80 4 TLK 1 0 07 +MAC @,@ 5D00 4 TLK 1 0 7F + +MACD @,!,@ 5C88 4 TLK 1 0 07 +MACD @,! 5C80 4 TLK 1 0 07 +MACD @,@ 5C00 4 TLK 1 0 7F + +MAR !,@ 5588 2 T1 1 0 07 +MAR ! 5580 2 NOP 1 +MAR @ 5500 2 T1 1 0 7F + +MPY !,@ 3888 2 T1 1 0 07 +MPY ! 3880 2 NOP 1 +MPY @ 3800 2 T1 1 0 7F + +MPYA !,@ 3A88 2 T1 1 0 07 +MPYA ! 3A80 2 NOP 1 +MPYA @ 3A00 2 T1 1 0 7F + +MPYK @ A000 2 T1 1 0 1FFF ;13 BIT CONTSTANT + +MPYS !,@ 3B88 2 T1 1 0 07 +MPYS ! 3B80 2 NOP 1 +MPYS @ 3B00 2 T1 1 0 7F + +MPYU !,@ CF88 2 T1 1 0 07 +MPYU ! CF80 2 NOP 1 +MPYU @ CF00 2 T1 1 0 7F + +NEG "" CE23 2 NOP 1 + +NOP "" 5500 2 NOP 1 + +NORM ! CE82 2 NOP 1 ; C25 +NORM "" CEA2 2 NOP 1 ; C20 + +OR !,@ 4D88 2 T1 1 0 07 +OR ! 4D80 2 NOP 1 +OR @ 4D00 2 T1 1 0 7F + +ORK @,@ D005 4 TLK 1 8 0F00 +ORK @ D005 4 TLK 1 + +OUT !,@,@ E088 2 T1 1 8 0F00 +OUT !,@ E080 2 T1 1 8 0F00 +OUT @,@ E000 2 TDMA 1 8 0F00 + +PAC "" CE14 2 NOP 1 + +POP "" CE1D 2 NOP 1 + +POPD !,@ 7A88 2 T1 1 0 07 +POPD ! 7A80 2 NOP 1 +POPD @ 7A00 2 T1 1 0 7F + +PSHD !,@ 5488 2 T1 1 0 07 +PSHD ! 5480 2 NOP 1 +PSHD @ 5400 2 T1 1 0 7F + +PUSH "" CE1C 2 NOP 1 +RC "" CE30 2 NOP 1 +RET "" CE26 2 NOP 1 +RFSM "" CE36 2 NOP 1 +RHM "" CE38 2 NOP 1 +ROL "" CE34 2 NOP 1 +ROR "" CE35 2 NOP 1 +ROVM "" CE02 2 NOP 1 + +RPT !,@ 4B88 2 T1 1 0 07 +RPT ! 4B80 2 NOP 1 +RPT @ 4B00 2 T1 1 0 7F + +RPTK @ CB00 2 T1 1 0 00FF ;8 bit constant + +RSXM "" CE06 2 NOP 1 +RTC "" CE32 2 NOP 1 +RTXM "" CE20 2 NOP 1 +RXF "" CE0C 2 NOP 1 + +/* shift count for SACH can only be 0,1, or 4 FOR 32020 +/* 0-7 FOR 320c25. For now, build the table specifically for the 320C25 +SACH !,@,@ 6888 2 T1 1 8 0700 +SACH !,@ 6880 2 T1 1 8 0700 +SACH ! 6880 2 NOP 1 +SACH @,@ 6800 2 TDMA 1 8 0700 +SACH @ 6800 2 T1 1 0 007F + +SACL !,@,@ 6088 2 T1 1 8 0700 +SACL !,@ 6080 2 T1 1 8 0700 +SACL ! 6080 2 NOP 1 +SACL @,@ 6000 2 TDMA 1 8 0700 +SACL @ 6000 2 T1 1 0 007F + +SAR @,!,@ 7088 2 TAR 1 0 0007 +SAR @,! 7080 2 TAR 1 0 0007 +SAR @,@ 7000 2 TAR 1 0 007F + +SBLK @,@ D003 4 TLK 1 8 0F00 +SBLK @ D003 4 TLK 1 + +SBRK @ 7F00 2 T1 1 0 00FF + +SC "" CE31 2 NOP 1 +SFL "" CE18 2 NOP 1 +SFR "" CE19 2 NOP 1 +SFSM "" CE37 2 NOP 1 +SHM "" CE39 2 NOP 1 +SOVM "" CE03 2 NOP 1 +SPAC "" CE16 2 NOP 1 + +SPH !,@ 7D88 2 T1 1 0 07 +SPH ! 7D80 2 NOP 1 +SPH @ 7D00 2 T1 1 0 7F + +SPL !,@ 7C88 2 T1 1 0 07 +SPL ! 7C80 2 NOP 1 +SPL @ 7C00 2 T1 1 0 7F + +SPM @ CE08 2 T1 1 0 03 ;2 bit constant + +SQRA !,@ 3988 2 T1 1 0 07 +SQRA ! 3980 2 NOP 1 +SQRA @ 3900 2 T1 1 0 7F + +SQRS !,@ 5A88 2 T1 1 0 07 +SQRS ! 5A80 2 NOP 1 +SQRS @ 5A00 2 T1 1 0 7F + +SST !,@ 7888 2 T1 1 0 07 +SST ! 7880 2 NOP 1 +SST @ 7800 2 T1 1 0 7F + +SST1 !,@ 7988 2 T1 1 0 07 +SST1 ! 7980 2 NOP 1 +SST1 @ 7900 2 T1 1 0 7F + +SSXM "" CE07 2 NOP 1 +STC "" CE33 2 NOP 1 +STXM "" CE21 2 NOP 1 + + +SUB !,@,@ 1088 2 T1 1 8 0F00 +SUB !,@ 1080 2 T1 1 8 0F00 +SUB ! 1080 2 NOP 1 +SUB @,@ 1000 2 TDMA 1 8 0F00 +SUB @ 1000 2 T1 1 0 007F + +SUBB !,@ 4F88 2 T1 1 0 07 +SUBB ! 4F80 2 NOP 1 +SUBB @ 4F00 2 T1 1 0 7F + +SUBC !,@ 4788 2 T1 1 0 07 +SUBC ! 4780 2 NOP 1 +SUBC @ 4700 2 T1 1 0 7F + +SUBH !,@ 4488 2 T1 1 0 07 +SUBH ! 4480 2 NOP 1 +SUBH @ 4400 2 T1 1 0 7F + +SUBK @ CD00 2 T1 1 0 00FF + +SUBS !,@ 4588 2 T1 1 0 07 +SUBS ! 4580 2 NOP 1 +SUBS @ 4500 2 T1 1 0 7F + +SUBT !,@ 4688 2 T1 1 0 07 +SUBT ! 4680 2 NOP 1 +SUBT @ 4600 2 T1 1 0 7F + +SXF "" CE0D 2 NOP 1 + +TBLR !,@ 5888 2 T1 1 0 07 +TBLR ! 5880 2 NOP 1 +TBLR @ 5800 2 T1 1 0 7F + +TBLW !,@ 5988 2 T1 1 0 07 +TBLW ! 5980 2 NOP 1 +TBLW @ 5900 2 T1 1 0 7F + +TRAP "" CE1E 2 NOP 1 + +XOR !,@ 4C88 2 T1 1 0 07 +XOR ! 4C80 2 NOP 1 +XOR @ 4C00 2 T1 1 0 7F + +XORK @,@ D006 4 TLK 1 8 0F00 +XORK @ D006 4 TLK 1 + +ZAC "" CA00 2 NOP 1 + +ZALH !,@ 4088 2 T1 1 0 07 +ZALH ! 4080 2 NOP 1 +ZALH @ 4000 2 T1 1 0 7F + +ZALR !,@ 7B88 2 T1 1 0 07 +ZALR ! 7B80 2 NOP 1 +ZALR @ 7B00 2 T1 1 0 7F + +ZALS !,@ 4188 2 T1 1 0 07 +ZALS ! 4180 2 NOP 1 +ZALS @ 4100 2 T1 1 0 7F + diff --git a/trunk/Tools/tasm32/TASM48.TAB b/trunk/Tools/tasm32/TASM48.TAB new file mode 100644 index 00000000..c241a0ff --- /dev/null +++ b/trunk/Tools/tasm32/TASM48.TAB @@ -0,0 +1,281 @@ +"TASM 8048 Assembler. " +/**************************************************************************** +/* $Id: tasm48.tab 1.1 1993/07/31 01:12:40 toma Exp $ +/**************************************************************************** +/* This is the instruction set definition table for the 8048 version of TASM. +/* Thomas N. Anderson, Speech Technology Incorported, June 1987. +/* CLASS bits are assigned as follows: +/* bit 0 = 8X48, 8035, 8039, 8049 instructions +/* bit 1 = 8X41A +/* bit 2 = 8022 +/* bit 3 = 8021 +/* Note that some of the base instructions should be disabled for the +/* 8041, 8022, and 8021, but are not. +/* +/*INSTR ARGS OPCODE BYTES MOD CLASS SHIFT OR */ +/*-------------------------------------------*/ +ADD A,R0 68 1 NOP 1 +ADD A,R1 69 1 NOP 1 +ADD A,R2 6A 1 NOP 1 +ADD A,R3 6B 1 NOP 1 +ADD A,R4 6C 1 NOP 1 +ADD A,R5 6D 1 NOP 1 +ADD A,R6 6E 1 NOP 1 +ADD A,R7 6F 1 NOP 1 +ADD A,@R0 60 1 NOP 1 +ADD A,@R1 61 1 NOP 1 +ADD A,#* 03 2 NOP 1 + +ADDC A,R0 78 1 NOP 1 +ADDC A,R1 79 1 NOP 1 +ADDC A,R2 7A 1 NOP 1 +ADDC A,R3 7B 1 NOP 1 +ADDC A,R4 7C 1 NOP 1 +ADDC A,R5 7D 1 NOP 1 +ADDC A,R6 7E 1 NOP 1 +ADDC A,R7 7F 1 NOP 1 +ADDC A,@R0 70 1 NOP 1 +ADDC A,@R1 71 1 NOP 1 +ADDC A,#* 13 2 NOP 1 + +ANL A,R0 58 1 NOP 1 +ANL A,R1 59 1 NOP 1 +ANL A,R2 5A 1 NOP 1 +ANL A,R3 5B 1 NOP 1 +ANL A,R4 5C 1 NOP 1 +ANL A,R5 5D 1 NOP 1 +ANL A,R6 5E 1 NOP 1 +ANL A,R7 5F 1 NOP 1 +ANL A,@R0 50 1 NOP 1 +ANL A,@R1 51 1 NOP 1 +ANL A,#* 53 2 NOP 1 +ANL BUS,#* 98 2 NOP 1 +ANL P1,#* 99 2 NOP 1 +ANL P2,#* 9A 2 NOP 1 + +ANLD P4,A 9C 1 NOP 1 +ANLD P5,A 9D 1 NOP 1 +ANLD P6,A 9E 1 NOP 1 +ANLD P7,A 9F 1 NOP 1 + +CALL * 14 2 JMP 1 + +CLR A 27 1 NOP 1 +CLR C 97 1 NOP 1 +CLR F0 85 1 NOP 1 +CLR F1 A5 1 NOP 1 + +CPL A 37 1 NOP 1 +CPL C A7 1 NOP 1 +CPL F0 95 1 NOP 1 +CPL F1 B5 1 NOP 1 + +DA A 57 1 NOP 1 + +DEC A 07 1 NOP 1 +DEC R0 C8 1 NOP 1 +DEC R1 C9 1 NOP 1 +DEC R2 CA 1 NOP 1 +DEC R3 CB 1 NOP 1 +DEC R4 CC 1 NOP 1 +DEC R5 CD 1 NOP 1 +DEC R6 CE 1 NOP 1 +DEC R7 CF 1 NOP 1 + +DIS I 15 1 NOP 1 +DIS TCNTI 35 1 NOP 1 + +DJNZ R0,* E8 2 JTHISPAGE 1 +DJNZ R1,* E9 2 JTHISPAGE 1 +DJNZ R2,* EA 2 JTHISPAGE 1 +DJNZ R3,* EB 2 JTHISPAGE 1 +DJNZ R4,* EC 2 JTHISPAGE 1 +DJNZ R5,* ED 2 JTHISPAGE 1 +DJNZ R6,* EE 2 JTHISPAGE 1 +DJNZ R7,* EF 2 JTHISPAGE 1 + +EN DMA E5 1 NOP 2 ;8041 +EN FLAGS F5 1 NOP 2 ;8041 +EN I 05 1 NOP 1 +EN TCNTI 25 1 NOP 1 +ENT0 CLK 75 1 NOP 1 + +IN A,DBB 22 1 NOP 2 ;8041 +IN A,P0 08 1 NOP 8 ;8021 +IN A,P1 09 1 NOP 1 +IN A,P2 0A 1 NOP 1 + +INC A 17 1 NOP 1 +INC R0 18 1 NOP 1 +INC R1 19 1 NOP 1 +INC R2 1A 1 NOP 1 +INC R3 1B 1 NOP 1 +INC R4 1C 1 NOP 1 +INC R5 1D 1 NOP 1 +INC R6 1E 1 NOP 1 +INC R7 1F 1 NOP 1 +INC @R0 10 1 NOP 1 +INC @R1 11 1 NOP 1 + +INS A,BUS 08 1 NOP 1 + +JB0 * 12 2 JTHISPAGE 1 +JB1 * 32 2 JTHISPAGE 1 +JB2 * 52 2 JTHISPAGE 1 +JB3 * 72 2 JTHISPAGE 1 +JB4 * 92 2 JTHISPAGE 1 +JB5 * B2 2 JTHISPAGE 1 +JB6 * D2 2 JTHISPAGE 1 +JB7 * F2 2 JTHISPAGE 1 + +JMP * 04 2 JMP 1 + +JC * F6 2 JTHISPAGE 1 +JF0 * B6 2 JTHISPAGE 1 +JF1 * 76 2 JTHISPAGE 1 +JNC * E6 2 JTHISPAGE 1 +JNI * 86 2 JTHISPAGE 1 +JNIBF * D6 2 JTHISPAGE 2 ;8041 +JNT0 * 26 2 JTHISPAGE 1 +JNT1 * 46 2 JTHISPAGE 1 +JNZ * 96 2 JTHISPAGE 1 +JOBF * 86 2 JTHISPAGE 2 ;8041 +JTF * 16 2 JTHISPAGE 1 +JT0 * 36 2 JTHISPAGE 1 +JT1 * 56 2 JTHISPAGE 1 +JZ * C6 2 JTHISPAGE 1 + +JMPP @A B3 1 NOP 1 + +MOV A,PSW C7 1 NOP 1 +MOV A,R0 F8 1 NOP 1 +MOV A,R1 F9 1 NOP 1 +MOV A,R2 FA 1 NOP 1 +MOV A,R3 FB 1 NOP 1 +MOV A,R4 FC 1 NOP 1 +MOV A,R5 FD 1 NOP 1 +MOV A,R6 FE 1 NOP 1 +MOV A,R7 FF 1 NOP 1 +MOV A,T 42 1 NOP 1 +MOV A,@R0 F0 1 NOP 1 +MOV A,@R1 F1 1 NOP 1 +MOV A,#* 23 2 NOP 1 +MOV PSW,A D7 1 NOP 1 +MOV R0,A A8 1 NOP 1 +MOV R1,A A9 1 NOP 1 +MOV R2,A AA 1 NOP 1 +MOV R3,A AB 1 NOP 1 +MOV R4,A AC 1 NOP 1 +MOV R5,A AD 1 NOP 1 +MOV R6,A AE 1 NOP 1 +MOV R7,A AF 1 NOP 1 +MOV R0,#* B8 2 NOP 1 +MOV R1,#* B9 2 NOP 1 +MOV R2,#* BA 2 NOP 1 +MOV R3,#* BB 2 NOP 1 +MOV R4,#* BC 2 NOP 1 +MOV R5,#* BD 2 NOP 1 +MOV R6,#* BE 2 NOP 1 +MOV R7,#* BF 2 NOP 1 +MOV STS,A 90 1 NOP 2 ;8041 +MOV T,A 62 1 NOP 1 +MOV @R0,A A0 1 NOP 1 +MOV @R1,A A1 1 NOP 1 +MOV @R0,#* B0 2 NOP 1 +MOV @R1,#* B1 2 NOP 1 + +MOVD A,P4 0C 1 NOP 1 +MOVD A,P5 0D 1 NOP 1 +MOVD A,P6 0E 1 NOP 1 +MOVD A,P7 0F 1 NOP 1 +MOVD P4,A 3C 1 NOP 1 +MOVD P5,A 3D 1 NOP 1 +MOVD P6,A 3E 1 NOP 1 +MOVD P7,A 3F 1 NOP 1 + +MOVP A,@A A3 1 NOP 1 +MOVP3 A,@A E3 1 NOP 1 + +MOVX A,@R0 80 1 NOP 1 +MOVX A,@R1 81 1 NOP 1 +MOVX @R0,A 90 1 NOP 1 +MOVX @R1,A 91 1 NOP 1 + +NOP "" 00 1 NOP 1 + +ORL A,R0 48 1 NOP 1 +ORL A,R1 49 1 NOP 1 +ORL A,R2 4A 1 NOP 1 +ORL A,R3 4B 1 NOP 1 +ORL A,R4 4C 1 NOP 1 +ORL A,R5 4D 1 NOP 1 +ORL A,R6 4E 1 NOP 1 +ORL A,R7 4F 1 NOP 1 +ORL A,@R0 40 1 NOP 1 +ORL A,@R1 41 1 NOP 1 +ORL A,#* 43 2 NOP 1 +ORL BUS,#* 88 2 NOP 1 +ORL P1,#* 89 2 NOP 1 +ORL P2,#* 8A 2 NOP 1 + +ORLD P4,A 8C 1 NOP 1 +ORLD P5,A 8D 1 NOP 1 +ORLD P6,A 8E 1 NOP 1 +ORLD P7,A 8F 1 NOP 1 + +OUTL BUS,A 02 1 NOP 1 +OUT DBB,A 02 1 NOP 2 ;8041 +OUTL P0,A 90 1 NOP 8 ;8021 +OUTL P1,A 39 1 NOP 1 +OUTL P2,A 3A 1 NOP 1 + +RAD "" 80 1 NOP 4 ;8022 + +RET "" 83 1 NOP 1 +RETI "" 93 1 NOP 4 ;8022 +RETR "" 93 1 NOP 1 + +RL A E7 1 NOP 1 +RLC A F7 1 NOP 1 +RR A 77 1 NOP 1 +RRC A 67 1 NOP 1 + +SEL AN0 85 1 NOP 4 ;8022 +SEL AN1 95 1 NOP 4 ;8022 +SEL MB0 E5 1 NOP 1 +SEL MB1 F5 1 NOP 1 +SEL RB0 C5 1 NOP 1 +SEL RB1 D5 1 NOP 1 + +STOP TCNT 65 1 NOP 1 +STRT CNT 45 1 NOP 1 +STRT T 55 1 NOP 1 + +SWAP A 47 1 NOP 1 + +XCH A,R0 28 1 NOP 1 +XCH A,R1 29 1 NOP 1 +XCH A,R2 2A 1 NOP 1 +XCH A,R3 2B 1 NOP 1 +XCH A,R4 2C 1 NOP 1 +XCH A,R5 2D 1 NOP 1 +XCH A,R6 2E 1 NOP 1 +XCH A,R7 2F 1 NOP 1 +XCH A,@R0 20 1 NOP 1 +XCH A,@R1 21 1 NOP 1 + +XCHD A,@R0 30 1 NOP 1 +XCHD A,@R1 31 1 NOP 1 + +XRL A,R0 D8 1 NOP 1 +XRL A,R1 D9 1 NOP 1 +XRL A,R2 DA 1 NOP 1 +XRL A,R3 DB 1 NOP 1 +XRL A,R4 DC 1 NOP 1 +XRL A,R5 DD 1 NOP 1 +XRL A,R6 DE 1 NOP 1 +XRL A,R7 DF 1 NOP 1 +XRL A,@R0 D0 1 NOP 1 +XRL A,@R1 D1 1 NOP 1 +XRL A,#* D3 2 NOP 1 + diff --git a/trunk/Tools/tasm32/TASM51.TAB b/trunk/Tools/tasm32/TASM51.TAB new file mode 100644 index 00000000..40fc3a56 --- /dev/null +++ b/trunk/Tools/tasm32/TASM51.TAB @@ -0,0 +1,285 @@ +"TASM 8051 Assembler. " +/**************************************************************************** +/* $Id: tasm51.tab 1.1 1993/07/31 01:12:40 toma Exp $ +/**************************************************************************** +/* This is the instruction set definition table for the 8051 version of TASM. +/* Thomas N. Anderson, Speech Technology Incorported, June 1987. +/* + +.NOARGSHIFT + +/*INSTR ARGS OPCODE BYTES MOD CLASS SHIFT OR */ +/*-------------------------------------------*/ +ACALL * 11 2 JMP 1 0 F800 + +ADD A,R0 28 1 NOP 1 +ADD A,R1 29 1 NOP 1 +ADD A,R2 2A 1 NOP 1 +ADD A,R3 2B 1 NOP 1 +ADD A,R4 2C 1 NOP 1 +ADD A,R5 2D 1 NOP 1 +ADD A,R6 2E 1 NOP 1 +ADD A,R7 2F 1 NOP 1 +ADD A,@R0 26 1 NOP 1 +ADD A,@R1 27 1 NOP 1 +ADD A,#* 24 2 NOP 1 +ADD A,* 25 2 NOP 1 + +ADDC A,R0 38 1 NOP 1 +ADDC A,R1 39 1 NOP 1 +ADDC A,R2 3A 1 NOP 1 +ADDC A,R3 3B 1 NOP 1 +ADDC A,R4 3C 1 NOP 1 +ADDC A,R5 3D 1 NOP 1 +ADDC A,R6 3E 1 NOP 1 +ADDC A,R7 3F 1 NOP 1 +ADDC A,@R0 36 1 NOP 1 +ADDC A,@R1 37 1 NOP 1 +ADDC A,#* 34 2 NOP 1 +ADDC A,* 35 2 NOP 1 + +AJMP * 01 2 JMP 1 0 F800 + +ANL A,R0 58 1 NOP 1 +ANL A,R1 59 1 NOP 1 +ANL A,R2 5A 1 NOP 1 +ANL A,R3 5B 1 NOP 1 +ANL A,R4 5C 1 NOP 1 +ANL A,R5 5D 1 NOP 1 +ANL A,R6 5E 1 NOP 1 +ANL A,R7 5F 1 NOP 1 +ANL A,@R0 56 1 NOP 1 +ANL A,@R1 57 1 NOP 1 +ANL A,#* 54 2 NOP 1 +ANL A,* 55 2 NOP 1 +ANL C,/* b0 2 NOP 1 +ANL C,* 82 2 NOP 1 +ANL *,A 52 2 NOP 1 +ANL *,#* 53 3 COMBINE 1 + +CJNE A,#*,* b4 3 CR 1 +CJNE A,*,* b5 3 CR 1 +CJNE R0,#*,* b8 3 CR 1 +CJNE R1,#*,* b9 3 CR 1 +CJNE R2,#*,* ba 3 CR 1 +CJNE R3,#*,* bb 3 CR 1 +CJNE R4,#*,* bc 3 CR 1 +CJNE R5,#*,* bd 3 CR 1 +CJNE R6,#*,* be 3 CR 1 +CJNE R7,#*,* bf 3 CR 1 +CJNE @R0,#*,* b6 3 CR 1 +CJNE @R1,#*,* b7 3 CR 1 + +CLR A e4 1 NOP 1 +CLR C c3 1 NOP 1 +CLR * c2 2 NOP 1 + +CPL A f4 1 NOP 1 +CPL C b3 1 NOP 1 +CPL * b2 2 NOP 1 + +DA A d4 1 NOP 1 + +DEC A 14 1 NOP 1 +DEC R0 18 1 NOP 1 +DEC R1 19 1 NOP 1 +DEC R2 1A 1 NOP 1 +DEC R3 1B 1 NOP 1 +DEC R4 1C 1 NOP 1 +DEC R5 1D 1 NOP 1 +DEC R6 1E 1 NOP 1 +DEC R7 1F 1 NOP 1 +DEC @R0 16 1 NOP 1 +DEC @R1 17 1 NOP 1 +DEC * 15 2 NOP 1 + +DIV AB 84 1 NOP 1 + +DJNZ R0,* d8 2 R1 1 +DJNZ R1,* d9 2 R1 1 +DJNZ R2,* dA 2 R1 1 +DJNZ R3,* dB 2 R1 1 +DJNZ R4,* dC 2 R1 1 +DJNZ R5,* dD 2 R1 1 +DJNZ R6,* dE 2 R1 1 +DJNZ R7,* dF 2 R1 1 +DJNZ *,* d5 3 CR 1 + +INC A 04 1 NOP 1 +INC R0 08 1 NOP 1 +INC R1 09 1 NOP 1 +INC R2 0A 1 NOP 1 +INC R3 0B 1 NOP 1 +INC R4 0C 1 NOP 1 +INC R5 0D 1 NOP 1 +INC R6 0E 1 NOP 1 +INC R7 0F 1 NOP 1 +INC @R0 06 1 NOP 1 +INC @R1 07 1 NOP 1 +INC DPTR a3 1 NOP 1 +INC * 05 2 NOP 1 + +JB *,* 20 3 CR 1 +JBC *,* 10 3 CR 1 +JC * 40 2 R1 1 +JMP @A+DPTR 73 1 NOP 1 +JNB *,* 30 3 CR 1 +JNC * 50 2 R1 1 +JNZ * 70 2 R1 1 +JZ * 60 2 R1 1 + +LCALL * 12 3 SWAP 1 + +LJMP * 02 3 SWAP 1 + +MOV A,R0 e8 1 NOP 1 +MOV A,R1 e9 1 NOP 1 +MOV A,R2 eA 1 NOP 1 +MOV A,R3 eB 1 NOP 1 +MOV A,R4 eC 1 NOP 1 +MOV A,R5 eD 1 NOP 1 +MOV A,R6 eE 1 NOP 1 +MOV A,R7 eF 1 NOP 1 +MOV A,@R0 e6 1 NOP 1 +MOV A,@R1 e7 1 NOP 1 +MOV A,#* 74 2 NOP 1 +MOV A,* e5 2 NOP 1 +MOV C,* a2 2 NOP 1 +MOV DPTR,#* 90 3 SWAP 1 +MOV R0,A f8 1 NOP 1 +MOV R1,A f9 1 NOP 1 +MOV R2,A fA 1 NOP 1 +MOV R3,A fB 1 NOP 1 +MOV R4,A fC 1 NOP 1 +MOV R5,A fD 1 NOP 1 +MOV R6,A fE 1 NOP 1 +MOV R7,A fF 1 NOP 1 +MOV R0,#* 78 2 NOP 1 +MOV R1,#* 79 2 NOP 1 +MOV R2,#* 7A 2 NOP 1 +MOV R3,#* 7B 2 NOP 1 +MOV R4,#* 7C 2 NOP 1 +MOV R5,#* 7D 2 NOP 1 +MOV R6,#* 7E 2 NOP 1 +MOV R7,#* 7F 2 NOP 1 +MOV R0,* a8 2 NOP 1 +MOV R1,* a9 2 NOP 1 +MOV R2,* aA 2 NOP 1 +MOV R3,* aB 2 NOP 1 +MOV R4,* aC 2 NOP 1 +MOV R5,* aD 2 NOP 1 +MOV R6,* aE 2 NOP 1 +MOV R7,* aF 2 NOP 1 +MOV @R0,A f6 1 NOP 1 +MOV @R1,A f7 1 NOP 1 +MOV @R0,#* 76 2 NOP 1 +MOV @R1,#* 77 2 NOP 1 +MOV @R0,* a6 2 NOP 1 +MOV @R1,* a7 2 NOP 1 +MOV *,A f5 2 NOP 1 +MOV *,C 92 2 NOP 1 +MOV *,R0 88 2 NOP 1 +MOV *,R1 89 2 NOP 1 +MOV *,R2 8A 2 NOP 1 +MOV *,R3 8B 2 NOP 1 +MOV *,R4 8C 2 NOP 1 +MOV *,R5 8D 2 NOP 1 +MOV *,R6 8E 2 NOP 1 +MOV *,R7 8F 2 NOP 1 +MOV *,@R0 86 2 NOP 1 +MOV *,@R1 87 2 NOP 1 +MOV *,#* 75 3 COMBINE 1 +MOV *,* 85 3 CSWAP 1 + +MOVC A,@A+DPTR 93 1 NOP 1 +MOVC A,@A+PC 83 1 NOP 1 + +MOVX A,@R0 e2 1 NOP 1 +MOVX A,@R1 e3 1 NOP 1 +MOVX A,@DPTR e0 1 NOP 1 +MOVX @R0,A f2 1 NOP 1 +MOVX @R1,A f3 1 NOP 1 +MOVX @DPTR,A f0 1 NOP 1 + +MUL AB a4 1 NOP 1 + +NOP "" 00 1 NOP 1 + +ORL A,R0 48 1 NOP 1 +ORL A,R1 49 1 NOP 1 +ORL A,R2 4A 1 NOP 1 +ORL A,R3 4B 1 NOP 1 +ORL A,R4 4C 1 NOP 1 +ORL A,R5 4D 1 NOP 1 +ORL A,R6 4E 1 NOP 1 +ORL A,R7 4F 1 NOP 1 +ORL A,@R0 46 1 NOP 1 +ORL A,@R1 47 1 NOP 1 +ORL A,#* 44 2 NOP 1 +ORL A,* 45 2 NOP 1 +ORL C,/* a0 2 NOP 1 +ORL C,* 72 2 NOP 1 +ORL *,A 42 2 NOP 1 +ORL *,#* 43 3 COMBINE 1 + +POP * d0 2 NOP 1 +PUSH * c0 2 NOP 1 + +RET "" 22 1 NOP 1 +RETI "" 32 1 NOP 1 + +RL A 23 1 NOP 1 +RLC A 33 1 NOP 1 +RR A 03 1 NOP 1 +RRC A 13 1 NOP 1 + +SETB C d3 1 NOP 1 +SETB * d2 2 NOP 1 + +SJMP * 80 2 R1 1 + +SUBB A,R0 98 1 NOP 1 +SUBB A,R1 99 1 NOP 1 +SUBB A,R2 9A 1 NOP 1 +SUBB A,R3 9B 1 NOP 1 +SUBB A,R4 9C 1 NOP 1 +SUBB A,R5 9D 1 NOP 1 +SUBB A,R6 9E 1 NOP 1 +SUBB A,R7 9F 1 NOP 1 +SUBB A,@R0 96 1 NOP 1 +SUBB A,@R1 97 1 NOP 1 +SUBB A,#* 94 2 NOP 1 +SUBB A,* 95 2 NOP 1 + +SWAP A c4 1 NOP 1 + +XCH A,R0 c8 1 NOP 1 +XCH A,R1 c9 1 NOP 1 +XCH A,R2 cA 1 NOP 1 +XCH A,R3 cB 1 NOP 1 +XCH A,R4 cC 1 NOP 1 +XCH A,R5 cD 1 NOP 1 +XCH A,R6 cE 1 NOP 1 +XCH A,R7 cF 1 NOP 1 +XCH A,@R0 c6 1 NOP 1 +XCH A,@R1 c7 1 NOP 1 +XCH A,* c5 2 NOP 1 + +XCHD A,@R0 d6 1 NOP 1 +XCHD A,@R1 d7 1 NOP 1 + +XRL A,R0 68 1 NOP 1 +XRL A,R1 69 1 NOP 1 +XRL A,R2 6A 1 NOP 1 +XRL A,R3 6B 1 NOP 1 +XRL A,R4 6C 1 NOP 1 +XRL A,R5 6D 1 NOP 1 +XRL A,R6 6E 1 NOP 1 +XRL A,R7 6F 1 NOP 1 +XRL A,@R0 66 1 NOP 1 +XRL A,@R1 67 1 NOP 1 +XRL A,#* 64 2 NOP 1 +XRL A,* 65 2 NOP 1 +XRL *,A 62 2 NOP 1 +XRL *,#* 63 3 COMBINE 1 + diff --git a/trunk/Tools/tasm32/TASM65.TAB b/trunk/Tools/tasm32/TASM65.TAB new file mode 100644 index 00000000..b30b4d20 --- /dev/null +++ b/trunk/Tools/tasm32/TASM65.TAB @@ -0,0 +1,222 @@ +"TASM 6502 Assembler. " +/**************************************************************************** +/* $Id: tasm65.tab 1.1 1993/07/31 01:12:40 toma Exp $ +/**************************************************************************** +/* This is the instruction set definition table for the 6502 version of TASM. +/* Thomas N. Anderson, Speech Technology Incorported, June 1987. +/* Note that there are two classes of extended instructions beyond +/* the standard set. The classes are assigned bits as follows: +/* bit 0 = standard set +/* bit 1 = extended instructions for R65C02 +/* bit 2 = extended instructions for R65C00/21 +/* +/*INSTR ARGS OPCODE BYTES MOD CLASS SHIFT OR */ +/*-------------------------------------------*/ +ADC #* 69 2 NOP 1 +ADC (*,X) 61 2 NOP 1 +ADC (*),Y 71 2 NOP 1 +ADC (*) 72 2 NOP 2 +ADC *,X 7D 3 ZP 1 +ADC *,Y 79 3 NOP 1 +ADC * 6D 3 ZP 1 + +AND #* 29 2 NOP 1 +AND (*,X) 21 2 NOP 1 +AND (*),Y 31 2 NOP 1 +AND (*) 32 2 NOP 2 +AND *,X 3D 3 ZP 1 +AND *,Y 39 3 NOP 1 +AND * 2D 3 ZP 1 + +ASL A 0A 1 NOP 1 +ASL *,X 1E 3 ZP 1 +ASL * 0E 3 ZP 1 + +BBR0 *,* 0f 3 CR 6 +BBR1 *,* 1f 3 CR 6 +BBR2 *,* 2f 3 CR 6 +BBR3 *,* 3f 3 CR 6 +BBR4 *,* 4f 3 CR 6 +BBR5 *,* 5f 3 CR 6 +BBR6 *,* 6f 3 CR 6 +BBR7 *,* 7f 3 CR 6 + +BBS0 *,* 8f 3 CR 6 +BBS1 *,* 9f 3 CR 6 +BBS2 *,* af 3 CR 6 +BBS3 *,* bf 3 CR 6 +BBS4 *,* cf 3 CR 6 +BBS5 *,* df 3 CR 6 +BBS6 *,* ef 3 CR 6 +BBS7 *,* ff 3 CR 6 + +BCC * 90 2 R1 1 +BCS * B0 2 R1 1 +BEQ * F0 2 R1 1 +BMI * 30 2 R1 1 +BNE * D0 2 R1 1 +BPL * 10 2 R1 1 +BRA * 80 2 R1 6 +BVC * 50 2 R1 1 +BVS * 70 2 R1 1 + +BIT #* 89 2 NOP 2 +BIT *,X 3C 3 ZP 2 +BIT * 2C 3 ZP 1 + +BRK "" 00 1 NOP 1 + +CLC "" 18 1 NOP 1 +CLD "" D8 1 NOP 1 +CLI "" 58 1 NOP 1 +CLV "" B8 1 NOP 1 + +CMP #* C9 2 NOP 1 +CMP (*,X) C1 2 NOP 1 +CMP (*),Y D1 2 NOP 1 +CMP (*) D2 2 NOP 2 +CMP *,X DD 3 ZP 1 +CMP *,Y D9 3 NOP 1 +CMP * CD 3 ZP 1 + +CPX #* E0 2 NOP 1 +CPX * EC 3 ZP 1 + +CPY #* C0 2 NOP 1 +CPY * CC 3 ZP 1 + +DEC A 3A 1 NOP 2 +DEC *,X DE 3 ZP 1 +DEC * CE 3 ZP 1 + +DEX "" CA 1 NOP 1 +DEY "" 88 1 NOP 1 + +EOR #* 49 2 NOP 1 +EOR (*,X) 41 2 NOP 1 +EOR (*),Y 51 2 NOP 1 +EOR (*) 52 2 NOP 2 +EOR *,X 5D 3 ZP 1 +EOR *,Y 59 3 NOP 1 +EOR * 4D 3 ZP 1 + +INC A 1A 1 NOP 2 +INC *,X FE 3 ZP 1 +INC * EE 3 ZP 1 + +INX "" E8 1 NOP 1 +INY "" C8 1 NOP 1 + +JMP (*,X) 7C 3 NOP 2 +JMP (*) 6C 3 NOP 1 +JMP * 4C 3 NOP 1 + +JSR * 20 3 NOP 1 + +LDA #* A9 2 NOP 1 +LDA (*,X) A1 2 NOP 1 +LDA (*),Y B1 2 NOP 1 +LDA (*) B2 2 NOP 2 +LDA *,X BD 3 ZP 1 +LDA *,Y B9 3 NOP 1 +LDA * AD 3 ZP 1 + +LDX #* A2 2 NOP 1 +LDX *,Y BE 3 ZP 1 +LDX * AE 3 ZP 1 + +LDY #* A0 2 NOP 1 +LDY *,X BC 3 ZP 1 +LDY * AC 3 ZP 1 + +LSR A 4A 1 NOP 1 +LSR *,X 5E 3 ZP 1 +LSR * 4E 3 ZP 1 + +MUL "" 02 1 NOP 4 /* R65C00/21 only*/ + +NOP "" EA 1 NOP 1 + +ORA #* 09 2 NOP 1 +ORA (*,X) 01 2 NOP 1 +ORA (*),Y 11 2 NOP 1 +ORA (*) 12 2 NOP 2 +ORA *,X 1D 3 ZP 1 +ORA *,Y 19 3 NOP 1 +ORA * 0D 3 ZP 1 + +PHA "" 48 1 NOP 1 +PHP "" 08 1 NOP 1 +PHX "" DA 1 NOP 6 +PHY "" 5A 1 NOP 6 +PLA "" 68 1 NOP 1 +PLP "" 28 1 NOP 1 +PLX "" FA 1 NOP 6 +PLY "" 7A 1 NOP 6 + +RMB0 * 07 2 NOP 6 +RMB1 * 17 2 NOP 6 +RMB2 * 27 2 NOP 6 +RMB3 * 37 2 NOP 6 +RMB4 * 47 2 NOP 6 +RMB5 * 57 2 NOP 6 +RMB6 * 67 2 NOP 6 +RMB7 * 77 2 NOP 6 + +ROL A 2A 1 NOP 1 +ROL *,X 3E 3 ZP 1 +ROL * 2E 3 ZP 1 + +ROR A 6A 1 NOP 1 +ROR *,X 7E 3 ZP 1 +ROR * 6E 3 ZP 1 + +RTI "" 40 1 NOP 1 +RTS "" 60 1 NOP 1 + +SBC #* E9 2 NOP 1 +SBC (*,X) E1 2 NOP 1 +SBC (*),Y F1 2 NOP 1 +SBC (*) F2 2 NOP 2 +SBC *,X FD 3 ZP 1 +SBC *,Y F9 3 NOP 1 +SBC * ED 3 ZP 1 + +SEC "" 38 1 NOP 1 +SED "" F8 1 NOP 1 +SEI "" 78 1 NOP 1 + +SMB0 * 87 2 NOP 6 +SMB1 * 97 2 NOP 6 +SMB2 * a7 2 NOP 6 +SMB3 * b7 2 NOP 6 +SMB4 * c7 2 NOP 6 +SMB5 * d7 2 NOP 6 +SMB6 * e7 2 NOP 6 +SMB7 * f7 2 NOP 6 + +STA (*,X) 81 2 NOP 1 +STA (*),Y 91 2 NOP 1 +STA (*) 92 2 NOP 2 +STA *,X 9D 3 ZP 1 +STA *,Y 99 3 NOP 1 +STA * 8D 3 ZP 1 + +STX *,Y 96 2 ZP 1 +STX * 8E 3 ZP 1 + +STY *,X 94 2 NOP 1 +STY * 8C 3 ZP 1 + +STZ *,X 9e 3 ZP 2 +STZ * 9c 3 ZP 2 + +TAX "" AA 1 NOP 1 +TAY "" A8 1 NOP 1 +TRB * 1c 3 ZP 2 +TSB * 0c 3 ZP 2 +TSX "" BA 1 NOP 1 +TXA "" 8A 1 NOP 1 +TXS "" 9A 1 NOP 1 +TYA "" 98 1 NOP 1 + diff --git a/trunk/Tools/tasm32/TASM68.TAB b/trunk/Tools/tasm32/TASM68.TAB new file mode 100644 index 00000000..c3543c5a --- /dev/null +++ b/trunk/Tools/tasm32/TASM68.TAB @@ -0,0 +1,348 @@ +"TASM 6800-6811 Assembler" +/**************************************************************************** +/* $Id: tasm68.tab 1.1 1993/07/31 01:12:40 toma Exp $ +/**************************************************************************** +/* Originally submitted by Richard P. White, June 4,1989 */ +/* Corrected and enhanced by T.N. Anderson, STI */ +/* Enhanced for the 68HC11 by George Blat, Nov 3, 1990 +/* Class bits defined as follows: +/* +/* bit 0 for 6800 +/* bit 1 for 6801/6803 +/* bit 2 for 68HC11 +/* +/* Note that TASM deviates from motorola syntax for BCLR, BSET, +/* BRCLR, and BRSET instructions. TASM requires commas between +/* each arg. Motorola requires white space before the make and +/* label args. + +.MSFIRST + +ABA "" 1B 1 NOP 1 +ABX "" 3A 1 NOP 2 +ABY "" 183A 2 NOP 4 + +ADCA #* 89 2 NOP 1 +ADCA *,Y 18A9 3 NOP 4 +ADCA *,X A9 2 NOP 1 +ADCA * B9 3 MZERO 1 + +ADCB #* C9 2 NOP 1 +ADCB *,Y 18E9 3 NOP 4 +ADCB *,X E9 2 NOP 1 +ADCB * F9 3 MZERO 1 + +ADDA #* 8B 2 NOP 1 +ADDA *,Y 18AB 3 NOP 4 +ADDA *,X AB 2 NOP 1 +ADDA * BB 3 MZERO 1 + +ADDB #* CB 2 NOP 1 +ADDB *,Y 18EB 3 NOP 4 +ADDB *,X EB 2 NOP 1 +ADDB * FB 3 MZERO 1 + +ADDD #* C3 3 SWAP 2 +ADDD *,Y 18E3 3 NOP 4 +ADDD *,X E3 2 NOP 2 +ADDD * F3 3 MZERO 2 + +ANDA #* 84 2 NOP 1 +ANDA *,Y 18A4 3 NOP 4 +ANDA *,X A4 2 NOP 1 +ANDA * B4 3 MZERO 1 + +ANDB #* C4 2 NOP 1 +ANDB *,Y 18E4 3 NOP 4 +ANDB *,X E4 2 NOP 1 +ANDB * F4 3 MZERO 1 + +ASL *,Y 1868 3 NOP 4 +ASL *,X 68 2 NOP 1 +ASL * 78 3 SWAP 1 +ASLA "" 48 1 NOP 1 +ASLB "" 58 1 NOP 1 +ASLD "" 05 1 NOP 2 + +ASR *,Y 1867 3 NOP 4 +ASR *,X 67 2 NOP 1 +ASR * 77 3 SWAP 1 +ASRA "" 47 1 NOP 1 +ASRB "" 57 1 NOP 1 + +BCC * 24 2 R1 1 +BCLR *,X,* 1D 3 COMB 4 +BCLR *,Y,* 181D 4 COMB 4 +BCLR *,#* 15 3 COMB 4 /* allow # since mask is immediate data +BCLR *,* 15 3 COMB 4 +BCS * 25 2 R1 1 +BEQ * 27 2 R1 1 +BGE * 2C 2 R1 1 +BGT * 2E 2 R1 1 +BHI * 22 2 R1 1 +BHS * 24 2 R1 1 +BITA #* 85 2 NOP 1 +BITA *,Y 18A5 3 NOP 4 +BITA *,X A5 2 NOP 1 +BITA * B5 3 MZERO 1 +BITB #* C5 2 NOP 1 +BITB *,Y 18E5 3 NOP 4 +BITB *,X E5 2 NOP 1 +BITB * F5 3 MZERO 1 +BLE * 2F 2 R1 1 +BLO * 25 2 R1 1 +BLS * 23 2 R1 1 +BLT * 2D 2 R1 1 +BMI * 2B 2 R1 1 +BNE * 26 2 R1 1 +BPL * 2A 2 R1 1 +BRA * 20 2 R1 1 +BRCLR *,X,*,* 1F 4 3REL 4 +BRCLR *,Y,*,* 181F 5 3REL 4 +BRCLR *,*,* 13 4 3REL 4 +BRN * 21 2 R1 2 /* NOT SURE ABOUT 6803 */ +BRSET *,X,*,* 1E 4 3REL 4 +BRSET *,Y,*,* 181E 5 3REL 4 +BRSET *,*,* 12 4 3REL 4 +BSET *,X,* 1C 3 COMB 4 +BSET *,Y,* 181C 4 COMB 4 +BSET *,#* 14 3 COMB 4 /* allow # +BSET *,* 14 3 COMB 4 +BSR * 8D 2 R1 1 +BVC * 28 2 R1 1 +BVS * 29 2 R1 1 +CBA "" 11 1 NOP 1 +CLC "" 0C 1 NOP 1 +CLI "" 0E 1 NOP 1 +CLR *,Y 186F 3 NOP 4 +CLR *,X 6F 2 NOP 1 +CLR * 7F 3 SWAP 1 +CLRA "" 4F 1 NOP 1 +CLRB "" 5F 1 NOP 1 +CLV "" 0A 1 NOP 1 +CMPA #* 81 2 NOP 1 +CMPA *,X A1 2 NOP 1 +CMPA *,Y 18A1 3 NOP 4 +CMPA * B1 3 MZERO 1 +CMPB #* C1 2 NOP 1 +CMPB *,Y 18E1 3 NOP 4 +CMPB *,X E1 2 NOP 1 +CMPB * F1 3 MZERO 1 +CMPD #* 1A83 4 SWAP 4 /* alias for CPD */ +CMPD *,X 1AA3 3 NOP 4 +CMPD *,Y CDA3 3 NOP 4 +CMPD * 1AB3 4 MZERO 4 +COM *,X 63 2 NOP 1 +COM *,Y 1863 3 NOP 4 +COM * 73 3 SWAP 1 +COMA "" 43 1 NOP 1 +COMB "" 53 1 NOP 1 +CPD #* 1A83 4 SWAP 4 +CPD *,X 1AA3 3 NOP 4 +CPD *,Y CDA3 3 NOP 4 +CPD * 1AB3 4 MZERO 4 +CPX #* 8C 3 SWAP 1 +CPX *,X AC 2 NOP 1 +CPX *,Y CDAC 3 NOP 4 +CPX * BC 3 MZERO 1 +CPY #* 188C 4 SWAP 4 +CPY *,Y 18AC 3 NOP 4 +CPY *,X 1AAC 3 NOP 4 +CPY * 18BC 4 MZERO 4 +DAA "" 19 1 NOP 1 +DEC *,Y 186A 3 NOP 4 +DEC *,X 6A 2 NOP 1 +DEC * 7A 3 SWAP 1 +DECA "" 4A 1 NOP 1 +DECB "" 5A 1 NOP 1 +DES "" 34 1 NOP 1 +DEX "" 09 1 NOP 1 +DEY "" 1809 2 NOP 4 +EORA #* 88 2 NOP 1 +EORA *,Y 18A8 3 NOP 4 +EORA *,X A8 2 NOP 1 +EORA * B8 3 MZERO 1 +EORB #* C8 2 NOP 1 +EORB *,Y 18E8 3 NOP 4 +EORB *,X E8 2 NOP 1 +EORB * F8 3 MZERO 1 +FDIV "" 03 1 NOP 4 +IDIV "" 02 1 NOP 4 +INC *,Y 186C 3 NOP 4 +INC *,X 6C 2 NOP 1 +INC * 7C 3 SWAP 1 +INCA "" 4C 1 NOP 1 +INCB "" 5C 1 NOP 1 +INS "" 31 1 NOP 1 +INX "" 08 1 NOP 1 +INY "" 1808 2 NOP 4 +JMP *,Y 186E 3 NOP 4 +JMP *,X 6E 2 NOP 1 +JMP * 7E 3 SWAP 1 +JSR *,Y 18AD 3 NOP 4 +JSR *,X AD 2 NOP 1 +JSR * BD 3 MZERO 1 + +LDAA #* 86 2 NOP 1 +LDAA *,Y 18A6 3 NOP 4 +LDAA *,X A6 2 NOP 1 +LDAA >* B6 3 SWAP 1 /* Force EXT mode */ +LDAA * B6 3 MZERO 1 + +LDAB #* C6 2 NOP 1 +LDAB *,Y 18E6 3 NOP 4 +LDAB *,X E6 2 NOP 1 +LDAB >* F6 3 SWAP 1 /* Force EXT mode */ +LDAB * F6 3 MZERO 1 + +LDD #* CC 3 SWAP 2 +LDD *,Y 18EC 3 NOP 4 +LDD *,X EC 2 NOP 2 +LDD >* FC 3 SWAP 2 /* Force EXT mode */ +LDD * FC 3 MZERO 2 + +LDS #* 8E 3 SWAP 1 +LDS *,Y 18AE 3 NOP 4 +LDS *,X AE 2 NOP 1 +LDS >* BE 3 SWAP 1 /* Force EXT mode */ +LDS * BE 3 MZERO 1 + +LDX #* CE 3 SWAP 1 +LDX *,X EE 2 NOP 1 +LDX *,Y CDEE 3 NOP 4 +LDX >* FE 3 SWAP 1 /* Force EXT mode */ +LDX * FE 3 MZERO 1 + +LDY #* 18CE 4 SWAP 4 +LDY *,Y 18EE 3 NOP 4 +LDY *,X 1AEE 3 NOP 4 +LDY >* 18FE 4 SWAP 4 /* Force EXT mode */ +LDY * 18FE 4 MZERO 4 + +LSL *,Y 1868 3 NOP 4 +LSL *,X 68 2 NOP 1 /*SAME AS ASL */ +LSL * 78 3 SWAP 1 +LSLA "" 48 1 NOP 1 +LSLB "" 58 1 NOP 1 +LSLD "" 05 1 NOP 2 +LSR *,Y 1864 3 NOP 4 +LSR *,X 64 2 NOP 1 +LSR * 74 3 SWAP 1 +LSRA "" 44 1 NOP 1 +LSRB "" 54 1 NOP 1 +LSRD "" 04 1 NOP 2 +MUL "" 3D 1 NOP 2 +NEG *,Y 1860 3 NOP 4 +NEG *,X 60 2 NOP 1 +NEG * 70 3 SWAP 1 +NEGA "" 40 1 NOP 1 +NEGB "" 50 1 NOP 1 +NOP "" 01 1 NOP 1 +ORAA #* 8A 2 NOP 1 +ORAA *,Y 18AA 3 NOP 4 +ORAA *,X AA 2 NOP 1 +ORAA * BA 3 MZERO 1 +ORAB #* CA 2 NOP 1 +ORAB *,Y 18EA 3 NOP 4 +ORAB *,X EA 2 NOP 1 +ORAB * FA 3 MZERO 1 +PSHA "" 36 1 NOP 1 +PSHB "" 37 1 NOP 1 +PSHX "" 3C 1 NOP 2 +PSHY "" 183C 2 NOP 4 +PULA "" 32 1 NOP 1 +PULB "" 33 1 NOP 1 +PULX "" 38 1 NOP 2 +PULY "" 1838 2 NOP 4 +ROL *,Y 1869 3 NOP 4 +ROL *,X 69 2 NOP 1 +ROL * 79 3 SWAP 1 +ROLA "" 49 1 NOP 1 +ROLB "" 59 1 NOP 1 +ROR *,Y 1866 3 NOP 4 +ROR *,X 66 2 NOP 1 +ROR * 76 3 SWAP 1 +RORA "" 46 1 NOP 1 +RORB "" 56 1 NOP 1 +RTI "" 3B 1 NOP 1 +RTS "" 39 1 NOP 1 +SBA "" 10 1 NOP 1 +SBCA #* 82 2 NOP 1 +SBCA *,Y 18A2 3 NOP 4 +SBCA *,X A2 2 NOP 1 +SBCA * B2 3 MZERO 1 +SBCB #* C2 2 NOP 1 +SBCB *,Y 18E2 3 NOP 4 +SBCB *,X E2 2 NOP 1 +SBCB * F2 3 MZERO 1 +SEC "" 0D 1 NOP 1 +SEI "" 0F 1 NOP 1 +SEV "" 0B 1 NOP 1 + +STAA *,Y 18A7 3 NOP 4 +STAA *,X A7 2 NOP 1 +STAA >* B7 3 SWAP 1 /* Force EXT mode */ +STAA * B7 3 MZERO 1 + +STAB *,Y 18E7 3 NOP 4 +STAB *,X E7 2 NOP 1 +STAB >* F7 3 SWAP 1 /* Force EXT mode */ +STAB * F7 3 MZERO 1 + +STD *,Y 18ED 3 NOP 4 +STD *,X ED 2 NOP 2 +STD >* FD 3 SWAP 2 /* Force EXT mode */ +STD * FD 3 MZERO 2 + +STOP "" CF 1 NOP 1 + +STS *,X AF 2 NOP 1 +STS *,Y 18AF 3 NOP 4 +STS >* BF 3 SWAP 1 /* Force EXT mode */ +STS * BF 3 MZERO 1 + +STX *,X EF 2 NOP 1 +STX *,Y CDEF 3 NOP 4 +STX >* FF 3 SWAP 1 /* Force EXT mode */ +STX * FF 3 MZERO 1 + +STY *,Y 18EF 3 NOP 4 +STY *,X 1AEF 3 NOP 4 +STY >* 18FF 4 SWAP 4 /* Force EXT mode */ +STY * 18FF 4 MZERO 4 + +SUBA #* 80 2 NOP 1 +SUBA *,Y 18A0 3 NOP 4 +SUBA *,X A0 2 NOP 1 +SUBA * B0 3 MZERO 1 + +SUBB #* C0 2 NOP 1 +SUBB *,Y 18E0 3 NOP 4 +SUBB *,X E0 2 NOP 1 +SUBB * F0 3 MZERO 1 + +SUBD #* 83 3 SWAP 2 +SUBD *,Y 18A3 3 NOP 4 +SUBD *,X A3 2 NOP 2 +SUBD * B3 3 MZERO 2 + +SWI "" 3F 1 NOP 1 +TAB "" 16 1 NOP 1 +TAP "" 06 1 NOP 1 +TBA "" 17 1 NOP 1 +TEST "" 00 1 NOP 1 +TPA "" 07 1 NOP 1 +TST *,Y 186D 3 NOP 4 +TST *,X 6D 2 NOP 1 +TST * 7D 3 SWAP 1 +TSTA "" 4D 1 NOP 1 +TSTB "" 5D 1 NOP 1 +TSX "" 30 1 NOP 1 +TSY "" 1830 2 NOP 4 +TXS "" 35 1 NOP 1 +TYS "" 1835 2 NOP 4 +WAI "" 3E 1 NOP 1 +XGDX "" 8F 1 NOP 4 +XGDY "" 188F 2 NOP 4 +/* That's all folks */ + diff --git a/trunk/Tools/tasm32/TASM70.TAB b/trunk/Tools/tasm32/TASM70.TAB new file mode 100644 index 00000000..7f8cf218 --- /dev/null +++ b/trunk/Tools/tasm32/TASM70.TAB @@ -0,0 +1,290 @@ +"TASM 7000 Assembler. " +/**************************************************************************** +/* $Id: tasm70.tab 1.1 1993/07/31 01:12:40 toma Exp $ +/**************************************************************************** +/* Table for TMS7000 micros +/* Note that the table does not require the 'Rnn' nomenclature +/* for reference of locations in the register file. Any expression +/* will do, the value of which indicates the register. This is more +/* flexible then making an entry like "ADC R*,A". +/* +/* TASM has trouble with the MOVD +(B),+ instruction so +/* we convert it to MOVD +[B],+ +/* +/*INSTR ARGS OPCODE BYTES MOD CLASS SHIFT OR */ +/*-------------------------------------------*/ +.ALTWILD+ + +ADC B,A 69 1 NOP 1 +ADC %+,A 29 2 NOP 1 +ADC %+,B 59 2 NOP 1 +ADC %+,+ 79 3 COMB 1 +ADC +,A 19 2 NOP 1 +ADC +,B 39 2 NOP 1 +ADC +,+ 49 3 COMB 1 + +ADD B,A 68 1 NOP 1 +ADD %+,A 28 2 NOP 1 +ADD %+,B 58 2 NOP 1 +ADD %+,+ 78 3 COMB 1 +ADD +,A 18 2 NOP 1 +ADD +,B 38 2 NOP 1 +ADD +,+ 48 3 COMB 1 + +AND B,A 63 1 NOP 1 +AND %+,A 23 2 NOP 1 +AND %+,B 53 2 NOP 1 +AND %+,+ 73 3 COMB 1 +AND +,A 13 2 NOP 1 +AND +,B 33 2 NOP 1 +AND +,+ 43 3 COMB 1 + +ANDP A,+ 83 2 NOP 1 +ANDP B,+ 93 2 NOP 1 +ANDP %+,+ A3 3 COMB 1 + +BTJO B,A,+ 66 2 R1 1 +BTJO %+,A,+ 26 3 CREL 1 +BTJO %+,B,+ 56 3 CREL 1 +BTJO %+,+,+ 76 4 3REL 1 +BTJO +,A,+ 16 3 CREL 1 +BTJO +,B,+ 36 3 CREL 1 +BTJO +,+,+ 46 4 3REL 1 + + +BTJOP A,+,+ 86 3 CREL 1 +BTJOP B,+,+ 96 3 CREL 1 +BTJOP %+,+,+ A6 4 3REL 1 + +BTJZ B,A,+ 67 2 R1 1 +BTJZ %+,A,+ 27 3 CREL 1 +BTJZ %+,B,+ 57 3 CREL 1 +BTJZ %+,+,+ 77 4 3REL 1 +BTJZ +,A,+ 17 3 CREL 1 +BTJZ +,B,+ 37 3 CREL 1 +BTJZ +,+,+ 47 4 3REL 1 + +BTJZP A,+,+ 87 3 CREL 1 +BTJZP B,+,+ 97 3 CREL 1 +BTJZP %+,+,+ A7 4 3REL 1 + +BR @+(B) AC 3 SWAP 1 +BR @+[B] AC 3 SWAP 1 +BR @+ 8C 3 SWAP 1 +BR *+ 9C 2 NOP 1 + +CALL @+(B) AE 3 SWAP 1 +CALL @+[B] AE 3 SWAP 1 +CALL @+ 8E 3 SWAP 1 +CALL *+ 9E 2 NOP 1 + +CLR A B5 1 NOP 1 +CLR B C5 1 NOP 1 +CLR + D5 2 NOP 1 + +CLRC "" B0 1 NOP 1 + +CMP B,A 6D 1 NOP 1 +CMP %+,A 2D 2 NOP 1 +CMP %+,B 5D 2 NOP 1 +CMP %+,+ 7D 3 COMB 1 +CMP +,A 1D 2 NOP 1 +CMP +,B 3D 2 NOP 1 +CMP +,+ 4D 3 COMB 1 + +CMPA @+(B) AD 3 SWAP 1 +CMPA @+[B] AD 3 SWAP 1 +CMPA @+ 8D 3 SWAP 1 +CMPA *+ 9D 2 NOP 1 + +DAC B,A 6E 1 NOP 1 +DAC %+,A 2E 2 NOP 1 +DAC %+,B 5E 2 NOP 1 +DAC %+,+ 7E 3 COMB 1 +DAC +,A 1E 2 NOP 1 +DAC +,B 3E 2 NOP 1 +DAC +,+ 4E 3 COMB 1 + +DEC A B2 1 NOP 1 +DEC B C2 1 NOP 1 +DEC + D2 2 NOP 1 + +DECD A BB 1 NOP 1 +DECD B CB 1 NOP 1 +DECD + DB 2 NOP 1 + +DINT "" 06 1 NOP 1 + +DJNZ A,+ BA 2 R1 1 +DJNZ B,+ CA 2 R1 1 +DJNZ +,+ DA 3 CREL 1 + +DSB B,A 6F 1 NOP 1 +DSB %+,A 2F 2 NOP 1 +DSB %+,B 5F 2 NOP 1 +DSB %+,+ 7F 3 COMB 1 +DSB +,A 1F 2 NOP 1 +DSB +,B 3F 2 NOP 1 +DSB +,+ 4F 3 COMB 1 + +EINT "" 05 1 NOP 1 + +IDLE "" 01 1 NOP 1 + +INC A B3 1 NOP 1 +INC B C3 1 NOP 1 +INC + D3 2 NOP 1 + +INV A B4 1 NOP 1 +INV B C4 1 NOP 1 +INV + D4 2 NOP 1 + +JMP + E0 2 R1 1 + +JC + E3 2 R1 1 +JEQ + E2 2 R1 1 +JGE + E5 2 R1 1 +JGT + E4 2 R1 1 +JHS + E3 2 R1 1 +JL + E7 2 R1 1 +JN + E1 2 R1 1 /+ ?? +JNC + E7 2 R1 1 +JNE + E6 2 R1 1 +JNZ + E6 2 R1 1 +JP + E4 2 R1 1 +JPZ + E5 2 R1 1 +JZ + E2 2 R1 1 + +LDA @+(B) AA 3 SWAP 1 +LDA @+[B] AA 3 SWAP 1 +LDA @+ 8A 3 SWAP 1 +LDA *+ 9A 2 NOP 1 + +LDSP "" 0D 1 NOP 1 + +MOV A,B C0 1 NOP 1 +MOV B,A 62 1 NOP 1 +MOV A,+ D0 2 NOP 1 +MOV B,+ D1 2 NOP 1 +MOV %+,A 22 2 NOP 1 +MOV %+,B 52 2 NOP 1 +MOV %+,+ 72 3 COMB 1 +MOV +,A 12 2 NOP 1 +MOV +,B 32 2 NOP 1 +MOV +,+ 42 3 COMB 1 + +MOVD %+[B],+ A8 4 CSWAP 1 +MOVD %+,+ 88 4 CSWAP 1 +MOVD +,+ 98 3 COMB 1 + +MOVP A,+ 82 2 NOP 1 +MOVP B,+ 92 2 NOP 1 +MOVP %+,+ A2 3 COMB 1 +MOVP +,A 80 2 NOP 1 +MOVP +,B 91 2 NOP 1 + +MPY B,A 6C 1 NOP 1 +MPY %+,A 2C 2 NOP 1 +MPY %+,B 5C 2 NOP 1 +MPY %+,+ 7C 3 COMB 1 +MPY +,A 1C 2 NOP 1 +MPY +,B 3C 2 NOP 1 +MPY +,+ 4C 3 COMB 1 + +NOP "" 00 1 NOP 1 + +OR B,A 64 1 NOP 1 +OR %+,A 24 2 NOP 1 +OR %+,B 54 2 NOP 1 +OR %+,+ 74 3 COMB 1 +OR +,A 14 2 NOP 1 +OR +,B 34 2 NOP 1 +OR +,+ 44 3 COMB 1 + +ORP A,+ 84 2 NOP 1 +ORP B,+ 94 2 NOP 1 +ORP %+,+ A4 3 COMB 1 + +POP A B9 1 NOP 1 +POP B C9 1 NOP 1 +POP ST 08 1 NOP 1 +POP + D9 2 NOP 1 +POPST "" 08 1 NOP 1 + +PUSH A B8 1 NOP 1 +PUSH B C8 1 NOP 1 +PUSH ST 0E 1 NOP 1 +PUSH + D8 2 NOP 1 +PUSHST "" 0E 1 NOP 1 + +RETI "" 0B 1 NOP 1 + +RETS "" 0A 1 NOP 1 + +RL A BE 1 NOP 1 +RL B CE 1 NOP 1 +RL + DE 2 NOP 1 + +RLC A BF 1 NOP 1 +RLC B CF 1 NOP 1 +RLC + DF 2 NOP 1 + +RR A BC 1 NOP 1 +RR B CC 1 NOP 1 +RR + DC 2 NOP 1 + +RRC A BD 1 NOP 1 +RRC B CD 1 NOP 1 +RRC + DD 2 NOP 1 + +SBB B,A 6B 1 NOP 1 +SBB %+,A 2B 2 NOP 1 +SBB %+,B 5B 2 NOP 1 +SBB %+,+ 7B 3 COMB 1 +SBB +,A 1B 2 NOP 1 +SBB +,B 3B 2 NOP 1 +SBB +,+ 4B 3 COMB 1 + +SETC "" 07 1 NOP 1 + +STA @+(B) AB 3 SWAP 1 +STA @+[B] AB 3 SWAP 1 +STA @+ 8B 3 SWAP 1 +STA *+ 9B 2 NOP 1 + +STSP "" 09 1 NOP 1 + +SUB B,A 6A 1 NOP 1 +SUB %+,A 2A 2 NOP 1 +SUB %+,B 5A 2 NOP 1 +SUB %+,+ 7A 3 COMB 1 +SUB +,A 1A 2 NOP 1 +SUB +,B 3A 2 NOP 1 +SUB +,+ 4A 3 COMB 1 + +SWAP A B7 1 NOP 1 +SWAP B C7 1 NOP 1 +SWAP + D7 2 NOP 1 + +TRAP + FF 1 SUB 1 + +TST A B0 1 NOP 1 +TSTA "" B0 1 NOP 1 +TST B C1 1 NOP 1 +TSTB "" C1 1 NOP 1 + +XCHB A B6 1 NOP 1 +XCHB + D6 2 NOP 1 + +XOR B,A 65 1 NOP 1 +XOR %+,A 25 2 NOP 1 +XOR %+,B 55 2 NOP 1 +XOR %+,+ 75 3 COMB 1 +XOR +,A 15 2 NOP 1 +XOR +,B 35 2 NOP 1 +XOR +,+ 45 3 COMB 1 + +XORP A,+ 85 2 NOP 1 +XORP B,+ 95 2 NOP 1 +XORP %+,+ A5 3 COMB 1 + diff --git a/trunk/Tools/tasm32/TASM80.TAB b/trunk/Tools/tasm32/TASM80.TAB new file mode 100644 index 00000000..058fa145 --- /dev/null +++ b/trunk/Tools/tasm32/TASM80.TAB @@ -0,0 +1,594 @@ +"TASM Z80 Assembler. " +/**************************************************************************** +/* $Id: tasm80.tab 1.2 1998/02/28 14:31:22 toma Exp $ +/**************************************************************************** +/* This is the instruction set definition table +/* for the Z80 version of TASM. +/* Thomas N. Anderson, Speech Technology Incorporated +/* This table authored and submitted by Carl A. Wall, VE3APY. +/* +/* Class bits assigned as follows: +/* Bit-0 = Z80 (base instruction set) +/* Bit-1 = HD64180 (extended instructions) +/* See TASM manual for info on table structure. +/* +/*INSTR ARGS OP BYTES RULE CLASS SHIFT OR */ +/*-------------------------------------------*/ + +ADC A,(HL) 8E 1 NOP 1 +ADC A,(IX*) 8EDD 3 ZIX 1 +ADC A,(IY*) 8EFD 3 ZIX 1 +ADC A,A 8F 1 NOP 1 +ADC A,B 88 1 NOP 1 +ADC A,C 89 1 NOP 1 +ADC A,D 8A 1 NOP 1 +ADC A,E 8B 1 NOP 1 +ADC A,H 8C 1 NOP 1 +ADC A,L 8D 1 NOP 1 +ADC A,* CE 2 NOP 1 +ADC HL,BC 4AED 2 NOP 1 +ADC HL,DE 5AED 2 NOP 1 +ADC HL,HL 6AED 2 NOP 1 +ADC HL,SP 7AED 2 NOP 1 + +ADD A,(HL) 86 1 NOP 1 +ADD A,(IX*) 86DD 3 ZIX 1 +ADD A,(IY*) 86FD 3 ZIX 1 +ADD A,A 87 1 NOP 1 +ADD A,B 80 1 NOP 1 +ADD A,C 81 1 NOP 1 +ADD A,D 82 1 NOP 1 +ADD A,E 83 1 NOP 1 +ADD A,H 84 1 NOP 1 +ADD A,L 85 1 NOP 1 +ADD A,* C6 2 NOP 1 +ADD HL,BC 09 1 NOP 1 +ADD HL,DE 19 1 NOP 1 +ADD HL,HL 29 1 NOP 1 +ADD HL,SP 39 1 NOP 1 +ADD IX,BC 09DD 2 NOP 1 +ADD IX,DE 19DD 2 NOP 1 +ADD IX,IX 29DD 2 NOP 1 +ADD IX,SP 39DD 2 NOP 1 +ADD IY,BC 09FD 2 NOP 1 +ADD IY,DE 19FD 2 NOP 1 +ADD IY,IY 29FD 2 NOP 1 +ADD IY,SP 39FD 2 NOP 1 + +AND (HL) A6 1 NOP 1 +AND (IX*) A6DD 3 ZIX 1 +AND (IY*) A6FD 3 ZIX 1 +AND A A7 1 NOP 1 +AND B A0 1 NOP 1 +AND C A1 1 NOP 1 +AND D A2 1 NOP 1 +AND E A3 1 NOP 1 +AND H A4 1 NOP 1 +AND L A5 1 NOP 1 +AND * E6 2 NOP 1 + +BIT *,(HL) 46CB 2 ZBIT 1 +BIT *,(IX*) CBDD 4 ZBIT 1 0 4600 +BIT *,(IY*) CBFD 4 ZBIT 1 0 4600 +BIT *,A 47CB 2 ZBIT 1 +BIT *,B 40CB 2 ZBIT 1 +BIT *,C 41CB 2 ZBIT 1 +BIT *,D 42CB 2 ZBIT 1 +BIT *,E 43CB 2 ZBIT 1 +BIT *,H 44CB 2 ZBIT 1 +BIT *,L 45CB 2 ZBIT 1 + +CALL C,* DC 3 NOP 1 +CALL M,* FC 3 NOP 1 +CALL NC,* D4 3 NOP 1 +CALL NZ,* C4 3 NOP 1 +CALL P,* F4 3 NOP 1 +CALL PE,* EC 3 NOP 1 +CALL PO,* E4 3 NOP 1 +CALL Z,* CC 3 NOP 1 +CALL * CD 3 NOP 1 + +CCF "" 3F 1 NOP 1 + +CP (HL) BE 1 NOP 1 +CP (IX*) BEDD 3 ZIX 1 +CP (IY*) BEFD 3 ZIX 1 +CP A BF 1 NOP 1 +CP B B8 1 NOP 1 +CP C B9 1 NOP 1 +CP D BA 1 NOP 1 +CP E BB 1 NOP 1 +CP H BC 1 NOP 1 +CP L BD 1 NOP 1 +CP * FE 2 NOP 1 +CPD "" A9ED 2 NOP 1 +CPDR "" B9ED 2 NOP 1 +CPIR "" B1ED 2 NOP 1 +CPI "" A1ED 2 NOP 1 +CPL "" 2F 1 NOP 1 + +DAA "" 27 1 NOP 1 + +DEC (HL) 35 1 NOP 1 +DEC (IX*) 35DD 3 ZIX 1 +DEC (IY*) 35FD 3 ZIX 1 +DEC A 3D 1 NOP 1 +DEC B 05 1 NOP 1 +DEC BC 0B 1 NOP 1 +DEC C 0D 1 NOP 1 +DEC D 15 1 NOP 1 +DEC DE 1B 1 NOP 1 +DEC E 1D 1 NOP 1 +DEC H 25 1 NOP 1 +DEC HL 2B 1 NOP 1 +DEC IX 2BDD 2 NOP 1 +DEC IY 2BFD 2 NOP 1 +DEC L 2D 1 NOP 1 +DEC SP 3B 1 NOP 1 +DI "" F3 1 NOP 1 +DJNZ * 10 2 R1 1 + +EI "" FB 1 NOP 1 +EX (SP),HL E3 1 NOP 1 +EX (SP),IX E3DD 2 NOP 1 +EX (SP),IY E3FD 2 NOP 1 +EX AF,AF' 08 1 NOP 1 +EX DE,HL EB 1 NOP 1 +EXX "" D9 1 NOP 1 +HALT "" 76 1 NOP 1 + +IM 0 46ED 2 NOP 1 +IM 1 56ED 2 NOP 1 +IM 2 5EED 2 NOP 1 + +/* Alternate form of above +IM0 46ED 2 NOP 1 +IM1 56ED 2 NOP 1 +IM2 5EED 2 NOP 1 + +IN A,(C) 78ED 2 NOP 1 +IN B,(C) 40ED 2 NOP 1 +IN C,(C) 48ED 2 NOP 1 +IN D,(C) 50ED 2 NOP 1 +IN E,(C) 58ED 2 NOP 1 +IN H,(C) 60ED 2 NOP 1 +IN L,(C) 68ED 2 NOP 1 + +IN A,(*) DB 2 NOP 1 + +IN0 A,(*) 38ED 3 NOP 2 +IN0 B,(*) 00ED 3 NOP 2 +IN0 C,(*) 08ED 3 NOP 2 +IN0 D,(*) 10ED 3 NOP 2 +IN0 E,(*) 18ED 3 NOP 2 +IN0 H,(*) 20ED 3 NOP 2 +IN0 L,(*) 28ED 3 NOP 2 + +INC (HL) 34 1 NOP 1 +INC (IX*) 34DD 3 ZIX 1 +INC (IY*) 34FD 3 ZIX 1 +INC A 3C 1 NOP 1 +INC B 04 1 NOP 1 +INC BC 03 1 NOP 1 +INC C 0C 1 NOP 1 +INC D 14 1 NOP 1 +INC DE 13 1 NOP 1 +INC E 1C 1 NOP 1 +INC H 24 1 NOP 1 +INC HL 23 1 NOP 1 +INC IX 23DD 2 NOP 1 +INC IY 23FD 2 NOP 1 +INC L 2C 1 NOP 1 +INC SP 33 1 NOP 1 + + +IND "" AAED 2 NOP 1 +INDR "" BAED 2 NOP 1 +INI "" A2ED 2 NOP 1 +INIR "" B2ED 2 NOP 1 + +JP (HL) E9 1 NOP 1 +JP (IX) E9DD 2 NOP 1 +JP (IY) E9FD 2 NOP 1 +JP C,* DA 3 NOP 1 +JP M,* FA 3 NOP 1 +JP NC,* D2 3 NOP 1 +JP NZ,* C2 3 NOP 1 +JP P,* F2 3 NOP 1 +JP PE,* EA 3 NOP 1 +JP PO,* E2 3 NOP 1 +JP Z,* CA 3 NOP 1 +JP * C3 3 NOP 1 + +JR C,* 38 2 R1 1 +JR NC,* 30 2 R1 1 +JR NZ,* 20 2 R1 1 +JR Z,* 28 2 R1 1 +JR * 18 2 R1 1 + +LD (BC),A 02 1 NOP 1 +LD (DE),A 12 1 NOP 1 +LD (HL),A 77 1 NOP 1 +LD (HL),B 70 1 NOP 1 +LD (HL),C 71 1 NOP 1 +LD (HL),D 72 1 NOP 1 +LD (HL),E 73 1 NOP 1 +LD (HL),H 74 1 NOP 1 +LD (HL),L 75 1 NOP 1 +LD (HL),* 36 2 NOP 1 +LD (IX*),A 77DD 3 ZIX 1 +LD (IX*),B 70DD 3 ZIX 1 +LD (IX*),C 71DD 3 ZIX 1 +LD (IX*),D 72DD 3 ZIX 1 +LD (IX*),E 73DD 3 ZIX 1 +LD (IX*),H 74DD 3 ZIX 1 +LD (IX*),L 75DD 3 ZIX 1 +LD (IX*),* 36DD 4 ZIX 1 +LD (IY*),A 77FD 3 ZIX 1 +LD (IY*),B 70FD 3 ZIX 1 +LD (IY*),C 71FD 3 ZIX 1 +LD (IY*),D 72FD 3 ZIX 1 +LD (IY*),E 73FD 3 ZIX 1 +LD (IY*),H 74FD 3 ZIX 1 +LD (IY*),L 75FD 3 ZIX 1 +LD (IY*),* 36FD 4 ZIX 1 +LD (*),A 32 3 NOP 1 +LD (*),BC 43ED 4 NOP 1 +LD (*),DE 53ED 4 NOP 1 +LD (*),HL 22 3 NOP 1 +LD (*),IX 22DD 4 NOP 1 +LD (*),IY 22FD 4 NOP 1 +LD (*),SP 73ED 4 NOP 1 +LD A,(BC) 0A 1 NOP 1 +LD A,(DE) 1A 1 NOP 1 +LD A,(HL) 7E 1 NOP 1 +LD A,(IX*) 7EDD 3 ZIX 1 +LD A,(IY*) 7EFD 3 ZIX 1 +LD A,A 7F 1 NOP 1 +LD A,B 78 1 NOP 1 +LD A,C 79 1 NOP 1 +LD A,D 7A 1 NOP 1 +LD A,E 7B 1 NOP 1 +LD A,H 7C 1 NOP 1 +LD A,I 57ED 2 NOP 1 +LD A,L 7D 1 NOP 1 +LD A,R 5FED 2 NOP 1 +LD A,(*) 3A 3 NOP 1 +LD A,* 3E 2 NOP 1 +LD B,(HL) 46 1 NOP 1 +LD B,(IX*) 46DD 3 ZIX 1 +LD B,(IY*) 46FD 3 ZIX 1 +LD B,A 47 1 NOP 1 +LD B,B 40 1 NOP 1 +LD B,C 41 1 NOP 1 +LD B,D 42 1 NOP 1 +LD B,E 43 1 NOP 1 +LD B,H 44 1 NOP 1 +LD B,L 45 1 NOP 1 +LD B,* 06 2 NOP 1 +LD BC,(*) 4BED 4 NOP 1 +LD BC,* 01 3 NOP 1 +LD C,(HL) 4E 1 NOP 1 +LD C,(IX*) 4EDD 3 ZIX 1 +LD C,(IY*) 4EFD 3 ZIX 1 +LD C,A 4F 1 NOP 1 +LD C,B 48 1 NOP 1 +LD C,C 49 1 NOP 1 +LD C,D 4A 1 NOP 1 +LD C,E 4B 1 NOP 1 +LD C,H 4C 1 NOP 1 +LD C,L 4D 1 NOP 1 +LD C,* 0E 2 NOP 1 +LD D,(HL) 56 1 NOP 1 +LD D,(IX*) 56DD 3 ZIX 1 +LD D,(IY*) 56FD 3 ZIX 1 +LD D,A 57 1 NOP 1 +LD D,B 50 1 NOP 1 +LD D,C 51 1 NOP 1 +LD D,D 52 1 NOP 1 +LD D,E 53 1 NOP 1 +LD D,H 54 1 NOP 1 +LD D,L 55 1 NOP 1 +LD D,* 16 2 NOP 1 +LD DE,(*) 5BED 4 NOP 1 +LD DE,* 11 3 NOP 1 +LD E,(HL) 5E 1 NOP 1 +LD E,(IX*) 5EDD 3 ZIX 1 +LD E,(IY*) 5EFD 3 ZIX 1 +LD E,A 5F 1 NOP 1 +LD E,B 58 1 NOP 1 +LD E,C 59 1 NOP 1 +LD E,D 5A 1 NOP 1 +LD E,E 5B 1 NOP 1 +LD E,H 5C 1 NOP 1 +LD E,L 5D 1 NOP 1 +LD E,* 1E 2 NOP 1 +LD H,(HL) 66 1 NOP 1 +LD H,(IX*) 66DD 3 ZIX 1 +LD H,(IY*) 66FD 3 ZIX 1 +LD H,A 67 1 NOP 1 +LD H,B 60 1 NOP 1 +LD H,C 61 1 NOP 1 +LD H,D 62 1 NOP 1 +LD H,E 63 1 NOP 1 +LD H,H 64 1 NOP 1 +LD H,L 65 1 NOP 1 +LD H,* 26 2 NOP 1 +LD HL,(*) 2A 3 NOP 1 +LD HL,* 21 3 NOP 1 +LD I,A 47ED 2 NOP 1 +LD IX,(*) 2ADD 4 NOP 1 +LD IX,* 21DD 4 NOP 1 +LD IY,(*) 2AFD 4 NOP 1 +LD IY,* 21FD 4 NOP 1 +LD L,(HL) 6E 1 NOP 1 +LD L,(IX*) 6EDD 3 ZIX 1 +LD L,(IY*) 6EFD 3 ZIX 1 +LD L,A 6F 1 NOP 1 +LD L,B 68 1 NOP 1 +LD L,C 69 1 NOP 1 +LD L,D 6A 1 NOP 1 +LD L,E 6B 1 NOP 1 +LD L,H 6C 1 NOP 1 +LD L,L 6D 1 NOP 1 +LD L,* 2E 2 NOP 1 +LD R,A 4FED 2 NOP 1 +LD SP,(*) 7BED 4 NOP 1 +LD SP,HL F9 1 NOP 1 +LD SP,IX F9DD 2 NOP 1 +LD SP,IY F9FD 2 NOP 1 +LD SP,* 31 3 NOP 1 +LDD "" A8ED 2 NOP 1 +LDDR "" B8ED 2 NOP 1 +LDI "" A0ED 2 NOP 1 +LDIR "" B0ED 2 NOP 1 +NEG "" 44ED 2 NOP 1 +NOP "" 00 1 NOP 1 + +MLT BC 4CED 2 NOP 2 +MLT DE 5CED 2 NOP 2 +MLT HL 6CED 2 NOP 2 +MLT SP 7CED 2 NOP 2 + +OR (HL) B6 1 NOP 1 +OR (IX*) B6DD 3 ZIX 1 +OR (IY*) B6FD 3 ZIX 1 +OR A B7 1 NOP 1 +OR B B0 1 NOP 1 +OR C B1 1 NOP 1 +OR D B2 1 NOP 1 +OR E B3 1 NOP 1 +OR H B4 1 NOP 1 +OR L B5 1 NOP 1 +OR * F6 2 NOP 1 + +OTDM "" 8BED 2 NOP 2 +OTDMR "" 9BED 2 NOP 2 +OTDR "" BBED 2 NOP 1 +OTIM "" 83ED 2 NOP 2 +OTIMR "" 93ED 2 NOP 2 +OTIR "" B3ED 2 NOP 1 + +OUT (C),A 79ED 2 NOP 1 +OUT (C),B 41ED 2 NOP 1 +OUT (C),C 49ED 2 NOP 1 +OUT (C),D 51ED 2 NOP 1 +OUT (C),E 59ED 2 NOP 1 +OUT (C),H 61ED 2 NOP 1 +OUT (C),L 69ED 2 NOP 1 +OUT (*),A D3 2 NOP 1 + +OUT0 (*),A 39ED 3 NOP 2 +OUT0 (*),B 01ED 3 NOP 2 +OUT0 (*),C 09ED 3 NOP 2 +OUT0 (*),D 11ED 3 NOP 2 +OUT0 (*),E 19ED 3 NOP 2 +OUT0 (*),H 21ED 3 NOP 2 +OUT0 (*),L 29ED 3 NOP 2 + +OUTD "" ABED 2 NOP 1 +OUTI "" A3ED 2 NOP 1 + +POP AF F1 1 NOP 1 +POP BC C1 1 NOP 1 +POP DE D1 1 NOP 1 +POP HL E1 1 NOP 1 +POP IX E1DD 2 NOP 1 +POP IY E1FD 2 NOP 1 + +PUSH AF F5 1 NOP 1 +PUSH BC C5 1 NOP 1 +PUSH DE D5 1 NOP 1 +PUSH HL E5 1 NOP 1 +PUSH IX E5DD 2 NOP 1 +PUSH IY E5FD 2 NOP 1 + +RES *,(HL) 86CB 2 ZBIT 1 +RES *,(IX*) CBDD 4 ZBIT 1 0 8600 +RES *,(IY*) CBFD 4 ZBIT 1 0 8600 +RES *,A 87CB 2 ZBIT 1 +RES *,B 80CB 2 ZBIT 1 +RES *,C 81CB 2 ZBIT 1 +RES *,D 82CB 2 ZBIT 1 +RES *,E 83CB 2 ZBIT 1 +RES *,H 84CB 2 ZBIT 1 +RES *,L 85CB 2 ZBIT 1 + +RET "" C9 1 NOP 1 +RET C D8 1 NOP 1 +RET M F8 1 NOP 1 +RET NC D0 1 NOP 1 +RET NZ C0 1 NOP 1 +RET P F0 1 NOP 1 +RET PE E8 1 NOP 1 +RET PO E0 1 NOP 1 +RET Z C8 1 NOP 1 +RETI "" 4DED 2 NOP 1 +RETN "" 45ED 2 NOP 1 + +RL (HL) 16CB 2 NOP 1 +RL (IX*) CBDD 4 ZIX 1 0 1600 +RL (IY*) CBFD 4 ZIX 1 0 1600 +RL A 17CB 2 NOP 1 +RL B 10CB 2 NOP 1 +RL C 11CB 2 NOP 1 +RL D 12CB 2 NOP 1 +RL E 13CB 2 NOP 1 +RL H 14CB 2 NOP 1 +RL L 15CB 2 NOP 1 +RLA "" 17 1 NOP 1 + +RLC (HL) 06CB 2 NOP 1 +RLC (IX*) CBDD 4 ZIX 1 0 0600 +RLC (IY*) CBFD 4 ZIX 1 0 0600 +RLC A 07CB 2 NOP 1 +RLC B 00CB 2 NOP 1 +RLC C 01CB 2 NOP 1 +RLC D 02CB 2 NOP 1 +RLC E 03CB 2 NOP 1 +RLC H 04CB 2 NOP 1 +RLC L 05CB 2 NOP 1 +RLCA "" 07 1 NOP 1 +RLD "" 6FED 2 NOP 1 + +RR (HL) 1ECB 2 NOP 1 +RR (IX*) CBDD 4 ZIX 1 0 1E00 +RR (IY*) CBFD 4 ZIX 1 0 1E00 +RR A 1FCB 2 NOP 1 +RR B 18CB 2 NOP 1 +RR C 19CB 2 NOP 1 +RR D 1ACB 2 NOP 1 +RR E 1BCB 2 NOP 1 +RR H 1CCB 2 NOP 1 +RR L 1DCB 2 NOP 1 +RRA "" 1F 1 NOP 1 +RRC (HL) 0ECB 2 NOP 1 +RRC (IX*) CBDD 4 ZIX 1 0 0E00 +RRC (IY*) CBFD 4 ZIX 1 0 0E00 +RRC A 0FCB 2 NOP 1 +RRC B 08CB 2 NOP 1 +RRC C 09CB 2 NOP 1 +RRC D 0ACB 2 NOP 1 +RRC E 0BCB 2 NOP 1 +RRC H 0CCB 2 NOP 1 +RRC L 0DCB 2 NOP 1 +RRCA "" 0F 1 NOP 1 +RRD "" 67ED 2 NOP 1 + +RST 00H C7 1 NOP 1 +RST 08H CF 1 NOP 1 +RST 10H D7 1 NOP 1 +RST 18H DF 1 NOP 1 +RST 20H E7 1 NOP 1 +RST 28H EF 1 NOP 1 +RST 30H F7 1 NOP 1 +RST 38H FF 1 NOP 1 + +/* Alternate form of above +RST 00 C7 1 NOP 1 +RST 08 CF 1 NOP 1 +RST 10 D7 1 NOP 1 +RST 18 DF 1 NOP 1 +RST 20 E7 1 NOP 1 +RST 28 EF 1 NOP 1 +RST 30 F7 1 NOP 1 +RST 38 FF 1 NOP 1 + +SBC A,(HL) 9E 1 NOP 1 +SBC A,(IX*) 9EDD 3 ZIX 1 +SBC A,(IY*) 9EFD 3 ZIX 1 +SBC A,A 9F 1 NOP 1 +SBC A,B 98 1 NOP 1 +SBC A,C 99 1 NOP 1 +SBC A,D 9A 1 NOP 1 +SBC A,E 9B 1 NOP 1 +SBC A,H 9C 1 NOP 1 +SBC A,L 9D 1 NOP 1 +SBC HL,BC 42ED 2 NOP 1 +SBC HL,DE 52ED 2 NOP 1 +SBC HL,HL 62ED 2 NOP 1 +SBC HL,SP 72ED 2 NOP 1 +SBC A,* DE 2 NOP 1 +SCF "" 37 1 NOP 1 + +SET *,(HL) C6CB 2 ZBIT 1 +SET *,(IX*) CBDD 4 ZBIT 1 0 C600 +SET *,(IY*) CBFD 4 ZBIT 1 0 C600 +SET *,A C7CB 2 ZBIT 1 +SET *,B C0CB 2 ZBIT 1 +SET *,C C1CB 2 ZBIT 1 +SET *,D C2CB 2 ZBIT 1 +SET *,E C3CB 2 ZBIT 1 +SET *,H C4CB 2 ZBIT 1 +SET *,L C5CB 2 ZBIT 1 + +SLA (HL) 26CB 2 NOP 1 +SLA (IX*) CBDD 4 ZIX 1 0 2600 +SLA (IY*) CBFD 4 ZIX 1 0 2600 +SLA A 27CB 2 NOP 1 +SLA B 20CB 2 NOP 1 +SLA C 21CB 2 NOP 1 +SLA D 22CB 2 NOP 1 +SLA E 23CB 2 NOP 1 +SLA H 24CB 2 NOP 1 +SLA L 25CB 2 NOP 1 + +SLP "" 76ED 2 NOP 2 + +SRA (HL) 2ECB 2 NOP 1 +SRA (IX*) CBDD 4 ZIX 1 0 2E00 +SRA (IY*) CBFD 4 ZIX 1 0 2E00 +SRA A 2FCB 2 NOP 1 +SRA B 28CB 2 NOP 1 +SRA C 29CB 2 NOP 1 +SRA D 2ACB 2 NOP 1 +SRA E 2BCB 2 NOP 1 +SRA H 2CCB 2 NOP 1 +SRA L 2DCB 2 NOP 1 + +SRL (HL) 3ECB 2 NOP 1 +SRL (IX*) CBDD 4 ZIX 1 0 3E00 +SRL (IY*) CBFD 4 ZIX 1 0 3E00 +SRL A 3FCB 2 NOP 1 +SRL B 38CB 2 NOP 1 +SRL C 39CB 2 NOP 1 +SRL D 3ACB 2 NOP 1 +SRL E 3BCB 2 NOP 1 +SRL H 3CCB 2 NOP 1 +SRL L 3DCB 2 NOP 1 + +SUB (HL) 96 1 NOP 1 +SUB (IX*) 96DD 3 ZIX 1 +SUB (IY*) 96FD 3 ZIX 1 +SUB A 97 1 NOP 1 +SUB B 90 1 NOP 1 +SUB C 91 1 NOP 1 +SUB D 92 1 NOP 1 +SUB E 93 1 NOP 1 +SUB H 94 1 NOP 1 +SUB L 95 1 NOP 1 +SUB * D6 2 NOP 1 + +TST A 3CED 2 NOP 2 +TST B 04ED 2 NOP 2 +TST C 0CED 2 NOP 2 +TST D 14ED 2 NOP 2 +TST E 1CED 2 NOP 2 +TST H 24ED 2 NOP 2 +TST L 2CED 2 NOP 2 +TST (HL) 34ED 2 NOP 2 +TST * 64ED 3 NOP 2 + +TSTIO * 74ED 3 NOP 2 + +XOR (HL) AE 1 NOP 1 +XOR (IX*) AEDD 3 ZIX 1 +XOR (IY*) AEFD 3 ZIX 1 +XOR A AF 1 NOP 1 +XOR B A8 1 NOP 1 +XOR C A9 1 NOP 1 +XOR D AA 1 NOP 1 +XOR E AB 1 NOP 1 +XOR H AC 1 NOP 1 +XOR L AD 1 NOP 1 +XOR * EE 2 NOP 1 diff --git a/trunk/Tools/tasm32/TASM85.TAB b/trunk/Tools/tasm32/TASM85.TAB new file mode 100644 index 00000000..33a1bf5b --- /dev/null +++ b/trunk/Tools/tasm32/TASM85.TAB @@ -0,0 +1,257 @@ +"TASM 8085 Assembler. " +/**************************************************************************** +/* $Id: tasm85.tab 1.1 1993/07/31 01:12:40 toma Exp $ +/**************************************************************************** +/* This is the instruction set definition table for the 8085 version of TASM. +/* Thomas N. Anderson, Speech Technology Incorporated +/* This table authored and submitted by Gary Kirk Bach. +/* +/*INSTR ARGS OPCODE BYTES MOD CLASS */ +/*-----------------*/ +ACI * CE 2 NOP 1 +ADC B 88 1 NOP 1 +ADC C 89 1 NOP 1 +ADC D 8A 1 NOP 1 +ADC E 8B 1 NOP 1 +ADC H 8C 1 NOP 1 +ADC L 8D 1 NOP 1 +ADC M 8E 1 NOP 1 +ADC A 8F 1 NOP 1 +ADD B 80 1 NOP 1 +ADD C 81 1 NOP 1 +ADD D 82 1 NOP 1 +ADD E 83 1 NOP 1 +ADD H 84 1 NOP 1 +ADD L 85 1 NOP 1 +ADD M 86 1 NOP 1 +ADD A 87 1 NOP 1 +ADI * C6 2 NOP 1 +ANA B A0 1 NOP 1 +ANA C A1 1 NOP 1 +ANA D A2 1 NOP 1 +ANA E A3 1 NOP 1 +ANA H A4 1 NOP 1 +ANA L A5 1 NOP 1 +ANA M A6 1 NOP 1 +ANA A A7 1 NOP 1 +ANI * E6 2 NOP 1 +CALL * CD 3 NOP 1 +CC * DC 3 NOP 1 +CM * FC 3 NOP 1 +CMA "" 2F 1 NOP 1 +CMC "" 3F 1 NOP 1 +CMP B B8 1 NOP 1 +CMP C B9 1 NOP 1 +CMP D BA 1 NOP 1 +CMP E BB 1 NOP 1 +CMP H BC 1 NOP 1 +CMP L BD 1 NOP 1 +CMP M BE 1 NOP 1 +CMP A BF 1 NOP 1 +CNC * D4 3 NOP 1 +CNZ * C4 3 NOP 1 +CP * F4 3 NOP 1 +CPE * EC 3 NOP 1 +CPI * FE 2 NOP 1 +CPO * E4 3 NOP 1 +CZ * CC 3 NOP 1 +DAA "" 27 1 NOP 1 +DAD B 09 1 NOP 1 +DAD D 19 1 NOP 1 +DAD H 29 1 NOP 1 +DAD SP 39 1 NOP 1 +DCR B 05 1 NOP 1 +DCR C 0D 1 NOP 1 +DCR D 15 1 NOP 1 +DCR E 1D 1 NOP 1 +DCR H 25 1 NOP 1 +DCR L 2D 1 NOP 1 +DCR M 35 1 NOP 1 +DCR A 3D 1 NOP 1 +DCX B 0B 1 NOP 1 +DCX D 1B 1 NOP 1 +DCX H 2B 1 NOP 1 +DCX SP 3B 1 NOP 1 +DI "" F3 1 NOP 1 +EI "" FB 1 NOP 1 +HLT "" 76 1 NOP 1 +IN * DB 2 NOP 1 +INR B 04 1 NOP 1 +INR C 0C 1 NOP 1 +INR D 14 1 NOP 1 +INR E 1C 1 NOP 1 +INR H 24 1 NOP 1 +INR L 2C 1 NOP 1 +INR M 34 1 NOP 1 +INR A 3C 1 NOP 1 +INX B 03 1 NOP 1 +INX D 13 1 NOP 1 +INX H 23 1 NOP 1 +INX SP 33 1 NOP 1 +JC * DA 3 NOP 1 +JM * FA 3 NOP 1 +JMP * C3 3 NOP 1 +JNC * D2 3 NOP 1 +JNZ * C2 3 NOP 1 +JP * F2 3 NOP 1 +JPE * EA 3 NOP 1 +JPO * E2 3 NOP 1 +JZ * CA 3 NOP 1 +LDA * 3A 3 NOP 1 +LDAX B 0A 1 NOP 1 +LDAX D 1A 1 NOP 1 +LHLD * 2A 3 NOP 1 +LXI B,* 01 3 NOP 1 +LXI D,* 11 3 NOP 1 +LXI H,* 21 3 NOP 1 +LXI SP,* 31 3 NOP 1 +MOV B,B 40 1 NOP 1 +MOV B,C 41 1 NOP 1 +MOV B,D 42 1 NOP 1 +MOV B,E 43 1 NOP 1 +MOV B,H 44 1 NOP 1 +MOV B,L 45 1 NOP 1 +MOV B,M 46 1 NOP 1 +MOV B,A 47 1 NOP 1 +MOV C,B 48 1 NOP 1 +MOV C,C 49 1 NOP 1 +MOV C,D 4A 1 NOP 1 +MOV C,E 4B 1 NOP 1 +MOV C,H 4C 1 NOP 1 +MOV C,L 4D 1 NOP 1 +MOV C,M 4E 1 NOP 1 +MOV C,A 4F 1 NOP 1 +MOV D,B 50 1 NOP 1 +MOV D,C 51 1 NOP 1 +MOV D,D 52 1 NOP 1 +MOV D,E 53 1 NOP 1 +MOV D,H 54 1 NOP 1 +MOV D,L 55 1 NOP 1 +MOV D,M 56 1 NOP 1 +MOV D,A 57 1 NOP 1 +MOV E,B 58 1 NOP 1 +MOV E,C 59 1 NOP 1 +MOV E,D 5A 1 NOP 1 +MOV E,E 5B 1 NOP 1 +MOV E,H 5C 1 NOP 1 +MOV E,L 5D 1 NOP 1 +MOV E,M 5E 1 NOP 1 +MOV E,A 5F 1 NOP 1 +MOV H,B 60 1 NOP 1 +MOV H,C 61 1 NOP 1 +MOV H,D 62 1 NOP 1 +MOV H,E 63 1 NOP 1 +MOV H,H 64 1 NOP 1 +MOV H,L 65 1 NOP 1 +MOV H,M 66 1 NOP 1 +MOV H,A 67 1 NOP 1 +MOV L,B 68 1 NOP 1 +MOV L,C 69 1 NOP 1 +MOV L,D 6A 1 NOP 1 +MOV L,E 6B 1 NOP 1 +MOV L,H 6C 1 NOP 1 +MOV L,L 6D 1 NOP 1 +MOV L,M 6E 1 NOP 1 +MOV L,A 6F 1 NOP 1 +MOV M,B 70 1 NOP 1 +MOV M,C 71 1 NOP 1 +MOV M,D 72 1 NOP 1 +MOV M,E 73 1 NOP 1 +MOV M,H 74 1 NOP 1 +MOV M,L 75 1 NOP 1 +MOV M,A 77 1 NOP 1 +MOV A,B 78 1 NOP 1 +MOV A,C 79 1 NOP 1 +MOV A,D 7A 1 NOP 1 +MOV A,E 7B 1 NOP 1 +MOV A,H 7C 1 NOP 1 +MOV A,L 7D 1 NOP 1 +MOV A,M 7E 1 NOP 1 +MOV A,A 7F 1 NOP 1 +MVI B,* 06 2 NOP 1 +MVI C,* 0E 2 NOP 1 +MVI D,* 16 2 NOP 1 +MVI E,* 1E 2 NOP 1 +MVI H,* 26 2 NOP 1 +MVI L,* 2E 2 NOP 1 +MVI M,* 36 2 NOP 1 +MVI A,* 3E 2 NOP 1 +NOP "" 00 1 NOP 1 +ORA B B0 1 NOP 1 +ORA C B1 1 NOP 1 +ORA D B2 1 NOP 1 +ORA E B3 1 NOP 1 +ORA H B4 1 NOP 1 +ORA L B5 1 NOP 1 +ORA M B6 1 NOP 1 +ORA A B7 1 NOP 1 +ORI * F6 2 NOP 1 +OUT * D3 2 NOP 1 +PCHL "" E9 1 NOP 1 +POP B C1 1 NOP 1 +POP D D1 1 NOP 1 +POP H E1 1 NOP 1 +POP PSW F1 1 NOP 1 +PUSH B C5 1 NOP 1 +PUSH D D5 1 NOP 1 +PUSH H E5 1 NOP 1 +PUSH PSW F5 1 NOP 1 +RAL "" 17 1 NOP 1 +RAR "" 1F 1 NOP 1 +RC "" D8 1 NOP 1 +RET "" C9 1 NOP 1 +RIM "" 20 1 NOP 1 +RLC "" 07 1 NOP 1 +RM "" F8 1 NOP 1 +RNC "" D0 1 NOP 1 +RNZ "" C0 1 NOP 1 +RP "" F0 1 NOP 1 +RPE "" E8 1 NOP 1 +RPO "" E0 1 NOP 1 +RRC "" 0F 1 NOP 1 +RST 0 C7 1 NOP 1 +RST 1 CF 1 NOP 1 +RST 2 D7 1 NOP 1 +RST 3 DF 1 NOP 1 +RST 4 E7 1 NOP 1 +RST 5 EF 1 NOP 1 +RST 6 F7 1 NOP 1 +RST 7 FF 1 NOP 1 +RZ "" C8 1 NOP 1 +SBB B 98 1 NOP 1 +SBB C 99 1 NOP 1 +SBB D 9A 1 NOP 1 +SBB E 9B 1 NOP 1 +SBB H 9C 1 NOP 1 +SBB L 9D 1 NOP 1 +SBB M 9E 1 NOP 1 +SBB A 9F 1 NOP 1 +SBI * DE 2 NOP 1 +SHLD * 22 3 NOP 1 +SIM "" 30 1 NOP 1 +SPHL "" F9 1 NOP 1 +STA * 32 3 NOP 1 +STAX B 02 1 NOP 1 +STAX D 12 1 NOP 1 +STC "" 37 1 NOP 1 +SUB B 90 1 NOP 1 +SUB C 91 1 NOP 1 +SUB D 92 1 NOP 1 +SUB E 93 1 NOP 1 +SUB H 94 1 NOP 1 +SUB L 95 1 NOP 1 +SUB M 96 1 NOP 1 +SUB A 97 1 NOP 1 +SUI * D6 2 NOP 1 +XCHG "" EB 1 NOP 1 +XRA B A8 1 NOP 1 +XRA C A9 1 NOP 1 +XRA D AA 1 NOP 1 +XRA E AB 1 NOP 1 +XRA H AC 1 NOP 1 +XRA L AD 1 NOP 1 +XRA M AE 1 NOP 1 +XRA A AF 1 NOP 1 +XRI * EE 2 NOP 1 +XTHL "" E3 1 NOP 1 + diff --git a/trunk/Tools/tasm32/TASM96.TAB b/trunk/Tools/tasm32/TASM96.TAB new file mode 100644 index 00000000..25268138 --- /dev/null +++ b/trunk/Tools/tasm32/TASM96.TAB @@ -0,0 +1,393 @@ +"TASM 8096 Assembler." +/**************************************************************************** +/* $Id: tasm96.tab 1.5 1997/09/28 22:14:30 toma Exp $ +/**************************************************************************** +;* This is the instruction set definition table +;* for the 8096 version of TASM. +;* Thomas N. Anderson, Speech Technology Incorporated +;* +;* See TASM manual for info on table structure. +;* +;*INSTR ARGS OPCODE BYTES MOD CLASS SHIFT MASK +;*-------------------------------------------* +; Revisions: +; Added I7 rule for single arg direct/far (PUSH/POP) +; Changed ADDB *,*,*[*] entry from rule I1 to I6. +; +; Generate opcodes high byte first/ +.MSFIRST +.NOARGSHIFT +; +; Note: +; The I1 rule uses ARGVAL for arg validation. If the combined +; args AND ARGVAL is not equal to the combined args then an +; error message is generated. +; +; The I1 rule also uses ARGOR. The value of that mask is OR'd +; with the first byte of the args. +; +; ARGOR +; BYTES CLASS | +; | | | +;INST ARGS OP v RULE v v ARGVAL +;-----------------------------------------; +;OK ADD +ADD *,*,[*]+ 46 4 I1 1 01 00FeFeFe ; +ADD *,*,[*] 46 4 I1 1 00 00FeFeFe ; +ADD *,*,*[*] 47 6 I6 1 00 00FeFeFe ; +ADD *,*,#* 45 5 I1 1 00 FeFeFFFF ; +ADD *,[*]+ 66 3 I1 1 01 0000FFFe ; 1st arg must be even, make odd +ADD *,[*] 66 3 I1 1 00 0000FFFe ; 1st arg must be even +ADD *,*[*] 67 5 I6 1 00 00FFFFFF ; +ADD *,*,* 4701 6 I3 1 00 0000FeFe ; 3rd arg may be far +ADD *,#* 65 4 I1 1 00 00FeFFFF ; 1st arg must be even +ADD *,* 6701 5 I2 1 00 0000FeFe ; 2nd arg may be far + +;OK ADDB +ADDB *,*,[*]+ 56 4 I1 1 01 00000000 ; no validation yet +ADDB *,*,[*] 56 4 I1 1 00 00000000 ; no validation yet +ADDB *,*,*[*] 57 6 I6 1 00 00000000 ; no validation yet +ADDB *,*,#* 55 4 I1 1 00 00000000 ; no validation yet +ADDB *,[*]+ 76 3 I1 1 01 0000FFFe ; 1st arg must be even, make odd +ADDB *,[*] 76 3 I1 1 00 0000FFFe ; 1st arg must be even +ADDB *,*[*] 77 5 I6 1 00 00FeFFFe ; 1st,3rd must be even +ADDB *,*,* 5701 6 I3 1 00 00000000 ; 3rd arg may be far +ADDB *,#* 75 3 I1 1 00 00FFFFFF ; odd args ok for byte operations +ADDB *,* 7701 5 I2 1 00 00000000 ; 2nd arg may be far + +; No three arg forms for ADDC or ADDCB +ADDC *,[*]+ A6 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +ADDC *,[*] A6 3 I1 1 00 0000FFFe ;1st arg must be even +ADDC *,*[*] A7 5 I6 1 00 00FFFFFF ; +ADDC *,#* A5 4 I1 1 00 00FeFFFF ;1st arg must be even +ADDC *,* A701 5 I2 1 00 00000000 ;2nd arg may be far + +ADDCB *,[*]+ B6 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +ADDCB *,[*] B6 3 I1 1 00 0000FFFe ;1st arg must be even +ADDCB *,*[*] B7 5 I6 1 00 00FFFFFF ; +ADDCB *,#* B5 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +ADDCB *,* B701 5 I2 1 00 00000000 ;2nd arg may be far + +; OK AND +AND *,*,[*]+ 42 4 I1 1 01 00000000 ;no validation yet +AND *,*,[*] 42 4 I1 1 00 00000000 ;no validation yet +AND *,*,*[*] 43 6 I6 1 00 00000000 ;no validation yet +AND *,*,#* 41 5 I1 1 00 00000000 ;no validation yet +AND *,[*]+ 62 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +AND *,[*] 62 3 I1 1 00 0000FFFe ;1st arg must be even +AND *,*[*] 63 5 I6 1 00 00FeFFFe ;1st,3rd must be even +AND *,*,* 4301 6 I3 1 00 00000000 ;3rd arg may be far +AND *,#* 61 4 I1 1 00 00FeFFFF ;1st arg must be even +AND *,* 6301 5 I2 1 00 00000000 ;2nd arg may be far + +ANDB *,*,[*]+ 52 4 I1 1 01 00000000 ;no validation yet +ANDB *,*,[*] 52 4 I1 1 00 00000000 ;no validation yet +ANDB *,*,*[*] 53 6 I6 1 00 00000000 ;no validation yet +ANDB *,*,#* 51 4 I1 1 00 00000000 ;no validation yet +ANDB *,[*]+ 72 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +ANDB *,[*] 72 3 I1 1 00 0000FFFe ;1st arg must be even +ANDB *,*[*] 73 5 I6 1 00 00FFFFFF ; +ANDB *,*,* 5301 6 I3 1 00 00000000 ;3rd arg may be far +ANDB *,#* 71 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +ANDB *,* 7301 5 I2 1 00 00000000 ;2nd arg may be far + +BMOV *,* C1 3 I1 2 00 0000FcFF ;long word ptr to two words +BMOVI *,* AD 3 I1 2 00 0000FcFF ;long word ptr to two words + +BR [*] E3 2 I1 1 00 00000000 ; +BR * 2000 2 I5 1 00 00000000 ; Same As SJMP + +CLR * 01 2 NOP 1 00 00000000 ; +CLRB * 11 2 NOP 1 00 00000000 ; +CLRC "" F8 1 NOP 1 00 00000000 ; +CLRVT "" FC 1 NOP 1 00 00000000 ; + +CMP *,[*]+ 8A 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +CMP *,[*] 8A 3 I1 1 00 0000FFFe ;1st arg must be even +CMP *,*[*] 8B 5 I6 1 00 00FFFFFF ; +CMP *,#* 89 4 I1 1 00 00FeFFFF ;1st arg must be even +CMP *,* 8B01 5 I2 1 00 00000000 ;2nd arg may be far + +CMPB *,[*]+ 9A 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +CMPB *,[*] 9A 3 I1 1 00 0000FFFe ;1st arg must be even +CMPB *,*[*] 9B 5 I6 1 00 00FFFFFF ; +CMPB *,#* 99 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +CMPB *,* 9B01 5 I2 1 00 00000000 ;2nd arg may be far + +CMPL *,* C5 3 I1 2 00 0000FcFc ;long align multiple of 4 + +DEC * 05 2 NOP 1 00 00000000 ; +DECB * 15 2 NOP 1 00 00000000 ; +DJNZ *,* E0 3 CREL 1 00 00000000 ; +DJNZW *,* E1 3 CREL 2 00 00000000 ; + +DI "" FA 1 NOP 1 00 00000000 ; + +DIVU *,[*]+ 8E 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +DIVU *,[*] 8E 3 I1 1 00 0000FFFe ;1st arg must be even +DIVU *,*[*] 8F 5 I6 1 00 0000FFFe ;1st arg must be even +DIVU *,#* 8D 4 I1 1 00 00FeFFFF ;1st arg must be even +DIVU *,* 8F01 5 I2 1 00 00000000 ;2nd arg may be far + +DIVUB *,[*]+ 9E 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +DIVUB *,[*] 9E 3 I1 1 00 0000FFFe ;1st arg must be even +DIVUB *,*[*] 9F 5 I6 1 00 0000FFFF ; +DIVUB *,#* 9D 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +DIVUB *,* 9F01 5 I2 1 00 00000000 ;2nd arg may be far + +DIV *,[*]+ FE8E 4 I1 1 01 0000FFFe ;1st arg must be even, make odd +DIV *,[*] FE8E 4 I1 1 00 0000FFFe ;1st arg must be even +DIV *,*[*] FE8F 6 I6 1 00 0000FFFe ;1st arg must be even +DIV *,#* FE8D 5 I1 1 00 00FeFFFF ;1st arg must be even +DIV *,* FE8F01 6 I2 1 00 00000000 ;2nd arg may be far + +DIVB *,[*]+ FE9E 4 I1 1 01 0000FFFe ;1st arg must be even, make odd +DIVB *,[*] FE9E 4 I1 1 00 0000FFFe ;1st arg must be even +DIVB *,*[*] FE9F 6 I6 1 00 0000FFFF ; +DIVB *,#* FE9D 4 I1 1 00 00FFFFFF ;odd args ok for byte operations; +DIVB *,* FE9F01 6 I2 1 00 00000000 ;2nd arg may be far + +DPTS "" EC 1 NOP 2 00 00000000 ; +EPTS "" ED 1 NOP 2 00 00000000 ; + +EI "" FB 1 NOP 1 00 00000000 ; + +EXT * 06 2 NOP 1 00 00000000 ; +EXTB * 16 2 NOP 1 00 00000000 ; + +IDLPD #* F6 2 NOP 2 00 00000000 ; + +INC * 07 2 NOP 1 00 00000000 ; +INCB * 17 2 NOP 1 00 00000000 ; + +JC * DB 2 R1 1 00 00000000 +JNC * D3 2 R1 1 00 00000000 +JH * D9 2 R1 1 00 00000000 +JNH * D1 2 R1 1 00 00000000 +JE * DF 2 R1 1 00 00000000 +JNE * D7 2 R1 1 00 00000000 +JV * DD 2 R1 1 00 00000000 +JNV * D5 2 R1 1 00 00000000 +JGE * D6 2 R1 1 00 00000000 +JLT * DE 2 R1 1 00 00000000 +JVT * DC 2 R1 1 00 00000000 +JNVT * D4 2 R1 1 00 00000000 +JGT * D2 2 R1 1 00 00000000 +JLE * DA 2 R1 1 00 00000000 +JST * D8 2 R1 1 00 00000000 +JNST * D0 2 R1 1 00 00000000 + +JBC *,*,* 30 3 I4 1 00 00000000 +JBS *,*,* 38 3 I4 1 00 00000000 + +LJMP * E7 3 R2 1 00 00000000 +LCALL * EF 3 R2 1 00 00000000 + +LD *,[*]+ A2 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +LD *,[*] A2 3 I1 1 00 0000FFFe ;1st arg must be even +LD *,*[*] A3 5 I6 1 00 00FFFFFF ; +LD *,#* A1 4 I1 1 00 00FFFFFF ; +LD *,* A301 5 I2 1 00 00000000 ;2nd arg may be far + +LDB *,[*]+ B2 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +LDB *,[*] B2 3 I1 1 00 0000FFFe ;1st arg must be even +LDB *,*[*] B3 5 I6 1 00 00FFFFFF ; +LDB *,#* B1 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +LDB *,* B301 5 I2 1 00 00000000 ;2nd arg may be far + +LDBSE *,[*]+ BE 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +LDBSE *,[*] BE 3 I1 1 00 0000FFFe ;1st arg must be even +LDBSE *,*[*] BF 5 I6 1 00 00FeFFFe ;1st,3rd must be even +LDBSE *,#* BD 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +LDBSE *,* BF01 5 I2 1 00 00000000 ;2nd arg may be far + +LDBZE *,[*]+ AE 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +LDBZE *,[*] AE 3 I1 1 00 0000FFFe ;1st arg must be even +LDBZE *,*[*] AF 5 I6 1 00 00FeFFFe ;1st,3rd must be even +LDBZE *,#* AD 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +LDBZE *,* AF01 5 I2 1 00 00000000 ;2nd arg may be far + +MULU *,*,[*]+ 4E 4 I1 1 01 00000000 ;no validation yet +MULU *,*,[*] 4E 4 I1 1 00 00000000 ;no validation yet +MULU *,*,*[*] 4F 6 I6 1 00 00000000 ;no validation yet +MULU *,*,#* 4D 5 I1 1 00 00000000 ;no validation yet +MULU *,[*]+ 6E 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +MULU *,[*] 6E 3 I1 1 00 0000FFFe ;1st arg must be even +MULU *,*[*] 6F 5 I6 1 00 00FeFFFe ;1st,3rd must be even +MULU *,*,* 4F01 6 I3 1 00 00000000 ;3rd arg may be far +MULU *,#* 6D 4 I1 1 00 00FeFFFF ;1st arg must be even +MULU *,* 6F01 5 I2 1 00 00000000 ;2nd arg may be far + + +MULUB *,*,[*]+ 5E 4 I1 1 01 00000000 ;no validation yet +MULUB *,*,[*] 5E 4 I1 1 00 00000000 ;no validation yet +MULUB *,*,*[*] 5F 6 I6 1 00 00000000 ;no validation yet +MULUB *,*,#* 5D 4 I1 1 00 00000000 ;no validation yet +MULUB *,[*]+ 7E 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +MULUB *,[*] 7E 3 I1 1 00 0000FFFe ;1st arg must be even +MULUB *,*[*] 7F 5 I6 1 00 00FFFFFF ; +MULUB *,*,* 5F01 6 I3 1 00 00000000 ;3rd arg may be far +MULUB *,#* 7D 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +MULUB *,* 7F01 5 I2 1 00 00000000 ;2nd arg may be far + +MUL *,*,[*]+ FE4E 5 I1 1 01 00000000 ;no validation yet +MUL *,*,[*] FE4E 5 I1 1 00 00000000 ;no validation yet +MUL *,*,*[*] FE4F 7 I6 1 00 00000000 ;no validation yet +MUL *,*,#* FE4D 6 I1 1 00 00000000 ;no validation yet +MUL *,[*]+ FE6E 4 I1 1 01 0000FFFe ;1st arg must be even, make odd +MUL *,[*] FE6E 4 I1 1 00 0000FFFe ;1st arg must be even +MUL *,*[*] FE6F 6 I6 1 00 00FeFFFe ;1st,3rd must be even +MUL *,*,* FE4F01 7 I3 1 00 00000000 ;3rd arg may be far +MUL *,#* FE6D 5 I1 1 00 00FFFFFF ;odd args ok for byte operations +MUL *,* FE6F01 6 I2 1 00 00000000 ;2nd arg may be far + +MULB *,*,[*]+ FE5E 5 I1 1 01 00000000 ;no validation yet +MULB *,*,[*] FE5E 5 I1 1 00 00000000 ;no validation yet +MULB *,*,*[*] FE5F 7 I6 1 00 00000000 ;no validation yet +MULB *,*,#* FE5D 5 I1 1 00 00000000 ;no validation yet +MULB *,[*]+ FE7E 4 I1 1 01 0000FFFe ;1st arg must be even, make odd +MULB *,[*] FE7E 4 I1 1 00 0000FFFe ;1st arg must be even +MULB *,*[*] FE7F 6 I6 1 00 00FFFFFF ; +MULB *,*,* FE5F01 7 I3 1 00 00000000 ;3rd arg may be far +MULB *,#* FE7D 4 I1 1 00 00FFFFFF ;odd args ok for byte operations +MULB *,* FE7F01 6 I2 1 00 00000000 ;2nd arg may be far + +NEG * 03 2 I1 1 00 000000FE ;arg must be even +NEGB * 13 2 I1 1 00 000000FF ; + +NOP "" FD 1 NOP 1 00 00000000 ; + +NORML *,* 0F 3 I1 1 00 0000FFFF ;long align + +NOT * 02 2 NOP 1 00 00000000 ; +NOTB * 12 2 NOP 1 00 00000000 ; + +OR *,[*]+ 82 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +OR *,[*] 82 3 I1 1 00 0000FFFe ;1st arg must be even +OR *,*[*] 83 5 I6 1 00 00FeFFFe ;1st,3rd must be even +OR *,#* 81 4 I1 1 00 00FeFFFF ;1st arg must be even +OR *,* 8301 5 I2 1 00 00000000 ;2nd arg may be far + +ORB *,[*]+ 92 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +ORB *,[*] 92 3 I1 1 00 0000FFFe ;1st arg must be even +ORB *,*[*] 93 5 I6 1 00 00FFFFFF ; +ORB *,#* 91 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +ORB *,* 9301 5 I2 1 00 00000000 ;2nd arg may be far + +PUSH #* C9 3 I1 1 00 00000000 ; +PUSH [*]+ CA 2 I1 1 01 000000Fe ;arg must be even +PUSH [*] CA 2 I1 1 00 000000Fe ;arg must be even +PUSH *[*] CB 4 I6 1 00 00FFFFFe ;arg must be even +PUSH * CB01 4 I7 1 00 0000FFFe ;arg must be even + +PUSHF "" F2 1 NOP 1 00 00000000 ; +PUSHA "" F4 1 NOP 1 00 00000000 ; + +POP [*]+ CE 2 I1 1 01 000000Fe ;arg must be even +POP [*] CE 2 I1 1 00 000000Fe ;arg must be even +POP *[*] CF 4 I6 1 00 00FFFFFE ; +POP * CF01 4 I7 1 00 0000FFFe ;arg must be even + +POPF "" F3 1 NOP 1 00 00000000 ; +POPA "" F5 1 NOP 1 00 00000000 ; + +RET "" F0 1 NOP 1 00 00000000 ; +RST "" FF 1 NOP 1 00 00000000 ; + +SJMP * 2000 2 I5 1 00 00000000 +SCALL * 2800 2 I5 1 00 00000000 + +SUB *,*,[*]+ 4A 4 I1 1 01 00000000 ;no validation yet +SUB *,*,[*] 4A 4 I1 1 00 00000000 ;no validation yet +SUB *,*,*[*] 4B 6 I6 1 00 00000000 ;no validation yet +SUB *,*,#* 49 5 I1 1 00 00000000 ;no validation yet +SUB *,[*]+ 6A 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +SUB *,[*] 6A 3 I1 1 00 0000FFFe ;1st arg must be even +SUB *,*[*] 6B 5 I6 1 00 00FeFFFe ;1st,3rd must be even +SUB *,*,* 4B01 6 I3 1 00 00000000 ;3rd arg may be far +SUB *,#* 69 4 I1 1 00 00FeFFFF ;1st arg must be even +SUB *,* 6B01 5 I2 1 00 00000000 ;2nd arg may be far + +SUBB *,*,[*]+ 5A 4 I1 1 01 00000000 ;no validation yet +SUBB *,*,[*] 5A 4 I1 1 00 00000000 ;no validation yet +SUBB *,*,*[*] 5B 6 I6 1 00 00000000 ;no validation yet +SUBB *,*,#* 59 4 I1 1 00 00000000 ;no validation yet +SUBB *,[*]+ 7A 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +SUBB *,[*] 7A 3 I1 1 00 0000FFFe ;1st arg must be even +SUBB *,*[*] 7B 5 I6 1 00 00FeFFFe ;1st,3rd must be even +SUBB *,*,* 5B01 6 I3 1 00 00000000 ;3rd arg may be far +SUBB *,#* 79 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +SUBB *,* 7B01 5 I2 1 00 00000000 ;2nd arg may be far + +SUBC *,[*]+ AA 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +SUBC *,[*] AA 3 I1 1 00 0000FFFe ;1st arg must be even +SUBC *,*[*] AB 5 I6 1 00 00FeFFFe ;1st,3rd must be even +SUBC *,#* A9 4 I1 1 00 00FeFFFF ;1st arg must be even +SUBC *,* AB01 5 I2 1 00 00000000 ;2nd arg may be far + +SUBCB *,[*]+ BA 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +SUBCB *,[*] BA 3 I1 1 00 0000FFFe ;1st arg must be even +SUBCB *,*[*] BB 5 I6 1 00 00FeFFFe ;1st,3rd must be even +SUBCB *,#* B9 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +SUBCB *,* BB01 5 I2 1 00 00000000 ;2nd arg may be far + +SHL *,#* 09 3 I1 1 00 0000FE0F ; F +SHL *,* 09 3 I1 1 00 0000FEFF ; +SHLB *,#* 19 3 I1 1 00 0000FF0F ; +SHLB *,* 19 3 I1 1 00 0000FFFF ; +SHLL *,#* 0D 3 I1 1 00 0000FF0F ; +SHLL *,* 0D 3 I1 1 00 0000FFFF ; + +SHR *,#* 08 3 I1 1 00 0000FF0F ;word align +SHR *,* 08 3 I1 1 00 0000FFFF ;word align +SHRB *,#* 18 3 I1 1 00 0000FF0F ;byte align +SHRB *,* 18 3 I1 1 00 0000FFFF ;byte align +SHRL *,#* 0C 3 I1 1 00 0000FF0F ;long align +SHRL *,* 0C 3 I1 1 00 0000FFFF ;long align + +SHRA *,#* 0A 3 I1 1 00 0000FF0F ;word align +SHRA *,* 0A 3 I1 1 00 0000FFFF ;word align +SHRAB *,#* 1A 3 I1 1 00 0000FF0F ;byte align +SHRAB *,* 1A 3 I1 1 00 0000FFFF ;byte align +SHRAL *,#* 0E 3 I1 1 00 0000FF0F ;long align +SHRAL *,* 0E 3 I1 1 00 0000FFFF ;long align + +SETC "" F9 1 NOP 1 00 00000000 ; + + +SKIP "" 0000 2 NOP 1 00 00000000 ; +SKIP * 00 2 I1 1 00 00000000 ; + +ST *,[*]+ C2 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +ST *,[*] C2 3 I1 1 00 0000FFFe ;1st arg must be even +ST *,*[*] C3 5 I6 1 00 FFFFFFFe ;1st,3rd must be even +ST *,* C301 5 I2 1 00 00000000 ;2nd arg may be far + +STB *,[*]+ C6 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +STB *,[*] C6 3 I1 1 00 0000FFFe ;1st arg must be even +STB *,*[*] C7 5 I6 1 00 FFFFFFFe ;1st,3rd must be even +STB *,* C701 5 I2 1 00 00000000 ;2nd arg may be far + +TRAP "" F7 1 NOP 1 00 00000000 ; + +TIJMP *,[*],#* E2 4 I8 2 00 00FEFEFF ; + +XCH *,*[*] 0B 5 I6 2 00 00FeFFFe ;1st,3rd must be even +XCH *,* 0B01 5 I2 2 0C 00000000 ;2nd arg may be far + +XCHB *,*[*] 1B 5 I6 2 00 00FFFFFF ; +XCHB *,* 1B01 5 I2 2 0C 00000000 ;2nd arg may be far + +XOR *,[*]+ 86 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +XOR *,[*] 86 3 I1 1 00 0000FFFe ;1st arg must be even +XOR *,*[*] 87 5 I6 1 00 00FeFFFe ;1st,3rd must be even +XOR *,#* 85 4 I1 1 00 00FeFFFF ;1st arg must be even +XOR *,* 8701 5 I2 1 00 00000000 ;2nd arg may be far + +XORB *,[*]+ 96 3 I1 1 01 0000FFFe ;1st arg must be even, make odd +XORB *,[*] 96 3 I1 1 00 0000FFFe ;1st arg must be even +XORB *,*[*] 97 5 I6 1 00 00FFFFFF ; +XORB *,#* 95 3 I1 1 00 00FFFFFF ;odd args ok for byte operations +XORB *,* 9701 5 I2 1 00 00000000 ;2nd arg may be far + + diff --git a/trunk/Tools/tasm32/TASMMAN.HTM b/trunk/Tools/tasm32/TASMMAN.HTM new file mode 100644 index 00000000..944ec1eb --- /dev/null +++ b/trunk/Tools/tasm32/TASMMAN.HTM @@ -0,0 +1,2865 @@ + + + + + + + The Telemark Assembler (TASM) User Manual + + + + +
+

+The Telemark Assembler (TASM) User Manual

+ +
Version 3.2
+
+ +
Thomas N. Anderson
+ +
Squak Valley Software
+ +
837 Front Street South
+ +
Issaquah, WA 98027
+ +
email: andersontn@acm.org
+ +
www.halcyon.com/squakvly/
+
+ +
Copyright (C) 1985-2000 by Thomas N. Anderson. All rights reserved.
+ +
+

+TABLE OF CONTENTS

+ + + +
+

+INTRODUCTION

+The Telemark Assembler (TASM) is a table driven cross assembler for the +MS-DOS and LINUX environments. Assembly source code, written in the appropriate +dialect (generally very close to the manufacturers assembly language), +can be assembled with TASM, and the resulting object code transferred to +the target microprocessor system via PROM or other mechanisms. + +

The microprocessor families supported by TASM are: +

    +
  • +6502
  • + +
  • +6800/6801/68HC11
  • + +
  • +6805
  • + +
  • +8048
  • + +
  • +8051
  • + +
  • +8080/8085, Z80
  • + +
  • +TMS32010, TMS320C25
  • + +
  • +TMS7000
  • + +
  • +8096/80196
  • +
+The user so inclined may build tables for other microprocessors. The descriptions +of the various existing tables and instructions on building new tables +are not in this document but can be found in the TASMTABS.HTM file on the +TASM distribution disk. + +

TASM characteristics include: +

    +
  1. +Powerful expression parsing (17 operators).
  2. + +
  3. +Supports a subset of the 'C' preprocessor commands.
  4. + +
  5. +Macro capability (through use of DEFINE directive).
  6. + +
  7. +Multiple statements per line.
  8. + +
  9. +Four object file formats: Intel hex, MOS Technology hex, Motorola hex, +binary.
  10. + +
  11. +Absolute code generation only.
  12. + +
  13. +Source code available (in C).
  14. + +
  15. +Uniform syntax across versions for different target machines.
  16. + +
  17. +Features in support of PROM programming (preset memory, contiguous block).
  18. + +
  19. +Supports extended instructions for many of the supported microprocessor +families.
  20. + +
  21. +Tables read at run time - single TASM executable for all table versions.
  22. + +
  23. +Symbol table export for inclusion in subsequent assemblies.
  24. + +
  25. +Symbol table export file for import with some simulator products.
  26. +
+ +
+

+SHAREWARE

+TASM is distributed as shareware. TASM is not in the public domain. The +TASM distribution files may be freely copied (excluding the source code +files) and freely used for the purpose of evaluating the suitability of +TASM for a given purpose. Use of TASM beyond a reasonable evaluation period +requires registration. Prolonged use without registration is unethical.  +
+

+INVOCATION

+TASM can be invoked as follows (optional fields shown in brackets, symbolic +fields in italics): +
  tasm -pn [-options ...] src_file [obj_file [lst_file [exp_file [sym_file]]]]
+Where options can be one or more of the following: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
-table Specify version (table = table designation) 
-ttable Table (alternate form of above) 
-aamask Assembly control (optional error checking) 
-b Produce object in binary (.COM) format 
-c Object file written as a contiguous block 
-dmacro Define a macro (or just a macro label) 
-e Show source lines after macro expansion 
-ffillbyte Fill entire memory space with fillbyte (hex) 
-gobjtype Object file (0=Intel Hex, 1=MOS Tech, 2=Motorola, +3=binary,4=Intel Hex (Word)) 
-h Produce hex table of the assembled code (in list +file) 
-i Ignore case for labels 
-l[al] Produce a label table in the listing 
-m Produce object in MOS Technology format 
-oobytes Bytes per object record (for hex obj formats) 
-p[linesPage the listing file (lines per page. default=60) 
-q Quiet, disable the listing file 
-s Write a symbol table file 
-x[xmaskEnable extended instruction set (if any) 
-y Time the assembly 
+

The filename parameters are defined as follows: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
src_file Source file name 
obj_file Object code file name 
lst_file Listing file name 
exp_file Symbol export file (only if the EXPORT directive +is used).
sym_file Symbol table file (only if the -s option +or the SYM/AVSYM directives are used). 
+

The source file must be specified. If not, some usage information is displayed. +Default file names for all the other files are generated if they are not +explicitly provided. The filename is formed by taking the source filename +and changing the extension to one of the following: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Extension File type 
.OBJ Object file 
.LST Listing file 
.EXP Symbol export file 
.SYM Symbol table file 
+

TASM has no built-in instruction set tables. Instruction set definition +files are read at run time. TASM determines which table to use based on +the '-table' field shown above. For example, to assemble the code +in a file called source.asm, one would enter +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
tasm -48 source.asm for an 8048 assembly 
tasm -65 source.asm for a 6502 assembly 
tasm -51 source.asm for an 8051 assembly. 
tasm -85 source.asm for an 8085 assembly. 
tasm -80 source.asm for a Z80 assembly. 
tasm -05 source.asm for a 6805 assembly. 
tasm -68 source.asm for a 6800/6801/68HC11 assembly. 
tasm -70 source.asm for a TMS7000 assembly. 
tasm -3210 source.asm for a TMS32010 assembly. 
tasm -3225 source.asm for a TMS320C25 assembly. 
tasm -96 source.asm for a 8096/80196 assembly
+

+Tables are read from a file named by taking the digits specified after +the '-' and appending it to 'TASM' then appending the '.TAB' extension. +Thus, the -48 flag would cause the tables to be read from the file +'TASM48.TAB'. + +

It is possible to designate tables by non numeric part numbers if the +-t flag is used. For example, if a user built a table called TASMF8.TAB +then TASM could be invoked as follows: +

    tasm -tf8 source.asm
+Each option flag must be preceded by a dash. Options need not precede the +file names. The various options are described in the sections that follow. +

+a - Assembly Control

+TASM can provide additional error checking by specifying the -a +option at the time of execution. If the -a is provided without a +digit following, then all the available error checking is done. If a digit +follows, then it is used as a mask to determine the error checks to be +made. The bits of the mask are defined as follows: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Bit Option Default Description 
-a1 OFF Check for apparent illegal use of indirection 
-a2 ON Check for unused data in the arguments 
-a4 ON Check for duplicate labels 
-a8 OFF Check for non-unary operators at start of expression. 
+

Combinations of the above bits can also be used. For example, -a5 +would enable the checking for illegal indirection and duplicate labels. + +

Illegal indirection applies to micros that use parenthesis around an +argument to indicate indirection. Since it is always legal to put an extra +pair of parenthesis around any expression (as far as the expression parser +is concerned), the user may think that he/she is indicating indirection +for an instruction that has no indirection and TASM would not complain. +Enabling this checking will result in an error message (warning) whenever +an outer pair of parenthesis is used and the instruction set definition +table does not explicitly indicate that to be a valid form of addressing. + +

Unused data in arguments applies to cases where a single byte of data +is needed from an argument, but the argument contains more than one byte +of data. If a full sixteen bit address is used in a 'Load Immediate' type +instruction that needs only a single byte, for example, an error message +would be generated. Here is an example (6502 code): +

    0001   1234                    .org $1234
+    test.asm line 0002: Unused data in MS byte of argument.
+    0002   1234 A9 34       start  lda  #start
+To make the above checks occur whenever you do an assembly, add a line +like this to your AUTOEXEC.BAT file: +
    SET TASMOPTS=-a
+ +

+b - Binary Object Format

+This option causes the object file to be written in binary - one byte for +each byte of code/data. Note that no address information is included in +the object file in this format. The contiguous block (-c) output mode is +forced when this option is invoked. This flag is equivalent to -g3. +

+c - Contiguous Block Output

+If this option is specified, then all bytes in the range from the lowest +used byte to the highest will be defined in the object file. Normally, +with the default Intel Hex object format enabled, if the Program Counter +(PC) jumps forward because of an .ORG directive, the +bytes skipped over will not have any value assigned them in the object +file. With this option enabled, no output to the object file occurs until +the end of the assembly at which time the whole block is written. This +is useful when using TASM to generate code that will be put into a PROM +so that all locations will have a known value. This option is often used +in conjunction with the -f option to ensure all unused bytes will have +a known value. +

+d - Define a Macro

+Macros are defined on the command line generally to control the assembly +of various IFDEF's that are in the source file. This is a convenient way +to generate various versions of object code from a single source file. +

+e - Expand Source.

+Normally TASM shows lines in the listing file just as they are in the source +file. If macros are in use (via the DEFINE directive) +it is sometimes desirable to see the source lines after expansion. Use +the '-e' flag to accomplish this. +

+f - Fill Memory.

+This option causes the memory image that TASM maintains to be initialized +to the value specified by the two hex characters immediately following +the 'f'. TASM maintains a memory image that is a full 64K bytes in size +(even if the target processor cannot utilize that memory space). Invocation +of this option introduces a delay at start up time. +

+g - Object File Format.

+TASM can generate object code in the formats indicated below: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Option Description
-g0 Intel hex (default) 
-g1 MOS Technology hex (same as -m
-g2 Motorola hex 
-g3 binary (same as -b
-g4 Intel hex with word addresses
+

The -m and -b flags may also be used, as indicated above. +If both are used the right-most option on the command line will be obeyed. + +

See the section on OBJECT FILE FORMATS for descriptions of each +of the above. +

+h - Hex Object Code Table.

+This option causes a hex table of the produced object code to appear in +the listing file. Each line of the table shows sixteen bytes of code. +

+i - Ignore Case in Labels.

+TASM is normally case sensitive when dealing with labels. For those that +prefer case insensitivity, the '-i' command line option can be employed. +

+l - Label Table.

+This option causes a label table to appear in the listing file. Each label +is shown with its corresponding value. Macro labels (as established via +the DEFINE directives) do not appear. + +

Two optional suffixes may follow the -l option: +
  + + + + + + + + + + + + + + + + + + +
Suffix Description 
Use long form listing 
Show all labels (including local labels) 
+

The suffix should immediately follow the '-l'. Here are some examples: +
  + + + + + + + + + + + + + + + + + + + + + + + + +
-l to show non-local labels in the short form 
-la to show all labels in the short form 
-ll to show non-local labels in the long form 
-lal to show all labels in the long form 
+ +

+m - MOS Technology Object Format.

+This option causes the object file to be written in MOS Technology hex +format rather than the default Intel hex format. See section on OBJECT +FILE FORMATS for a description of the format. +

+o - Set Number of Bytes per Object Record.

+When generating object code in either the MOS Technology format or the +Intel hex format, a default of 24 (decimal) bytes of object are defined +on each record. This can be altered by invoking the '-o' option immediately +followed by two hex digits defining the number of bytes per record desired. +For example, if 32 bytes per record are desired, one might invoke TASM +as: +
    tasm -48 -o20 source.asm
+ +

+p - Page Listing File.

+This option causes the listing file to have top of page headers and form +feeds inserted at appropriate intervals (every sixty lines of output). +To override the default of sixty lines per page, indicate the desired number +of lines per page as a decimal number immediately following the '-p'. Here +is an example: +
    tasm -48 -p56 source.asm
+ +

+q - Disable Listing File.

+This option causes all output to the listing file to be suppressed, unless +a .LIST directive is encountered in the source file (see LIST/NOLIST +directives). +

+s - Enable Symbol File Generation.

+If this flag is set, a symbol file is generated at the end of the assembly. +The format of the file is one line per label, each label starts in the +first column and is followed by white space and then four hexadecimal digits +representing the value of the label. The following illustrates the format: +
    label1         FFFE
+    label2         FFFF
+    label3         1000
+The symbol file name can be provided as the fifth file name on the command +line, or the name will be generated from the source file name with a '.SYM' +extension. The symbol table file can also be generated by invoking the +SYM directive. The AVSYM directive also generates the symbol file but in +a different format (see section on ASSEMBLER +DIRECTIVES). +

+t - Table Name.

+As an alternative to specifying the instruction set table as two decimal +digits, the table indication may be proceeded by the '-t' option. This +is useful if the desired table name starts with a non-numeric. Thus, a +table for an F8 might be selected as: +
    tasm -tf8 source.asm
+TASM would expect to read the instruction set definition tables from a +file named TASMF8.TAB. +

+x - Enable Extended Instruction Set.

+If a processor family has instructions that are valid for only certain +members, this option can be used to enable those beyond the basic standard +instruction set. A hex digit may follow the 'x' to indicate a mask value +used in selecting the appropriate instruction set. Bit 0 of the mask selects +the basic instruction set, thus a '-x1' would have no effect. A '-x3' would +enable the basic set plus whatever instructions have bit 1 set in their +class mask. A '-x' without a digit following is equivalent to a '-xf' which +sets all four of the mask bits. The following table indicates the current +extended instruction sets available in the TASM tables: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Base Table Base Family Ext 1 (-x3) Ext 2 (-x7) Ext 3 (-x5) Ext 4 (-x9) 
48 8048 8041A 8022 8021 
65 6502 R65C02 R65C00/21 
05 6805 M146805 CMOS HC05C4 
80 Z80 HD64180 
68 6800 6801/6803 68HC11 
51 8051 
85 8080 
3210 TMS32010 
3225 TMS320C25 TMS320C26 
70 TMS7000 
+  +
  + +

The above table does not attempt to show the many microprocessor family +members that may apply under a given column. + +

See the TASMTABS.HTM on-line document for details on each specific table. +

+y - Enable Assembly Timing

+If this option is enabled TASM will generate a statement of elapsed time +and assembled lines per second at the end of the assembly. +

+ +
ENVIRONMENT VARIABLES

+The TASM environment can be customized by using the environment variables +listed below: +

+TASMTABS

+The TASMTABS variable specifies the path to be searched for TASM instruction +set definition tables. If it is not defined then the table(s) must exist +in the current working directory. The following examples illustrate possible +usage: +
  + + + + + + + + + + + + +
For MSDOS set TASMTABS=C:\TASM
For LINUX TASMTABS=/tasm
+ +

+TASMOPTS

+This variable specifies TASM command line options that are to be invoked +every time TASM is executed. For example, if TASM is being used for 8048 +assemblies with binary object file output desired, the following statement +would be appropriate in the AUTOEXEC.BAT file: +
    set TASMOPTS=-48 -b
+ +

+TASMERRFORMAT

+The TASMERRFORMAT variable provides user control of the format of error +messages.  The format string must be a valid printf format string +for ANSI C.  The default value is: +
    +
    "%s line %04d: %s %s"
    +
+Which provides error messages like this: +
    +
    Main.asm line 1234: No such label: Start
    +
+The four fields associated with an error message are: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field DescriptionAssociated Data Type (ANSI C)
File namechar *
Line number within fileint
Error descriptionchar *
Error data (optional)char *
+ + +

No user control of the order of the error message fields is provided. +
Here are sample usages: + +

For MSDOS: +

    +
    set TASMERRFORMAT=”%s(%d) %s %s”
    +
+For LINUX: +
    +
    TASMERRFORMAT=”%s(%d) %s %s”
    +
+ +
+

+EXIT CODES

+When TASM terminates, it will return to the OS the following exit codes: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Exit Code Definition
Normal completion, no assembly errors 
Normal completion, with assembly errors 
Abnormal completion, insufficient memory 
Abnormal completion, file access error 
Abnormal completion, general error 
+

Exit codes 2 and above will also be accompanied by messages to the console +concerning the error. +
+


+

+SOURCE FILE FORMAT

+Statements in the source file must conform to a format as follows (except +for assembler directive statements which are described in a subsequent +section): +
  +
    label operation operand comment
+All of the fields are optional, under appropriate circumstances. An arbitrary +amount of white space (space and tabs) can separate each field (as long +as the maximum line length of 255 characters is not exceeded). Each of +the fields are described in the following sections. +

+Label Field.

+If the first character of the line is alphabetic, it is assumed to be the +start of a label. Subsequent characters are accepted as part of that label +until a space, tab, or ':' is encountered. The assembler assigns a value +to the label corresponding to the current location counter. Labels can +be a maximum of 32 characters long. Labels can contain upper and lower +case letters, digits, underscores, and periods (the first character must +be alphabetic). Labels are case sensitive - the label 'START' is a different +label from 'start' - unless the '-i' (ignore case) option is enabled. +

+Operation Field.

+The operation field contains an instruction mnemonic which specifies the +action to be carried out by the target processor when this instruction +is executed. The interpretation of each mnemonic is dependent on the target +microprocessor (as indicated by the selected TASM table). The operation +field may begin in any column except the first. The operation field is +case insensitive. +

+Operand Field.

+The operand field specifies the data to be operated on by the instruction. +It may include expressions and/or special symbols describing the addressing +mode to be used. The actual format and interpretation is dependent on the +target processor. For a description of the format for currently supported +processors, see the TASMTABS.DOC file on the TASM distribution disk. +

+Comment Field.

+The comment field always begins with a semicolon. The rest of the line +from the semicolon to the end of the line is ignored by TASM, but passed +on to the listing file for annotation purposes. The comment field must +be the last field on a line, but it may be the only field, starting in +column one, if desired. +

+Multiple Statement Lines.

+If the backslash character is encountered on a source line, it is treated +as a newline. The remainder of the line following the backslash will be +processed as an independent line of source code. This allows one to put +multiple statements on a line. This facility is not so useful of itself, +but when coupled with the capability of the DEFINE directive, powerful +multiple statement macros can be constructed (see section on ASSEMBLER +DIRECTIVES). Note that when using the statement separator, the +character immediately following it should be considered the first character +of a new line, and thus must either be a start of a label or white space +(not an instruction). As the examples show, a space is put between the +backslash and the start of the next instruction. +

+Sample Source Listing.

+Some examples of valid source statements follow (6502 mnemonics shown): +
  lab1       lda    byte1   ;get the first byte
+             dec    byte1
+             jne    label1
+  ;            
+  lab2       sta    byte2,X
+  ;  a multiple statement line follows
+             lda    byte1\ sta byte1+4\ lda byte2\ sta byte2+4
+ +
+

+EXPRESSIONS

+Expressions are made up of various syntactic elements combined according +to a set of syntactical rules. Expressions can be comprised of the following +elements: +
    +
  • +Labels
  • + +
  • +Constants
  • + +
  • +Location Counter Symbol
  • + +
  • +Operators
  • + +
  • +Parenthesis
  • +
+ +

+Labels

+Labels are strings of characters that have a numeric value associated with +them, generally representing an address. Labels can contain upper and lower +case letters, digits, underscores, and periods. The first character must +be a letter or the local label prefix (default '_'). The value of a label +is limited to 32 bit precision. Labels can contain up to 32 characters, +all of which are significant (none are ignored when looking at a label's +value, as in some assemblers). Case is significant unless the '-i' command +line option is invoked. + +

Local labels must only be unique within the scope of the current module. +Modules are defined with the MODULE directive. Here +is an example: +

          .MODULE xxx
+          lda regx
+          jne _skip
+          dec
+   _skip  rts
+          .MODULE yyy
+          lda regy
+          jne _skip
+          dec
+   _skip  rts
+In the above example, the _skip label is reused without harm. As +a default, local labels are not shown in the label table listing (resulting +from the '-l' command line option). See also sections on MODULE +and LOCALLABELCHAR directives. +

+Numeric Constants

+Numeric constants must always begin with a decimal digit (thus hexadecimal +constants that start with a letter must be prefixed by a '0' unless the +'$' prefix is used). The radix is determined by a letter immediately following +the digit string according to the following table: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Radix Suffix Prefix 
B or b 
O or o 
10 D or d (or nothing) 
16 H or h 
+ +

Decimal is the default radix, so decimal constants need no suffix or prefix. + +

The following representations are equivalent: +

    1234H          or     $1234
+    100d           or     100
+    177400o        or     @177400
+    01011000b      or     %01011000
+The prefixes are provided for compatibility with some other source code +formats but introduce a problem of ambiguity. Both '%' and '$' have alternate +uses ('%' for modulo, '$' for location counter symbol). The ambiguity is +resolved by examining the context. The '%' character is interpreted as +the modulo operator only if it is in a position suitable for a binary operator. +Similarly, if the first character following a '$' is a valid hexadecimal +digit, it is assumed to be a radix specifier and not the location counter. +

+Character Constants

+Character constants are single characters surrounded by single quotes. +The ASCII value of the character in the quotes is returned. No escape provision +exists to represent non-printable characters within the quotes, but this +is not necessary since these can be just as easily represented as numeric +constants (or using the TEXT directive which does allow +escapes). +

+String Constants.

+String constants are one or more characters surrounded by double quotes. +Note that string constants are not allowed in expressions. They are only +allowable following the TITLE, BYTE, +DB, and TEXT assembler directives. +The quoted strings may also contain escape sequences to put in unprintable +values. The following escape sequences are supported: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Escape Sequence Description 
\n Line Feed 
\r Carriage return 
\b Backspace 
\t Tab 
\f Formfeed 
\\ Backslash 
\" Quote 
\000 Octal value of character 
+ +

+Location Counter Symbol

+The current value of the location counter (PC) can be used in expressions +by placing a '$' in the desired place. The Location Counter Symbol is allowable +anywhere a numeric constant is. (Note that if the '$' is followed by a +decimal digit then it is taken to be the hexadecimal radix indicator instead +of the Location Counter symbol, as mentioned above). The '*' may also be +used to represent the location counter, but is less preferred because of +its ambiguity with the multiplicative operator. +

+Operators

+Expressions can optionally contain operators to perform some alterations +or calculations on particular values. The operators are summarized as follows: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Operator Type Description 
Additive addition 
subtraction 
Multiplicative multiplication 
division 
modulo 
<<logical shift left 
>> logical shift right 
Unary bit inversion (one's complement) 
unary negation 
Relational equal 
== equal 
!= not equal 
<less than 
>greater than 
<= less than or equal 
>= greater than or equal 
&Binary binary 'and' 
binary 'or' 
binary 'exclusive or' 
+ +

The syntax is much the same as in ANSI C with the following notes: + +

    +
  1. +No operator precedence is in effect. Evaluation is from left to right unless +grouped by parenthesis (see example below).
  2. + +
  3. +All evaluations are done with 32 bit signed precision.
  4. + +
  5. +Both '=' and '==' are allowable equality checkers. This is allowed since +the syntax does not provide assignment capability (as '=' would normally +imply).
  6. +
+The relational operators return a value of 1 if the relation is true and +0 if it is false. Thirty-two bit signed arithmetic is used. + +

It is always a good idea to explicitly indicate the desired order of +evaluation with parenthesis, especially to maintain portability since TASM +does not evaluate expressions in the same manner as many other assemblers. +To understand how it does arrive at the values for expressions, consider +the following example: +

    1 + 2*3 + 4
+TASM would evaluate this as: +
    (((1 + 2) * 3) + 4) = 13
+Typical rules of precedence would cause the (2*3) to be evaluated first, +such as: +
    1 + (2*3) + 4      = 11
+To make sure you get the desired order of evaluation, use parenthesis liberally. +Here are some examples of valid expressions: +
    (0f800H + tab)
+    (label_2 >> 8)
+    (label_3 << 8) & $f000
+    $ + 4
+    010010000100100b + 'a'
+    (base + ((label_4 >> 5) & (mask << 2))
+ +
+

+ASSEMBLER DIRECTIVES

+Most of the assembler directives have a format similar to the machine instruction +format. However, instead of specifying operations for the processor to +carry out, the directives cause the assembler to perform some function +related to the assembly process. TASM has two types of assembler directives +- those that mimic the 'C' preprocessor functions, and those that resemble +the more traditional assembler directive functions. Each of these will +be discussed. + +

The ANSI C preprocessor style directives are invoked with a '#' as the +first character of the line followed by the appropriate directive (just +as in 'C'). Thus, these directives cannot have a label preceding them (on +the same line). Note that in the examples directives are shown in upper +case, however, either upper or lower case is acceptable. +

+ADDINSTR

+The ADDINSTR directive can be used to define additional instructions for +TASM to use in this assembly. The format is: +
    [label] .ADDINSTR inst args opcode nbytes rule class shift binor
+The fields are separated by white space just as they would appear in an +instruction definition file. See the TASMTABS.HTM file on the TASM distribution +disk for more detail. +

+AVSYM

+See SYM/AVSYM. +

+BLOCK

+The BLOCK directive causes the Instruction Pointer to advance the specified +number of bytes without assigning values to the skipped over locations. +The format is: +
    [label] .BLOCK        expr
+Some valid examples are: +
    word1   .BLOCK     2
+    byte1   .block     1
+    buffer  .block     80
+ +

+BSEG/CSEG/DSEG/NSEG/XSEG

+These directives can be invoked to indicate the appropriate address space +for symbols and labels defined in the subsequent code. The invocation of +these directives in no way affects the code generated, only provides more +information in the symbol table file if the AVSYM directive is employed. +Segment control directives such as these are generally supported by assemblers +that generate relocatable object code. TASM does not generate relocatable +object code and does not support a link phase, so these directives have +no direct effect on the resulting object code. The segments are defined +as follows: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Directive Segment Description 
BSEG Bit address 
CSEG Code address 
DSEG Data address (internal RAM) 
NSEG Number or constant (EQU) 
XSEG External data address (external RAM) 
+ +

+BYTE

+The BYTE directive allows a value assignment to the byte pointed to by +the current Instruction Pointer. The format is: +
    [label] .BYTE   expr [, expr ...]
+Only the lower eight bits of expr are used. Multiple bytes may be +assigned by separating them with commas or (for printable strings) enclosed +in double quotes. Here are some examples: +
    label1   .BYTE     10010110B
+             .byte     'a'
+             .byte     0
+             .byte     100010110b,'a',0
+             .byte     "Hello", 10, 13, "World"
+ +

+CHK

+The CHK directive causes a checksum to be computed and deposited at the +current location. The starting point of the checksum calculation is indicated +as an argument. Here is the format: +
    [label]    .CHK    starting_addr
+Here is an example: +
    start: NOP
+           LDA #1
+           .CHK start
+The checksum is calculated as the simple arithmetic sum of all bytes starting +at the starting_addr up to but not including the address of the +CHK directive. The least significant byte is all that +is used. +

+CODES/NOCODES

+The CODES/NOCODES directives can be used to alternately turn on or off +the generation of formatted listing output with line numbers, opcodes, +data, etc. With NOCODES in effect, the source lines are sent to the listing +file untouched. This is useful around blocks of comments that need a full +80 columns of width for clarity. +

+DB

+This is alternate form of the BYTE directive. +

+DW

+This is alternate form of the WORD directive. +

+DEFINE

+The DEFINE directive is one of the most powerful of the directives and +allows string substitution with optional arguments (macros). The format +is as follows: +
    #DEFINE  macro_label[(arg_list)]  [macro_definition]
+Where: +
+
+macro_label
+ +
+character string to be expanded when found in the source file
+ +
+arg_list
+ +
+optional argument list for variable substitution in macro expansion
+ +
+macro_def
+ +
+string to replace the occurrences of macro_label in the source file.
+
+The simplest form of the DEFINE directive might look like this: +
    #DEFINE         MLABEL
+Notice that no substitutionary string is specified. The purpose of a statement +like this would typically be to define a label for the purpose of controlling +some subsequent conditional assembly (IFDEF or IFNDEF). + +

A more complicated example, performing simple substitution, might look +like this: +

    #DEFINE         VAR1_LO         (VAR1 & 255)
+This statement would cause all occurrences of the string 'VAR1_LO' in the +source to be substituted with '(VAR1 & 255)'. + +

As a more complicated example, using the argument expansion capability, +consider this: +

    #DEFINE  ADD(xx,yy)    clc\ lda xx\ adc yy\ sta xx
+If the source file then contained a line like this: +
    ADD(VARX,VARY)
+It would be expanded to: +
    clc\ lda VARX\ adc VARY\ sta VARX
+The above example shows the use of the backslash ('\') character as a multiple +instruction statement delimiter. This approach allows the definition of +fairly powerful, multiple statement macros. The example shown generates +6502 instructions to add one memory location to another. + +

Some rules associated with the argument list: +

    +
  1. +Use a maximum of 10 arguments.
  2. + +
  3. +Each argument should be a maximum of 15 characters.
  4. +
+Note that macros can be defined on the TASM command line, also, with the +-d option flag. +

+DEFCONT

+The DEFCONT directive can be used to add to the last macro started with +a DEFINE directive. This provides a convenient way +to define long macros without running off the edge of the page. The ADD +macro shown above could be defined as follows: +
    #DEFINE         ADD(xx,yy)     clc
+    #DEFCONT                     \ lda xx
+    #DEFCONT                     \ adc yy
+    #DEFCONT                     \ sta xx
+ +

+ECHO

+The ECHO directive can be used to send output to the console (stderr). +It can accept either a quoted text string (with the standard escape sequences +allowed) or a valid expression. It can accept only one or the other, however. +Multiple instances of the directive may be used to create output that contains +both. Consider the following example: +
    .ECHO "The size of the table is "
+    .ECHO (table_end - table_start)
+    .ECHO " bytes long.\n"
+This would result in a single line of output something like this: +
    The size of the table is 196 bytes long.
+ +

+EJECT

+The EJECT directive can be used to force a top-of-form and the generation +of a page header on the list file. It has no effect if the paging mode +is off (see PAGE/NOPAGE). The format is: +
    [label]    .EJECT
+ +

+ELSE

+The ELSE directive can optionally be used with IFDEF, IFNDEF and IF to +delineate an alternate block of code to be assembled if the block immediately +following the IFDEF, IFNDEF or IF is not assembled. + +

Here are some examples of the use of IFDEF, IFNDEF, IF, ELSE, and ENDIF: +

    #IFDEF   label1
+        lda      byte1
+        sta      byte2
+    #ENDIF   
+
+    #ifdef   label1
+        lda      byte1
+    #else    
+        lda      byte2
+    #endif   
+
+    #ifndef  label1
+        lda      byte2
+    #else    
+        lda      byte1
+    #endif   
+
+    #if ($ >= 1000h)
+    ; generate an invalid statement to cause an error
+    ;  when we go over the 4K boundary.
+    !!! PROM bounds exceeded.
+    #endif
+ +

+END

+The END directive should follow all code/data generating statements in +the source file. It forces the last record to be written to the object +file. The format is: +
    [label]       .END [addr]
+The optional addr will appear in the last object record (Motorola +S9 record type) if the object format is Motorola hex. The addr field +is ignored for all other object formats. +

+ENDIF

+The ENDIF directive must always follow an IFDEF, IFNDEF, or IF directive +and signifies the end of the conditional block. +

+EQU

+The EQU directive can be used to assign values to labels. The labels can +then be used in expressions in place of the literal constant. The format +is: +
    label   .EQU   expr
+Here is an example: +
    MASK   .EQU  0F0H
+    ;
+           lda   IN_BYTE
+           and   MASK
+           sta   OUT_BYTE
+An alternate form of the EQU directive is '='. The previous example is +equivalent to any of the following: +
    MASK    =   0F0H
+    MASK    =0F0H
+    MASK    =$F0
+White space must exist after the label, but none is required after +the '='. +

+EXPORT

+The EXPORT directive can be used to define labels (symbols) that are to +be written to the export symbol file. The symbols are written as equates +(using the .EQU directive) so that the resulting file can be included in +a subsequent assembly. This feature can help overcome some of the deficiencies +of TASM due to its lack of a relocating linker. The format is: +
    [label]  .EXPORT      label [,label...]
+The following example illustrates the use of the EXPORT directive and the +format of the resulting export file: + +

Source file: +

    EXPORT        read_byte
+    EXPORT        write_byte, open_file
+Resulting export file: +
    read_byte      .EQU   $1243
+    write_byte     .EQU   $12AF
+    open_file      .EQU   $1301
+ +

+FILL

+The FILL directive can be used to fill a selected number of object bytes +with a fixed value. Object memory is filled from the current program counter +forward. The format is as follows: +
    [label]  .FILL      number_of_bytes [,fill_value]
+The number_of_bytes value can be provided as any valid expression. +The optional fill_value can also be any valid expression. If fill_value +is not provided, a default value of 255 ($FF) is used. +

+IFDEF

+The IFDEF directive can be used to optionally assemble a block of code. +It has the following form: +
    #IFDEF  macro_label
+When invoked, the list of macro labels (established via DEFINE +directives) is searched. If the label is found, the following lines of +code are assembled. If not found, the input file is skipped until an ENDIF +or ELSE directive is found. + +

Lines that are skipped over still appear in the listing file, but a +'~' will appear immediately after the current PC and no object code will +be generated (this is applicable to IFDEF, IFNDEF, and IF). +

+IFNDEF

+The IFNDEF directive is the opposite of the IFDEF directive. The block +of code following is assembled only if the specified macro_label +is undefined. It has the following form: +
    #IFNDEF  macro_label
+When invoked, the list of macro labels (established via DEFINE directives) +is searched. If the label is not found, the following lines of code are +assembled. If it is found, the input file is skipped until an ENDIF or +ELSE directive is found. +

+IF

+The IF directive can be used to optionally assemble a block of code dependent +on the value of a given expression. The format is as follows: +
    #IF     expr
+If the expression expr evaluates to non-zero, the following block +of code is assembled (until an ENDIF or ELSE is encountered). +

+INCLUDE

+The INCLUDE directive reads in and assembles the indicated source file. +INCLUDEs can be nested up to four levels. This allows a convenient means +to keep common definitions, declarations, or subroutines in files to be +included as needed. The format is as follows: +
#INCLUDE        filename
+The filename must be enclosed in double quotes. Here are some examples: +
    #INCLUDE       "macros.h"
+    #include       "equates"
+    #include       "subs.asm"
+ +

+LIST/NOLIST

+The LIST and NOLIST directives can be used to alternately turn the output +to the list file on (LIST) or off (NOLIST). The formats are: +
    .LIST
+    .NOLIST
+ +

+LOCALLABELCHAR

+The LOCALLABELCHAR directive can be used to override the default "_" as +the label prefix indicating a local label. For example, to change the prefix +to "?" do this: +
    [label]   .LOCALLABELCHAR "?"
+Be careful to use only characters that are not operators for expression +evaluation. To do so causes ambiguity for the expression evaluator. Some +safe characters are "?", "{", and "}".  See Labels +for an example of local label usage. +

+LSFIRST/MSFIRST

+The LSFIRST and MSFIRST directives determine the byte order rule to be +employed for the WORD directive. The default (whether +correct or not) for all TASM versions is the least significant byte first +(LSFIRST). The following illustrates its effect: +
    0000  34 12    .word $1234
+    0002           .msfirst
+    0002  12 34    .word $1234
+    0004           .lsfirst
+    0004  34 12    .word $1234
+ +

+MODULE

+The MODULE directive defines the scope of local labels. The format is: +
    [label]   .MODULE label
+Here is an example: +
          .MODULE module_x
+          lda regx
+          jne _skip
+          dec
+   _skip  rts
+          .MODULE module_y
+          lda regy
+          jne _skip
+          dec
+   _skip  rts
+In the above example, the local label _skip is reused without harm +since the two usages are in separate modules. See also section LOCALLABELCHAR +directive. +

+ORG

+The ORG directive provides the means to set the Instruction Pointer (a.k.a. +Program Counter) to the desired value. The format is: +
    [label] .ORG    expr
+The label is optional. The Instruction pointer is assigned the value +of the expr. For example, to generate code starting at address 1000H, +the following could be done: +
    start   .ORG    1000H
+The expression (expr) may contain references to the current Instruction +Pointer, thus allowing various manipulations to be done. For example, to +align the Instruction Pointer on the next 256 byte boundary, the following +could be done: +
    .ORG  (($ + 0FFH) & 0FF00H)
+ORG can also be used to reserve space without assigning values: +
    .ORG    $+8
+An alternate form of ORG is '*=' or '$='. Thus the following two examples +are exactly equivalent to the previous example: +
    *=*+8
+    $=$+8
+ +

+PAGE/NOPAGE

+The PAGE/NOPAGE directives can be used to alternately turn the paging mode +on (PAGE) or off (NOPAGE). If paging is in effect, then every sixty lines +of output will be followed by a Top of Form character and a two line header +containing page number, filename, and the title. The format is: +
    
+    .PAGE
+    .NOPAGE
+The number of lines per page can be set with the '-p' command line option. +

+SET

+The SET directive allows the value of an existing label to be changed. +The format is: +
    label   .SET    expr
+The use of the SET directive should be avoided since changing the value +of a label can sometimes cause phase errors between pass 1 and pass 2 of +the assembly. +

+SYM/AVSYM

+These directives can be used to cause a symbol table file to be generated. +The format is: +
    .SYM    ["symbol_filename"]
+    .AVSYM  ["symbol_filename"]
+For example: +
    .SYM       "symbol.map"
+    .SYM       
+    .AVSYM     "prog.sym"
+    .AVSYM
+The two directives are similar, but result in a different format of the +symbol table file. The format of the SYM file is one line per symbol, each +symbol starts in the first column and is followed by white space and then +four hexadecimal digits representing the value of the symbol. The following +illustrates the format: +
    label1         FFFE
+    label2         FFFF
+    label3         1000
+The AVSYM directive is provided to generate symbol tables compatible with +the Avocet 8051 simulator. The format is similar, but each line is prefixed +by an 'AS' and each symbol value is prefixed by a segment indicator: +
    AS     start          C:1000
+    AS     read_byte      C:1245
+    AS     write_byte     C:1280
+    AS     low_nib_mask   N:000F
+    AS     buffer         X:0080
+The segment prefixes are determined by the most recent segment directive +invoked (see BSEG/CSEG/DSEG/NSEG/XSEG directives). +

+TEXT

+This directive allows an ASCII string to be used to assign values to a +sequence of locations starting at the current Instruction Pointer. The +format is: +
    [label] .TEXT   "string"
+The ASCII value of each character in string is taken and assigned to the +next sequential location. Some escape sequences are supported as follows: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Escape Sequence Description 
\n Line Feed 
\r Carriage return 
\b Backspace 
\t Tab 
\f Formfeed 
\\ Backslash 
\" Quote 
\000 Octal value of character 
+ +

Here are some examples: + +

    message1   .TEXT   "Disk I/O error"
+    message2   .text   "Enter file name "
+               .text   "abcdefg\n\r"
+               .text   "I said \"NO\""
+ +

+TITLE

+The TITLE directive allows the user to define a title string that appears +at the top of each page of the list file (assuming the PAGE mode is on). +The format is: +
    [label]    .TITLE  "string"
+The string should not exceed 80 characters. Here are some examples: +
    .TITLE  "Controller version 1.1"
+    .title  "This is the title of the assembly"
+    .title  ""
+ +

+WORD

+The WORD directive allows a value assignment to the next two bytes pointed +to by the current Instruction Pointer. The format is: +
    [label] .WORD expr [,expr...]
+The least significant byte of expr is put at the current Instruction Pointer +with the most significant byte at the next sequential location (unless +the MSFIRST directive has been invoked). Here are some examples: +
    data_table     .WORD   (data_table + 1)
+                   .word   $1234
+                   .Word   (('x' - 'a')  << 2)
+                   .Word  12, 55, 32
+ +
+

+OBJECT FILE FORMATS

+TASM can generate object code in the formats indicated below: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Option Description
-g0 Intel hex (default) 
-g1 MOS Technology hex (same as -m
-g2 Motorola hex 
-g3 binary (same as -b
-g4 Intel hex with word addresses
+

The -m and -b flags may also be used, as indicated above. +If both are used the right-most option on the command line will be obeyed. +

+Intel Hex Object Format

+This is the default object file format. This format is line oriented and +uses only printable ASCII characters except for the carriage return/line +feed at the end of each line. The format is symbolically represented as: + +

:NN AAAA RR HH CC CRLF + +

Where: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
:Record Start Character (colon)
NNByte Count (2 hex digits)
AAAAAddress of first byte (4 hex digits)
RRRecord Type (00 except for last record +which is 01)
HHData Bytes (a pair of hex digits for each byte +of data in the record)
CCCheck Sum (2 hex digits)
CRLFLine Terminator (CR/LF for DOS, LF for LINUX)
+

The last line of the file will be a record conforming to the above format +with a byte count of zero. + +

The checksum is defined as: + +

sum = byte_count+address_hi+address_lo+record_type+(sum of all data +bytes) +
checksum = ((-sum) & ffh) + +

Here is a sample listing file followed by the resulting object file: +

0001   0000             
+0002   1000                     .org   $1000
+0003   1000 010203040506        .byte  1, 2, 3, 4, 5, 6, 7, 8
+0003   1006 0708
+0004   1008 090A0B0C0D0E        .byte  9,10,11,12,13,14,15,16
+0004   100E 0F10
+0005   1010 111213141516        .byte 17,18,19,20,21,22,23,24,25,26
+0005   1016 1718191A
+0006   101A                     .end
+ +
    :181000000102030405060708090A0B0C0D0E0F101112131415161718AC
+    :02101800191AA3
+    :00000001FF
+ +

+Intel Hex Word Address Object Format

+This format is identical to the Intel Hex Object Format except that +the address for each line of object code is divided by two thus converting +it to a word address (16 bit word). All other fields are identical. + +

Here is an example: +

:180800000102030405060708090A0B0C0D0E0F101112131415161718AC
+:02080C00191AA3
+:00000001FF
+ +

+MOS Technology Hex Object Format

+This format is line oriented and uses only printable ASCII characters except +for the carriage return/line feed at the end of each line. Each line in +the file is of the following format: + +

:NN AAAA HH CC CRLF + +

Where: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
;Record Start Character (semicolon)
NNByte Count (2 hex digits)
AAAAAddress of first byte (4 hex digits)
HHData Bytes (a pair of hex digits for each byte +of data in the record)
CCCCCheck Sum (4 hex digits)
CRLFLine Terminator (CR/LF for DOS, LF for LINUX)
+

The last line of the file will be a record conforming to the above format +with a byte count of zero. + +

The checksum is defined as: + +

sum =byte_count+address_hi+address_lo+record_type+(sum of all data +bytes) +
checksum = (sum & ffffh) + +

Here is a sample object file: +

;1810000102030405060708090A0B0C0D0E0F1011121314151617180154
+;021018191A005D
+;00
+ +

+Motorola Hex Object Format

+This format is line oriented and uses only printable ASCII characters except +for the carriage return/line feed at the end of each line. The format is +symbolically represented as: + +

S1 NN AAAA HH CCCC CRLF + +

Where: +
  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
S1Record Start tag 
NNByte Count (2 hex digits) (data byte count + +3)
AAAAAddress of first byte (4 hex digits)
HHData Bytes (a pair of hex digits for each byte +of data in the record)
CCCheck Sum (2 hex digits)
CRLFLine Terminator (CR/LF for DOS, LF for LINUX)
+ +

The checksum is defined as: + +

sum = byte_count+address_hi+address_lo+(sum of all data bytes) +
checksum = ((~sum) & ffh) + +

Here is a sample file: +

S11B10000102030405060708090A0B0C0D0E0F101112131415161718A8
+S1051018191A9F
+S9030000FC
+

The last line of the file will be a record with a byte count of zero and +a tag of S9. The address field will be 0000 unless and address was provided +with the END directive in which case it will appear in the address field. +

+Binary Object Format.

+This file format is essentially a memory image of the object code without +address, checksum or format description information. + +

Note that when this object format is selected (-b option), the -c option +is forced. This is done so that no ambiguity results from the lack of address +information in the file. Without the -c option, discontinuous blocks of +object code would appear contiguous. +
  + +

+


+

+LISTING FILE FORMAT

+Each line of source code generates one (or more) lines of output in the +listing file. The fields of the output line are as follows: +
    +
  1. +Current source file line number (4 decimal digits).
  2. + +
  3. +An optional '+' appears if this is an 'INCLUDE' file. (One '+' for each +level of INCLUDE invoked).
  4. + +
  5. +Current Instruction Pointer (4 hex digits). An optional '~' follows the +Instruction Pointer if the line of source code is not being assembled because +of an IFDEF, IFNDEF, or IF directive.
  6. + +
  7. +Resulting code/data generated from this source line (two hex digits per +byte, each byte separated by a space, up to six bytes per line).
  8. + +
  9. +The source line exactly as it appears in the source file.
  10. +
+If paging is enabled (by either the '-p' option flag or the .PAGE directive) +some additional fields will be inserted into the listing file every 60 +lines. These fields are: +
    +
  1. +Top of Form (form feed).
  2. + +
  3. +Assembler identifier (e.g. "TASM 6502 Assembler").
  4. + +
  5. +Initial source file name.
  6. + +
  7. +Page number.
  8. + +
  9. +Title.
  10. +
+If errors are encountered, then error messages will be interspersed in +the listing. TASM outputs error messages proceeding the offending line. +The following example illustrates the format: +
    0001   0000             label1  .equ  40h
+    0002   0000             label2  .equ  44h
+    0003   0000 
+    0004   1000             start:  .org  1000h
+    0005   1000 E6 40               inc   label1
+    0006   1002 E6 44               inc   label2
+    tt.asm line 0007: Label not found: (label3)
+    0007   1004 EE 00 00            inc   label3
+    0008   1007 4C 00 10            jmp   start
+    0009   100A                     .end  
+    0010   100A                            
+    tasm: Number of errors = 1
+ +
+

+PROM PROGRAMMING

+A wide variety of PROM programming equipment is available that can use +object code in one or more of the formats supported by TASM. Here are some +notes concerning the generation of code to be programmed into PROMs: +

+PRESET MEMORY

+It is often desirable to have all bytes in the PROM programmed even if +not explicitly assigned a value in the source code (e.g. the bytes are +skipped over with a .ORG statement). This can be accomplished by using +the -c (contiguous block) and the -f (fill) command line +option flags. The -c will ensure that every byte from the lowest +byte assigned a value to the highest byte assigned a value will be in the +object file with no gaps. The -f flag will assign the specified +value to all bytes before the assembly begins so that when the object file +is written, all bytes not assigned a value in the source code will have +a known value. As an example, the following command line will generate +object code in the default Intel Hex format with all bytes not assigned +a value in the source set to EA (hex, 6502 NOP instruction): +
    tasm -65 -c -fEA test.asm
+ +

+CONTIGUOUS BLOCKS

+To ensure that TASM generates object code to cover the full address range +of the target PROM, put a .ORG statement at the end of the source file +set to the last address desired. For example, to generate code to be put +in a 2716 EPROM (2 Kbytes) from hex address $1000 to $17ff, do something +like this in the source file: +
    ;start of the file
+        .ORG    $1000
+    ;rest of the source code follows
+    source code
+    ;end of the source code
+        .ORG    $17ff
+        .BYTE   0
+        .END
+Now, to invoke TASM to generate the code in the binary format with all +unassigned bytes set to 00 (6502 BRK instruction), do the following: +
tasm -65 -b -f00 test.asm
+Note: -b forces the -c option. +
+
+

+ERROR MESSAGES

+ +

+Error Message Format

+TASM error messages take the following general form: +
    filename line line_number: error_message
+For example: +
    main.asm line 0032: Duplicate label (start)
+Many editors and IDE’s can run assemblies from within and parse the error +messages to make it convenient to jump to each error and correct.  +If the above format is not satisfactory for your editor or IDE, use the +TASMERRFORMAT environment variable to alter +the error message format. + +

When using automatic invocation of TASM from within an editor or IDE, +it may be useful to use the TASMOPTS environment +variable to set other command line options.  For example, to cause +TASM to perform 6502 assemblies, set TASMOPTS like this: +

    +
    SET TASMOPTS=-65
    +
+ +

+ERROR MESSAGE DESCRIPTIONS

+ +
+
+Binary operator where value expected
+ +
+Two binary operators in a row indicate a missing value.
+ +
+Branch off of current 2K page
+ +
+An instruction is attempting to branch to a location not within the current +2K byte page.
+ +
+Branch off of current page
+ +
+An instruction is attempting to branch to a location not within the current +256 byte page.
+ +
+Cannot malloc for label storage
+ +
+Insufficient memory to store more labels. See LIMITATIONS.
+ +
+Duplicate label
+ +
+The label for the current line has already been assigned a value. Duplicate +label checks are optionally enabled by the -a option.
+ +
+File name too short
+ +
+A file name on the command line is fewer than 3 characters. A two character +file name may be valid, of course, but it is detected as an error to prevent +a garbled option flag from being taken as a source file, which in turn +can result in the true source file being taken as the object file. Since +the object file is truncated at startup time, the source file could be +clobbered.
+ +
+Forward reference in equate
+ +
+An EQU directive is using a label on the right hand side that has not yet +been defined.
+ +
+Heap overflow on label definition
+ +
+TASM was unable to allocate memory to store the label.
+ +
+Imbalanced conditional.
+ +
+An end-of-file was encountered at which time the level of descent in conditional +directives was different from when the file was entered. Conditional directives +include IF, IFDEF, and IFNDEF.
+ +
+Invalid Object file type.
+ +
+An object file type was requested by the -g command line option that is +not valid. See section on Option g - Object File Format.
+ +
+Invalid operand.
+ +
+No indirection for this instruction. The first character of an operand +was a left parenthesis for an instruction that does not explicitly specify +that as the format. Some micros use the parenthesis as an indicator of +indirection, but putting a layer of parenthesis around an expression is +always a valid thing to do (as far as the expression evaluator is concerned). +The test for this case is only done if the -a4 option is selected. +See section on ASSEMBLY CONTROL.
+ +
+Invalid token where value expected.
+ +
+Two binary operators in a row are not allowed.
+ +
+Label too long.
+ +
+Labels are limited to 31 characters.
+ +
+Label value misaligned
+ +
+The value of a label appears to have a different value on the second pass +then it was computed to have on the first pass. This is generally due to +Zero Page Addressing mode problems with the 6502 version of TASM. Labels +that are used in operands for statements that could utilize Zero Page addressing +mode should always be defined before used as an operand.
+ +
+Label not found
+ +
+A label used in an expression was not found in the current label table.
+ +
+Label must pre-exist for SET.
+ +
+The SET directive can only be applied to an existing label.
+ +
+Label table overflow
+ +
+To many labels have been encountered.
+ +
+List file open error
+ +
+TASM was not able to open the specified list file.
+ +
+Macro expansion too long.
+ +
+The expansion of a macro resulted in a line that exceeded the maximum length.
+ +
+Max number of nested conditionals exceeded
+ +
+Too many levels of IF, IFDEF, or IFNDEF.
+ +
+Maximum number of args exceeded
+ +
+Too many macro arguments.
+ +
+Maximum number of macros exceeded
+ +
+Too many macros (DEFINEs) have been encountered.
+ +
+No END directive before EOF
+ +
+The source file did not have an END directive in it. This is not fatal, +but may cause the last object file record to be lost.
+ +
+No files specified
+ +
+TASM was invoked with no source file specified.
+ +
+No such label
+ +
+A SET directive was encountered for a label not yet defined. The value +of labels that are modified by the SET directive must already exist.
+ +
+No terminating quote
+ +
+A double quote was used at the start of a a text string but was not used +at the end of the string.
+ +
+No indirection for this instruction.
+ +
+A parenthesis was found around the operand expression. This may indicate +an attempt to use indirection where it is inappropriate.
+ +
+Non-unary operator at start of expression
+ +
+A binary operator (such as '*') was found at the beginning of an expression. +Some micros use '*' as an indirection operator. Since it is also a legitimate +operator in an expression, some ambiguity can arise. If a particular instruction/addressing +mode does not allow indirection, and a '*' is placed in front of the associated +expression, the assembler will assume this error. See the -a8 option +of ASSEMBLY CONTROL.
+ +
+Object file open error
+ +
+TASM was not able to open the specified object file.
+ +
+Range of argument exceeded
+ +
+The value of an argument exceeds the valid range for the current instruction +and addressing mode.
+ +
+Range of relative branch exceeded
+ +
+A branch instruction exceeds the maximum range.
+ +
+Source file open error
+ +
+TASM was not able to open the specified source file.
+ +
+Unrecognized directive
+ +
+A statement starting with a '.' or '#' has a mnemonic that is not defined +as a directive.
+ +
+Unrecognized instruction
+ +
+A statement has an opcode mnemonic that is not defined.
+ +
+Unrecognized argument
+ +
+A statement has an operand format that is not defined.
+ +
+Unknown token
+ +
+Unexpected characters were encountered while parsing an expression.
+ +
+Unused data in MS byte of argument
+ +
+An instruction or directive used the least significant byte of an argument +and left the most significant byte unused, but it was non-zero.
+ +
+Unknown option Flag.
+ +
+Invalid option flag has been specified on the command line. invoke TASM +with nothing on the command line to see a list of valid options.
+
+ +
+

+LIMITATIONS

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Maximum number of labels 15000 
Maximum length of labels 32 characters 
Maximum address space 64 Kbytes (65536 bytes) 
Maximum number of nested INCLUDES
Maximum length of TITLE string 79 characters 
Maximum source line length 511 characters 
Maximum length after macro expansion 511 characters 
Maximum length of expressions 511 characters 
Maximum length of pathnames 79 characters 
Maximum length of command line 127 characters 
Maximum number of instructions (per table) 1200 
Maximum number of macros 1000 
Maximum number of macro arguments 10 
Maximum length of macro argument 16 characters 
Memory requirements 512K 
+ +

+Other Limitations

+ +
    +
  1. +The 8048 version of TASM does not check for use of memory beyond any reasonable +bounds (e.g. an 8048 has a maximum address space of 4 Kbytes but TASM will +let you pretend that you have 64 Kbytes).
  2. + +
  3. +Expression evaluation has no operator precedence in effect which can make +for unexpected results if not explicitly grouped with parenthesis.
  4. + +
  5. +First page of listing file will not show a user defined title (defined +via TITLE directive).
  6. +
+ +
+
Top + + diff --git a/trunk/Tools/tasm32/TASMTABS.HTM b/trunk/Tools/tasm32/TASMTABS.HTM new file mode 100644 index 00000000..0f8297a7 --- /dev/null +++ b/trunk/Tools/tasm32/TASMTABS.HTM @@ -0,0 +1,2989 @@ + + + +TASM Table Syntax + +

TASM TABLE SYNTAX DESCRIPTION

+

The tables that control TASM's interpretation of the source file are read +from a file at run time. The table file name is determined by taking the +numeric option field specified on the TASM command line and appending it to the +string "TASM", then a ".TAB" extension is added. Thus, +if the following command line is entered: +

+
        tasm -51  test.asm
+
+

then TASM would read the table file named "TASM51.TAB". +

+

The following rules apply to the structure of the table file: +

+
    +
  • The first line of the file should contain a string surrounded by double +quotes that should identify the version of the assembler table. This string +will appear at the top of each page in the list file. It should be limited to +24 characters.
  • +
  • Any line that starts with a '.' is considered a directive. Directives +should preceed instruction defintion lines. The following directives are +available: +
+ + + + + + + + + + + + + + + + + + +
DIRECTIVEDESCRIPTION
MSFIRSTGenerate opcodes MS byte first. Useful for tables with multibyte opcodes.
ALTWILDUse '@' instead of '*' as the wild card in the table. Useful if the +instruction syntax uses '*' to denote certain addressing modes.
NOARGSHIFTSuppress the shift/or operation that applies if the optional SHIFT and OR +fields are provided. Some RULEs use the SHIFT/OR fields for other purposes.
REGSETDefine a register mnemonic and associated bit field. See example below.
WORDADDRSSet word addressing mode (one word = 2 bytes)
+
    +
  • Any line whose first character is not a '.' and is not alphabetic is +considered to be a comment and is discarded.
  • +
  • Any line that has an alphabetic character as the first character is assumed +to be an instruction definition record and is parsed to build the internal +representation of the instruction set tables. Eight fields (separated by white +space) are expected, as follows: +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field Name Description
INSTRUCTION Instruction Mnemonic
ARGS Argument definition
OPCODE Opcode value
NBYTES Number of bytes
RULE Modifier operation
CLASS Instruction class
SHIFT Argument left shift count
OR Argument bitwise OR mask
+

The fields are further defined below:

+
+
INSTRUCTION
+
The INSTRUCTION field should contain the string to be used as the mnemonic +for this instruction. Upper case letters should be used (the source statements +are converted to upper case before comparison).
+
ARGS.
+
The ARGS field should contain a string describing the format of the operand +field. All characters are taken literally except the '*' which denotes the +presence of a valid TASM expression. Multiple '*'s can be used, but all but the +last one must be followed by a comma, '[', or ']'. If a single '*' appears in +the ARGS field, then the default action of TASM will be to determine the value +of the expression that matches the field and insert one or two bytes of it into +the object file depending on the NBYTES field. If multiple '*'s are used, then +special operators (RULE) must be used to take advantage of them (see the +examples below). An ARGS field of a pair of double quotes means that no +arguments are expected. +
+
OPCODE.
+
The OPCODE field should contain the opcode value (two to six hex digits) +for this instruction and address mode. Each pair of hex digits represent a +single byte of the opcode, ordered with the right most pair being placed in the +lowest memory location. +
+
NBYTES.
+
The NBYTES field should specify the number of bytes this instruction is to +occupy (a single decimal digit). This number includes both opcode bytes and +argument bytes, thus, the number of bytes of argument is computed by subtracting +the number of bytes of opcode (dictated by the length of the OPCODE field) from +NBYTES. +
+
RULE.
+
The RULE field determines if any special operations need to be performed +on the code generated for this instruction. For example, the zero-page +addressing mode of the 6502 is a special case of the absolute addressing mode, +and is handled by a special RULE code. See the Encoding Rules below. +
+
CLASS.
+
The CLASS field is used to specify whether this instruction is part of the +standard instruction set or a member of a set of extended instructions. Bit 0 of +this field should be set to denote a member of the standard instruction set. +Other bits can be used as needed to establish several classes (or sets) of +instructions that can be enabled or disabled via the '-x' command line option. + +
+
SHIFT (optional).
+
The SHIFT field is used to cause the first argument of the given +instruction to be shifted left the specified number of bits. (Except T1, TDMA, +TAR RULES as noted below). +
+
OR (optional).
+
The OR field is used to perform a bitwise OR with the first argument of the +given instruction. Specified as hex digits. (Except T1, TDMA, TAR RULES as +noted below). +
+

Note that the SHIFT/OR fields are used somewhat differently for T1, TDMA, +and TAR RULES. In those cases, the SHIFT and OR fields are used but the OR +field is really an AND mask and the result is OR'd with the opcode. +

+

Encoding Rules

+

The following encoding rules are available:

+
+
NOTOUCH or NOP
+
Do nothing to instruction or args
+
JMPPAGE
+
Put bits 8-10 of first arg into bits 5-7 of opcode (8048 JMP)
+
ZPAGE
+
If arg < 256 then use zero-page (6502)
+
R1
+
Make arg relative to PC (single byte)
+
R2
+
Make arg relative to PC (two byte)
+
CREL
+
Combine LS bytes of first two args making the second one relative to PC
+
SWAP
+
Swap bytes of first arg
+
COMBINE
+
Combine LS bytes of first two args into first arg (arg1 -> LSB, arg2 ->MSB).
+
CSWAP
+
Combine LS bytes of first two args into first arg and swap.
+
ZBIT
+
Z80 bit instructions.
+
ZIDX
+
Z80 Indexed Instructions (e.g. ADC A,(IX+x))
+
MBIT
+
Motorola (6805) bit instructions
+
MZERO
+
Motorola (6805) zero page (direct)
+
3ARG
+
Three args, one byte each.
+
3REL
+
Three args, one byte each, last one relative
+
T1
+
TMS320 instruction with one arg. Shift according to SHIFT and mask with OR +and OR into opcode. If a second arg exists assume it is an arp and OR intoLSB +of opcode.
+
TDMA
+
TMS320 instruction with first arg dma. Second arg gets shift/and/or +treatment as with T1.
+
TAR
+
TMS320 instruction with first arg ar. Second arg gets shift/and/or +treatment as with T1.
+
I1
+
I8096 Combine
+
I2
+
I8096 two far args
+
I3
+
I8096 three far args
+
I4
+
I8096 Jump with bit mask
+
I5
+
I8096 Relative
+
I6
+
I8096 Indirect
+
I7
+
I8096 One far arg
+
I8
+
I8096 Jump
+

Encoding Examples

+

Note that the reason for the combining of arguments (COMBINE and CSWAP) is +that TASM assumes that all object bytes to be inserted in the object file are +derived from a variable representing the value of the first argument (argval). +If two arguments are in the ARGS field, then one of the previously mentioned +RULE`s must be used. They have the effect of combining the low bytes of the +first two arguments into the variable (argval) from which the object code will +be generated. TASM`s argument parsing routine can handle a large number of +arguments, but the code that generates the object code is less capable. +

+

The following table shows possible instruction definition records, followed +by possible source statements that would match it, followed by the resulting +object code that would be generated (in hex): +

+
                                          EXAMPLE         EXAMPLE
+INSTRUCTION DEFINITION                    SOURCE          OBJECT
+-------------------------------------------------------------------
+XYZ  *      FF   3  NOTOUCH 1             xyz 1234h       FF 34 12
+XYZ  *      FF   2  NOTOUCH 1             xyz 1234h       FF 34
+ZYX  *      FE   3  SWAP    1             zyx 1234h       FE 12 34
+ZYX  *      FE   3  R2      1             zyx $+4         FE 01 00
+ABC  *,*    FD   3  COMBINE 1             abc 45h,67h     FD 45 67
+ABC  *,*    FD   3  CSWAP   1             abc 45h,67h     FD 67 45
+ADD  A,#*   FC   2  NOTOUCH 1             add A,#'B'      FC 42
+RET  ""     FB   1  NOTOUCH 1             ret             FB
+LD   IX,*   21DD 4  NOTOUCH 1             ld  IX,1234h    DD 21 34 12
+LD   IX,*   21DD 4  NOTOUCH 1 1 0         ld  IX,1234h    DD 21 68 24
+LD   IX,*   21DD 4  NOTOUCH 1 0 1         ld  IX,1234h    DD 21 35 12
+LD   IX,*   21DD 4  NOTOUCH 1 1 1         ld  IX,1234h    DD 21 69 24
+LD   IX,*   21DD 4  NOTOUCH 1 8 12        ld  IX,34h      DD 21 12 34
+
+

The order of the entries for various addressing modes of a given instruction +is important. Since the wild card matches anything, it is important to specify +the ARGS for the addressing modes that have the most qualifying characters +first. For example, if an instruction had two addressing modes, one that +accepted any expression, and another that required a pound sign in front of an +expression, the pound sign entry should go first otherwise all occurrences of +the instruction would match the more general ARGS expression that it +encountered first. The following entries illustrate the proper sequencing: +

+
        ADD #*  12 3 NOTOUCH 1
+        ADD *   13 3 NOTOUCH 1
+
+

Table Lookup Method

+

The current version of TASM uses a very simple hashing method based on the +first character of the nmemonic. A search is begun at the first table entry +that starts with that letter. Thus, the table should be sorted alphabetically +for optimum lookup speed. If the table is not sorted in this way it will not +break anything, but just slow it down a bit.

+

REGSET Directive

+

For instruction sets that have a well defined set of registers that map to a +bit field in the opcode it may be convenient to use the REGSET directive. The +value field following each register definition is OR'd into the opcode when a +match is found. The '!' character is used to indicate the expected occurance of +a register. Consider the following example:

+
.REGSET R0  00 1
+.REGSET R1  01 1
+.REGSET R2  02 1
+.REGSET R3  03 1
+.REGSET R4  04 1
+.REGSET R5  05 1
+.REGSET R6  06 1
+.REGSET R7  07 1
+
+...
+INC !  E0  1 NOP
+...
+
+

A source instruction INC R3 would be encoded by ORing E0 with 03 +resulting in E3.

+
+

6502 INSTRUCTIONS AND ADDRESSING MODES

+

The acceptable 6502 opcode mnemonics for TASM are as follows: +

+
 ADC  AND  ASL  BCC  BCS  BEQ  BNE  BMI  BPL  BVC  BVS  BIT
+ BRK  CLC  CLD  CLI  CLV  CMP  CPX  CPY  DEC  DEX  DEY  EOR
+ INC  INX  INY  JMP  JSR  LDA  LDX  LDY  LSR  NOP  ORA  PHA
+ PHP  PLA  PLP  ROL  ROR  RTI  RTS  SBC  SEC  SED  SEI  STA
+ STX  STY  TAX  TAY  TSX  TXA  TXS  TYA
+
+

TASM also supports the following instructions that are part of the +Rockwell R65C02 and R65C00/21 microprocessor instruction sets. Those that + are marked as set A are applicable to the R65C02 and those marked as set B +are applicable to the R65C00/21 (A+B for both): +

+
        Mnemonic        Description                Address Mode  Set
+        ---------------------------------------------------------------
+        ADC             Add with carry             (IND)         A
+        AND             And memory with A          (IND)         A
+        BIT             Test memory bits with A    ABS,X         A
+        BIT             Test memory bits with A    ZP,X          A
+        BIT             Test memory bits with A    IMM           A
+        CMP             Compare memory with A      (IND)         A
+        DEC             Decrement A                A             A
+        EOR             Exclusive OR memory with A (IND)         A
+        INC             Increment A                A             A
+        JMP             Jump                       (ABS,X)       A
+        LDA             Load A with memory         (IND)         A
+        ORA             OR A with memory           (IND)         A
+        SBC             Subtract memory form A     (IND)         A
+        STA             Store A in memory          (IND)         A
+        STZ             Store zero                 ABS           A
+        STZ             Store zero                 ABS,X         A
+        STZ             Store zero                 ZP            A
+        STZ             Store zero                 ZP,X          A
+        TRB             Test and reset memory bit  ABS           A
+        TRB             Test and reset memory bit  ZP            A
+        TSB             Test and set memory bit    ABS           A
+        TSB             Test and set memory bit    ZP            A
+
+        BRA             Branch Always              REL           A+B
+
+        BBR0            Branch on Bit 0 Reset      ZP,REL        A+B
+        BBR1            Branch on Bit 1 Reset      ZP,REL        A+B
+        BBR2            Branch on Bit 2 Reset      ZP,REL        A+B
+        BBR3            Branch on Bit 3 Reset      ZP,REL        A+B
+        BBR4            Branch on Bit 4 Reset      ZP,REL        A+B
+        BBR5            Branch on Bit 5 Reset      ZP,REL        A+B
+        BBR6            Branch on Bit 6 Reset      ZP,REL        A+B
+        BBR7            Branch on Bit 7 Reset      ZP,REL        A+B
+
+        BBS0            Branch on Bit 0 Set        ZP,REL        A+B
+        BBS1            Branch on Bit 1 Set        ZP,REL        A+B
+        BBS2            Branch on Bit 2 Set        ZP,REL        A+B
+        BBS3            Branch on Bit 3 Set        ZP,REL        A+B
+        BBS4            Branch on Bit 4 Set        ZP,REL        A+B
+        BBS5            Branch on Bit 5 Set        ZP,REL        A+B
+        BBS6            Branch on Bit 6 Set        ZP,REL        A+B
+        BBS7            Branch on Bit 7 Set        ZP,REL        A+B
+
+        MUL             Multiply                   Implied       B
+
+        PHX             Push Index X               Implied       A+B
+        PHY             Push Index Y               Implied       A+B
+        PLX             Pull Index X               Implied       A+B
+        PLY             Pull Index Y               Implied       A+B
+
+        RMB0            Reset Memory Bit 0         ZP            A+B
+        RMB1            Reset Memory Bit 1         ZP            A+B
+        RMB2            Reset Memory Bit 2         ZP            A+B
+        RMB3            Reset Memory Bit 3         ZP            A+B
+        RMB4            Reset Memory Bit 4         ZP            A+B
+        RMB5            Reset Memory Bit 5         ZP            A+B
+        RMB6            Reset Memory Bit 6         ZP            A+B
+        RMB7            Reset Memory Bit 7         ZP            A+B
+
+        SMB0            Set   Memory Bit 0         ZP            A+B
+        SMB1            Set   Memory Bit 1         ZP            A+B
+        SMB2            Set   Memory Bit 2         ZP            A+B
+        SMB3            Set   Memory Bit 3         ZP            A+B
+        SMB4            Set   Memory Bit 4         ZP            A+B
+        SMB5            Set   Memory Bit 5         ZP            A+B
+        SMB6            Set   Memory Bit 6         ZP            A+B
+        SMB7            Set   Memory Bit 7         ZP            A+B
+
+

Addressing modes are denoted as follows: +

+
ABS               Absolute
+ZP                Zero Page
+ABS,X             Absolute X
+ZP,X              Zero Page X
+ABS,Y             Absolute Y
+ZP,Y              Zero Page Y
+A                 Accumulator
+(IND,X)           Indirect X
+(IND),Y           Indirect Y
+(IND)             Indirect
+#IMM              Immediate
+REL               Relative (Branch instructions only)
+ZP,REL            Zero Page, Relative
+Implied           Implied
+
+

Note that Zero Page addressing can not be explicitly requested. It is used +if the value of the operand is representable in a single byte for the +applicable statements. +

+

The '-x' command line option can be used to enable the extended +instructions. A '-x' with no digit following will enable the standard set plus +both extended sets. The 6502 version of TASM uses three bits in the instruction +class mask to determine whether a given instruction is enabled or not. Bit 0 +enables the basic set, bit 1 enables set A (R65C02) and bit 2 enables set B +(R65C00/21). The following table shows various options: +

+
Class Mask        Enabled Instructions
+                BASIC   R65C02  R65C00/21
+--------------------------------------------
+1               yes     no      no
+2               no      yes     no
+3               yes     yes     no
+4               no      no      yes
+5               yes     no      yes
+6               no      yes     yes
+7               yes     yes     yes
+
+

Thus, to enable the basic set plus the R65C02 instructions, invoke the +'-x3' command line option. +

+

See manufacturer's data for a more complete description of the meaning of +the mnemonics and addressing modes. +

+
+

68xx INSTRUCTIONS AND ADDRESSING MODES +

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the 6800/68HC11 version of TASM. Symbolic +fields are defined as follows: +

+
SYMBOLIC            DESCRIPTION
+-----------------------------------------------
+_addr8_             Absolute address (8 bits)
+_addr16_            Absolute address (16 bits)
+                      Values that can fit in 8 bits can
+                      result in the DIRECT addressing mode.
+_addr16_no8_        Absolute address (16 bits)
+                      DIRECT addressing not applicable.
+_bmsk_              Bit mask (8 bits)
+_rel8_              Relative address (8 bit signed)
+_immed8_            Immediate data (8 bits)
+_immed16_           Immediate data (16 bits)
+
+

Any valid TASM expression can appear in the place of any of the above +symbolics. +

+

The lines that are marked with an 'a' or 'b' are extended instructions that +are available only if a -x option has been invoked on the command line. The +classes of instructions (and their bit assignment in the class mask) are shown +below: +

+
BIT     PROCESSOR      EXT LABEL     COMMAND LINE OPTION
+--------------------------------------------------------
+0       6800
+1       6801/6803       a            -x3
+2       68HC11          b            -x7
+
+

Thus, to enable the 68HC11 instructions, a -x7 could be used on the command +line. +

+

TASM deviates from standard Motorola syntax for the BSET, BRSET, BCLR, +and BRCLR instructions. TASM requires commas separating all arguments. +Motorola assemblers use white space to separate the last one or two +arguments for these instructions. Here are examples of each applicable +instruction: +

+
TASM                                MOTOROLA
+----------------------              --------------------
+BCLR    _addr8_,Y,_bmsk_            BCLR    _addr8_,Y _bmsk_
+BCLR    _addr8_,X,_bmsk_            BCLR    _addr8_,X _bmsk_
+BCLR    _addr8_  ,_bmsk_            BCLR    _addr8_   _bmsk_
+BSET    _addr8_,Y,_bmsk_            BSET    _addr8_,Y _bmsk_
+BSET    _addr8_,X,_bmsk_            BSET    _addr8_,X _bmsk_
+BSET    _addr8_  ,_bmsk_            BSET    _addr8_   _bmsk_
+BRCLR   _addr8_,Y,_bmsk_,_rel8_     BRCLR   _addr8_,Y _bmsk_ _rel8_
+BRCLR   _addr8_,X,_bmsk_,_rel8_     BRCLR   _addr8_,X _bmsk_ _rel8_
+BRCLR   _addr8_  ,_bmsk_,_rel8_     BRCLR   _addr8_   _bmsk_ _rel8_
+BRSET   _addr8_,Y,_bmsk_,_rel8_     BRSET   _addr8_,Y _bmsk_ _rel8_
+BRSET   _addr8_,X,_bmsk_,_rel8_     BRSET   _addr8_,X _bmsk_ _rel8_
+BRSET   _addr8_  ,_bmsk_,_rel8_     BRSET   _addr8_   _bmsk_ _rel8_
+
+
OPCODE  OPERANDS       EXT   DESCRIPTION
+--------------------------------------------------------------
+ABA                          Add Accumulator B to Accumulator A
+ABX                     a    Add Accumulator B to Index Reg X
+ABY                     b    Add Accumulator B to Index reg Y
+
+ADCA    #_immed8_            Add with carry immediate  to Reg A
+ADCA    _addr8_,X            Add with carry indirect,X to Reg A
+ADCA    _addr8_,Y       b    Add with carry indirect,Y to Reg A
+ADCA    _addr16_             Add with carry extended   to Reg A
+
+ADCB    #_immed8_            Add with carry immediate  to Reg B
+ADCB    _addr8_,X            Add with carry indirect,X to Reg B
+ADCB    _addr8_,Y       b    Add with carry indirect,Y to Reg B
+ADCB    _addr16_             Add with carry extended   to Reg B
+
+ADDA    #_immed8_            Add w/o  carry immediate  to Reg A
+ADDA    _addr8_,X            Add w/o  carry indirect,X to Reg A
+ADDA    _addr8_,Y       b    Add w/o  carry indirect,Y to Reg A
+ADDA    _addr16_             Add w/o  carry extended   to Reg A
+
+ADDB    #_immed8_            Add w/o  carry immediate  to Reg B
+ADDB    _addr8_,X            Add w/o  carry indirect,X to Reg B
+ADDB    _addr8_,Y       b    Add w/o  carry indirect,Y to Reg B
+ADDB    _addr16_             Add w/o  carry extended   to Reg B
+
+ADDD    #_immed8_       a    Add double immediate  to Reg D
+ADDD    _addr8_,X       a    Add double indirect,X to Reg D
+ADDD    _addr8_,Y       b    Add double indirect,Y to Reg D
+ADDD    _addr16_        a    Add double extended   to Reg D
+
+ANDA    #_immed8_            AND immediate  to Reg A
+ANDA    _addr8_,X            AND indirect,X to Reg A
+ANDA    _addr8_,Y       b    AND indirect,Y to Reg A
+ANDA    _addr16_             AND extended   to Reg A
+
+ANDB    #_immed8_            AND immediate  to Reg B
+ANDB    _addr8_,X            AND indirect,X to Reg B
+ANDB    _addr8_,Y       b    AND indirect,Y to Reg B
+ANDB    _addr16_             AND extended   to Reg B
+
+ASL     _addr8_,X            Arithmetic shift left indirect,X
+ASL     _addr8_,Y       b    Arithmetic shift left indirect,Y
+ASL     _addr16_             Arithmetic shift left extended
+ASLA                         Arithmetic shift left Reg A
+ASLB                         Arithmetic shift left Reg B
+ASLD                    a    Arithmetic shift left double Reg D
+
+ASR     _addr8_,X            Arithmetic shift right indirect,X
+ASR     _addr8_,Y       b    Arithmetic shift right indirect,Y
+ASR     _addr16_             Arithmetic shift right extended
+ASRA                         Arithmetic shift right Reg A
+ASRB                         Arithmetic shift right Reg B
+
+OPCODE  OPERANDS       EXT   DESCRIPTION
+--------------------------------------------------------------
+BCC     _rel8_               Branch if carry clear
+BCS     _rel8_               Branch if carry set
+BEQ     _rel8_               Branch if equal
+BGE     _rel8_               Branch if greater or equal
+BGT     _rel8_               Branch if greater
+BHI     _rel8_               Branch if higher
+BHS     _rel8_               Branch if higher or same
+BRA     _rel8_               Branch always
+
+BITA    #_immed8_            AND immediate  with Reg A (set condition codes)
+BITA    _addr8_,X            AND indirect,X with Reg A (set condition codes)
+BITA    _addr8_,Y       b    AND indirect,Y with Reg A (set condition codes)
+BITA    _addr16_             AND extended   with Reg A (set condition codes)
+
+BITB    #_immed8_            AND immediate  with Reg B (set condition codes)
+BITB    _addr8_,X            AND indirect,X with Reg B (set condition codes)
+BITB    _addr8_,Y       b    AND indirect,Y with Reg B (set condition codes)
+BITB    _addr16_             AND extended   with Reg B (set condition codes)
+
+BLE     _rel8_               Branch if less than or equal
+BLO     _rel8_               Branch if lower (same as BCS)
+BLS     _rel8_               Branch if lower or same
+BLT     _rel8_               Branch if less than zero
+BMI     _rel8_               Branch if minus
+BNE     _rel8_               Branch if not equal
+BPL     _rel8_               Branch if plus
+BRA     _rel8_               Branch always
+
+BRCLR _addr8_,X,_bmsk_,_rel8_  b Branch if bits clear indirect X
+BRCLR _addr8_,Y,_bmsk_,_rel8_  b Branch if bits clear indirect Y
+BRCLR _addr8_,_bmsk_,  _rel8_  b Branch if bits clear direct
+
+BRN     _rel8_               Branch never
+
+BRSET _addr8_,X,_bmsk_,_rel8_  b Branch if bits set indirect X
+BRSET _addr8_,Y,_bmsk_,_rel8_  b Branch if bits set indirect Y
+BRSET _addr8_,_bmsk_,  _rel8_  b Branch if bits set direct
+
+BSET    _addr8_,X,_bmsk_ b   Bit set indirect X
+BSET    _addr8_,Y,_bmsk_ b   Bit set indirect Y
+BSET    _addr8_,_bmsk_   b   Bit set direct
+BSET    _addr8_,#_bmsk_  b   Bit set direct (alternate form)
+
+BSR     _rel8_               Branch subroutine
+BVC     _rel8_               Branch if overflow clear
+BVS     _rel8_               Branch if overflow set
+
+OPCODE  OPERANDS       EXT   DESCRIPTION
+--------------------------------------------------------------
+CBA                          Compare registers A & B
+CLC                          Clear Carry
+CLI                          Clear Interrupt Mask
+
+CLR     _addr8_,X            Arithmetic shift right indirect,X
+CLR     _addr8_,Y       b    Arithmetic shift right indirect,Y
+CLR     _addr16_             Arithmetic shift right extended
+CLRA                         Arithmetic shift right Reg A
+CLRB                         Arithmetic shift right Reg B
+
+CLV                          Clear Overflow Bit
+
+CMPA    #_immed8_            Compare immediate  with Reg A
+CMPA    _addr8_,X            Compare indirect,X with Reg A
+CMPA    _addr8_,Y       b    Compare indirect,Y with Reg A
+CMPA    _addr16_             Compare extended   with Reg A
+
+CMPB    #_immed8_            Compare immediate  with Reg B
+CMPB    _addr8_,X            Compare indirect,X with Reg B
+CMPB    _addr8_,Y       b    Compare indirect,Y with Reg B
+CMPB    _addr16_             Compare extended   with Reg B
+
+COM     _addr8_,X            Complement indirect,X
+COM     _addr8_,Y       b    Complement indirect,Y
+COM     _addr16_             Complement extended
+COMA                         Complement Reg A
+COMB                         Complement Reg B
+
+CPD     #_immed16_      b    Compare double immediate  to Reg D
+CPD     _addr8_,X       b    Compare double indirect,X to Reg D
+CPD     _addr8_,Y       b    Compare double indirect,Y to Reg D
+CPD     _addr16_        b    Compare double extended   to Reg D
+
+CPX     #_immed8_            Compare double immediate  to Reg X
+CPX     _addr8_,X            Compare double indirect,X to Reg X
+CPX     _addr8_,Y       b    Compare double indirect,Y to Reg X
+CPX     _addr16_             Compare double extended   to Reg X
+
+CPY     #_immed8_       b    Compare double immediate  to Reg Y
+CPY     _addr8_,X       b    Compare double indirect,X to Reg Y
+CPY     _addr8_,Y       b    Compare double indirect,Y to Reg Y
+CPY     _addr16_        b    Compare double extended   to Reg Y
+
+OPCODE  OPERANDS       EXT   DESCRIPTION
+--------------------------------------------------------------
+DAA                          Decimal Adjust Reg A
+
+DEC     _addr8_,X            Decrement indirect,X
+DEC     _addr8_,Y            Decrement indirect,Y
+DEC     _addr16_no8_         Decrement extended
+DECA                         Decrement Reg A
+DECB                         Decrement Reg B
+DES                          Decrement stack pointer
+DEX                          Decrement Reg X
+DEY                     b    Decrement Reg Y
+
+EORA    #_immed8_            Exclusive OR immediate  with Reg A
+EORA    _addr8_,X            Exclusive OR indirect,X with Reg A
+EORA    _addr8_,Y       b    Exclusive OR indirect,Y with Reg A
+EORA    _addr16_             Exclusive OR extended   with Reg A
+
+EORB    #_immed8_            Exclusive OR immediate  with Reg B
+EORB    _addr8_,X            Exclusive OR indirect,X with Reg B
+EORB    _addr8_,Y       b    Exclusive OR indirect,Y with Reg B
+EORB    _addr16_             Exclusive OR extended   with Reg B
+
+FDIV                    b    Fractional Divide (ACCD/IX)
+IDIV                    b    Integer Divide (ACCD/IX)
+
+INC     _addr8_,X            Increment indirect,X
+INC     _addr8_,Y            Increment indirect,Y
+INC     _addr16_no8_         Increment extended
+INCA                         Increment Reg A
+INCB                         Increment Reg B
+INS                          Increment stack pointer
+INX                          Increment Reg X
+INY                     b    Increment Reg Y
+
+JMP     _addr8_,X            Jump indirect,X
+JMP     _addr8_,Y       b    Jump indirect,Y
+JMP     _addr16_no8_         Jump extended
+
+JSR     _addr8_,X            Jump Subroutine indirect,X
+JSR     _addr8_,Y       b    Jump Subroutine indirect,Y
+JSR     _addr16_             Jump Subroutine extended
+
+LDAA    #_immed8_            Load Accumulator immediate  with Reg A
+LDAA    _addr8_,X            Load Accumulator indirect,X with Reg A
+LDAA    _addr8_,Y       b    Load Accumulator indirect,Y with Reg A
+LDAA    _addr16_             Load Accumulator extended   with Reg A
+
+LDAB    #_immed8_            Load Accumulator immediate  with Reg B
+LDAB    _addr8_,X            Load Accumulator indirect,X with Reg B
+LDAB    _addr8_,Y       b    Load Accumulator indirect,Y with Reg B
+LDAB    _addr16_             Load Accumulator extended   with Reg B
+
+OPCODE  OPERANDS       EXT   DESCRIPTION
+--------------------------------------------------------------
+LDD     #_immed16_      a    Load double immediate  to Reg D
+LDD     _addr8_,X       a    Load double indirect,X to Reg D
+LDD     _addr8_,Y       b    Load double indirect,Y to Reg D
+LDD     _addr16_        a    Load double extended   to Reg D
+
+LDS     #_immed16_           Load double immediate  to Reg D
+LDS     _addr8_,X            Load double indirect,X to Reg D
+LDS     _addr8_,Y       b    Load double indirect,Y to Reg D
+LDS     _addr16_             Load double extended   to Reg D
+
+LDX     #_immed16_           Load immediate  to Reg X
+LDX     _addr8_,X            Load indirect,X to Reg X
+LDX     _addr8_,Y       b    Load indirect,Y to Reg X
+LDX     _addr16_             Load extended   to Reg X
+
+LDY     #_immed16_      b    Load immediate  to Reg Y
+LDY     _addr8_,X       b    Load indirect,X to Reg Y
+LDY     _addr8_,Y       b    Load indirect,Y to Reg Y
+LDY     _addr16_        b    Load extended   to Reg Y
+
+LSL     _addr8_,X            Logical Shift Left indirect,X
+LSL     _addr8_,Y       b    Logical Shift Left indirect,Y
+LSL     _addr16_no8_         Logical Shift Left extended
+LSLA                         Logical Shift Left Reg A
+LSLB                         Logical Shift Left Reg B
+LSLD                         Logical Shift Left Double Reg D
+
+LSR     _addr8_,X            Logical Shift Right indirect,X
+LSR     _addr8_,Y       b    Logical Shift Right indirect,Y
+LSR     _addr16_no8_         Logical Shift Right extended
+LSRA                         Logical Shift Right Reg A
+LSRB                         Logical Shift Right Reg B
+LSRD                         Logical Shift Right Double Reg D
+
+MUL                          Multiply Unsigned
+
+NEG     _addr8_,X            Negate indirect,X
+NEG     _addr8_,Y       b    Negate indirect,Y
+NEG     _addr16_no8_         Negate extended
+NEGA                         Negate Reg A
+NEGB                         Negate Reg B
+
+NOP                          No Operation
+
+OPCODE  OPERANDS       EXT   DESCRIPTION
+--------------------------------------------------------------
+ORAA    #_immed8_            Inclusive OR immediate  with Reg A
+ORAA    _addr8_,X            Inclusive OR indirect,X with Reg A
+ORAA    _addr8_,Y       b    Inclusive OR indirect,Y with Reg A
+ORAA    _addr16_             Inclusive OR extended   with Reg A
+
+ORAB    #_immed8_            Inclusive OR immediate  with Reg B
+ORAB    _addr8_,X            Inclusive OR indirect,X with Reg B
+ORAB    _addr8_,Y       b    Inclusive OR indirect,Y with Reg B
+ORAB    _addr16_             Inclusive OR extended   with Reg B
+
+PSHA                         Push Reg A onto stack
+PSHB                         Push Reg B onto stack
+PSHX                         Push Reg X onto stack
+PSHY                         Push Reg Y onto stack
+
+PULA                         Pull Reg A from stack
+PULB                         Pull Reg B from stack
+PULX                         Pull Reg X from stack
+PULY                         Pull Reg Y from stack
+
+ROL     _addr8_,X            Rotate Left indirect,X
+ROL     _addr8_,Y            Rotate Left indirect,Y
+ROL     _addr16_no8_         Rotate Left extended
+ROLA                         Rotate Left Reg A
+ROLB                         Rotate Left Reg B
+
+ROR     _addr8_,X            Rotate Right indirect,X
+ROR     _addr8_,Y            Rotate Right indirect,Y
+ROR     _addr16_no8_         Rotate Right extended
+RORA                         Rotate Right Reg A
+RORB                         Rotate Right Reg B
+RTI                          Return from Interrupt
+RTS                          Return from subroutine
+
+SBA                          Subtract Accumulators
+SBCA    #_immed8_            Subtract with Carry immediate  with Reg A
+SBCA    _addr8_,X            Subtract with Carry indirect,X with Reg A
+SBCA    _addr8_,Y       b    Subtract with Carry indirect,Y with Reg A
+SBCA    _addr16_             Subtract with Carry extended   with Reg A
+SBCB    #_immed8_            Subtract with Carry immediate  with Reg B
+SBCB    _addr8_,X            Subtract with Carry indirect,X with Reg B
+SBCB    _addr8_,Y       b    Subtract with Carry indirect,Y with Reg B
+SBCB    _addr16_             Subtract with Carry extended   with Reg B
+SEC                          Set Carry
+SEI                          Set Interrupt Mask
+SEV                          Set Twos Complement Overflow Bit
+STAA    _addr8_,X            Store Reg A indirect,X
+STAA    _addr8_,Y       b    Store Reg A indirect,Y
+STAA    _addr16_             Store Reg A extended
+
+STAB    _addr8_,X            Store Reg B indirect,X
+STAB    _addr8_,Y       b    Store Reg B indirect,Y
+STAB    _addr16_             Store Reg B extended
+
+OPCODE  OPERANDS       EXT   DESCRIPTION
+--------------------------------------------------------------
+STD     _addr8_,X            Store Double Acc indirect,X to Reg B
+STD     _addr8_,Y       b    Store Double Acc indirect,Y to Reg B
+STD     _addr16_             Store Double Acc extended   to Reg B
+
+STOP                         Stop Processing
+
+STS     _addr8_,X            Store Accumulator indirect,X
+STS     _addr8_,Y       b    Store Accumulator indirect,Y
+STS     _addr16_             Store Accumulator extended
+
+STX     _addr8_,X            Store Index Reg X indirect,X
+STX     _addr8_,Y       b    Store Index Reg X indirect,Y
+STX     _addr16_             Store Index Reg X extended
+
+STY     _addr8_,X       b    Store Index Reg Y indirect,X
+STY     _addr8_,Y       b    Store Index Reg Y indirect,Y
+STY     _addr16_        b    Store Index Reg Y extended
+
+SUBA    #_immed8_            Subtract immediate  from Reg A
+SUBA    _addr8_,X            Subtract indirect,X from Reg A
+SUBA    _addr8_,Y       b    Subtract indirect,Y from Reg A
+SUBA    _addr16_             Subtract extended   from Reg A
+
+SUBB    #_immed8_            Subtract immediate  from Reg B
+SUBB    _addr8_,X            Subtract indirect,X from Reg B
+SUBB    _addr8_,Y       b    Subtract indirect,Y from Reg B
+SUBB    _addr16_             Subtract extended   from Reg B
+
+SUBD    #_immed16_      b    Subtract double immediate  from Reg D
+SUBD    _addr8_,X       b    Subtract double indirect,X from Reg D
+SUBD    _addr8_,Y       b    Subtract double indirect,Y from Reg D
+SUBD    _addr16_        b    Subtract double extended   from Reg D
+
+SWI                          Software Interrupt
+
+TAB                          Transfer Reg A to Reg B
+TAP                          Transfer Reg A to Condition Code Reg
+TPA                          Transfer Condition Code Reg to Reg A
+TBA                          Transfer Reg B to Reg A
+
+TST     _addr8_,X            Test indirect,X
+TST     _addr8_,Y            Test indirect,Y
+TST     _addr16_no8_         Test extended
+TSTA                         Test Reg A
+TSTB                         Test Reg B
+
+TSX                          Transfer Stack Pointer to Reg X
+TSY                     b    Transfer Stack Pointer to Reg Y
+TXS                          Transfer Reg X to Stack Pointer
+TYS                     b    Transfer Reg Y to Stack Pointer
+
+WAI                          Wait for Interrupt
+XGDX                    b    Exchange Double Reg D and Reg X
+XGDY                    b    Exchange Double Reg D and Reg Y
+
+
+
+

8048 INSTRUCTIONS AND ADDRESSING MODES

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the 8048 version of TASM. Where 'Rn' is seen, +R0 through R7 may be substituted. Other symbolic fields are as follows: +

+
SYMBOLIC            DESCRIPTION
+-----------------------------------------------
+_addr8_             Absolute address (8 bits)
+_addr11_            Absolute address (11 bits)
+_immed_             Immediate data
+
+
+

Any valid TASM expression can appear in the place of any of the above +symbolics. +

+

The lines that are marked with an (8041), (8022), or (8021) on the far +right are extended instructions that are available only if a -x option has been +invoked on the command line. The classes of instructions (and their bit +assignment in the class mask) are shown below: +

+
BIT     PROCESSOR
+-------------------------------
+0       8X48, 8035, 8039, 8049
+1       8X41A
+2       8022
+3       8021
+
+

Thus, to enable the basic 8048 set plus the 8022 set, a -x5 could be used on +the command line. +

+

Note that some of the base instructions should be disabled for the 8041, +8022, and 8021, but are not. +

+
OPCODE  OPERANDS        DESCRIPTION
+-------------------------------------------------------------------
+ADD     A,Rn            Add Register to Acc
+ADD     A,@R0           Add Indirect RAM to Acc
+ADD     A,@R1           Add Indirect RAM to Acc
+ADD     A,#_immed_      Add Immediate data to Acc
+
+ADDC    A,Rn            Add Register to Acc with carry
+ADDC    A,@R0           Add Indirect RAM to Acc with carry
+ADDC    A,@R1           Add Indirect RAM to Acc with carry
+ADDC    A,#_immed_      Add Immediate data to Acc with carry
+
+ANL     A,Rn            AND Register to Acc
+ANL     A,@R0           AND Indirect RAM to Acc
+ANL     A,@R1           AND Indirect RAM to Acc
+ANL     A,#_immed_      AND Immediate data to Acc
+ANL     BUS,#_immed_    AND Immediate data to BUS
+ANL     P1,#_immed_     AND Immediate data to port P1
+ANL     P2,#_immed_     AND Immediate data to port P2
+
+ANLD    P4,A            AND Acc to Expander port P4
+ANLD    P5,A            AND Acc to Expander port P5
+ANLD    P6,A            AND Acc to Expander port P6
+ANLD    P7,A            AND Acc to Expander port P7
+
+CALL    _addr11_        Call subroutine
+
+CLR     A               Clear Acc
+CLR     C               Clear Carry
+CLR     F0              Clear Flag 0
+CLR     F1              Clear Flag 1
+
+CPL     A               Complement Acc
+CPL     C               Complement Carry
+CPL     F0              Complement Flag F0
+CPL     F1              Complement Flag F1
+
+DA      A               Decimal adjust Acc
+
+DEC     A               Decrement Acc
+DEC     Rn              Decrement Register
+
+DIS     I               Disable Interrupts
+DIS     TCNTI           Disable Timer/Counter Interrupt
+
+DJNZ    Rn,_addr8_      Decrement Register and Jump if nonzero
+
+EN      DMA             Enable DMA                           (8041)
+EN      FLAGS           Enable Flags                         (8041)
+EN      I               Enable External Interrupt
+EN      TCNTI           Enable Timer/Counter Interrupt
+ENT0    CLK             Enable Clock Output
+
+IN      A,DBB           Input Data Bus to Acc                (8041)
+IN      A,P0            Input Port 0 to Acc                  (8021)
+IN      A,P1            Input Port 1 to Acc
+IN      A,P2            Input Port 2 to Acc
+
+INC     A               Increment Acc
+INC     Rn              Increment Register
+INC     @R0             Increment Indirect RAM
+INC     @R1             Increment Indirect RAM
+
+INS     A,BUS           Strobed Input of Bus to Acc
+
+JB0     _addr8_         Jump if Acc bit 0 is set
+JB1     _addr8_         Jump if Acc bit 1 is set
+JB2     _addr8_         Jump if Acc bit 2 is set
+JB3     _addr8_         Jump if Acc bit 3 is set
+JB4     _addr8_         Jump if Acc bit 4 is set
+JB5     _addr8_         Jump if Acc bit 5 is set
+JB6     _addr8_         Jump if Acc bit 6 is set
+JB7     _addr8_         Jump if Acc bit 7 is set
+JMP     _addr11_        Jump
+JC      _addr8_         Jump if Carry is set
+JF0     _addr8_         Jump if Flag F0 is set
+JF1     _addr8_         Jump if Flag F1 is set
+JNC     _addr8_         Jump if Carry is clear
+JNI     _addr8_         Jump if Interrupt input is clear
+JNIBF   _addr8_         Jump if IBF is clear                 (8041)
+JNT0    _addr8_         Jump if T0 is clear
+JNT1    _addr8_         Jump if T1 is clear
+JNZ     _addr8_         Jump if Acc is not zero
+JOBF    _addr8_         Jump if OBF is set                   (8041)
+JTF     _addr8_         Jump if Timer Flag is set
+JT0     _addr8_         Jump if T0 pin is high
+JT1     _addr8_         Jump if T1 pin is high
+JZ      _addr8_         Jump if Acc is zero
+JMPP    @A              Jump Indirect (current page)
+
+MOV     A,PSW           Move PSW to Acc
+MOV     A,Rn            Move Register to Acc
+MOV     A,T             Move Timer/Counter to Acc
+MOV     A,@R0           Move Indirect RAM to Acc
+MOV     A,@R1           Move Indirect RAM to Acc
+MOV     A,#_immed_      Move Immediate data to Acc
+MOV     PSW,A           Move Acc to PSW
+MOV     Rn,A            Move Acc to Register
+MOV     Rn,#_immed_     Move Immediate data to Register
+MOV     STS,A           Move Acc to STS                      (8041)
+MOV     T,A             Move Acc to Timer/Counter
+MOV     @R0,A           Move Acc to Indirect RAM
+MOV     @R1,A           Move Acc to Indirect RAM
+MOV     @R0,#_immed_    Move Immediate data to Indirect RAM
+MOV     @R1,#_immed_    Move Immediate data to Indirect RAM
+
+MOVD    A,P4            Move half-byte Port 4 to Acc (lower nibble)
+MOVD    A,P5            Move half-byte Port 5 to Acc (lower nibble)
+MOVD    A,P6            Move half-byte Port 6 to Acc (lower nibble)
+MOVD    A,P7            Move half-byte Port 7 to Acc (lower nibble)
+MOVD    P4,A            Move lower nibble of Acc to Port 4
+MOVD    P5,A            Move lower nibble of Acc to Port 5
+MOVD    P6,A            Move lower nibble of Acc to Port 6
+MOVD    P7,A            Move lower nibble of Acc to Port 7
+
+MOVP    A,@A            Move Indirect Program data to Acc
+MOVP3   A,@A            Move Indirect Program data to Acc (page 3)
+
+MOVX    A,@R0           Move Indirect External RAM to Acc
+MOVX    A,@R1           Move Indirect External RAM to Acc
+MOVX    @R0,A           Move Acc to Indirect External RAM
+MOVX    @R1,A           Move Acc to Indirect External RAM
+
+NOP                     No operation
+
+ORL     A,Rn            OR Register to Acc
+ORL     A,@R0           OR Indirect RAM to Acc
+ORL     A,@R1           OR Indirect RAM to Acc
+ORL     A,#_immed_      OR Immediate data to Acc
+ORL     BUS,#_immed_    OR Immediate data to BUS
+ORL     P1,#_immed_     OR Immediate data to port P1
+ORL     P2,#_immed_     OR Immediate data to port P2
+
+ORLD    P4,A            OR lower nibble of Acc with P4
+ORLD    P5,A            OR lower nibble of Acc with P5
+ORLD    P6,A            OR lower nibble of Acc with P6
+ORLD    P7,A            OR lower nibble of Acc with P7
+
+OUTL    BUS,A           Output Acc to Bus
+OUT     DBB,A           Output Acc to DBB                    (8041)
+OUTL    P0,A            Output Acc to Port P0                (8021)
+OUTL    P1,A            Output Acc to Port P1
+OUTL    P2,A            Output Acc to Port P2
+
+RAD                     Move A/D Converter to Acc            (8022)
+
+RET                     Return from subroutine
+RETI                    Return from Interrupt w/o PSW restore(8022)
+RETR                    Return from Interrupt w/  PSW restore
+
+RL      A               Rotate Acc Left
+RLC     A               Rotate Acc Left through Carry
+RR      A               Rotate Acc Right
+RRC     A               Rotate Acc Right through Carry
+
+SEL     AN0             Select Analog Input 0                (8022)
+SEL     AN1             Select Analog Input 1                (8022)
+SEL     MB0             Select Memory Bank 0
+SEL     MB1             Select Memory Bank 1
+SEL     RB0             Select Register Bank 0
+SEL     RB1             Select Register Bank 1
+
+STOP    TCNT            Stop Timer/Counter
+STRT    CNT             Start Counter
+STRT    T               Start Timer
+
+SWAP    A               Swap nibbles of Acc
+
+XCH     A,Rn            Exchange Register with Acc
+XCH     A,@R0           Exchange Indirect RAM with Acc
+XCH     A,@R1           Exchange Indirect RAM with Acc
+
+XCHD    A,@R0           Exchange lower nibble of Indirect RAM w/ Acc
+XCHD    A,@R1           Exchange lower nibble of Indirect RAM w/ Acc
+
+XRL     A,Rn            Exclusive OR Register to Acc
+XRL     A,@R0           Exclusive OR Indirect RAM to Acc
+XRL     A,@R1           Exclusive OR Indirect RAM to Acc
+XRL     A,#_immed_      Exclusive OR Immediate data to Acc
+
+

See manufacturer's data for a more complete description of the meaning of +the mnemonics and addressing modes. +

+
+

8051 INSTRUCTIONS AND ADDRESSING MODES

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the 8051 version of TASM. Where 'Rn' is +seen, R0 through R7 may be substituted. Other symbolic fields are as +follows: +

+
        
+SYMBOLIC            DESCRIPTION
+-----------------------------------------------
+_addr11_            Absolute address (11 bits)
+_addr16_            Absolute address (16 bits)
+_bit_               Bit address
+_immed_             Immediate data
+_direct_            Direct RAM address
+_rel_               Relative address
+
+

Any valid TASM expression can appear in the place of any of the above +symbolics. +

+
OPCODE  OPERAND             DESCRIPTION
+--------------------------------------------------------------------
+ACALL   _addr11_            Absolute Call
+ADD     A,Rn                Add Register to Acc
+ADD     A,@R0               Add Indirect RAM to Acc
+ADD     A,@R1               Add Indirect RAM to Acc
+ADD     A,#_immed_          Add Immediate data to Acc
+ADD     A,_direct_          Add Direct RAM to Acc
+ADDC    A,Rn                Add Register to Acc with carry
+ADDC    A,@R0               Add Indirect RAM to Acc with carry
+ADDC    A,@R1               Add Indirect RAM to Acc with carry
+ADDC    A,#_immed_          Add Immediate data to Acc with carry
+ADDC    A,_direct_          Add Direct RAM to Acc with carry
+
+AJMP    _addr11_            Absolute Jump
+
+ANL     A,Rn                AND Register and Acc
+ANL     A,@R0               AND Indirect RAM and Acc
+ANL     A,@R1               AND Indirect RAM and Acc
+ANL     A,#_immed_          AND Immediate data and Acc
+ANL     A,_direct_          AND Direct RAM and Acc
+ANL     C,/_bit_            AND Complement of direct bit to Carry
+ANL     C,bit>              AND direct bit to Carry
+ANL     _direct_,A          AND Acc to direct RAM
+ANL     _direct_,#_immed_   AND Immediate data and direct RAM
+
+CJNE    A,#_immed_,_rel_    Compare Immediate to Acc   and JNE
+CJNE    A,_direct_,_rel_    Compare direct RAM to Acc and JNE
+CJNE    Rn,#_immed_,_rel_   Compare Immediate to Register and JNE
+CJNE    @R0,#_immed_,_rel_  Compare Immediate to Indirect RAM and JNE
+CJNE    @R1,#_immed_,_rel_  Compare Immediate to Indirect RAM and JNE
+
+CLR     A                   Clear Accumulator
+CLR     C                   Clear Carry
+CLR     _bit_               Clear Bit
+
+CPL     A                   Complement Accumulator
+CPL     C                   Complement Carry
+CPL     _bit_               Complement Bit
+
+DA      A                   Decimal Adjust Accumulator
+DEC     A                   Decrement Acc
+DEC     Rn                  Decrement Register
+DEC     @R0                 Decrement Indirect RAM
+DEC     @R1                 Decrement Indirect RAM
+DEC     _direct_            Decrement Direct RAM
+
+DIV     AB                  Divide Acc by B
+
+DJNZ    Rn,_rel_            Decrement Register and JNZ
+DJNZ    _direct_,_rel_      Decrement Direct RAM and JNZ
+
+INC     A                   Increment Acc
+INC     Rn                  Increment Register
+INC     @R0                 Increment Indirect RAM
+INC     @R1                 Increment Indirect RAM
+INC     DPTR                Increment Data Pointer
+INC     _direct_            Increment Direct RAM
+
+JB      _bit_,_rel_         Jump if Bit is set
+JBC     _bit_,_rel_         Jump if Bit is set & clear Bit
+JC      _rel_               Jump if Carry is set
+JMP     @A+DPTR             Jump indirect relative to Data Pointer
+JNB     _bit_,_rel_         Jump if Bit is clear
+JNC     _rel_               Jump if Carry is clear
+JNZ     _rel_               Jump if Acc is not zero
+JZ      _rel_               Jump if Acc is zero
+
+LCALL   _addr16_            Long Subroutine Call
+LJMP    _addr16_            Long Jump
+
+MOV     A,Rn                Move Register to Acc
+MOV     A,@R0               Move Indirect RAM to Acc
+MOV     A,@R1               Move Indirect RAM to Acc
+MOV     A,#_immed_          Move Immediate data to Acc
+MOV     A,_direct_          Move direct RAM to Acc
+MOV     C,_bit_             Move bit to Acc
+MOV     DPTR,#_immed_       Move immediate data to Data Pointer
+MOV     Rn,A                Move Acc to Register
+MOV     Rn,#_immed_         Move Immediate data to Register
+MOV     Rn,_direct_         Move Direct RAM to Register
+MOV     @R0,A               Move Acc to Indirect RAM
+MOV     @R1,A               Move Acc to Indirect RAM
+MOV     @R0,#_immed_        Move Immediate data to Indirect RAM
+MOV     @R1,#_immed_        Move Immediate data to Indirect RAM
+MOV     @R0,_direct_        Move Direct RAM to Indirect RAM
+MOV     @R1,_direct_        Move Direct RAM to Indirect RAM
+MOV     _direct_,A          Move Acc to Direct RAM
+MOV     _bit_,C             Move Carry to Bit
+MOV     _direct_,Rn         Move Register to Direct RAM
+MOV     _direct_,@R0        Move Indirect RAM to Direct RAM
+MOV     _direct_,@R1        Move Indirect RAM to Direct RAM
+MOV     _direct_,#_immed_   Move Immediate data to Direct RAM
+MOV     _direct_,_direct_   Move Direct RAM to Direct RAM
+MOVC    A,@A+DPTR           Move code byte relative to DPTR to Acc
+MOVC    A,@A+PC             Move code byte relative to PC to Acc
+
+MOVX    A,@R0               Move external RAM to Acc
+MOVX    A,@R1               Move external RAM to Acc
+MOVX    A,@DPTR             Move external RAM to Acc (16 bit addr)
+MOVX    @R0,A               Move Acc to external RAM
+MOVX    @R1,A               Move Acc to external RAM
+MOVX    @DPTR,A             Move Acc to external RAM (16 bit addr)
+
+MUL     AB                  Multiply Acc by B
+
+NOP                         No operation
+
+ORL     A,Rn                OR Register and Acc
+ORL     A,@R0               OR Indirect RAM and Acc
+ORL     A,@R1               OR Indirect RAM and Acc
+ORL     A,#_immed_          OR Immediate data and Acc
+ORL     A,_direct_          OR Direct RAM and Acc
+ORL     C,/_bit_            OR Complement of direct bit to Carry
+ORL     C,_bit_             OR direct bit to Carry
+ORL     _direct_,A          OR Acc to direct RAM
+ORL     _direct_,#_immed_   OR Immediate data and direct RAM
+
+POP     _direct_            Pop  from Stack and put in Direct RAM
+PUSH    _direct_            Push from Direct RAM to Stack
+
+RET                         Return from subroutine
+RETI                        Return from Interrupt
+
+RL      A                   Rotate Acc left
+RLC     A                   Rotate Acc left through Carry
+RR      A                   Rotate Acc right
+RRC     A                   Rotate Acc right through Carry
+
+SETB    C                   Set the Carry Bit
+SETB    _bit_               Set Direct Bit
+
+SJMP    _rel_               Short jump
+
+SUBB    A,Rn                Subtract Register from Acc with Borrow
+SUBB    A,@R0               Subtract Indirect RAM from Acc w/ Borrow
+SUBB    A,@R1               Subtract Indirect RAM from Acc w/ Borrow
+SUBB    A,#_immed_          Subtract Immediate data from Acc w/ Borrow
+SUBB    A,_direct_          Subtract Direct RAM from Acc w/ Borrow
+
+SWAP    A                   Swap nibbles of Acc
+
+XCH     A,Rn                Exchange Acc with Register
+XCH     A,@R0               Exchange Acc with Indirect RAM
+XCH     A,@R1               Exchange Acc with Indirect RAM
+XCH     A,_direct_          Exchange Acc with Direct RAM
+
+XCHD    A,@R0               Exchange Digit in Acc with Indirect RAM
+XCHD    A,@R1               Exchange Digit in Acc with Indirect RAM
+
+XRL     A,Rn                Exclusive OR Register and Acc
+XRL     A,@R0               Exclusive OR Indirect RAM and Acc
+XRL     A,@R1               Exclusive OR Indirect RAM and Acc
+XRL     A,#_immed_          Exclusive OR Immediate data and Acc
+XRL     A,_direct_          Exclusive OR Direct RAM and Acc
+XRL     _direct_,A          Exclusive OR Acc to direct RAM
+XRL     _direct_,#_immed_   Exclusive OR Immediate data and direct RAM
+
+

Note that the above tables do not automatically define the various +mnemonics that may be used for addressing the special function registers +of the 8051. The user may wish to set up a file of equates (EQU's) that +can be included in the source file for this purpose. The following +illustrates some of the appropriate equates: +

+
P0      .equ    080H    ;Port 0
+SP      .equ    081H    ;Stack pointer
+DPL     .equ    082H
+DPH     .equ    083H
+PCON    .equ    087H
+TCON    .equ    088H
+TMOD    .equ    089H
+TL0     .equ    08AH
+TL1     .equ    08BH
+TH0     .equ    08CH
+TH1     .equ    08DH
+P1      .equ    090H    ;Port 1
+SCON    .equ    098H
+SBUF    .equ    099H
+P2      .equ    0A0H    ;Port 2
+IEC     .equ    0A8H
+P3      .equ    0B0H    ;Port 3
+IPC     .equ    0B8H
+PSW     .equ    0D0H
+ACC     .equ    0E0H    ;Accumulator
+B       .equ    0F0H    ;Secondary Accumulator
+;Now some bit addresses
+P0.0    .equ    080H    ;Port 0 bit 0
+P0.1    .equ    081H    ;Port 0 bit 1
+P0.2    .equ    082H    ;Port 0 bit 2
+P0.3    .equ    083H    ;Port 0 bit 3
+P0.4    .equ    084H    ;Port 0 bit 4
+P0.5    .equ    085H    ;Port 0 bit 5
+P0.6    .equ    086H    ;Port 0 bit 6
+P0.7    .equ    087H    ;Port 0 bit 7
+ACC.0   .equ    0E0H    ;Acc bit 0
+ACC.1   .equ    0E1H    ;Acc bit 1
+ACC.2   .equ    0E2H    ;Acc bit 2
+ACC.3   .equ    0E3H    ;Acc bit 3
+ACC.4   .equ    0E4H    ;Acc bit 4
+ACC.5   .equ    0E5H    ;Acc bit 5
+ACC.6   .equ    0E6H    ;Acc bit 6
+ACC.7   .equ    0E7H    ;Acc bit 7
+
+

See the manufacturer's data sheets for more information. +

+
+

8085 INSTRUCTIONS AND ADDRESSING MODES

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the 8085 version of TASM. The following +symbols are used in the table: +

+
SYMBOLIC            DESCRIPTION
+-----------------------------------------------
+_addr_              Absolute address (16 bits)
+_data_              Immediate data (8 bits)
+_data16_            Immediate data (16 bits)
+_reg_               Register (A,B,C,D,E,H,L)
+_rp_                Register pair (B,D,H,SP)
+_port_              Port address (0-255)
+_int_               Interrupt level (0 - 7)
+
+
+

Any valid TASM expression can appear in the place of any of the above +symbolics except _reg_, _rp_ and _int_. +

+
OPCODE  OPERAND        DESCRIPTION
+--------------------------------------------------------------------
+ACI      _data_         Add immediate to A with carry
+ADC      _reg_          Add _reg_ to A with carry
+ADC      M              Add indirect memory (HL) with carry
+ADD      _reg_          Add _reg_ to A
+ADD      M              Add indirect memory (HL) to A
+ADI      _data_         Add immediate to A
+
+ANA      _reg_          And register with A
+ANA      M              And indirect memory (HL) to A
+ANI      _data_         And immediate to A
+
+CALL     _addr_         Call subroutine at _addr_
+CC       _addr_         Call subroutine if carry set
+CNC      _addr_         Call subroutine if carry clear
+CZ       _addr_         Call subroutine if zero
+CNZ      _addr_         Call subroutine if non zero
+CP       _addr_         Call subroutine if positive
+CM       _addr_         Call subroutine if negative
+CPE      _addr_         Call subroutine if even parity
+CPO      _addr_         Call subroutine if odd  parity
+CMA                     Complement A
+CMC                     Complemennt carry
+CMP      _reg_          Compare register with A
+CMP      M              Compare indirect memory (HL) with A
+CPI      _data_         Compare immediate data with A
+
+DAA                     Decimal adjust A
+DAD      _rp_           Add register pair to HL
+DCR      _reg_          Decrement register
+DCR      M              Decrement indirect memory (HL)
+DCX      _rp_           Decrement register pair
+
+DI                      Disable interrupts
+EI                      Enable interrupts
+HLT                     Halt
+
+IN       _port_         Input on port
+INR      _reg_          Increment register
+INR      M              Increment indirect memory (HL)
+INX      _rp_           Increment register pair
+
+JMP      _addr_         Jump
+JC       _addr_         Jump if carry set
+JNC      _addr_         Jump if carry clear
+JZ       _addr_         Jump if zero
+JNZ      _addr_         Jump if not zero
+JM       _addr_         Jump if minus
+JP       _addr_         Jump if plus
+JPE      _addr_         Jump if parity even
+JPO      _addr_         Jump if parity odd
+
+LDA      _addr_         Load A direct from memory
+LDAX     B              Load A indirect from memory using BC
+LDAX     D              Load A indirect from memory using DE
+LHLD     _addr_         Load HL direct from memory
+LXI      _rp_,_data16_  Load register pair with immediate data
+
+MOV      _reg_,_reg_    Move register to register
+MOV      _reg_,M        Move indirect memory (HL) to register
+MVI      _reg_,_data_   Move immediate data to register
+
+NOP                     No operation
+
+ORA      _reg_          Or register with A
+ORA      M              Or indirect memory (HL) with A
+ORI      _data_         Or immediate data to A
+OUT      _port_         Ouput to port
+
+PCHL                    Jump to instruction at (HL)
+POP      _rp_           Pop  register pair (excluding SP) from stack
+PUSH     _rp_           Push register pair (excluding SP) onto stack
+POP      PSW            Pop  PSW from stack
+PUSH     PSW            Pop  PSW onto stack
+
+RAL                     Rotate A left  with carry
+RAR                     Rotate A right with carry
+RLC                     Rotate A left  with branch carry
+RRC                     Rotate A right with branch carry
+
+RET                     Return from subroutine
+RZ                      Return if zero
+RNZ                     Return if non zero
+RC                      Return if carry set
+RNC                     Return if carry clear
+RM                      Return if minus
+RP                      Return if plus
+RPE                     Return if parity even
+RPO                     Return if parity odd
+
+RIM                     Read interrupt mask
+RST      _int_          Restart at vector _int_
+
+SBB      _reg_          Subtract _reg_ from A         with borrow
+SBB      M              Subtract indirect memory (HL) with borrow
+SBI      _data_         Subtract immediate from A     with borrow
+SUB      _reg_          Subtract _reg_ from A
+SUB      M              Subtract indirect memory (HL) from A
+SUI      _data_         Subtract immediate from A
+
+SHLD     _addr_         Store HL
+SIM                     Store Interrupt mask
+SPHL                    Exchange SP with HL
+
+STA      _addr_         Store A direct memory
+STAX     B              Store A indirect using BC
+STAX     D              Store A indirect using DE
+
+STC                     Set carry
+
+XRA      _reg_          Exclusive OR A with register
+XRA      M              Exclusive Or A with indirect memory (HL)
+XRI      _data_         Exclusive Or A with immediate data
+XCHG                    Exchange DE with HL
+XTHL                    Exchange HL with top of stack
+
+
+

See the manufacturer's data sheets for more information. +

+
+

Z80 INSTRUCTIONS AND ADDRESSING MODES

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the Z80 version of TASM. The following +symbols are used in the table: +

+
SYMBOLIC            DESCRIPTION
+-----------------------------------------------
+_addr_              Absolute address (16 bits)
+_bit_               Bit address
+_data_              Immediate data (8 bits)
+_data16_            Immediate data (16 bits)
+_disp_              Relative address
+_reg_               Register (A, B, C, D, E, H, or L)
+_rp_                Register pair (BC, DE, HL, or SP)
+_port_              Port (0 - 255)
+_cond_              Condition
+			NZ - not zero
+			Z  - zero
+			NC - not carry
+			C  - carry
+			PO - parity odd
+			PE - parity even
+			P  - positive
+			M  - minus
+
+
+

Any valid TASM expression can appear in the place of the _addr_, _bit_, +_data_, _data16_, or _disp_ symbolics. +

+
OPCODE  OPERAND         DESCRIPTION
+--------------------------------------------------------------------
+ADC  A,_data_           Add immediate with carry to accumulator
+ADC  A,_reg_            Add register with carry to accumulator
+ADC  A,(HL)             Add indirect memory with carry to accumulator
+ADC  A,(IX+_disp_)      Add indirect memory with carry to accumulator
+ADC  A,(IY+_disp_)      Add indirect memory with carry to accumulator
+ADC  HL,_rp_            Add register pair with carry to HL
+
+ADD  A,_data_           Add immediate to accumulator
+ADD  A,_reg_            Add register to accumulator
+ADD  A,(HL)             Add indirect memory to accumulator
+ADD  A,(IX+_disp_)      Add indirect memory to accumulator
+ADD  A,(IY+_disp_)      Add indirect memory to accumulator
+ADD  HL,_rp_            Add register pair to HL
+ADD  IX,_rp_            Add register pair to index register
+ADD  IY,_rp_            Add register pair to index register
+
+AND  _data_             And immediate with accumulator
+AND  _reg_              And register  with accumulator
+AND  (HL)               And memory with accumulator
+AND  (IX+_disp_)        And memory with accumulator
+AND  (IY+_disp_)        And memory with accumulator
+
+BIT  _bit_,_reg_        Test _bit_ in register
+BIT  _bit_,(HL)         Test _bit_ in indirect memory
+BIT  _bit_,(IY+_disp_)  Test _bit_ in indirect memory
+BIT  _bit_,(IX+_disp_)  Test _bit_ in indirect memory
+
+CALL _addr_             Call the routine at _addr_
+CALL _cond_,_addr_      Call the routine if _cond_ is satisfied
+
+CCF                     Complement carry flag
+
+CP   _data_             Compare immediate data with accumulator
+CP   _reg_              Compare register with accumulator
+CP   (HL)               Compare indirect memory with accumulator
+CP   (IX+_disp_)        Compare indirect memory with accumulator
+CP   (IY+_disp_)        Compare indirect memory with accumulator
+CPD                     Compare accumulator with memory and
+                            decrement address and byte counters
+CPDR                    Compare accumulator with memory and
+                            decrement address and byte counter,
+                            continue until match is found or
+                            byte counter is zero
+
+CPI                     Compare accumulator with memory and
+                            increment address and byte counters
+CPIR                    Compare accumulator with memory and
+                            increment address and byte counter,
+                            continue until match is found or
+                            byte counter is zero
+CPL                     Complement the accumulator
+DAA                     Decimal adjust accumulator
+DEC  _reg_              Decrement register contents
+DI                      Disable interrupts
+DJNZ _disp_             Decrement reg B and jump relative if zero
+EI                      Enable interrupts
+EX   AF,AF'             Exchange program status and alt program stat
+EX   DE,HL              Exchange DE and HL contents
+EX   (SP),HL            Exchange contents of HL and top of stack
+EX   (SP),IX            Exchange contents of IX and top of stack
+EX   (SP),IY            Exchange contents of IY and top of stack
+EXX                     Exchange register pairs and alt reg pairs
+HALT                    Program execution stops
+IM   0                  Interrupt mode 0
+IM   1                  Interrupt mode 1
+IM   2                  Interrupt mode 2
+IN   A,_port_           Input port to accumulator
+INC  _reg_              Increment contents of register
+INC  _rp_               Increment contents of register pair
+INC  IX                 Increment IX
+INC  IY                 Increment IY
+INC  (HL)               Increment indirect memory
+INC  (IX+_disp_)        Increment indirect memory
+INC  (IY+_disp_)        Increment indirect memory
+IND                     Input to memory and decrement pointer
+INDR                    Input to memory and decrement pointer until
+                            byte counter is zero
+INI                     Input to memory and increment pointer
+INIR                    Input to memory and increment pointer until
+                            byte counter is zero
+IN   _reg_,(C)          Input to register
+
+JP   _addr_             Jump to location
+JP   _cond_,_addr_      Jump to location if condition satisifed
+JP   (HL)               Jump to location pointed to by HL
+JP   (IX)               Jump to location pointed to by IX
+JP   (IY)               Jump to location pointed to by IY
+
+JR   _disp_             Jump relative
+JR   C,_disp_           Jump relative if carry is set
+JR   NC,_disp_          Jump relative if carry bit is reset
+JR   NZ,_disp_          Jump relative if zero flag is reset
+JR   Z,_disp_           Jump relative if zero flag is set
+
+LD   A,I                Move interrupt vector contents to accumulator
+LD   A,R                Move refresh reg contents to accumulator
+LD   A,(_addr_)         Load accumulator indirect from memory
+LD   A,(_rp_)           Load accumulator indirect from memory by _rp_
+LD   _reg_,_reg_        Load source register to destination register
+LD   _rp_,(_addr_)      Load register pair indirect from memory
+LD   IX,(_addr_)        Load IX indirect from memory
+LD   IY,(_addr_)        Load IY indirect from memory
+LD   I,A                Load interrup vector from accumulator
+LD   R,A                Load refresh register from accumulator
+LD   _reg_,_data_       Load register with immediate data
+LD   _rp_,_data16_      Load register pair with immediate data
+LD   IX,_data16_        Load  IX  with immediate data
+LD   IY,_data16_        Load  IY  with immediate data
+LD   _reg_,(HL)         Load register indirect from memory
+LD   _reg_,(IX+_disp_)  Load register indirect from memory
+LD   _reg_,(IY+_disp_)  Load register indirect from memory
+LD   SP,HL              Load contents of HL to stack pointer
+LD   SP,IX              Load contents of IX to stack pointer
+LD   SP,IY              Load contents of IY to stack pointer
+LD   (addr),A           Load contents of A to memory
+LD   (_addr_),HL        Load contents of HL to memory
+LD   (_addr_),_rp_      Load contents of register pair to memory
+LD   (_addr_),IX        Load contents of IX to memory
+LD   (_addr_),IY        Load contents of IY to memory
+LD   (HL),_data_        Load immediate into indirect memory
+LD   (IX+_disp_),_data_ Load immediate into indirect memory
+LD   (IY+_disp_),_data_ Load immediate into indirect memory
+LD   (HL),_reg_         Load register  into indirect memory
+LD   (IX+_disp_),_reg_  Load register  into indirect memory
+LD   (IY+_disp_),_reg_  Load register  into indirect memory
+LD   (_rp_),A           Load accumulator into indirect memory
+LDD                     Transfer data between memory and decrement
+                            destination and source addresses
+LDDR                    Transfer data between memory until byte
+                            counter is zero, decrement destintation
+                            and source addresses
+LDI                     Transfer data between memory and increment
+                            destination and source addresses
+LDIR                    Transfer data between memory until byte
+                            counter is zero, increment destination
+                            and source addresses
+NEG                     Negate contents of accumulator
+NOP                     No operation
+OR   _data_             Or immediate with accumulator
+OR   _reg_              Or register with accumulator
+OR   (HL)               Or indirect memory with accumulator
+OR   (IX+_disp_)        Or indirect memory with accumulator
+OR   (IY+_disp_)        Or indirect memory with accumulator
+OUT  (C),_reg_          Output from registor
+OUTD                    Output from memory, decrement address
+OTDR                    Output from memory, decrement address
+                            continue until reg B is zero
+OUTI                    Output from memory, increment address
+OTIR                    Output from memory, increment address
+                            continue until reg B is zero
+OUT  _port_,A           Output from accumulator
+POP  _rp_               Load register pair from top of stack
+POP  IX                 Load IX from top of stack
+POP  IY                 Load IY from top of stack
+PUSH _rp_               Store resister pair on top of stack
+PUSH IX                 Store IX on top of stack
+PUSH IY                 Store IY on top of stack
+RES  _bit_,_reg_        Reset register bit
+RES  _bit_,(HL)         Reset bit at indirect memory location
+RES  _bit_,(IX+disp)    Reset bit at indirect memory location
+RES  _bit_,(IY+_disp_)  Reset bit at indirect memory location
+RET                     Return from subroutine
+RET  _cond_             Return from subroutine if condition true
+RETI                    Return from interrupt
+RETN                    Return from non-maskable interrupt
+RL   _reg_              Rotate left through carry register contents
+RL   (HL)               Rotate left through carry indirect memory
+RL   (IX+_disp_)        Rotate left through carry indirect memory
+RL   (IY+_disp_)        Rotate left through carry indirect memory
+RLA                     Rotate left through carry accumulator
+RLC  _reg_              Rotate left branch  carry register contents
+RLC  (HL)               Rotate left branch  carry indirect memory
+RLC  (IX+_disp_)        Rotate left branch  carry indirect memory
+RLC  (IY+_disp_)        Rotate left branch  carry indirect memory
+RLCA                    Rotate left accumulator
+RLD                     Rotate one BCD digit left between the
+                            accumulator and memory
+RR   _reg_              Rotate right through carry register contents
+RR   (HL)               Rotate right through carry indirect memory
+RR   (IX+_disp_)        Rotate right through carry indirect memory
+RR   (IY+_disp_)        Rotate right through carry indirect memory
+RRA                     Rotate right through carry accumulator
+RRC  _reg_              Rotate right branch  carry register contents
+RRC  (HL)               Rotate right branch  carry indirect memory
+RRC  (IX+_disp_)        Rotate right branch  carry indirect memory
+RRC  (IY+_disp_)        Rotate right branch  carry indirect memory
+RRCA                    Rotate right branch  carry accumulator
+RRD                     Rotate one BCD digit right between the
+                            accumulator and memory
+RST                     Restart
+SBC  A,_data_           Subtract data            from A with borrow
+SBC  A,_reg_            Subtract register        from A with borrow
+SBC  A,(HL)             Subtract indirect memory from A with borrow
+SBC  A,(IX+_disp_)      Subtract indirect memory from A with borrow
+SBC  A,(IY+_disp_)      Subtract indirect memory from A with borrow
+SBC  HL,_rp_            Subtract register pair from HL with borrow
+SCF                     Set carry flag
+SET  _bit_,_reg_        Set register bit
+SET  _bit_,(HL)         Set indirect memory bit
+SET  _bit_,(IX+_disp_)  Set indirect memory bit
+SET  _bit_,(IY+_disp_)  Set indirect memory bit
+SLA  _reg_              Shift register left arithmetic
+SLA  (HL)               Shift indirect memory left arithmetic
+SLA  (IX+_disp_)        Shift indirect memory left arithmetic
+SLA  (IY+_disp_)        Shift indirect memory left arithmetic
+SRA  _reg_              Shift register right arithmetic
+SRA  (HL)               Shift indirect memory right arithmetic
+SRA  (IX+_disp_)        Shift indirect memory right arithmetic
+SRA  (IY+_disp_)        Shift indirect memory right arithmetic
+SRL  _reg_              Shift register right logical
+SRL  (HL)               Shift indirect memory right logical
+SRL  (IX+_disp_)        Shift indirect memory right logical
+SRL  (IY+_disp_)        Shift indirect memory right logical
+SUB  _data_             Subtract immediate from accumulator
+SUB  _reg_              Subtract register from accumulator
+SUB  (HL)               Subtract indirect memory from accumulator
+SUB  (IX+_disp_)        Subtract indirect memory from accumulator
+SUB  (IY+_disp_)        Subtract indirect memory from accumulator
+XOR  _data_             Exclusive or immediate with accumulator
+XOR  _reg_              Exclusive or register with accumulator
+XOR  (HL)               Exclusive or indirect memory with accumulator
+XOR  (IX+_disp_)        Exclusive or indirect memory with accumulator
+XOR  (IY+_disp_)        Exclusive or indirect memory with accumulator
+
+

See the manufacturer's data sheets for more information. +

+
+

6805 INSTRUCTIONS AND ADDRESSING MODES

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the 6805 version of TASM. The following +symbols are used in the table: +

+
SYMBOLIC            DESCRIPTION
+-----------------------------------------------
+_addr_              Absolute address (16 bits)
+_addr8_             Absolute address (8 bits)
+_bit_               Bit address
+_data_              Immediate data (8 bits)
+_rel_               Relative address
+
+
+

Any valid TASM expression can appear in the place of the _addr_, _addr8_, +_bit_, _data_, or _rel_ symbolics. +

+
OPCODE  OPERAND         DESCRIPTION
+--------------------------------------------------------------
+ADC     #_data_         Add with carry, immediate
+ADC     ,X              Add with carry, indexed, no offset
+ADC     _addr8_,X       Add with carry, indexed, 1 byte offset
+ADC     _addr_,X        Add with carry, indexed, 2 byte offset
+ADC     _addr8_         Add with carry, direct
+ADC     _addr_          Add with carry, extended
+
+ADD     #_data_         Add, immediate
+ADD     ,X              Add, indexed, no offset
+ADD     _addr8_,X       Add, indexed, 1 byte offset
+ADD     _addr_,X        Add, indexed, 2 byte offset
+ADD     _addr8_         Add, direct
+ADD     _addr_          Add, extended
+
+AND     #_data_         And, immediate
+AND     ,X              And, indexed, no offset
+AND     _addr8_,X       And, indexed, 1 byte offset
+AND     _addr_,X        And, indexed, 2 byte offset
+AND     _addr8_         And, direct
+AND     _addr_          And, extended
+
+ASLA                    Arithmetic Shift Left, accumulator
+ASLX                    Arithmetic Shift Left, index register
+ASL     _addr8_         Arithmetic Shift Left, direct
+ASL     ,X              Arithmetic Shift Left, indexed, no offset
+ASL     _addr8_,X       Arithmetic Shift Left, indexed, 1 byte offset
+
+ASRA                    Arithmetic Shift Right, accumulator
+ASRX                    Arithmetic Shift Right, index register
+ASR     _addr8_         Arithmetic Shift Right, direct
+ASR     ,X              Arithmetic Shift Right, indexed, no offset
+ASR     _addr8_,X       Arithmetic Shift Right, indexed, 1 byte offset
+
+BCC     _rel_           Branch if carry clear
+BCLR    _bit_,_addr8_   Bit Clear in memory
+BCS     _rel_           Branch if carry set
+BEQ     _rel_           Branch if equal
+BHCC    _rel_           Branch if half carry clear
+BHCS    _rel_           Branch if half carry set
+BHI     _rel_           Branch if higher
+BHS     _rel_           Branch if higher or same
+BIH     _rel_           Branch if interrupt line is high
+BIL     _rel_           Branch if interrupt is low
+
+BIT     #_data_         Bit test, immediate
+BIT     ,X              Bit test, indexed, no offset
+BIT     _addr8_,X       Bit test, indexed, 1 byte offset
+BIT     _addr_,X        Bit test, indexed, 2 byte offset
+BIT     _addr8_         Bit test, direct
+BIT     _addr_          Bit test, extended
+
+BLO     _rel_           Branch if lower
+BLS     _rel_           Branch if lower or same
+BMC     _rel_           Branch if interrupt mask is clear
+BMI     _rel_           Branch if minus
+BMS     _rel_           Branch if interuupt mask bit is set
+BNE     _rel_           Branch if not equal
+BPL     _rel_           Branch if plus
+BRA     _rel_           Branch always
+BRCLR   _bit_,_addr8_,_rel_     Branch if bit is clear
+BRN     _rel_           Branch never
+BRSET   _bit_,_addr8_,_rel_     Branch if bit is set
+BSET    _bit_,_addr8_   Bit set in memory
+BSR     _rel_           Branch to subroutine
+
+CLC                     Clear carry bit
+CLI                     Clear interuupt mask bit
+
+CLRA                    Clear, accumulator
+CLRX                    Clear, index register
+CLR     _addr8_         Clear, direct
+CLR     ,X              Clear, indexed, no offset
+CLR     _addr8_,X       Clear, indexed, 1 byte offset
+
+CMP     #_data_         Compare Acc, immediate
+CMP     ,X              Compare Acc, indexed, no offset
+CMP     _addr8_,X       Compare Acc, indexed, 1 byte offset
+CMP     _addr_,X        Compare Acc, indexed, 2 byte offset
+CMP     _addr8_         Compare Acc, direct
+CMP     _addr_          Compare Acc, extended
+
+COMA                    Complement, accumulator
+COMX                    Complement, index register
+COM     _addr8_         Complement, direct
+COM     ,X              Complement, indexed, no offset
+COM     _addr8_,X       Complement, indexed, 1 byte offset
+
+CPX     #_data_         Compare Index, immediate
+CPX     ,X              Compare Index, indexed, no offset
+CPX     _addr8_,X       Compare Index, indexed, 1 byte offset
+CPX     _addr_,X        Compare Index, indexed, 2 byte offset
+CPX     _addr8_         Compare Index, direct
+CPX     _addr_          Compare Index, extended
+
+DECA                    Decrement, accumulator
+DECX                    Decrement, index register
+DEX                     Decrement, index register (alternate of DECX)
+DEC     _addr8_         Decrement, direct
+DEC     ,X              Decrement, indexed, no offset
+DEC     _addr8_,X       Decrement, indexed, 1 byte offset
+
+EOR     #_data_         Exclusive OR, immediate
+EOR     ,X              Exclusive OR, indexed, no offset
+EOR     _addr8_,X       Exclusive OR, indexed, 1 byte offset
+EOR     _addr_,X        Exclusive OR, indexed, 2 byte offset
+EOR     _addr8_         Exclusive OR, direct
+EOR     _addr_          Exclusive OR, extended
+
+INCA                    Increment, accumulator
+INCX                    Increment, index register
+INX                     Increment, index register (alternate of INCX)
+INC     _addr8_         Increment, direct
+INC     ,X              Increment, indexed, no offset
+INC     _addr8_,X       Increment, indexed, 1 byte offset
+
+JMP     ,X              Jump, indexed, no offset
+JMP     _addr8_,X       Jump, indexed, 1 byte offset
+JMP     _addr_,X        Jump, indexed, 2 byte offset
+JMP     _addr8_         Jump, direct
+JMP     _addr_          Jump, extended
+
+JSR     ,X              Jump Subroutine, indexed, no offset
+JSR     _addr8_,X       Jump Subroutine, indexed, 1 byte offset
+JSR     _addr_,X        Jump Subroutine, indexed, 2 byte offset
+JSR     _addr8_         Jump Subroutine, direct
+JSR     _addr_          Jump Subroutine, extended
+
+LDA     #_data_         Load Acc, immediate
+LDA     ,X              Load Acc, indexed, no offset
+LDA     _addr8_,X       Load Acc, indexed, 1 byte offset
+LDA     _addr_,X        Load Acc, indexed, 2 byte offset
+LDA     _addr8_         Load Acc, direct
+LDA     _addr_          Load Acc, extended
+
+LDX     #_data_         Load Index, immediate
+LDX     ,X              Load Index, indexed, no offset
+LDX     _addr8_,X       Load Index, indexed, 1 byte offset
+LDX     _addr_,X        Load Index, indexed, 2 byte offset
+LDX     _addr8_         Load Index, direct
+LDX     _addr_          Load Index, extended
+
+LSLA                    Logical Shift Left, accumulator
+LSLX                    Logical Shift Left, index register
+LSL     _addr8_         Logical Shift Left, direct
+LSL     ,X              Logical Shift Left, indexed, no offset
+LSL     _addr8_,X       Logical Shift Left, indexed, 1 byte offset
+
+LSRA                    Logical Shift Right, accumulator
+LSRX                    Logical Shift Right, index register
+LSR     _addr8_         Logical Shift Right, direct
+LSR     ,X              Logical Shift Right, indexed, no offset
+LSR     _addr8_,X       Logical Shift Right, indexed, 1 byte offset
+
+NEGA                    Negate, accumulator
+NEGX                    Negate, index register
+NEG     _addr8_         Negate, direct
+NEG     ,X              Negate, indexed, no offset
+NEG     _addr8_,X       Negate, indexed, 1 byte offset
+
+NOP                     No Operation
+
+ORA     #_data_         Inclusive OR Acc, immediate
+ORA     ,X              Inclusive OR Acc, indexed, no offset
+ORA     _addr8_,X       Inclusive OR Acc, indexed, 1 byte offset
+ORA     _addr_,X        Inclusive OR Acc, indexed, 2 byte offset
+ORA     _addr8_         Inclusive OR Acc, direct
+ORA     _addr_          Inclusive OR Acc, extended
+
+ROLA                    Rotate Left thru Carry, accumulator
+ROLX                    Rotate Left thru Carry, index register
+ROL     _addr8_         Rotate Left thru Carry, direct
+ROL     ,X              Rotate Left thru Carry, indexed, no offset
+ROL     _addr8_,X       Rotate Left thru Carry, indexed, 1 byte offset
+
+RORA                    Rotate Right thru Carry, accumulator
+RORX                    Rotate Right thru Carry, index register
+ROR     _addr8_         Rotate Right thru Carry, direct
+ROR     ,X              Rotate Right thru Carry, indexed, no offset
+ROR     _addr8_,X       Rotate Right thru Carry, indexed, 1 byte offset
+
+RSP                     Reset Stack Pointer
+RTI                     Return from Interrupt
+RTS                     Return from Subroutine
+
+SBC     #_data_         Subtract with Carry, immediate
+SBC     ,X              Subtract with Carry, indexed, no offset
+SBC     _addr8_,X       Subtract with Carry, indexed, 1 byte offset
+SBC     _addr_,X        Subtract with Carry, indexed, 2 byte offset
+SBC     _addr8_         Subtract with Carry, direct
+SBC     _addr_          Subtract with Carry, extended
+
+SEC                     Set carry bit
+SEI                     Set interrupt Mask bit
+
+STA     #_data_         Store Acc, immediate
+STA     ,X              Store Acc, indexed, no offset
+STA     _addr8_,X       Store Acc, indexed, 1 byte offset
+STA     _addr_,X        Store Acc, indexed, 2 byte offset
+STA     _addr8_         Store Acc, direct
+STA     _addr_          Store Acc, extended
+
+STOP                    Enable IRQ, Stop Oscillator
+
+STX     #_data_         Store Index, immediate
+STX     ,X              Store Index, indexed, no offset
+STX     _addr8_,X       Store Index, indexed, 1 byte offset
+STX     _addr_,X        Store Index, indexed, 2 byte offset
+STX     _addr8_         Store Index, direct
+STX     _addr_          Store Index, extended
+
+SUB     #_data_         Subtract, immediate
+SUB     ,X              Subtract, indexed, no offset
+SUB     _addr8_,X       Subtract, indexed, 1 byte offset
+SUB     _addr_,X        Subtract, indexed, 2 byte offset
+SUB     _addr8_         Subtract, direct
+SUB     _addr_          Subtract, extended
+
+SWI                     Software Interrupt
+
+TAX                     Transfer Acc to Index
+
+TSTA                    Test for neg or zero, accumulator
+TSTX                    Test for neg or zero, index register
+TST     _addr8_         Test for neg or zero, direct
+TST     ,X              Test for neg or zero, indexed, no offset
+TST     _addr8_,X       Test for neg or zero, indexed, 1 byte offset
+
+TXA                     Transfer Index to Acc
+
+WAIT                    Enable Interrupt, Stop Processor
+
+
+

See the manufacturer's data sheets for more information. +

+
+

TMS32010 INSTRUCTIONS AND ADDRESSING MODES

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the TMS32010 version of TASM. The following +symbols are used in the table: +

+
SYMBOLIC            DESCRIPTION
+-----------------------------------------------
+_ar_                Auxiliary register (AR0, AR1)
+_arp_               Auxiliary register pointer
+_dma_               Direct memory address
+_pma_               Program memory address
+_port_              Port address (0 - 7)
+_shift_             Shift count  (0 - 15)
+_const1_            Constant (1 bit)
+_const8_            Constant (8 bit)
+_const13_           Constant (13 bit)
+
+
+

Any valid TASM expression can appear in the place of any of the above +symbolics. +

+
OPCODE   OPERAND            DESCRIPTION
+--------------------------------------------------------------------
+ABS                         Absolute value of ACC
+
+ADD      *+,_shift_,_arp_   Add to ACC with shift
+ADD      *-,_shift_,_arp_
+ADD      *, _shift_,_arp_
+ADD      *+,_shift_
+ADD      *-,_shift_
+ADD      *, _shift_
+ADD      *+
+ADD      *-
+ADD      *
+ADD      _dma_,_shift_
+ADD      _dma_
+
+ADDH     *+,_arp_           Add to high-order ACC bits
+ADDH     *-,_arp_
+ADDH     *, _arp_
+ADDH     *+
+ADDH     *-
+ADDH     *
+ADDH     _dma_
+
+ADDS     *+,_arp_           Add to ACC with no sign extension
+ADDS     *-,_arp_
+ADDS     *, _arp_
+ADDS     *+
+ADDS     *-
+ADDS     *
+ADDS     _dma_
+
+AND      *+,_arp_           AND with ACC
+AND      *-,_arp_
+AND      *, _arp_
+AND      *+
+AND      *-
+AND      *
+AND      _dma_
+
+APAC                        Add P register to ACC
+
+B        _pma_              Branch unconditionally
+BANZ     _pma_              Branch on auxiliary register not zero
+BGEZ     _pma_              Branch if ACC >= 0
+BGZ      _pma_              Branch if ACC >  0
+BIOZ     _pma_              Branch on BIO- = 0
+BLEZ     _pma_              Branch if ACC <= 0
+BLZ      _pma_              Branch if ACC <  0
+BNZ      _pma_              Branch if ACC 
+
 0
+BV       _pma_              Branch on overflow
+BZ       _pma_              Branch if ACC =  0
+
+CALA                        Call subroutine from ACC
+CALL     _pma_              Call subroutine at _pma_
+
+DINT                        Disable interrupt
+
+DMOV     *+,_arp_           Data move in memory
+DMOV     *-,_arp_
+DMOV     *, _arp_
+DMOV     *+
+DMOV     *-
+DMOV     *
+DMOV     _dma_
+
+EINT                        Enable Interrupt
+
+IN       *+,_port_ ,_arp_   Input data from port
+IN       *-,_port_ ,_arp_
+IN       * ,_port_ ,_arp_
+IN       *+,_port_
+IN       *-,_port_
+IN       * ,_port_
+IN       _dma_,_port_
+
+LAC      *+,_shift_,_arp_   Load ACC with shift
+LAC      *-,_shift_,_arp_
+LAC      *, _shift_,_arp_
+LAC      *+,_shift_
+LAC      *-,_shift_
+LAC      *, _shift_
+LAC      *+
+LAC      *-
+LAC      *
+LAC      _dma_,_shift_
+LAC      _dma_
+
+LACK     _const8_                   Load ACC with 8 bit constant
+
+LAR      _ar_,*+,_arp_              Load auxiliary Register
+LAR      _ar_,*-,_arp_
+LAR      _ar_,*, _arp_
+LAR      _ar_,*+
+LAR      _ar_,*-
+LAR      _ar_,*
+LAR      _ar_,_dma_
+
+LARK     _ar_,_const8_              Load aux register with constant
+LARP     _const1_                   Load aux register pointer immed
+
+LDP      *+,_arp_                   Load data memory page pointer
+LDP      *-,_arp_
+LDP      *, _arp_
+LDP      *+
+LDP      *-
+LDP      *
+LDP      _dma_
+
+LDPK     _const1_                   Load data page pointer immediate
+
+LST      *+,_arp_                   Load status from data memory
+LST      *-,_arp_
+LST      *, _arp_
+LST      *+
+LST      *-
+LST      *
+LST      _dma_
+
+LT       *+,_arp_                   Load T register
+LT       *-,_arp_
+LT       *, _arp_
+LT       *+
+LT       *-
+LT       *
+LT       _dma_
+
+LTA      *+,_arp_                   Load T register and accumulate
+LTA      *-,_arp_                     product
+LTA      *, _arp_
+LTA      *+
+LTA      *-
+LTA      *
+LTA      _dma_
+
+LTD      *+,_arp_                   Load T reg, accumulate product,
+LTD      *-,_arp_                     and move
+LTD      *, _arp_
+LTD      *+
+LTD      *-
+LTD      *
+LTD      _dma_
+
+MAR      *+,_arp_                   Modify auxiliary register
+MAR      *-,_arp_
+MAR      *, _arp_
+MAR      *+
+MAR      *-
+MAR      *
+MAR      _dma_
+
+MPY      *+,_arp_                   Multiply
+MPY      *-,_arp_
+MPY      *, _arp_
+MPY      *+
+MPY      *-
+MPY      *
+MPY      _dma_
+
+MPYK     _const13_                  Multiply immediate
+
+NOP                                 No Operation
+
+OR       *+,_arp_                   OR  with low order bits of ACC
+OR       *-,_arp_
+OR       *, _arp_
+OR       *+
+OR       *-
+OR       *
+OR       _dma_
+
+OUT      *+,_port_,_arp_            Output data to port
+OUT      *-,_port_,_arp_
+OUT      *, _port_,_arp_
+OUT      *+,_port_
+OUT      *-,_port_
+OUT      *, _port_
+OUT      _dma_,_port_
+
+PAC                                 Load ACC with P register
+POP                                 Pop top of stack to ACC
+PUSH                                Push ACC onto stack
+RET                                 Return from subroutine
+ROVM                                Reset overflow mode register
+
+SACH     *+,_shift_,_arp_           Store ACC high with shift
+SACH     *-,_shift_,_arp_             Note: shift can only be 0, 1,
+SACH     *, _shift_,_arp_                   or 4
+SACH     *+,_shift_
+SACH     *-,_shift_
+SACH     *, _shift_
+SACH     *+
+SACH     *-
+SACH     *
+SACH     _dma_,_shift_
+SACH     _dma_
+
+SACL     *+,_arp_                   Store ACC low
+SACL     *-,_arp_
+SACL     *, _arp_
+SACL     *+
+SACL     *-
+SACL     *
+SACL     _dma_
+
+SAR      _ar_,*+,_arp_              Store auxiliary Register
+SAR      _ar_,*-,_arp_
+SAR      _ar_,*, _arp_
+SAR      _ar_,*+
+SAR      _ar_,*-
+SAR      _ar_,*
+SAR      _ar_,_dma_
+
+SOVM                                Set overflow mode register
+SPAC                                Subtract P register from ACC
+
+SST      *+,_arp_                   Store status
+SST      *-,_arp_
+SST      *, _arp_
+SST      *+
+SST      *-
+SST      *
+SST      _dma_
+
+SUB      *+,_shift_,_arp_           Subtract from ACC with shift
+SUB      *-,_shift_,_arp_
+SUB      *, _shift_,_arp_
+SUB      *+,_shift_
+SUB      *-,_shift_
+SUB      *, _shift_
+SUB      *+
+SUB      *-
+SUB      *
+SUB      _dma_,_shift_
+SUB      _dma_
+
+SUBC     *+,_arp_                   Conditional subtract
+SUBC     *-,_arp_
+SUBC     *, _arp_
+SUBC     *+
+SUBC     *-
+SUBC     *
+SUBC     _dma_
+
+SUBH     *+,_arp_                   Subtract from high-order ACC
+SUBH     *-,_arp_
+SUBH     *, _arp_
+SUBH     *+
+SUBH     *-
+SUBH     *
+SUBH     _dma_
+
+SUBS     *+,_arp_                   Subtract from low ACC with
+SUBS     *-,_arp_                     sign-extension suppressed
+SUBS     *, _arp_
+SUBS     *+
+SUBS     *-
+SUBS     *
+SUBS     _dma_
+
+TBLR     *+,_arp_                   Table Read
+TBLR     *-,_arp_
+TBLR     *, _arp_
+TBLR     *+
+TBLR     *-
+TBLR     *
+TBLR     _dma_
+
+TBLW     *+,_arp_                   Table Write
+TBLW     *-,_arp_
+TBLW     *, _arp_
+TBLW     *+
+TBLW     *-
+TBLW     *
+TBLW     _dma_
+
+XOR      *+,_arp_                   Exclusive OR with low bits of ACC
+XOR      *-,_arp_
+XOR      *, _arp_
+XOR      *+
+XOR      *-
+XOR      *
+XOR      _dma_
+
+ZAC                                 Zero the ACC
+
+ZALH     *+,_arp_                   Zero ACC and load high
+ZALH     *-,_arp_
+ZALH     *, _arp_
+ZALH     *+
+ZALH     *-
+ZALH     *
+ZALH     _dma_
+
+ZALS     *+,_arp_                   Zero ACC and load low with
+ZALS     *-,_arp_                     sign extension suppressed
+ZALS     *, _arp_
+ZALS     *+
+ZALS     *-
+ZALS     *
+ZALS     _dma_
+
+

See manufacturer's data for more information. +

+
+

TMS32025 INSTRUCTIONS AND ADDRESSING MODES

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the TMS32025 version of TASM. The following +symbols are used in the table: +

+
SYMBOLIC            DESCRIPTION
+-----------------------------------------------
+_ar_                Auxiliary register (AR0, AR1, ...)
+_arp_               Auxiliary register pointer
+_nextarp_           Auxiliary register pointer (for next operation)
+_dma_               Direct memory address
+_pma_               Program memory address
+_port_              Port address (0 - 7)
+_shift_             Shift count  (0 - 15)
+_const1_            Constant (1 bit)
+_const2_            Constant (2 bit)
+_const8_            Constant (8 bit)
+_const13_           Constant (13 bit)
+_ind_               Indirect addressing mode indicator
+                      (see following table)
+
+
+

Any valid TASM expression can appear in the place of any of the above +symbolics except for _ind_. The _ind_ symbolic must be one of the following: +

+
        
+_ind_
+-------
+*BR0+
+*BR0-
+*0+
+*0-
+*+
+*-
+*
+
+OPCODE   OPERAND                DESCRIPTION
+--------------------------------------------------------------------
+ABS                             Absolute value of ACC
+
+ADD  _ind_,_shift_,_nextarp_    Add to ACC with shift
+ADD  _ind_,_shift_
+ADD  _ind_
+ADD  _dma_,_shift_
+ADD  _dma_
+
+ADDC _ind_,_nextarp_            Add to ACC with carry
+ADDC _ind_
+ADDC _dma_
+
+ADDH _ind_,_nextarp_            Add to high ACC
+ADDH _ind_
+ADDH _dma_
+
+ADDK _const8_                   Add to ACC short immediate
+ADDS _ind_,_nextarp_            Add to ACC with sign-extension suppressed
+ADDS _ind_
+ADDS _dma_
+
+ADDT _ind_,_nextarp_            Add to ACC with shift specified by T reg
+ADDT _ind_
+ADDT _dma_
+
+ADLK _const8_,_shift_           Add to ACC long immediate with shift
+ADLK _const8_
+
+ADRK _const8_                   Add to aux register short immediate
+
+AND  _ind_,_nextarp_            And with ACC
+AND  _ind_
+AND  _dma_
+
+ANDK _const8_,_shift_           And immediate with ACC with shift
+ANDK _const8_
+
+APAC                            Add P register to ACC
+
+B    _pma_,_ind_,_nextarp_      Branch unconditionally
+B    _pma_,_ind_
+B    _pma_
+
+BACC                            Branch to address specified by ACC
+
+BANZ _pma_,_ind_,_nextarp_      Branch on Aux register not zero
+BANZ _pma_,_ind_
+BANZ _pma_
+
+BBNZ _pma_,_ind_,_nextarp_      Branch on TC bit not zero
+BBNZ _pma_,_ind_
+BBNZ _pma_
+
+BBZ  _pma_,_ind_,_nextarp_      Branch on TC bit equal to zero
+BBZ  _pma_,_ind_
+BBZ  _pma_
+
+BC   _pma_,_ind_,_nextarp_      Branch on carry
+BC   _pma_,_ind_
+BC   _pma_
+
+BGEZ _pma_,_ind_,_nextarp_      Branch if ACC >= zero
+BGEZ _pma_,_ind_
+BGEZ _pma_
+
+BGZ  _pma_,_ind_,_nextarp_      Branch if ACC > zero
+BGZ  _pma_,_ind_
+BGZ  _pma_
+
+BIOZ _pma_,_ind_,_nextarp_      Branch on I/O status = zero
+BIOZ _pma_,_ind_
+BIOZ _pma_
+
+BIT  _ind_,_bitcode_,_nextarp_  Test bit
+BIT  _ind_,_bitcode_
+BIT  _dma_,_bitcode_
+
+BITT _ind_,_nextarp_            Test bit specified by T register
+BITT _ind_
+BITT _dma_
+
+BLEZ _pma_,_ind_,_nextarp_      Branch if ACC <= zero
+BLEZ _pma_,_ind_
+BLEZ _pma_
+
+BLKD _dma_,_ind_,_nextarp_      Block move from data mem to data mem
+BLKD _dma_,_ind_
+BLKD _dma_,_dma_
+
+BLKP _pma_,_ind_,_nextarp_      Block move from prog mem to data mem
+BLKP _pma_,_ind_
+BLKP _pma_,_dma_
+
+BLZ  _pma_,_ind_,_nextarp_      Branch if ACC < zero
+BLZ  _pma_,_ind_
+BLZ  _pma_
+
+BNC  _pma_,_ind_,_nextarp_      Branch on no carry
+BNC  _pma_,_ind_
+BNC  _pma_
+
+BNV  _pma_,_ind_,_nextarp_      Branch if no overflow
+BNV  _pma_,_ind_
+BNV  _pma_
+
+BNZ  _pma_,_ind_,_nextarp_      Branch if ACC 
+
 zero
+BNZ  _pma_,_ind_
+BNZ  _pma_
+
+BV   _pma_,_ind_,_nextarp_      Branch on overflow
+BV   _pma_,_ind_
+BV   _pma_
+
+BZ   _pma_,_ind_,_nextarp_      Branch if ACC = zero
+BZ   _pma_,_ind_
+BZ   _pma_
+
+CALA                            Call subroutine indirect
+
+CALL _pma_,_ind_,_nextarp_      Call subroutine
+CALL _pma_,_ind_
+CALL _pma_
+
+CMPL                            Complement ACC
+CMPR _const2_                   Compare Aux reg with Aux AR0
+CNFD                            Configure block as data memory
+CNFP                            Configure block as program memory
+CONF _const2_                   Configure block as data/prog memory
+DINT                            Disable interrupt
+
+DMOV _ind_,_nextarp_            Data move in data memory
+DMOV _ind_
+DMOV _dma_
+
+EINT                            Enable interrupt
+
+FORT _const1_                   Format serial port registers
+
+IDLE                            Idle until interrupt
+
+IN   _ind_,_port_,_nextarp_     Input data from port
+IN   _ind_,_port_
+IN   _dma_,_port_
+
+LAC  _ind_,_shift_,_nextarp_    Load ACC with shift
+LAC  _ind_,_shift_
+LAC  _ind_
+LAC  _dma_,_shift_
+LAC  _dma_
+
+LACK _const8_                   Load ACC immediate short
+
+LACT _ind_,_nextarp_            Load ACC with shift specified by T reg
+LACT _ind_
+LACT _dma_
+
+LALK _const16_,_shift_          Load ACC long immediate with shift
+LALK _const16_
+
+LAR  _ar_,_ind_,_nextarp_       Load auxilary register
+LAR  _ar_,_ind_
+LAR  _ar_,_dma_
+
+LARK _ar_,_const8_              Load auxilary register immediate short
+
+LARP _arp_                      Load auxilary register pointer
+
+LDP  _ind_,_nextarp_            Load data memory page pointer
+LDP  _ind_
+LDP  _dma_
+
+LDPK _const8_                   Load data memory page pointer immediate
+
+LPH  _ind_,_nextarp_            Load high P register
+LPH  _ind_
+LPH  _dma_
+
+LRLK _ar_,_const16_             Load auxilary register long immediate
+
+LST  _ind_,_nextarp_            Load status register ST0
+LST  _ind_
+LST  _dma_
+
+LST1 _ind_,_nextarp_            Load status register ST1
+LST1 _ind_
+LST1 _dma_
+
+LT   _ind_,_nextarp_            Load T register
+LT   _ind_
+LT   _dma_
+
+LTA  _ind_,_nextarp_            Load T reg and accumulate prev product
+LTA  _ind_
+LTA  _dma_
+
+LTD  _ind_,_nextarp_            Load T reg, accum prev product & move
+LTD  _ind_
+LTD  _dma_
+
+LTP  _ind_,_nextarp_            Load T reg and store P in ACC
+LTP  _ind_
+LTP  _dma_
+
+LTS  _ind_,_nextarp_            Load T reg, subract previous product
+LTS  _ind_
+LTS  _dma_
+
+MAC  _pma_,_ind_,_nextarp_      Multiply and accumulate
+MAC  _pma_,_ind_
+MAC  _pma_,_dma_
+
+MACD _pma_,_ind_,_nextarp_      Multiply and accumulate with data move
+MACD _pma_,_ind_
+MACD _pma_,_dma_
+
+MAR  _ind_,_nextarp_            Modify auxiliary register
+MAR  _ind_
+MAR  _dma_
+
+MPY  _ind_,_nextarp_            Multiply
+MPY  _ind_
+MPY  _dma_
+
+MPYA _ind_,_nextarp_            Multiply and accum previous product
+MPYA _ind_
+MPYA _dma_
+
+MPYK _const13_                  Multiply immediate
+
+MPYS _ind_,_nextarp_            Multiply and subtract previous product
+MPYS _ind_
+MPYS _dma_
+
+MPYU _ind_,_nextarp_            Multiply unsigned
+MPYU _ind_
+MPYU _dma_
+
+NEG                             Negate ACC
+
+NOP                             No operation
+
+NORM _ind_                      Normalize contents of ACC
+NORM
+
+OR   _ind_,_nextarp_            Or with ACC
+OR   _ind_
+OR   _dma_
+
+ORK  _dma_,_shift_              Or immediate with ACC with shift
+ORK  _dma_
+
+OUT  _ind_,_shift_,_nextarp_    Output data to port
+OUT  _ind_,_shift_
+OUT  _dma_,_shift_
+
+PAC                             Load ACC with P register
+
+POP                             Pop top of stack to low ACC
+
+POPD _ind_,_nextarp_            Pop top of stack to data memory
+POPD _ind_
+POPD _dma_
+
+PSHD _ind_,_nextarp_            Push data memory value onto stack
+PSHD _ind_
+PSHD _dma_
+
+PUSH                            Push low ACC onto stack
+RC                              Reset carry bit
+RET                             Return from subroutine
+RFSM                            Reset serial port frame syn mode
+RHM                             Reset hold mode
+ROL                             Rotate ACC left
+ROR                             Rotate ACC right
+ROVM                            Reset overflow mode
+
+RPT  _ind_,_nextarp_            Repeat instructions as per data mem
+RPT  _ind_
+RPT  _dma_
+
+RPTK _const8_                   Repeat instructions as per immediate
+
+RSXM                            Reset sign extension mode
+RTC                             Reset test control flag
+RTXM                            Reset serial port transmit mode
+RXF                             Reset external flag
+
+SACH _ind_,_shift_,_nextarp_    Store high ACC with shift
+SACH _ind_,_shift_
+SACH _ind_
+SACH _dma_,_shift_
+SACH _dma_
+
+SACL _ind_,_shift_,_nextarp_    Store low ACC with shift
+SACL _ind_,_shift_
+SACL _ind_
+SACL _dma_,_shift_
+SACL _dma_
+
+SAR  _ar_,_ind_,_nextarp_       Store AUX register
+SAR  _ar_,_ind_
+SAR  _ar_,_dma_
+
+SBLK _const16_,_shift_          Subtract from ACC long immediate with shift
+SBLK _const16_
+
+SBRK _const8_                   Subtract from AUX register short immediate
+
+SC                              Set carry bit
+SFL                             Shift ACC left
+SFR                             Shift ACC right
+SFSM                            Set serial port frame sync mode
+SHM                             Set hold mode
+SOVM                            Set overflow mode
+SPAC                            Subtract P register from ACC
+
+SPH  _ind_,_nextarp_            Store high P register
+SPH  _ind_
+SPH  _dma_
+
+SPL  _ind_,_nextarp_            Store low P register
+SPL  _ind_
+SPL  _dma_
+
+SPM  _dma_                      Set P register output shift mode
+
+SQRA _ind_,_nextarp_            Square and accumulate previous product
+SQRA _ind_
+SQRA _dma_
+
+SQRS _ind_,_nextarp_            Square and subtract previous product
+SQRS _ind_
+SQRS _dma_
+
+SST  _ind_,_nextarp_            Store status register ST0
+SST  _ind_
+SST  _dma_
+
+SST1 _ind_,_nextarp_            Store status register ST1
+SST1 _ind_
+SST1 _dma_
+
+SSXM                            Set sign extension mode
+STC                             Set test/control flag
+STXM                            Set serial port transmit mode
+
+
+SUB  _ind_,_shift_,_nextarp_    Subtract from ACC with shift
+SUB  _ind_,_shift_
+SUB  _ind_
+SUB  _dma_,_shift_
+SUB  _dma_
+
+SUBB _ind_,_nextarp_            Subtract from ACC with borrow
+SUBB _ind_
+SUBB _dma_
+SUBC _ind_,_nextarp_            Subtract conditional
+SUBC _ind_
+SUBC _dma_
+
+SUBH _ind_,_nextarp_            Subtract from high ACC
+SUBH _ind_
+SUBH _dma_
+
+SUBK _const8_                   Subtract from ACC short immediate
+
+SUBS _ind_,_nextarp_            Subtract from low ACC without sign-extension
+SUBS _ind_
+SUBS _dma_
+
+SUBT _ind_,_nextarp_            Subtract from ACC with shift as per T reg
+SUBT _ind_
+SUBT _dma_
+
+SXF                             Set external flag
+
+TBLR _ind_,_nextarp_            Table read
+TBLR _ind_
+TBLR _dma_
+
+TBLW _ind_,_nextarp_            Table write
+TBLW _ind_
+TBLW _dma_
+
+TRAP                            Software interrupt
+
+XOR  _ind_,_nextarp_            Exclusive OR with ACC
+XOR  _ind_
+XOR  _dma_
+
+XORK_dma_,_shift_               Exclusive OR immediate ACC with shift
+XORK _dma_
+
+ZAC                             Zero ACC
+
+ZALH _ind_,_nextarp_            Zero low ACC and load high ACC
+ZALH _ind_
+ZALH _dma_
+
+ZALR _ind_,_nextarp_            Zero low ACC, load high ACC with rounding
+ZALR _ind_
+ZALR _dma_
+
+ZALS _ind_,_nextarp_            Zero ACC, load low ACC without sign-extension
+ZALS _ind_
+ZALS _dma_
+
+
+
+

TMS7000 INSTRUCTIONS AND ADDRESSING MODES

+

The following list shows the acceptable opcode mnemonics and their +corresponding operand formats for the TMS7000 version of TASM. The following +symbolic fields used in the table: +

+
SYMBOLIC        DESCRIPTION
+-------------------------------------------
+_iop_           Immediate data (8 bits)
+_Rn_            Register file (memory locations 0 to 127 or
+                   0 to 255 depending on on-chip RAM)
+_Pn_            Peripheral file (0-255)
+_rel_           Program address (relative)
+_addr_          Program address (16 bit)
+_trap_          Trap number (0-23)
+
+

Any valid TASM expression can appear in the place of any of the above +symbolics. +

+

Note that TASM allows an alternate syntax for expressing indirection. +Parenthesis can be replaced with brackets (which are less ambiguous because they +do not occur in expressions). Thus, the following are equivalent: +

+
    BR      @addr1(B)
+    BR      @addr1[B]
+
+
OPCODE  OPERANDS
+---------------------------------------
+ADC    B,A
+ADC    %_iop_,A
+ADC    %_iop_,B
+ADC    %_iop_,_Rn_
+ADC    _Rn_,A
+ADC    _Rn_,B
+ADC    _Rn_,_Rn_
+
+ADD    B,A
+ADD    %_iop_,A
+ADD    %_iop_,B
+ADD    %_iop_,_Rn_
+ADD    _Rn_,A
+ADD    _Rn_,B
+ADD    _Rn_,_Rn_
+
+AND    B,A
+AND    %_iop_,A
+AND    %_iop_,B
+AND    %_iop_,_Rn_
+AND    _Rn_,A
+AND    _Rn_,B
+AND    _Rn_,_Rn_
+
+ANDP   A,_Pn_
+ANDP   B,_Pn_
+ANDP   %_iop_,_Pn_
+
+BTJO   B,A,_rel_
+BTJO   %_iop_,A,_rel_
+BTJO   %_iop_,B,_rel_
+BTJO   %_iop_,_Rn_,_rel_
+BTJO   _Rn_,A,_rel_
+BTJO   _Rn_,B,_rel_
+BTJO   _Rn_,_Rn_,_rel_
+
+BTJOP  A,_Pn_,_rel_
+BTJOP  B,_Pn_,_rel_
+BTJOP  %_iop_,_Pn_,_rel_
+
+BTJZ   B,A,_rel_
+BTJZ   %_iop_,A,_rel_
+BTJZ   %_iop_,B,_rel_
+BTJZ   %_iop_,_Rn_,_rel_
+BTJZ   _Rn_,A,_rel_
+BTJZ   _Rn_,B,_rel_
+BTJZ   _Rn_,_Rn_,_rel_
+
+BTJZP  A,_Pn_,_rel_
+BTJZP  B,_Pn_,_rel_
+BTJZP  %_iop_,_Pn_,_rel_
+
+BR      @_addr_(B)
+BR      @_addr_[B]
+BR      @_addr_
+BR      *_Rn_
+
+CALL    @_addr_(B)
+CALL    @_addr_[B]
+CALL    @_addr_
+CALL    *_Rn_
+
+CLR     A
+CLR     B
+CLR     _Rn_
+CLRC
+
+CMP     B,A
+CMP     %_iop_,A
+CMP     %_iop_,B
+CMP     %_iop_,_Rn_
+CMP     _Rn_,A
+CMP     _Rn_,B
+CMP     _Rn_,_Rn_
+
+CMPA    @_addr_(B)
+CMPA    @_addr_[B]
+CMPA    @_addr_
+CMPA    *_Rn_
+
+DAC     B,A
+DAC     %_iop_,A
+DAC     %_iop_,B
+DAC     %_iop_,_Rn_
+DAC     _Rn_,A
+DAC     _Rn_,B
+DAC     _Rn_,_Rn_
+
+DEC     A
+DEC     B
+DEC     _Rn_
+
+DECD    A
+DECD    B
+DECD    _Rn_
+
+DINT
+
+DJNZ    A,_rel_
+DJNZ    B,_rel_
+DJNZ    _Rn_,_rel_
+
+DSB     B,A
+DSB     %_iop_,A
+DSB     %_iop_,B
+DSB     %_iop_,_Rn_
+DSB     _Rn_,A
+DSB     _Rn_,B
+DSB     _Rn_,_Rn_
+
+EINT
+IDLE
+
+INC     A
+INC     B
+INC     _Rn_
+
+INV     A
+INV     B
+INV     _Rn_
+
+JMP     _rel_
+
+JC      _rel_
+JEQ     _rel_
+JGE     _rel_
+JGT     _rel_
+JHS     _rel_
+JL      _rel_
+JN      _rel_
+JNC     _rel_
+JNE     _rel_
+JNZ     _rel_
+JP      _rel_
+JPZ     _rel_
+JZ      _rel_
+
+LDA     @_addr_(B)
+LDA     @_addr_[B]
+LDA     @_addr_
+LDA     *_Rn_
+
+LDSP
+
+MOV     A,B
+MOV     B,A
+MOV     A,_Rn_
+MOV     B,_Rn_
+MOV     %_iop_,A
+MOV     %_iop_,B
+MOV     %_iop_,_Rn_
+MOV     _Rn_,A
+MOV     _Rn_,B
+MOV     _Rn_,_Rn_
+
+MOVD    %_iop_[B],_Rn_
+MOVD    %_iop_,_Rn_
+MOVD    _Rn_,_Rn_
+
+MOVP    A,_Pn_
+MOVP    B,_Pn_
+MOVP    %_iop_,_Pn_
+MOVP    _Pn_,A
+MOVP    _Pn_,B
+
+MPY     B,A
+MPY     %_iop_,A
+MPY     %_iop_,B
+MPY     %_iop_,_Rn_
+MPY     _Rn_,A
+MPY     _Rn_,B
+MPY     _Rn_,_Rn_
+
+NOP
+
+OR      B,A
+OR      %_iop_,A
+OR      %_iop_,B
+OR      %_iop_,_Rn_
+OR      _Rn_,A
+OR      _Rn_,B
+OR      _Rn_,_Rn_
+
+ORP     A,_Pn_
+ORP     B,_Pn_
+ORP     %_iop_,_Pn_
+
+POP     A
+POP     B
+POP     ST
+POP     _Rn_
+POPST
+
+PUSH    A
+PUSH    B
+PUSH    ST
+PUSH    _Rn_
+PUSHST
+
+RETI
+
+RETS
+
+RL      A
+RL      B
+RL      _Rn_
+
+RLC     A
+RLC     B
+RLC     _Rn_
+
+RR      A
+RR      B
+RR      _Rn_
+
+RRC     A
+RRC     B
+RRC     _Rn_
+
+SBB     B,A
+SBB     %_iop_,A
+SBB     %_iop_,B
+SBB     %_iop_,_Rn_
+SBB     _Rn_,A
+SBB     _Rn_,B
+SBB     _Rn_,_Rn_
+
+SETC
+
+STA     @_addr_(B)
+STA     @_addr_[B]
+STA     @_addr_
+STA     *_Rn_
+
+STSP
+
+SUB     B,A
+SUB     %_iop_,A
+SUB     %_iop_,B
+SUB     %_iop_,_Rn_
+SUB     _Rn_,A
+SUB     _Rn_,B
+SUB     _Rn_,_Rn_
+
+SWAP    A
+SWAP    B
+SWAP    _Rn_
+
+TRAP    _trap_
+
+TST     A
+TSTA
+TST     B
+TSTB
+
+XCHB    A
+XCHB    _Rn_
+
+XOR     B,A
+XOR     %_iop_,A
+XOR     %_iop_,B
+XOR     %_iop_,_Rn_
+XOR     _Rn_,A
+XOR     _Rn_,B
+XOR     _Rn_,_Rn_
+
+XORP    A,_Pn_
+XORP    B,_Pn_
+XORP    %_iop_,_Pn_
+
+
diff --git a/trunk/Tools/tasm32/TEST05.ASM b/trunk/Tools/tasm32/TEST05.ASM new file mode 100644 index 00000000..858a575d --- /dev/null +++ b/trunk/Tools/tasm32/TEST05.ASM @@ -0,0 +1,251 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test05.asm 1.1 1993/08/02 01:24:21 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: 6805 +; + + + .org 0 +bit3 .equ 3 +data .equ $12 + .block $46 +addz .equ $46 + + .org $1007 +addr: + ADC #data ;A9 2 NOP 1 + ADC ,X ;F9 1 NOP 1 + ADC addr,X ;D9 3 MZERO 1 + ADC addz,X ;D9 3 MZERO 1 + ADC addr ;C9 3 MZERO 1 + ADC addz ;C9 3 MZERO 1 + + ADD #data ;AB 2 NOP 1 + ADD ,X ;FB 1 NOP 1 + ADD addr,X ;DB 3 MZERO 1 + ADD addz,X ;DB 3 MZERO 1 + ADD addr ;CB 3 MZERO 1 + ADD addz ;CB 3 MZERO 1 + + AND #data ;A4 2 NOP 1 + AND ,X ;F4 1 NOP 1 + AND addr,X ;D4 3 MZERO 1 + AND addz,X ;D4 3 MZERO 1 + AND addr ;C4 3 MZERO 1 + AND addz ;C4 3 MZERO 1 + + ASLA ;48 1 NOP 1 + ASLX ;58 1 NOP 1 + ASL ,X ;78 1 NOP 1 + ASL addz,X ;68 2 NOP 1 + ASL addz ;38 2 NOP 1 + + ASRA ;47 1 NOP 1 + ASRX ;57 1 NOP 1 + ASR ,X ;77 1 NOP 1 + ASR addz,X ;37 2 NOP 1 + ASR addz ;37 2 NOP 1 + +loop1: + BCC loop1 ;24 2 R1 1 + BCS loop1 ;25 2 R1 1 + BEQ loop1 ;27 2 R1 1 + BHCC loop1 ;28 2 R1 1 + BHCS loop1 ;29 2 R1 1 + BHI loop1 ;22 2 R1 1 + BHS loop1 ;24 2 R1 1 + BIH loop1 ;2F 2 R1 1 + BIL loop1 ;2E 2 R1 1 + + BIT #data ;A5 2 NOP 1 + BIT ,X ;F5 1 NOP 1 + BIT addr,X ;D5 3 MZERO 1 + BIT addz,X ;C5 3 MZERO 1 + BIT addr ;C5 3 MZERO 1 + BIT addz ;C5 3 MZERO 1 + + BLO loop1 ;25 2 R1 1 + BLS loop1 ;23 2 R1 1 + BMC loop1 ;2C 2 R1 1 + BMI loop1 ;2B 2 R1 1 + BMS loop1 ;2D 2 R1 1 + BNE loop1 ;26 2 R1 1 + BPL loop1 ;2A 2 R1 1 + BRA loop1 ;20 2 R1 1 + BRN loop1 ;21 2 R1 1 + BSR loop1 ;AD 2 R1 1 + + BRCLR bit3,addz,loop1 ;01 3 MBIT 1 + BRSET bit3,addz,loop1 ;00 3 MBIT 1 + + BCLR bit3,addz ;11 2 MBIT 1 + BSET bit3,addz ;10 2 MBIT 1 + + CLC ;98 1 NOP 1 + CLI ;9A 1 NOP 1 + + CLRA ;4F 1 NOP 1 + CLRX ;5F 1 NOP 1 + CLR ,X ;7F 1 NOP 1 + CLR addz,X ;6F 2 NOP 1 + CLR addz ;3F 2 NOP 1 + + CMP #data ;A1 2 NOP 1 + CMP ,X ;F1 1 NOP 1 + CMP addr,X ;D1 3 MZERO 1 + CMP addz,X ;D1 3 MZERO 1 + CMP addr ;C1 3 MZERO 1 + CMP addz ;C1 3 MZERO 1 + + COMA ;43 1 NOP 1 + COMX ;53 1 NOP 1 + COM ,X ;73 1 NOP 1 + COM addz,X ;63 2 NOP 1 + COM addz ;33 2 NOP 1 + + CPX #data ;A3 2 NOP 1 + CPX ,X ;F3 1 NOP 1 + CPX addr,X ;D3 3 MZERO 1 + CPX addz,X ;D3 3 MZERO 1 + CPX addr ;C3 3 MZERO 1 + CPX addz ;C3 3 MZERO 1 + + DECA ;4A 1 NOP 1 + DECX ;5A 1 NOP 1 + DEX ;5A 1 NOP 1 + DEC ,X ;7A 1 NOP 1 + DEC addz,X ;6A 2 NOP 1 + DEC addz ;3A 2 NOP 1 + + EOR #data ;A8 2 NOP 1 + EOR ,X ;F8 1 NOP 1 + EOR addr,X ;D8 3 MZERO 1 + EOR addz,X ;D8 3 MZERO 1 + EOR addr ;C8 3 MZERO 1 + EOR addz ;C8 3 MZERO 1 + + INCA ;4C 1 NOP 1 + INCX ;5C 1 NOP 1 + INX ;5C 1 NOP 1 + INC ,X ;7C 1 NOP 1 + INC addz,X ;6C 2 NOP 1 + INC addz ;3C 2 NOP 1 + + JMP ,X ;FC 1 NOP 1 + JMP addr,X ;DC 3 MZERO 1 + JMP addz,X ;DC 3 MZERO 1 + JMP addr ;CC 3 MZERO 1 + JMP addz ;CC 3 MZERO 1 + + JSR ,X ;FD 1 NOP 1 + JSR addr,X ;DD 3 MZERO 1 + JSR addz,X ;DD 3 MZERO 1 + JSR addr ;CD 3 MZERO 1 + JSR addz ;CD 3 MZERO 1 + + LDA #data ;A6 2 NOP 1 + LDA ,X ;F6 1 NOP 1 + LDA addr,X ;D6 3 MZERO 1 + LDA addz,X ;D6 3 MZERO 1 + LDA addr ;C6 3 MZERO 1 + LDA addz ;C6 3 MZERO 1 + + LDX #data ;AE 2 NOP 1 + LDX ,X ;FE 1 NOP 1 + LDX addr,X ;DE 3 MZERO 1 + LDX addz,X ;DE 3 MZERO 1 + LDX addr ;CE 3 MZERO 1 + LDX addz ;CE 3 MZERO 1 + + LSLA ;48 1 NOP 1 + LSLX ;58 1 NOP 1 + LSL ,X ;78 1 NOP 1 + LSL addz,X ;68 2 NOP 1 + LSL addz ;38 2 NOP 1 + + LSRA ;44 1 NOP 1 + LSRX ;54 1 NOP 1 + LSR ,X ;74 1 NOP 1 + LSR addz,X ;64 2 NOP 1 + LSR addz ;34 2 NOP 1 + + NEGA ;40 1 NOP 1 + NEGX ;50 1 NOP 1 + NEG ,X ;70 1 NOP 1 + NEG addz,X ;60 2 NOP 1 + NEG addz ;30 2 NOP 1 + + NOP ;9D 1 NOP 1 + + ORA #data ;AA 2 NOP 1 + ORA ,X ;FA 1 NOP 1 + ORA addr,X ;DA 3 MZERO 1 + ORA addz,X ;DA 3 MZERO 1 + ORA addr ;CA 3 MZERO 1 + ORA addz ;CA 3 MZERO 1 + + ROLA ;49 1 NOP 1 + ROLX ;59 1 NOP 1 + ROL ,X ;79 1 NOP 1 + ROL addz,X ;69 2 NOP 1 + ROL addz ;39 2 NOP 1 + + RORA ;46 1 NOP 1 + RORX ;56 1 NOP 1 + ROR ,X ;76 1 NOP 1 + ROR addz,X ;66 2 NOP 1 + ROR addz ;36 2 NOP 1 + + RSP ;9C 1 NOP 1 + RTI ;80 1 NOP 1 + RTS ;81 1 NOP 1 + + SBC #data ;A2 2 NOP 1 + SBC ,X ;F2 1 NOP 1 + SBC addr,X ;D2 3 MZERO 1 + SBC addz,X ;D2 3 MZERO 1 + SBC addr ;C2 3 MZERO 1 + SBC addz ;C2 3 MZERO 1 + + SEC ;99 1 NOP 1 + SEI ;9B 1 NOP 1 + + STA ,X ;F7 1 NOP 1 + STA addr,X ;D7 3 MZERO 1 + STA addz,X ;D7 3 MZERO 1 + STA addr ;C7 3 MZERO 1 + STA addz ;C7 3 MZERO 1 + + STOP ;8E 1 NOP 1 + + STX ,X ;FF 1 NOP 1 + STX addr,X ;DF 3 MZERO 1 + STX addz,X ;DF 3 MZERO 1 + STX addr ;CF 3 MZERO 1 + STX addz ;CF 3 MZERO 1 + + SUB #data ;A0 2 NOP 1 + SUB ,X ;F0 1 NOP 1 + SUB addr,X ;D0 3 MZERO 1 + SUB addz,X ;D0 3 MZERO 1 + SUB addr ;C0 3 MZERO 1 + SUB addz ;C0 3 MZERO 1 + + SWI ;83 1 NOP 1 + + TAX ;97 1 NOP 1 + + TSTA ;4D 1 NOP 1 + TSTX ;5D 1 NOP 1 + TST ,X ;7D 1 NOP 1 + TST addz,X ;6D 2 NOP 1 + TST addz ;3D 2 NOP 1 + + TXA ;9F 1 NOP 1 + + WAIT ;8F 1 NOP 1 + .end diff --git a/trunk/Tools/tasm32/TEST3210.ASM b/trunk/Tools/tasm32/TEST3210.ASM new file mode 100644 index 00000000..80b4e98d --- /dev/null +++ b/trunk/Tools/tasm32/TEST3210.ASM @@ -0,0 +1,328 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test3210.asm 1.1 1993/08/02 01:24:21 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: TMS32010 +; + + + .org 100h +shift .equ 4 +shift0 .equ 0 +addr .equ 12h +port .equ 2 +arp .equ 1 +ar .equ 1 +const .equ 34h +const1 .equ 1h + + ABS ;7F88 2 NOP 1 + + ADD *+,shift,arp ;00A0 2 T1 1 8 0F00 + ADD *-,shift,arp ;0090 2 T1 1 8 0F00 + ADD *,shift,arp ;0080 2 T1 1 8 0F00 + ADD *+,shift ;00A8 2 T1 1 8 0F00 + ADD *-,shift ;0098 2 T1 1 8 0F00 + ADD *,shift ;0088 2 T1 1 8 0F00 + ADD *+ ;00A8 2 NOP 1 + ADD *- ;0098 2 NOP 1 + ADD * ;0088 2 NOP 1 + ADD addr,shift ;0000 2 TDMA 1 8 0F00 + ADD addr ;0000 2 T1 1 0 007F + + ADDH *+,arp ;60A0 2 T1 1 0 01 + ADDH *-,arp ;6090 2 T1 1 0 01 + ADDH *,arp ;6080 2 T1 1 0 01 + ADDH *+ ;60A8 2 NOP 1 + ADDH *- ;6098 2 NOP 1 + ADDH * ;6088 2 NOP 1 + ADDH addr ;6000 2 T1 1 0 007F + + ADDS *+,arp ;61A0 2 T1 1 0 01 + ADDS *-,arp ;6190 2 T1 1 0 01 + ADDS *,arp ;6180 2 T1 1 0 01 + ADDS *+ ;61A8 2 NOP 1 + ADDS *- ;6198 2 NOP 1 + ADDS * ;6188 2 NOP 1 + ADDS addr ;6100 2 T1 1 0 007F + + AND *+,arp ;79A0 2 T1 1 0 01 + AND *-,arp ;7990 2 T1 1 0 01 + AND *,arp ;7980 2 T1 1 0 01 + AND *+ ;79A8 2 NOP 1 + AND *- ;7998 2 NOP 1 + AND * ;7988 2 NOP 1 + AND addr ;7900 2 T1 1 0 7F + + APAC ;7F8F 2 NOP 1 + +loop1: + B loop1 ;F900 4 SWAP 1 + BANZ loop1 ;F400 4 SWAP 1 + BGEZ loop1 ;FD00 4 SWAP 1 + BGZ loop1 ;FC00 4 SWAP 1 + BIOZ loop1 ;F600 4 SWAP 1 + BLEZ loop1 ;FB00 4 SWAP 1 + BLZ loop1 ;FA00 4 SWAP 1 + BNZ loop1 ;FE00 4 SWAP 1 + BV loop1 ;F500 4 SWAP 1 + BZ loop1 ;FF00 4 SWAP 1 + + CALA ;7F8C 2 NOP 1 + CALL loop1 ;F800 4 SWAP 1 + DINT ;7F81 2 NOP 1 + + DMOV *+,arp ;69A0 2 T1 1 0 01 + DMOV *-,arp ;6990 2 T1 1 0 01 + DMOV *,arp ;6980 2 T1 1 0 01 + DMOV *+ ;69A8 2 NOP 1 + DMOV *- ;6998 2 NOP 1 + DMOV * ;6988 2 NOP 1 + DMOV addr ;6900 2 T1 1 0 007F + + EINT ;7F82 2 NOP 1 + + IN *+,port ,arp ;40A0 2 T1 1 8 0700 + IN *-,port ,arp ;4090 2 T1 1 8 0700 + IN * ,port ,arp ;4080 2 T1 1 8 0700 + IN *+,port ;40A8 2 T1 1 8 0700 + IN *-,port ;4098 2 T1 1 8 0700 + IN * ,port ;4088 2 T1 1 8 0700 + IN addr,port ;4000 2 TDMA 1 8 0700 + + LAC *+,shift,arp ;20A0 2 T1 1 8 0F00 + LAC *-,shift,arp ;2090 2 T1 1 8 0F00 + LAC *,shift,arp ;2080 2 T1 1 8 0F00 + LAC *+,shift ;20A8 2 T1 1 8 0F00 + LAC *-,shift ;2098 2 T1 1 8 0F00 + LAC *,shift ;2088 2 T1 1 8 0F00 + LAC *+ ;20A8 2 NOP 1 + LAC *- ;2098 2 NOP 1 + LAC * ;2088 2 NOP 1 + LAC addr,shift ;2000 2 TDMA 1 8 0F00 + LAC addr ;2000 2 T1 1 0 007F + + LACK const ;7E00 2 T1 1 0 00FF + + LAR ar,*+,arp ;38A0 2 TAR 1 0 0001 + LAR ar,*-,arp ;3890 2 TAR 1 0 0001 + LAR ar,*,arp ;3880 2 TAR 1 0 0001 + LAR ar,*+ ;38A8 2 TAR 1 0 0001 + LAR ar,*- ;3898 2 TAR 1 0 0001 + LAR ar,* ;3888 2 TAR 1 0 0001 + LAR ar, addr ;3800 2 TAR 1 0 007F + + LARK ar,const ;7000 2 TAR 1 0 00FF + LARP const1 ;6880 2 T1 1 0 0001 + + LDP *+,arp ;6FA0 2 T1 1 0 01 + LDP *-,arp ;6F90 2 T1 1 0 01 + LDP *,arp ;6F80 2 T1 1 0 01 + LDP *+ ;6FA8 2 NOP 1 + LDP *- ;6F98 2 NOP 1 + LDP * ;6F88 2 NOP 1 + LDP addr ;6F00 2 T1 1 0 007F + + LDPK const1 ;6E00 2 T1 1 0 01 + + LST *+,arp ;7BA0 2 T1 1 0 01 + LST *-,arp ;7B90 2 T1 1 0 01 + LST *,arp ;7B80 2 T1 1 0 01 + LST *+ ;7BA8 2 NOP 1 + LST *- ;7B98 2 NOP 1 + LST * ;7B88 2 NOP 1 + LST addr ;7B00 2 T1 1 0 007F + + LT *+,arp ;6AA0 2 T1 1 0 01 + LT *-,arp ;6A90 2 T1 1 0 01 + LT *,arp ;6A80 2 T1 1 0 01 + LT *+ ;6AA8 2 NOP 1 + LT *- ;6A98 2 NOP 1 + LT * ;6A88 2 NOP 1 + LT addr ;6A00 2 T1 1 0 007F + + LTA *+,arp ;6CA0 2 T1 1 0 01 + LTA *-,arp ;6C90 2 T1 1 0 01 + LTA *,arp ;6C80 2 T1 1 0 01 + LTA *+ ;6CA8 2 NOP 1 + LTA *- ;6C98 2 NOP 1 + LTA * ;6C88 2 NOP 1 + LTA addr ;6C00 2 T1 1 0 007F + + LTD *+,arp ;6BA0 2 T1 1 0 01 + LTD *-,arp ;6B90 2 T1 1 0 01 + LTD *,arp ;6B80 2 T1 1 0 01 + LTD *+ ;6BA8 2 NOP 1 + LTD *- ;6B98 2 NOP 1 + LTD * ;6B88 2 NOP 1 + LTD addr ;6B00 2 T1 1 0 007F + + MAR *+,arp ;68A0 2 T1 1 0 01 + MAR *-,arp ;6890 2 T1 1 0 01 + MAR *,arp ;6880 2 T1 1 0 01 + MAR *+ ;68A8 2 NOP 1 + MAR *- ;6898 2 NOP 1 + MAR * ;6888 2 NOP 1 + MAR addr ;6800 2 T1 1 0 007F + + MPY *+,arp ;6DA0 2 T1 1 0 01 + MPY *-,arp ;6D90 2 T1 1 0 01 + MPY *,arp ;6D80 2 T1 1 0 01 + MPY *+ ;6DA8 2 NOP 1 + MPY *- ;6D98 2 NOP 1 + MPY * ;6D88 2 NOP 1 + MPY addr ;6D00 2 T1 1 0 007F + + MPYK const ;8000 2 T1 1 0 1FFF + + NOP ;7F80 2 NOP 1 + + OR *+,arp ;7AA0 2 T1 1 0 01 + OR *-,arp ;7A90 2 T1 1 0 01 + OR *,arp ;7A80 2 T1 1 0 01 + OR *+ ;7AA8 2 NOP 1 + OR *- ;7A98 2 NOP 1 + OR * ;7A88 2 NOP 1 + OR addr ;7A00 2 T1 1 0 007F + + OUT *+,port,arp ;48A0 2 T1 1 8 0700 + OUT *-,port,arp ;4890 2 T1 1 8 0700 + OUT *, port,arp ;4880 2 T1 1 8 0700 + OUT *+,port ;48A8 2 T1 1 8 0700 + OUT *-,port ;4898 2 T1 1 8 0700 + OUT *, port ;4888 2 T1 1 8 0700 + OUT addr,port ;4800 2 TDMA 1 8 0700 + + PAC ;7F8E 2 NOP 1 + POP ;7F9D 2 NOP 1 + PUSH ;7F9C 2 NOP 1 + RET ;7F8D 2 NOP 1 + ROVM ;7F8A 2 NOP 1 + +;Note that shift count can only be 0,1, or 4. +;Mask also allows 5. Beware. + SACH *+,shift,arp ;58A0 2 T1 1 8 0500 + SACH *-,shift,arp ;5890 2 T1 1 8 0500 + SACH *, shift,arp ;5880 2 T1 1 8 0500 + SACH *+,shift ;58A8 2 T1 1 8 0500 + SACH *-,shift ;5898 2 T1 1 8 0500 + SACH *, shift ;5888 2 T1 1 8 0500 + SACH *+ ;58A8 2 NOP 1 + SACH *- ;5898 2 NOP 1 + SACH * ;5888 2 NOP 1 + SACH addr,shift ;5800 2 TDMA 1 8 0500 + SACH addr ;5800 2 T1 1 0 007F + +; Shift count must be zero for SACL + SACL *+,shift0,arp ;50A0 2 T1 1 8 0000 + SACL *-,shift0,arp ;5090 2 T1 1 8 0000 + SACL *, shift0,arp ;5080 2 T1 1 8 0000 + SACL *+,shift0 ;50A8 2 T1 1 8 0000 + SACL *-,shift0 ;5098 2 T1 1 8 0000 + SACL *, shift0 ;5088 2 T1 1 8 0000 + SACL *+ ;50A8 2 NOP 1 + SACL *- ;5098 2 NOP 1 + SACL * ;5088 2 NOP 1 + SACL addr,shift0 ;5000 2 TDMA 1 8 0000 + SACL addr ;5000 2 T1 1 0 007F + + SAR ar,*+,arp ;30A0 2 TAR 1 0 0001 + SAR ar,*-,arp ;3090 2 TAR 1 0 0001 + SAR ar,*,arp ;3080 2 TAR 1 0 0001 + SAR ar,*+ ;30A8 2 TAR 1 0 0001 + SAR ar,*- ;3098 2 TAR 1 0 0001 + SAR ar,* ;3088 2 TAR 1 0 0001 + SAR ar,addr ;3000 2 TAR 1 0 007F + + SOVM ;7F8B 2 NOP 1 + SPAC ;7F90 2 NOP 1 + + SST *+,arp ;7CA0 2 T1 1 0 0001 + SST *-,arp ;7C90 2 T1 1 0 0001 + SST *,arp ;7C80 2 T1 1 0 0001 + SST *+ ;7CA8 2 NOP 1 + SST *- ;7C98 2 NOP 1 + SST * ;7C88 2 NOP 1 + SST addr ;7C00 2 T1 1 0 007F + + SUB *+,shift,arp ;10A0 2 T1 1 8 0F00 + SUB *-,shift,arp ;1090 2 T1 1 8 0F00 + SUB *, shift,arp ;1080 2 T1 1 8 0F00 + SUB *+,shift ;10A8 2 T1 1 8 0F00 + SUB *-,shift ;1098 2 T1 1 8 0F00 + SUB *, shift ;1088 2 T1 1 8 0F00 + SUB *+ ;10A8 2 NOP 1 + SUB *- ;1098 2 NOP 1 + SUB * ;1088 2 NOP 1 + SUB addr,shift ;1000 2 TDMA 1 8 0F00 + SUB addr ;1000 2 T1 1 0 007F + + SUBC *+,arp ;64A0 2 T1 1 0 01 + SUBC *-,arp ;6490 2 T1 1 0 01 + SUBC *,arp ;6480 2 T1 1 0 01 + SUBC *+ ;64A8 2 NOP 1 + SUBC *- ;6498 2 NOP 1 + SUBC * ;6488 2 NOP 1 + SUBC addr ;6400 2 T1 1 0 007F + + SUBH *+,arp ;62A0 2 T1 1 0 01 + SUBH *-,arp ;6290 2 T1 1 0 01 + SUBH *,arp ;6280 2 T1 1 0 01 + SUBH *+ ;62A8 2 NOP 1 + SUBH *- ;6298 2 NOP 1 + SUBH * ;6288 2 NOP 1 + SUBH addr ;6200 2 T1 1 0 007F + + SUBS *+,arp ;63A0 2 T1 1 0 01 + SUBS *-,arp ;6390 2 T1 1 0 01 + SUBS *,arp ;6380 2 T1 1 0 01 + SUBS *+ ;63A8 2 NOP 1 + SUBS *- ;6398 2 NOP 1 + SUBS * ;6388 2 NOP 1 + SUBS addr ;6300 2 T1 1 0 007F + + TBLR *+,arp ;67A0 2 T1 1 0 01 + TBLR *-,arp ;6790 2 T1 1 0 01 + TBLR *,arp ;6780 2 T1 1 0 01 + TBLR *+ ;67A8 2 NOP 1 + TBLR *- ;6798 2 NOP 1 + TBLR * ;6788 2 NOP 1 + TBLR addr ;6700 2 T1 1 0 007F + + TBLW *+,arp ;7DA0 2 T1 1 0 01 + TBLW *-,arp ;7D90 2 T1 1 0 01 + TBLW *,arp ;7D80 2 T1 1 0 01 + TBLW *+ ;7DA8 2 NOP 1 + TBLW *- ;7D98 2 NOP 1 + TBLW * ;7D88 2 NOP 1 + TBLW addr ;7D00 2 T1 1 0 007F + + XOR *+,arp ;78A0 2 T1 1 0 01 + XOR *-,arp ;7890 2 T1 1 0 01 + XOR *,arp ;7880 2 T1 1 0 01 + XOR *+ ;78A8 2 NOP 1 + XOR *- ;7898 2 NOP 1 + XOR * ;7888 2 NOP 1 + XOR addr ;7800 2 T1 1 0 007F + + ZAC ;7F89 2 NOP 1 + + ZALH *+,arp ;65A0 2 T1 1 0 01 + ZALH *-,arp ;6590 2 T1 1 0 01 + ZALH *,arp ;6580 2 T1 1 0 01 + ZALH *+ ;65A8 2 NOP 1 + ZALH *- ;6598 2 NOP 1 + ZALH * ;6588 2 NOP 1 + ZALH addr ;6500 2 T1 1 0 007F + + ZALS *+,arp ;66A0 2 T1 1 0 01 + ZALS *-,arp ;6690 2 T1 1 0 01 + ZALS *,arp ;6680 2 T1 1 0 01 + ZALS *+ ;66A8 2 NOP 1 + ZALS *- ;6698 2 NOP 1 + ZALS * ;6688 2 NOP 1 + ZALS addr ;6600 2 T1 1 0 007F + .end diff --git a/trunk/Tools/tasm32/TEST3225.ASM b/trunk/Tools/tasm32/TEST3225.ASM new file mode 100644 index 00000000..16c885cd --- /dev/null +++ b/trunk/Tools/tasm32/TEST3225.ASM @@ -0,0 +1,1363 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test3225.asm 1.1 1993/08/02 01:24:21 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: TMS320C25 +; + + + .org 100h +shift: .equ 4 +shift0: .equ 0 +shiftmode: .equ 3 ;SPM instruction only +addr7: .equ 12h +addr9: .equ 123h +addr16: .equ 1234h +bit: .equ 05h +port: .equ 2 +arp: .equ 3 +nextarp: .equ 4 +ar: .equ 1 +const: .equ 34h +const1: .equ 1h +const8: .equ 0ffh +const13: .equ 0234h +const16: .equ 5678h +cmode: .equ 2 +format: .equ 1 + + ABS + + + ADD *BR0+,shift,nextarp + ADD *BR0-,shift,nextarp + ADD *0+, shift,nextarp + ADD *0-, shift,nextarp + ADD *+, shift,nextarp + ADD *-, shift,nextarp + ADD *, shift,nextarp + ADD *BR0+,shift + ADD *BR0-,shift + ADD *0+, shift + ADD *0-, shift + ADD *+, shift + ADD *-, shift + ADD *, shift + ADD *BR0+ + ADD *BR0- + ADD *0+ + ADD *0- + ADD *+ + ADD *- + ADD * + ADD addr7,shift + ADD addr7 + + ADDC *BR0+,nextarp + ADDC *BR0-,nextarp + ADDC *0+, nextarp + ADDC *0-, nextarp + ADDC *+, nextarp + ADDC *-, nextarp + ADDC *, nextarp + ADDC *BR0+ + ADDC *BR0- + ADDC *0+ + ADDC *0- + ADDC *+ + ADDC *- + ADDC * + ADDC addr7 + + ADDH *BR0+,nextarp + ADDH *BR0-,nextarp + ADDH *0+, nextarp + ADDH *0-, nextarp + ADDH *+, nextarp + ADDH *-, nextarp + ADDH *, nextarp + ADDH *BR0+ + ADDH *BR0- + ADDH *0+ + ADDH *0- + ADDH *+ + ADDH *- + ADDH * + ADDH addr7 + + + ADDK const8 + + ADDS *BR0+,nextarp + ADDS *BR0-,nextarp + ADDS *0+, nextarp + ADDS *0-, nextarp + ADDS *+, nextarp + ADDS *-, nextarp + ADDS *, nextarp + ADDS *BR0+ + ADDS *BR0- + ADDS *0+ + ADDS *0- + ADDS *+ + ADDS *- + ADDS * + ADDS addr7 + + ADDT *BR0+,nextarp + ADDT *BR0-,nextarp + ADDT *0+, nextarp + ADDT *0-, nextarp + ADDT *+, nextarp + ADDT *-, nextarp + ADDT *, nextarp + ADDT *BR0+ + ADDT *BR0- + ADDT *0+ + ADDT *0- + ADDT *+ + ADDT *- + ADDT * + ADDT addr7 + + ADLK const16,shift + ADLK const16 + ADLK 0 + ADLK 1 + ADLK 256 + ADLK 512 + ADLK $1234 + ADLK $1234,0 + + ADRK const8 + + AND *BR0+,nextarp + AND *BR0-,nextarp + AND *0+, nextarp + AND *0-, nextarp + AND *+, nextarp + AND *-, nextarp + AND *, nextarp + AND *BR0+ + AND *BR0- + AND *0+ + AND *0- + AND *+ + AND *- + AND * + AND addr7 + + ANDK const16,shift + ANDK const16 + + APAC + +loop1: + + B loop1,*BR0+,nextarp + B loop1,*BR0-,nextarp + B loop1,*0+, nextarp + B loop1,*0-, nextarp + B loop1,*+, nextarp + B loop1,*-, nextarp + B loop1,*, nextarp + B loop1,*BR0+ + B loop1,*BR0- + B loop1,*0+ + B loop1,*0- + B loop1,*+ + B loop1,*- + B loop1,* + B loop1 + + BACC + + BANZ loop1,*BR0+,nextarp + BANZ loop1,*BR0-,nextarp + BANZ loop1,*0+, nextarp + BANZ loop1,*0-, nextarp + BANZ loop1,*+, nextarp + BANZ loop1,*-, nextarp + BANZ loop1,*, nextarp + BANZ loop1,*BR0+ + BANZ loop1,*BR0- + BANZ loop1,*0+ + BANZ loop1,*0- + BANZ loop1,*+ + BANZ loop1,*- + BANZ loop1,* + BANZ loop1 + + BBNZ loop1,*BR0+,nextarp + BBNZ loop1,*BR0-,nextarp + BBNZ loop1,*0+, nextarp + BBNZ loop1,*0-, nextarp + BBNZ loop1,*+, nextarp + BBNZ loop1,*-, nextarp + BBNZ loop1,*, nextarp + BBNZ loop1,*BR0+ + BBNZ loop1,*BR0- + BBNZ loop1,*0+ + BBNZ loop1,*0- + BBNZ loop1,*+ + BBNZ loop1,*- + BBNZ loop1,* + BBNZ loop1 + + BBZ loop1,*BR0+,nextarp + BBZ loop1,*BR0-,nextarp + BBZ loop1,*0+, nextarp + BBZ loop1,*0-, nextarp + BBZ loop1,*+, nextarp + BBZ loop1,*-, nextarp + BBZ loop1,*, nextarp + BBZ loop1,*BR0+ + BBZ loop1,*BR0- + BBZ loop1,*0+ + BBZ loop1,*0- + BBZ loop1,*+ + BBZ loop1,*- + BBZ loop1,* + BBZ loop1 + + BC loop1,*BR0+,nextarp + BC loop1,*BR0-,nextarp + BC loop1,*0+, nextarp + BC loop1,*0-, nextarp + BC loop1,*+, nextarp + BC loop1,*-, nextarp + BC loop1,*, nextarp + BC loop1,*BR0+ + BC loop1,*BR0- + BC loop1,*0+ + BC loop1,*0- + BC loop1,*+ + BC loop1,*- + BC loop1,* + BC loop1 + + BGEZ loop1,*BR0+,nextarp + BGEZ loop1,*BR0-,nextarp + BGEZ loop1,*0+, nextarp + BGEZ loop1,*0-, nextarp + BGEZ loop1,*+, nextarp + BGEZ loop1,*-, nextarp + BGEZ loop1,*, nextarp + BGEZ loop1,*BR0+ + BGEZ loop1,*BR0- + BGEZ loop1,*0+ + BGEZ loop1,*0- + BGEZ loop1,*+ + BGEZ loop1,*- + BGEZ loop1,* + BGEZ loop1 + + BGZ loop1,*BR0+,nextarp + BGZ loop1,*BR0-,nextarp + BGZ loop1,*0+, nextarp + BGZ loop1,*0-, nextarp + BGZ loop1,*+, nextarp + BGZ loop1,*-, nextarp + BGZ loop1,*, nextarp + BGZ loop1,*BR0+ + BGZ loop1,*BR0- + BGZ loop1,*0+ + BGZ loop1,*0- + BGZ loop1,*+ + BGZ loop1,*- + BGZ loop1,* + BGZ loop1 + + BIOZ loop1,*BR0+,nextarp + BIOZ loop1,*BR0-,nextarp + BIOZ loop1,*0+, nextarp + BIOZ loop1,*0-, nextarp + BIOZ loop1,*+, nextarp + BIOZ loop1,*-, nextarp + BIOZ loop1,*, nextarp + BIOZ loop1,*BR0+ + BIOZ loop1,*BR0- + BIOZ loop1,*0+ + BIOZ loop1,*0- + BIOZ loop1,*+ + BIOZ loop1,*- + BIOZ loop1,* + BIOZ loop1 + + BLEZ loop1,*BR0+,nextarp + BLEZ loop1,*BR0-,nextarp + BLEZ loop1,*0+, nextarp + BLEZ loop1,*0-, nextarp + BLEZ loop1,*+, nextarp + BLEZ loop1,*-, nextarp + BLEZ loop1,*, nextarp + BLEZ loop1,*BR0+ + BLEZ loop1,*BR0- + BLEZ loop1,*0+ + BLEZ loop1,*0- + BLEZ loop1,*+ + BLEZ loop1,*- + BLEZ loop1,* + BLEZ loop1 + + BLZ loop1,*BR0+,nextarp + BLZ loop1,*BR0-,nextarp + BLZ loop1,*0+, nextarp + BLZ loop1,*0-, nextarp + BLZ loop1,*+, nextarp + BLZ loop1,*-, nextarp + BLZ loop1,*, nextarp + BLZ loop1,*BR0+ + BLZ loop1,*BR0- + BLZ loop1,*0+ + BLZ loop1,*0- + BLZ loop1,*+ + BLZ loop1,*- + BLZ loop1,* + BLZ loop1 + + BNC loop1,*BR0+,nextarp + BNC loop1,*BR0-,nextarp + BNC loop1,*0+, nextarp + BNC loop1,*0-, nextarp + BNC loop1,*+, nextarp + BNC loop1,*-, nextarp + BNC loop1,*, nextarp + BNC loop1,*BR0+ + BNC loop1,*BR0- + BNC loop1,*0+ + BNC loop1,*0- + BNC loop1,*+ + BNC loop1,*- + BNC loop1,* + BNC loop1 + + BNV loop1,*BR0+,nextarp + BNV loop1,*BR0-,nextarp + BNV loop1,*0+, nextarp + BNV loop1,*0-, nextarp + BNV loop1,*+, nextarp + BNV loop1,*-, nextarp + BNV loop1,*, nextarp + BNV loop1,*BR0+ + BNV loop1,*BR0- + BNV loop1,*0+ + BNV loop1,*0- + BNV loop1,*+ + BNV loop1,*- + BNV loop1,* + BNV loop1 + + BNZ loop1,*BR0+,nextarp + BNZ loop1,*BR0-,nextarp + BNZ loop1,*0+, nextarp + BNZ loop1,*0-, nextarp + BNZ loop1,*+, nextarp + BNZ loop1,*-, nextarp + BNZ loop1,*, nextarp + BNZ loop1,*BR0+ + BNZ loop1,*BR0- + BNZ loop1,*0+ + BNZ loop1,*0- + BNZ loop1,*+ + BNZ loop1,*- + BNZ loop1,* + BNZ loop1 + + BV loop1,*BR0+,nextarp + BV loop1,*BR0-,nextarp + BV loop1,*0+, nextarp + BV loop1,*0-, nextarp + BV loop1,*+, nextarp + BV loop1,*-, nextarp + BV loop1,*, nextarp + BV loop1,*BR0+ + BV loop1,*BR0- + BV loop1,*0+ + BV loop1,*0- + BV loop1,*+ + BV loop1,*- + BV loop1,* + BV loop1 + + BZ loop1,*BR0+,nextarp + BZ loop1,*BR0-,nextarp + BZ loop1,*0+, nextarp + BZ loop1,*0-, nextarp + BZ loop1,*+, nextarp + BZ loop1,*-, nextarp + BZ loop1,*, nextarp + BZ loop1,*BR0+ + BZ loop1,*BR0- + BZ loop1,*0+ + BZ loop1,*0- + BZ loop1,*+ + BZ loop1,*- + BZ loop1,* + BZ loop1 + + BIT *BR0+,bit ,nextarp + BIT *BR0-,bit ,nextarp + BIT *0+, bit ,nextarp + BIT *0-, bit ,nextarp + BIT *+, bit ,nextarp + BIT *-, bit ,nextarp + BIT *, bit ,nextarp + BIT *BR0+,bit + BIT *BR0-,bit + BIT *0+, bit + BIT *0-, bit + BIT *+, bit + BIT *-, bit + BIT *, bit + BIT addr7,bit + + BITT *BR0+,nextarp + BITT *BR0-,nextarp + BITT *0+, nextarp + BITT *0-, nextarp + BITT *+, nextarp + BITT *-, nextarp + BITT *, nextarp + BITT *BR0+ + BITT *BR0- + BITT *0+ + BITT *0- + BITT *+ + BITT *- + BITT * + BITT addr7 + + BLKD addr16,*BR0+,nextarp + BLKD addr16,*BR0-,nextarp + BLKD addr16,*0+, nextarp + BLKD addr16,*0-, nextarp + BLKD addr16,*+, nextarp + BLKD addr16,*-, nextarp + BLKD addr16,*, nextarp + BLKD addr16,*BR0+ + BLKD addr16,*BR0- + BLKD addr16,*0+ + BLKD addr16,*0- + BLKD addr16,*+ + BLKD addr16,*- + BLKD addr16,* + BLKD addr16,addr7 + + BLKP addr16,*BR0+,nextarp + BLKP addr16,*BR0-,nextarp + BLKP addr16,*0+, nextarp + BLKP addr16,*0-, nextarp + BLKP addr16,*+, nextarp + BLKP addr16,*-, nextarp + BLKP addr16,*, nextarp + BLKP addr16,*BR0+ + BLKP addr16,*BR0- + BLKP addr16,*0+ + BLKP addr16,*0- + BLKP addr16,*+ + BLKP addr16,*- + BLKP addr16,* + BLKP addr16,addr7 + + CALA + + CALL addr16,*BR0+,nextarp + CALL addr16,*BR0-,nextarp + CALL addr16,*0+, nextarp + CALL addr16,*0-, nextarp + CALL addr16,*+, nextarp + CALL addr16,*-, nextarp + CALL addr16,*, nextarp + CALL addr16,*BR0+ + CALL addr16,*BR0- + CALL addr16,*0+ + CALL addr16,*0- + CALL addr16,*+ + CALL addr16,*- + CALL addr16,* + CALL addr16 + + CMPL + + CMPR cmode + + CNFD + CNFP + + DINT + + DMOV *BR0+,nextarp + DMOV *BR0-,nextarp + DMOV *0+, nextarp + DMOV *0-, nextarp + DMOV *+, nextarp + DMOV *-, nextarp + DMOV *, nextarp + DMOV *BR0+ + DMOV *BR0- + DMOV *0+ + DMOV *0- + DMOV *+ + DMOV *- + DMOV * + DMOV addr7 + + EINT + + FORT format + + IDLE + + IN *BR0+,port,nextarp + IN *BR0-,port,nextarp + IN *0+, port,nextarp + IN *0-, port,nextarp + IN *+, port,nextarp + IN *-, port,nextarp + IN *, port,nextarp + IN *BR0+,port + IN *BR0-,port + IN *0+, port + IN *0-, port + IN *+, port + IN *-, port + IN *, port + IN addr7,port + + LAC *BR0+,shift,nextarp + LAC *BR0-,shift,nextarp + LAC *0+, shift,nextarp + LAC *0-, shift,nextarp + LAC *+, shift,nextarp + LAC *-, shift,nextarp + LAC *, shift,nextarp + LAC *BR0+,shift + LAC *BR0-,shift + LAC *0+, shift + LAC *0-, shift + LAC *+, shift + LAC *-, shift + LAC *, shift + LAC *BR0+ + LAC *BR0- + LAC *0+ + LAC *0- + LAC *+ + LAC *- + LAC * + LAC addr7,shift + LAC addr7 + + LACK const8 + + LACT *BR0+,nextarp + LACT *BR0-,nextarp + LACT *0+, nextarp + LACT *0-, nextarp + LACT *+, nextarp + LACT *-, nextarp + LACT *, nextarp + LACT *BR0+ + LACT *BR0- + LACT *0+ + LACT *0- + LACT *+ + LACT *- + LACT * + LACT addr7 + + LALK const16,shift + LALK const16 + + LAR arp,*BR0+,nextarp + LAR arp,*BR0-,nextarp + LAR arp,*0+, nextarp + LAR arp,*0-, nextarp + LAR arp,*+, nextarp + LAR arp,*-, nextarp + LAR arp,*, nextarp + LAR arp,*BR0+ + LAR arp,*BR0- + LAR arp,*0+ + LAR arp,*0- + LAR arp,*+ + LAR arp,*- + LAR arp,* + LAR arp,addr7 + + LARK arp, const8 + + LARP arp + + LDP *BR0+,nextarp + LDP *BR0-,nextarp + LDP *0+, nextarp + LDP *0-, nextarp + LDP *+, nextarp + LDP *-, nextarp + LDP *, nextarp + LDP *BR0+ + LDP *BR0- + LDP *0+ + LDP *0- + LDP *+ + LDP *- + LDP * + LDP addr7 + + LDPK addr9 + + LPH *BR0+,nextarp + LPH *BR0-,nextarp + LPH *0+, nextarp + LPH *0-, nextarp + LPH *+, nextarp + LPH *-, nextarp + LPH *, nextarp + LPH *BR0+ + LPH *BR0- + LPH *0+ + LPH *0- + LPH *+ + LPH *- + LPH * + LPH addr7 + + LRLK arp, const16 + + LST *BR0+,nextarp + LST *BR0-,nextarp + LST *0+, nextarp + LST *0-, nextarp + LST *+, nextarp + LST *-, nextarp + LST *, nextarp + LST *BR0+ + LST *BR0- + LST *0+ + LST *0- + LST *+ + LST *- + LST * + LST addr7 + + LST1 *BR0+,nextarp + LST1 *BR0-,nextarp + LST1 *0+, nextarp + LST1 *0-, nextarp + LST1 *+, nextarp + LST1 *-, nextarp + LST1 *, nextarp + LST1 *BR0+ + LST1 *BR0- + LST1 *0+ + LST1 *0- + LST1 *+ + LST1 *- + LST1 * + LST1 addr7 + + LT *BR0+,nextarp + LT *BR0-,nextarp + LT *0+, nextarp + LT *0-, nextarp + LT *+, nextarp + LT *-, nextarp + LT *, nextarp + LT *BR0+ + LT *BR0- + LT *0+ + LT *0- + LT *+ + LT *- + LT * + LT addr7 + + LTA *BR0+,nextarp + LTA *BR0-,nextarp + LTA *0+, nextarp + LTA *0-, nextarp + LTA *+, nextarp + LTA *-, nextarp + LTA *, nextarp + LTA *BR0+ + LTA *BR0- + LTA *0+ + LTA *0- + LTA *+ + LTA *- + LTA * + LTA addr7 + + LTD *BR0+,nextarp + LTD *BR0-,nextarp + LTD *0+, nextarp + LTD *0-, nextarp + LTD *+, nextarp + LTD *-, nextarp + LTD *, nextarp + LTD *BR0+ + LTD *BR0- + LTD *0+ + LTD *0- + LTD *+ + LTD *- + LTD * + LTD addr7 + + LTP *BR0+,nextarp + LTP *BR0-,nextarp + LTP *0+, nextarp + LTP *0-, nextarp + LTP *+, nextarp + LTP *-, nextarp + LTP *, nextarp + LTP *BR0+ + LTP *BR0- + LTP *0+ + LTP *0- + LTP *+ + LTP *- + LTP * + LTP addr7 + + LTS *BR0+,nextarp + LTS *BR0-,nextarp + LTS *0+, nextarp + LTS *0-, nextarp + LTS *+, nextarp + LTS *-, nextarp + LTS *, nextarp + LTS *BR0+ + LTS *BR0- + LTS *0+ + LTS *0- + LTS *+ + LTS *- + LTS * + LTS addr7 + + MAC addr16,*BR0+,nextarp + MAC addr16,*BR0-,nextarp + MAC addr16,*0+, nextarp + MAC addr16,*0-, nextarp + MAC addr16,*+, nextarp + MAC addr16,*-, nextarp + MAC addr16,*, nextarp + MAC addr16,*BR0+ + MAC addr16,*BR0- + MAC addr16,*0+ + MAC addr16,*0- + MAC addr16,*+ + MAC addr16,*- + MAC addr16,* + MAC addr16,addr7 + + MACD addr16,*BR0+,nextarp + MACD addr16,*BR0-,nextarp + MACD addr16,*0+, nextarp + MACD addr16,*0-, nextarp + MACD addr16,*+, nextarp + MACD addr16,*-, nextarp + MACD addr16,*, nextarp + MACD addr16,*BR0+ + MACD addr16,*BR0- + MACD addr16,*0+ + MACD addr16,*0- + MACD addr16,*+ + MACD addr16,*- + MACD addr16,* + MACD addr16,addr7 + + MAR *BR0+,nextarp + MAR *BR0-,nextarp + MAR *0+, nextarp + MAR *0-, nextarp + MAR *+, nextarp + MAR *-, nextarp + MAR *, nextarp + MAR *BR0+ + MAR *BR0- + MAR *0+ + MAR *0- + MAR *+ + MAR *- + MAR * + MAR addr7 + + MPY *BR0+,nextarp + MPY *BR0-,nextarp + MPY *0+, nextarp + MPY *0-, nextarp + MPY *+, nextarp + MPY *-, nextarp + MPY *, nextarp + MPY *BR0+ + MPY *BR0- + MPY *0+ + MPY *0- + MPY *+ + MPY *- + MPY * + MPY addr7 + + MPYA *BR0+,nextarp + MPYA *BR0-,nextarp + MPYA *0+, nextarp + MPYA *0-, nextarp + MPYA *+, nextarp + MPYA *-, nextarp + MPYA *, nextarp + MPYA *BR0+ + MPYA *BR0- + MPYA *0+ + MPYA *0- + MPYA *+ + MPYA *- + MPYA * + MPYA addr7 + + MPYK const13 + + MPYS *BR0+,nextarp + MPYS *BR0-,nextarp + MPYS *0+, nextarp + MPYS *0-, nextarp + MPYS *+, nextarp + MPYS *-, nextarp + MPYS *, nextarp + MPYS *BR0+ + MPYS *BR0- + MPYS *0+ + MPYS *0- + MPYS *+ + MPYS *- + MPYS * + MPYS addr7 + + MPYU *BR0+,nextarp + MPYU *BR0-,nextarp + MPYU *0+, nextarp + MPYU *0-, nextarp + MPYU *+, nextarp + MPYU *-, nextarp + MPYU *, nextarp + MPYU *BR0+ + MPYU *BR0- + MPYU *0+ + MPYU *0- + MPYU *+ + MPYU *- + MPYU * + MPYU addr7 + + NEG + + NOP + + NORM *BR0+ + NORM *BR0- + NORM *0+ + NORM *0- + NORM *+ + NORM *- + NORM * + NORM + + OR *BR0+,nextarp + OR *BR0-,nextarp + OR *0+, nextarp + OR *0-, nextarp + OR *+, nextarp + OR *-, nextarp + OR *, nextarp + OR *BR0+ + OR *BR0- + OR *0+ + OR *0- + OR *+ + OR *- + OR * + OR addr7 + + ORK const16, shift + ORK const16 + + OUT *BR0+,port,nextarp + OUT *BR0-,port,nextarp + OUT *0+, port,nextarp + OUT *0-, port,nextarp + OUT *+, port,nextarp + OUT *-, port,nextarp + OUT *, port,nextarp + OUT *BR0+,port + OUT *BR0-,port + OUT *0+, port + OUT *0-, port + OUT *+, port + OUT *-, port + OUT *, port + OUT addr7,port + + PAC + POP + + POPD *BR0+,nextarp + POPD *BR0-,nextarp + POPD *0+, nextarp + POPD *0-, nextarp + POPD *+, nextarp + POPD *-, nextarp + POPD *, nextarp + POPD *BR0+ + POPD *BR0- + POPD *0+ + POPD *0- + POPD *+ + POPD *- + POPD * + POPD addr7 + + PSHD *BR0+,nextarp + PSHD *BR0-,nextarp + PSHD *0+, nextarp + PSHD *0-, nextarp + PSHD *+, nextarp + PSHD *-, nextarp + PSHD *, nextarp + PSHD *BR0+ + PSHD *BR0- + PSHD *0+ + PSHD *0- + PSHD *+ + PSHD *- + PSHD * + PSHD addr7 + + PUSH + RC + RET + RFSM + RHM + ROL + ROR + ROVM + + RPT *BR0+,nextarp + RPT *BR0-,nextarp + RPT *0+, nextarp + RPT *0-, nextarp + RPT *+, nextarp + RPT *-, nextarp + RPT *, nextarp + RPT *BR0+ + RPT *BR0- + RPT *0+ + RPT *0- + RPT *+ + RPT *- + RPT * + RPT addr7 + + RPTK const8 + + RSXM + RTC + RTXM + RXF + + SACH *BR0+,shift,nextarp + SACH *BR0-,shift,nextarp + SACH *0+, shift,nextarp + SACH *0-, shift,nextarp + SACH *+, shift,nextarp + SACH *-, shift,nextarp + SACH *, shift,nextarp + SACH *BR0+,shift + SACH *BR0-,shift + SACH *0+, shift + SACH *0-, shift + SACH *+, shift + SACH *-, shift + SACH *, shift + SACH *BR0+ + SACH *BR0- + SACH *0+ + SACH *0- + SACH *+ + SACH *- + SACH * + SACH addr7,shift + SACH addr7 + + SACL *BR0+,shift,nextarp + SACL *BR0-,shift,nextarp + SACL *0+, shift,nextarp + SACL *0-, shift,nextarp + SACL *+, shift,nextarp + SACL *-, shift,nextarp + SACL *, shift,nextarp + SACL *BR0+,shift + SACL *BR0-,shift + SACL *0+, shift + SACL *0-, shift + SACL *+, shift + SACL *-, shift + SACL *, shift + SACL *BR0+ + SACL *BR0- + SACL *0+ + SACL *0- + SACL *+ + SACL *- + SACL * + SACL addr7,shift + SACL addr7 + + SAR arp,*BR0+,nextarp + SAR arp,*BR0-,nextarp + SAR arp,*0+, nextarp + SAR arp,*0-, nextarp + SAR arp,*+, nextarp + SAR arp,*-, nextarp + SAR arp,*, nextarp + SAR arp,*BR0+ + SAR arp,*BR0- + SAR arp,*0+ + SAR arp,*0- + SAR arp,*+ + SAR arp,*- + SAR arp,* + SAR arp,addr7 + + SBLK const16, shift + SBLK const16 + + SBRK const8 + + SC + SFL + SFR + SFSM + SHM + SOVM + SPAC + + SPH *BR0+,nextarp + SPH *BR0-,nextarp + SPH *0+, nextarp + SPH *0-, nextarp + SPH *+, nextarp + SPH *-, nextarp + SPH *, nextarp + SPH *BR0+ + SPH *BR0- + SPH *0+ + SPH *0- + SPH *+ + SPH *- + SPH * + SPH addr7 + + SPL *BR0+,nextarp + SPL *BR0-,nextarp + SPL *0+, nextarp + SPL *0-, nextarp + SPL *+, nextarp + SPL *-, nextarp + SPL *, nextarp + SPL *BR0+ + SPL *BR0- + SPL *0+ + SPL *0- + SPL *+ + SPL *- + SPL * + SPL addr7 + + SPM shiftmode + + SQRA *BR0+,nextarp + SQRA *BR0-,nextarp + SQRA *0+, nextarp + SQRA *0-, nextarp + SQRA *+, nextarp + SQRA *-, nextarp + SQRA *, nextarp + SQRA *BR0+ + SQRA *BR0- + SQRA *0+ + SQRA *0- + SQRA *+ + SQRA *- + SQRA * + SQRA addr7 + + SQRS *BR0+,nextarp + SQRS *BR0-,nextarp + SQRS *0+, nextarp + SQRS *0-, nextarp + SQRS *+, nextarp + SQRS *-, nextarp + SQRS *, nextarp + SQRS *BR0+ + SQRS *BR0- + SQRS *0+ + SQRS *0- + SQRS *+ + SQRS *- + SQRS * + SQRS addr7 + + SST *BR0+,nextarp + SST *BR0-,nextarp + SST *0+, nextarp + SST *0-, nextarp + SST *+, nextarp + SST *-, nextarp + SST *, nextarp + SST *BR0+ + SST *BR0- + SST *0+ + SST *0- + SST *+ + SST *- + SST * + SST addr7 + + SST1 *BR0+,nextarp + SST1 *BR0-,nextarp + SST1 *0+, nextarp + SST1 *0-, nextarp + SST1 *+, nextarp + SST1 *-, nextarp + SST1 *, nextarp + SST1 *BR0+ + SST1 *BR0- + SST1 *0+ + SST1 *0- + SST1 *+ + SST1 *- + SST1 * + SST1 addr7 + + SSXM + STC + STXM + + SUB *BR0+,shift,nextarp + SUB *BR0-,shift,nextarp + SUB *0+, shift,nextarp + SUB *0-, shift,nextarp + SUB *+, shift,nextarp + SUB *-, shift,nextarp + SUB *, shift,nextarp + SUB *BR0+,shift + SUB *BR0-,shift + SUB *0+, shift + SUB *0-, shift + SUB *+, shift + SUB *-, shift + SUB *, shift + SUB *BR0+ + SUB *BR0- + SUB *0+ + SUB *0- + SUB *+ + SUB *- + SUB * + SUB addr7,shift + SUB addr7 + + SUBB *BR0+,nextarp + SUBB *BR0-,nextarp + SUBB *0+, nextarp + SUBB *0-, nextarp + SUBB *+, nextarp + SUBB *-, nextarp + SUBB *, nextarp + SUBB *BR0+ + SUBB *BR0- + SUBB *0+ + SUBB *0- + SUBB *+ + SUBB *- + SUBB * + SUBB addr7 + + SUBC *BR0+,nextarp + SUBC *BR0-,nextarp + SUBC *0+, nextarp + SUBC *0-, nextarp + SUBC *+, nextarp + SUBC *-, nextarp + SUBC *, nextarp + SUBC *BR0+ + SUBC *BR0- + SUBC *0+ + SUBC *0- + SUBC *+ + SUBC *- + SUBC * + SUBC addr7 + + SUBH *BR0+,nextarp + SUBH *BR0-,nextarp + SUBH *0+, nextarp + SUBH *0-, nextarp + SUBH *+, nextarp + SUBH *-, nextarp + SUBH *, nextarp + SUBH *BR0+ + SUBH *BR0- + SUBH *0+ + SUBH *0- + SUBH *+ + SUBH *- + SUBH * + SUBH addr7 + + SUBK const8 + + SUBS *BR0+,nextarp + SUBS *BR0-,nextarp + SUBS *0+, nextarp + SUBS *0-, nextarp + SUBS *+, nextarp + SUBS *-, nextarp + SUBS *, nextarp + SUBS *BR0+ + SUBS *BR0- + SUBS *0+ + SUBS *0- + SUBS *+ + SUBS *- + SUBS * + SUBS addr7 + + SUBT *BR0+,nextarp + SUBT *BR0-,nextarp + SUBT *0+, nextarp + SUBT *0-, nextarp + SUBT *+, nextarp + SUBT *-, nextarp + SUBT *, nextarp + SUBT *BR0+ + SUBT *BR0- + SUBT *0+ + SUBT *0- + SUBT *+ + SUBT *- + SUBT * + SUBT addr7 + + SXF + + TBLR *BR0+,nextarp + TBLR *BR0-,nextarp + TBLR *0+, nextarp + TBLR *0-, nextarp + TBLR *+, nextarp + TBLR *-, nextarp + TBLR *, nextarp + TBLR *BR0+ + TBLR *BR0- + TBLR *0+ + TBLR *0- + TBLR *+ + TBLR *- + TBLR * + TBLR addr7 + + TBLW *BR0+,nextarp + TBLW *BR0-,nextarp + TBLW *0+, nextarp + TBLW *0-, nextarp + TBLW *+, nextarp + TBLW *-, nextarp + TBLW *, nextarp + TBLW *BR0+ + TBLW *BR0- + TBLW *0+ + TBLW *0- + TBLW *+ + TBLW *- + TBLW * + TBLW addr7 + + TRAP + + XOR *BR0+,nextarp + XOR *BR0-,nextarp + XOR *0+, nextarp + XOR *0-, nextarp + XOR *+, nextarp + XOR *-, nextarp + XOR *, nextarp + XOR *BR0+ + XOR *BR0- + XOR *0+ + XOR *0- + XOR *+ + XOR *- + XOR * + XOR addr7 + + XORK const16, shift + XORK const16 + + ZAC + + ZALH *BR0+,nextarp + ZALH *BR0-,nextarp + ZALH *0+, nextarp + ZALH *0-, nextarp + ZALH *+, nextarp + ZALH *-, nextarp + ZALH *, nextarp + ZALH *BR0+ + ZALH *BR0- + ZALH *0+ + ZALH *0- + ZALH *+ + ZALH *- + ZALH * + ZALH addr7 + + ZALR *BR0+,nextarp + ZALR *BR0-,nextarp + ZALR *0+, nextarp + ZALR *0-, nextarp + ZALR *+, nextarp + ZALR *-, nextarp + ZALR *, nextarp + ZALR *BR0+ + ZALR *BR0- + ZALR *0+ + ZALR *0- + ZALR *+ + ZALR *- + ZALR * + ZALR addr7 + + ZALS *BR0+,nextarp + ZALS *BR0-,nextarp + ZALS *0+, nextarp + ZALS *0-, nextarp + ZALS *+, nextarp + ZALS *-, nextarp + ZALS *, nextarp + ZALS *BR0+ + ZALS *BR0- + ZALS *0+ + ZALS *0- + ZALS *+ + ZALS *- + ZALS * + ZALS addr7 + .end + diff --git a/trunk/Tools/tasm32/TEST48.ASM b/trunk/Tools/tasm32/TEST48.ASM new file mode 100644 index 00000000..8cab0e93 --- /dev/null +++ b/trunk/Tools/tasm32/TEST48.ASM @@ -0,0 +1,279 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test48.asm 1.1 1993/08/02 01:24:21 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: 8048 +; + + +label1 .equ 12H + + ADD A,R0 + ADD A,R1 + ADD A,R2 + ADD A,R3 + ADD A,R4 + ADD A,R5 + ADD A,R6 + ADD A,R7 + ADD A,@R0 + ADD A,@R1 + ADD A,#label1 + + ADDC A,R0 + ADDC A,R1 + ADDC A,R2 + ADDC A,R3 + ADDC A,R4 + ADDC A,R5 + ADDC A,R6 + ADDC A,R7 + ADDC A,@R0 + ADDC A,@R1 + ADDC A,#label1 + + ANL A,R0 + ANL A,R1 + ANL A,R2 + ANL A,R3 + ANL A,R4 + ANL A,R5 + ANL A,R6 + ANL A,R7 + ANL A,@R0 + ANL A,@R1 + ANL A,#label1 + ANL BUS,#label1 + ANL P1,#label1 + ANL P2,#label1 + + ANLD P4,A + ANLD P5,A + ANLD P6,A + ANLD P7,A + + CALL label1 + + CLR A + CLR C + CLR F0 + CLR F1 + + CPL A + CPL C + CPL F0 + CPL F1 + + DA A + + DEC A + DEC R0 + DEC R1 + DEC R2 + DEC R3 + DEC R4 + DEC R5 + DEC R6 + DEC R7 + + DIS I + DIS TCNTI + + DJNZ R0,label1 + DJNZ R1,label1 + DJNZ R2,label1 + DJNZ R3,label1 + DJNZ R4,label1 + DJNZ R5,label1 + DJNZ R6,label1 + DJNZ R7,label1 + + EN DMA + EN FLAGS + EN I + EN TCNTI + ENT0 CLK + + IN A,DBB + IN A,P0 + IN A,P1 + IN A,P2 + + INC A + INC R0 + INC R1 + INC R2 + INC R3 + INC R4 + INC R5 + INC R6 + INC R7 + INC @R0 + INC @R1 + + INS A,BUS + + JB0 label1 + JB1 label1 + JB2 label1 + JB3 label1 + JB4 label1 + JB5 label1 + JB6 label1 + JB7 label1 + + JMP label1 + + JC label1 + JF0 label1 + JF1 label1 + JNC label1 + JNI label1 + JNIBF label1 + JNT0 label1 + JNT1 label1 + JNZ label1 + JOBF label1 + JTF label1 + JT0 label1 + JT1 label1 + JZ label1 + + JMPP @A + + MOV A,PSW + MOV A,R0 + MOV A,R1 + MOV A,R2 + MOV A,R3 + MOV A,R4 + MOV A,R5 + MOV A,R6 + MOV A,R7 + MOV A,T + MOV A,@R0 + MOV A,@R1 + MOV A,#label1 + MOV PSW,A + MOV R0,A + MOV R1,A + MOV R2,A + MOV R3,A + MOV R4,A + MOV R5,A + MOV R6,A + MOV R7,A + MOV R0,#label1 + MOV R1,#label1 + MOV R2,#label1 + MOV R3,#label1 + MOV R4,#label1 + MOV R5,#label1 + MOV R6,#label1 + MOV R7,#label1 + MOV STS,A + MOV T,A + MOV @R0,A + MOV @R1,A + MOV @R0,#label1 + MOV @R1,#label1 + + MOVD A,P4 + MOVD A,P5 + MOVD A,P6 + MOVD A,P7 + MOVD P4,A + MOVD P5,A + MOVD P6,A + MOVD P7,A + + MOVP A,@A + MOVP3 A,@A + + + MOVX A,@R0 + MOVX A,@R1 + MOVX @R0,A + MOVX @R1,A + + NOP + + ORL A,R0 + ORL A,R1 + ORL A,R2 + ORL A,R3 + ORL A,R4 + ORL A,R5 + ORL A,R6 + ORL A,R7 + ORL A,@R0 + ORL A,@R1 + ORL A,#label1 + ORL BUS,#label1 + ORL P1,#label1 + ORL P2,#label1 + + ORLD P4,A + ORLD P5,A + ORLD P6,A + ORLD P7,A + + OUTL BUS,A + OUT DBB,A + OUTL P0,A + OUTL P1,A + OUTL P2,A + + RAD + + RET + RETI + RETR + + RL A + RLC A + RR A + RRC A + + SEL AN0 + SEL AN1 + SEL MB0 + SEL MB1 + SEL RB0 + SEL RB1 + + STOP TCNT + STRT CNT + STRT T + + SWAP A + + XCH A,R0 + XCH A,R1 + XCH A,R2 + XCH A,R3 + XCH A,R4 + XCH A,R5 + XCH A,R6 + XCH A,R7 + XCH A,@R0 + XCH A,@R1 + + XCHD A,@R0 + XCHD A,@R1 + + XRL A,R0 + XRL A,R1 + XRL A,R2 + XRL A,R3 + XRL A,R4 + XRL A,R5 + XRL A,R6 + XRL A,R7 + XRL A,@R0 + XRL A,@R1 + XRL A,#label1 + .end diff --git a/trunk/Tools/tasm32/TEST51.ASM b/trunk/Tools/tasm32/TEST51.ASM new file mode 100644 index 00000000..76c43c9f --- /dev/null +++ b/trunk/Tools/tasm32/TEST51.ASM @@ -0,0 +1,297 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test51.asm 1.1 1993/08/02 01:24:21 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: 8051 +; + + + .AVSYM + +labimm: .EQU 56h +lab2: .EQU 12h +lab3: .EQU 1234h +lab5: .EQU 0feh +labbt_1: .EQU 34h +bit .equ 81h + + + ACALL lab4 ;11 2 JMP 1 +lab4: + ADD A,R0 ;28 1 NOP 1 + ADD A,R1 ;29 1 NOP 1 + ADD A,R2 ;2A 1 NOP 1 + ADD A,R3 ;2B 1 NOP 1 + ADD A,R4 ;2C 1 NOP 1 + ADD A,R5 ;2D 1 NOP 1 + ADD A,R6 ;2E 1 NOP 1 + ADD A,R7 ;2F 1 NOP 1 + ADD A,@R0 ;26 1 NOP 1 + ADD A,@R1 ;27 1 NOP 1 + ADD A,#labimm ;24 2 NOP 1 + ADD A,lab2 ;25 2 NOP 1 + + ADDC A,R0 ;38 1 NOP 1 + ADDC A,R1 ;39 1 NOP 1 + ADDC A,R2 ;3A 1 NOP 1 + ADDC A,R3 ;3B 1 NOP 1 + ADDC A,R4 ;3C 1 NOP 1 + ADDC A,R5 ;3D 1 NOP 1 + ADDC A,R6 ;3E 1 NOP 1 + ADDC A,R7 ;3F 1 NOP 1 + ADDC A,@R0 ;36 1 NOP 1 + ADDC A,@R1 ;37 1 NOP 1 + ADDC A,#labimm ;34 2 NOP 1 + ADDC A,lab2 ;35 2 NOP 1 + + AJMP jlab ;01 2 JMP 1 + + ANL A,R0 ;58 1 NOP 1 + ANL A,R1 ;59 1 NOP 1 + ANL A,R2 ;5A 1 NOP 1 + ANL A,R3 ;5B 1 NOP 1 + ANL A,R4 ;5C 1 NOP 1 + ANL A,R5 ;5D 1 NOP 1 + ANL A,R6 ;5E 1 NOP 1 + ANL A,R7 ;5F 1 NOP 1 + ANL A,@R0 ;56 1 NOP 1 + ANL A,@R1 ;57 1 NOP 1 + ANL A,#labimm + ANL A,lab2 + ANL C,/bit + ANL C,bit + ANL lab2,A + ANL lab2,#labimm + + CJNE A,#labimm,jlab ;b4 3 CR 1 + CJNE A,lab2,jlab ;b5 3 CR 1 + CJNE R0,#labimm,jlab ;b8 3 CR 1 + CJNE R1,#labimm,jlab ;b9 3 CR 1 + CJNE R2,#labimm,jlab ;ba 3 CR 1 + CJNE R3,#labimm,jlab ;bb 3 CR 1 + CJNE R4,#labimm,jlab ;bc 3 CR 1 + CJNE R5,#labimm,jlab ;bd 3 CR 1 + CJNE R6,#labimm,jlab ;be 3 CR 1 + CJNE R7,#labimm,jlab ;bf 3 CR 1 + CJNE @R0,#labimm,jlab ;b6 3 CR 1 + CJNE @R1,#labimm,jlab ;b7 3 CR 1 + + CLR A ;e4 1 NOP 1 + CLR C ;c3 1 NOP 1 + CLR bit + + CPL A ;f4 1 NOP 1 + CPL C ;b3 1 NOP 1 + CPL bit + + DA A ;d4 1 NOP 1 + + DEC A ;14 1 NOP 1 + DEC R0 ;18 1 NOP 1 + DEC R1 ;19 1 NOP 1 + DEC R2 ;1A 1 NOP 1 + DEC R3 ;1B 1 NOP 1 + DEC R4 ;1C 1 NOP 1 + DEC R5 ;1D 1 NOP 1 + DEC R6 ;1E 1 NOP 1 + DEC R7 ;1F 1 NOP 1 + DEC @R0 ;16 1 NOP 1 + DEC @R1 ;17 1 NOP 1 + DEC lab2 ;15 2 NOP 1 + + DIV AB ;84 1 NOP 1 + + DJNZ R0,jlab ;d8 2 NOP 1 + DJNZ R1,jlab ;d9 2 NOP 1 + DJNZ R2,jlab ;dA 2 NOP 1 + DJNZ R3,jlab ;dB 2 NOP 1 + DJNZ R4,jlab ;dC 2 NOP 1 + DJNZ R5,jlab ;dD 2 NOP 1 + DJNZ R6,jlab ;dE 2 NOP 1 + DJNZ R7,jlab ;dF 2 NOP 1 + DJNZ lab2,jlab ;d5 3 CR 1 + + INC A ;04 1 NOP 1 + INC R0 ;08 1 NOP 1 + INC R1 ;09 1 NOP 1 + INC R2 ;0A 1 NOP 1 + INC R3 ;0B 1 NOP 1 + INC R4 ;0C 1 NOP 1 + INC R5 ;0D 1 NOP 1 + INC R6 ;0E 1 NOP 1 + INC R7 ;0F 1 NOP 1 + INC @R0 ;06 1 NOP 1 + INC @R1 ;07 1 NOP 1 + INC DPTR ;a3 1 NOP 1 + INC lab2 ;05 2 NOP 1 + +jlab: + JB labbt_1,jlab ;20 3 CR 1 + JBC labbt_1,jlab ;10 3 CR 1 + JC jlab ;40 2 R1 1 + JMP @A+DPTR ;73 1 NOP 1 + JNB labbt_1,jlab ;30 3 CR 1 + JNC jlab ;50 2 R1 1 + JNZ jlab ;70 2 R1 1 + JZ jlab ;60 2 R1 1 + + LCALL lab3 ;12 3 SWAP 1 + + LJMP lab3 ;02 3 SWAP 1 + + MOV A,R0 ;e8 1 NOP 1 + MOV A,R1 ;e9 1 NOP 1 + MOV A,R2 ;eA 1 NOP 1 + MOV A,R3 ;eB 1 NOP 1 + MOV A,R4 ;eC 1 NOP 1 + MOV A,R5 ;eD 1 NOP 1 + MOV A,R6 ;eE 1 NOP 1 + MOV A,R7 ;eF 1 NOP 1 + MOV A,@R0 ;e6 1 NOP 1 + MOV A,@R1 ;e7 1 NOP 1 + MOV A,#labimm ;74 2 NOP 1 + MOV A,lab2 ;e5 2 NOP 1 + MOV C,bit ;a2 2 NOP 1 + MOV DPTR,#labimm ;90 3 SWAP 1 + MOV R0,A ;f8 1 NOP 1 + MOV R1,A ;f9 1 NOP 1 + MOV R2,A ;fA 1 NOP 1 + MOV R3,A ;fB 1 NOP 1 + MOV R4,A ;fC 1 NOP 1 + MOV R5,A ;fD 1 NOP 1 + MOV R6,A ;fE 1 NOP 1 + MOV R7,A ;fF 1 NOP 1 + MOV R0,#labimm ;78 2 NOP 1 + MOV R1,#labimm ;79 2 NOP 1 + MOV R2,#labimm ;7A 2 NOP 1 + MOV R3,#labimm ;7B 2 NOP 1 + MOV R4,#labimm ;7C 2 NOP 1 + MOV R5,#labimm ;7D 2 NOP 1 + MOV R6,#labimm ;7E 2 NOP 1 + MOV R7,#labimm ;7F 2 NOP 1 + MOV R0,lab2 ;a8 2 NOP 1 + MOV R1,lab2 ;a9 2 NOP 1 + MOV R2,lab2 ;aA 2 NOP 1 + MOV R3,lab2 ;aB 2 NOP 1 + MOV R4,lab2 ;aC 2 NOP 1 + MOV R5,lab2 ;aD 2 NOP 1 + MOV R6,lab2 ;aE 2 NOP 1 + MOV R7,lab2 ;aF 2 NOP 1 + MOV @R0,A ;f6 1 NOP 1 + MOV @R1,A ;f7 1 NOP 1 + MOV @R0,#labimm ;76 2 NOP 1 + MOV @R1,#labimm ;77 2 NOP 1 + MOV @R0,lab2 ;a6 2 NOP 1 + MOV @R1,lab2 ;a7 2 NOP 1 + MOV lab2,A ;f5 2 NOP 1 + MOV bit,C ;92 2 NOP 1 + MOV lab2,R0 ;88 2 NOP 1 + MOV lab2,R1 ;89 2 NOP 1 + MOV lab2,R2 ;8A 2 NOP 1 + MOV lab2,R3 ;8B 2 NOP 1 + MOV lab2,R4 ;8C 2 NOP 1 + MOV lab2,R5 ;8D 2 NOP 1 + MOV lab2,R6 ;8E 2 NOP 1 + MOV lab2,R7 ;8F 2 NOP 1 + MOV lab2,@R0 ;86 2 NOP 1 + MOV lab2,@R1 ;87 2 NOP 1 + MOV lab2,#labimm ;75 3 COMBINE 1 + MOV lab5,lab2 ;85 3 COMBINE 1 + + MOVC A,@A+DPTR ;93 1 NOP 1 + MOVC A,@A+PC ;83 1 NOP 1 + + MOVX A,@R0 ;e2 1 NOP 1 + MOVX A,@R1 ;e3 1 NOP 1 + MOVX A,@DPTR ;e0 1 NOP 1 + MOVX @R0,A ;f2 1 NOP 1 + MOVX @R1,A ;f3 1 NOP 1 + MOVX @DPTR,A ;f0 1 NOP 1 + + MUL AB ;a4 1 NOP 1 + + NOP ;00 1 NOP 1 + + ORL A,R0 ;48 1 NOP 1 + ORL A,R1 ;49 1 NOP 1 + ORL A,R2 ;4A 1 NOP 1 + ORL A,R3 ;4B 1 NOP 1 + ORL A,R4 ;4C 1 NOP 1 + ORL A,R5 ;4D 1 NOP 1 + ORL A,R6 ;4E 1 NOP 1 + ORL A,R7 ;4F 1 NOP 1 + ORL A,@R0 ;46 1 NOP 1 + ORL A,@R1 ;47 1 NOP 1 + ORL A,#labimm ;44 2 NOP 1 + ORL A,lab2 ;45 2 NOP 1 + ORL C,/bit ;a0 2 NOP 1 + ORL C,bit ;72 2 NOP 1 + ORL lab2,A ;42 2 NOP 1 + ORL lab2,#labimm ;43 3 COMBINE 1 + + POP lab2 ;d0 2 NOP 1 + PUSH lab2 ;c0 2 NOP 1 + + RET ;22 1 NOP 1 + RETI ;32 1 NOP 1 + + RL A ;23 1 NOP 1 + RLC A ;33 1 NOP 1 + RR A ;03 1 NOP 1 + RRC A ;13 1 NOP 1 + +jlab5: + SETB C ;d3 1 NOP 1 + SETB bit ;d2 2 NOP 1 + + SJMP jlab5 ;80 2 NOP 1 + + SUBB A,R0 ;98 1 NOP 1 + SUBB A,R1 ;99 1 NOP 1 + SUBB A,R2 ;9A 1 NOP 1 + SUBB A,R3 ;9B 1 NOP 1 + SUBB A,R4 ;9C 1 NOP 1 + SUBB A,R5 ;9D 1 NOP 1 + SUBB A,R6 ;9E 1 NOP 1 + SUBB A,R7 ;9F 1 NOP 1 + SUBB A,@R0 ;96 1 NOP 1 + SUBB A,@R1 ;97 1 NOP 1 + SUBB A,#labimm ;94 2 NOP 1 + SUBB A,lab2 ;95 2 NOP 1 + + SWAP A ;c4 1 NOP 1 + + XCH A,R0 ;c8 1 NOP 1 + XCH A,R1 ;c9 1 NOP 1 + XCH A,R2 ;cA 1 NOP 1 + XCH A,R3 ;cB 1 NOP 1 + XCH A,R4 ;cC 1 NOP 1 + XCH A,R5 ;cD 1 NOP 1 + XCH A,R6 ;cE 1 NOP 1 + XCH A,R7 ;cF 1 NOP 1 + XCH A,@R0 ;c6 1 NOP 1 + XCH A,@R1 ;c7 1 NOP 1 + XCH A,lab2 ;c5 2 NOP 1 + + XCHD A,@R0 ;d6 1 NOP 1 + XCHD A,@R1 ;d7 1 NOP 1 + + XRL A,R0 ;68 1 NOP 1 + XRL A,R1 ;69 1 NOP 1 + XRL A,R2 ;6A 1 NOP 1 + XRL A,R3 ;6B 1 NOP 1 + XRL A,R4 ;6C 1 NOP 1 + XRL A,R5 ;6D 1 NOP 1 + XRL A,R6 ;6E 1 NOP 1 + XRL A,R7 ;6F 1 NOP 1 + XRL A,@R0 ;66 1 NOP 1 + XRL A,@R1 ;67 1 NOP 1 + XRL A,#labimm ;64 2 NOP 1 + XRL A,lab2 ;65 2 NOP 1 + XRL lab2,A ;62 2 NOP 1 + XRL lab2,#labimm ;63 3 COMBINE 1 + + .end diff --git a/trunk/Tools/tasm32/TEST65.ASM b/trunk/Tools/tasm32/TEST65.ASM new file mode 100644 index 00000000..7f5f8f2f --- /dev/null +++ b/trunk/Tools/tasm32/TEST65.ASM @@ -0,0 +1,298 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test65.asm 1.2 1997/11/29 13:07:53 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: 6502 +; + + + +#define FLAG1 +#define TORG $1234 + .org $56 +zlabel .byte $12 + .word $1234 + .word $1234/3 + .word 1234h + .word %0101010 + .word 0101010b + .word @1234 + .word 1234o + .word 1234 + .word 1234d + .word 0d + .word 1d + .word 2d + .word 3d + .word 4d + .word 10d + .word 20d + .word 100d + .word * + .word $ + .word 3 * 7 + .word 3 + 7 + .word 3 - 7 + .word 73 % 7 + .word $1234 >> 4 + .word $1234 << 4 + .word 1 = 1 + .word 1 = 0 + .word 1 >= 1 + .word 1 >= 2 + .word 1 >= 0 + .word 1 <= 1 + .word 1 <= 2 + .word 1 <= 0 + .word 1 <= -1 + .word TORG + + .org $0234 +alabel + ADC #zlabel + ADC (zlabel,X) + ADC (zlabel),Y + ADC (zlabel) + ADC (alabel & $ff) ; suppress UNUSED DATA error + ADC zlabel,X + ADC zlabel,Y + ADC zlabel + ADC alabel + + AND #zlabel + AND (zlabel,X) + AND (zlabel),Y + AND (zlabel) + AND zlabel,X + AND zlabel,Y + AND zlabel + AND alabel + + ASL A + ASL zlabel,X + ASL zlabel +loop + BCC loop + BCS loop + BEQ loop + BNE loop + BMI loop + BPL loop + BVC loop + BVS loop + + BIT #zlabel + BIT zlabel,X + BIT zlabel + BIT alabel + + BRK + + CLC + CLD + CLI + CLV + + CMP #zlabel + CMP (zlabel,X) + CMP (zlabel),Y + CMP (zlabel) + CMP zlabel,X + CMP zlabel,Y + CMP zlabel + CMP alabel + + CPX #zlabel + CPX zlabel + CPX alabel + + CPY #zlabel + CPY zlabel + CPY alabel + + DEC A + DEC zlabel,X + DEC alabel,X + DEC zlabel + DEC alabel + + DEX + DEY + + EOR #zlabel + EOR (zlabel,X) + EOR (zlabel),Y + EOR (zlabel) + EOR zlabel,X + EOR zlabel,Y + EOR zlabel + EOR alabel + + INC A + INC zlabel,X + INC alabel,X + INC zlabel + INC alabel + + INX + INY + + JMP (zlabel,X) + JMP (zlabel) + JMP zlabel + + JSR zlabel + JSR alabel + + LDA #zlabel + LDA (zlabel,X) + LDA (zlabel),Y + LDA (zlabel) + LDA zlabel,X + LDA zlabel,Y + LDA zlabel + LDA alabel + + LDX #zlabel + LDX zlabel,Y + LDX zlabel + LDX alabel + + LDY #zlabel + LDY zlabel,X + LDY zlabel + LDY alabel + + LSR A + LSR zlabel,X + LSR zlabel + LSR alabel + + NOP + + ORA #zlabel + ORA (zlabel,X) + ORA (zlabel),Y + ORA (zlabel) + ORA zlabel,X + ORA zlabel,Y + ORA zlabel + ORA alabel + + PHA + PHP + PLA + PLP + + ROL A + ROL zlabel,X + ROL zlabel + ROL alabel + + ROR A + ROR zlabel,X + ROR alabel,X + ROR zlabel + ROR alabel + + RTI + RTS + + SBC #zlabel + SBC (zlabel,X) + SBC (zlabel),Y + SBC (zlabel) + SBC zlabel,X + SBC zlabel,Y + SBC zlabel + SBC alabel + + SEC + SED + SEI + + STA (zlabel,X) + STA (zlabel),Y + STA (zlabel) + STA zlabel,X + STA zlabel,Y + STA zlabel + STA alabel + + STX zlabel,Y + STX zlabel + STX alabel + + STY zlabel,X + STY zlabel + STY alabel + + TAX + TAY + TSX + TXA + TXS + TYA + + BRA loop2 +loop2 + BBR0 zlabel,loop2 + BBR1 zlabel,loop2 + BBR2 zlabel,loop2 + BBR3 zlabel,loop2 + BBR4 zlabel,loop2 + BBR5 zlabel,loop2 + BBR6 zlabel,loop2 + BBR7 zlabel,loop2 + + BBS0 zlabel,loop2 + BBS1 zlabel,loop2 + BBS2 zlabel,loop2 + BBS3 zlabel,loop2 + BBS4 zlabel,loop2 + BBS5 zlabel,loop2 + BBS6 zlabel,loop2 + BBS7 zlabel,loop2 + + MUL + + PHX + PHY + PLX + PLY + + RMB0 zlabel + RMB1 zlabel + RMB2 zlabel + RMB3 zlabel + RMB4 zlabel + RMB5 zlabel + RMB6 zlabel + RMB7 zlabel + + SMB0 zlabel + SMB1 zlabel + SMB2 zlabel + SMB3 zlabel + SMB4 zlabel + SMB5 zlabel + SMB6 zlabel + SMB7 zlabel + + + STZ zlabel,X + STZ zlabel + STZ alabel + + TRB zlabel + TSB zlabel + .end + + + + + + diff --git a/trunk/Tools/tasm32/TEST68.ASM b/trunk/Tools/tasm32/TEST68.ASM new file mode 100644 index 00000000..bd80b02b --- /dev/null +++ b/trunk/Tools/tasm32/TEST68.ASM @@ -0,0 +1,422 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test68.asm 1.1 1993/08/02 01:24:21 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: 6801/6803/68HC11 +; + + +data1 .equ $12 +data2 .equ $1234 + + ABA + ABX + + ADDA #data1 ;8B + ADDA data1,X ;AB + ADDA data1 ;9B + ADDA data2 ;BB + + ADDB #data1 ;CB + ADDB data1,X ;EB + ADDB data1 ;DB + ADDB data2 ;FB + + ADCA #data1 ;89 + ADCA data1,X ;A9 + ADCA data1 ;99 + ADCA data2 ;B9 + + ADCB #data1 ;C9 + ADCB data1,X ;E9 + ADCB data1 ;D9 + ADCB data2 ;F9 + + ADDD #data1 ;C3 + ADDD data1,X ;E3 + ADDD data1 ;D3 + ADDD data2 ;F3 + + ANDA #data1 ;84 + ANDA data1,X ;A4 + ANDA data1 ;94 + ANDA data2 ;B4 + + ANDB #data1 ;C4 + ANDB data1,X ;E4 + ANDB data1 ;D4 + ANDB data2 ;F4 + + ASL data1,X ;68 + ASL data1 ;78 + ASL data2 ;78 + ASLA ;48 + ASLB ;58 + ASLD ;05 + + ASR data1,X ; + ASR data1 ; + ASR data2 ; + ASRA ; + ASRB ; + +loop1: + BRA loop1 ;20 + BRN loop1 ;21 + BCC loop1 ;24 + BCS loop1 ;25 + BEQ loop1 ;27 + BGE loop1 ;2C + BGT loop1 ;2E + BHI loop1 ;22 + BHS loop1 ;24 + + BITA #data1 ;85 + BITA data1,X ;A5 + BITA data1 ;B5 + BITA data2 ;B5 + + BITB #data1 ;C5 + BITB data1,X ;E5 + BITB data1 ;F5 + BITB data2 ;F5 + + BLE loop1 ;2F + BLO loop1 ;25 + BLS loop1 ;23 + BLT loop1 ;2D + BMI loop1 ;2B + BNE loop1 ;26 + BVC loop1 ;28 + BVS loop1 ;29 + BPL loop1 ;2A + BSR loop1 ;8D + + CBA + CLC ;0C + CLI ;0E + CLR data1,X ;6F + CLR data1 ;7F + CLR data2 ;7F + CLRA ;4F + CLRB ;5F + CLV ;0A + + COM data1,X ;63 + COM data1 ;73 + COM data2 ;73 + COMA ;43 + COMB ;53 + + CPX #data1 ;8C + CPX data1,X ;AC + CPX data1 ;9C + CPX data2 ;BC + + CMPA #data1 ; + CMPA data1,X ; + CMPA data1 ; + CMPA data2 ; + + CMPB #data1 ; + CMPB data1,X ; + CMPB data1 ; + CMPB data2 ; + + DAA ;19 + + DEC data1,X + DEC data1 + DEC data2 + + DECA ;4A + DECB ;5A + DES ;34 + DEX ;09 + + EORA #data1 ; + EORA data1,X ; + EORA data1 ; + EORA data2 ; + + EORB #data1 ; + EORB data1,X ; + EORB data1 ; + EORB data2 ; + + INC data1,X + INC data1 + INC data2 + + INCA ;4C + INCB ;5C + INS ;31 + INX ;08 + + JMP data1,X ;63 + JMP data1 ;7E + JMP data2 ;7E + + JSR data1,X ;AD + JSR data1 ;9D + JSR data2 ;BD + + LDAA #data1 ;86 + LDAA data1,X ;A6 + LDAA data1 ;96 + LDAA data2 ;B6 + + LDAB #data1 ;C6 + LDAB data1,X ;E6 + LDAB data1 ;D6 + LDAB data2 ;F6 + + LDD #data1 ;CC + LDD data1,X ;EC + LDD data1 ;DC + LDD data2 ;FC + + LDS #data1 ;8E + LDS data1,X ;AE + LDS data1 ;9E + LDS data2 ;BE + + LDX #data1 ;CE + LDX data1,X ;EE + LDX data1 ;DE + LDX data2 ;FE + + LSLA ;48 + LSLB ;58 + LSLD ;05 + + LSRA ;44 + LSRB ;54 + LSRD ;04 + LSR data1,X ;64 + LSR data1 ;74 + LSR data2 ;74 + + MUL ;3D + + NEG data1,X ;60 + NEG data1 ;70 + NEG data2 ;70 + NEGA ;40 + NEGB ;50 + + NOP ;01 + + ORAA #data1 ;8A + ORAA data1,X ;AA + ORAA data1 ;BA + ORAA data2 ;9A + + ORAB #data1 ;CA + ORAB data1,X ;EA + ORAB data1 ;DA + ORAB data2 ;FA + + PSHA ;36 + PSHB ;37 + PSHX ;3C + + PULA ;32 + PULB ;33 + PULX ;38 + + ROL data1,X ;69 + ROL data1 ;79 + ROLA ;49 + ROLB ;59 + + ROR data1,X ;66 + ROR data1 ;76 + RORA ;46 + RORB ;56 + + RTI ;3B + RTS ;39 + + SBA ;10 + + SBCA #data1 ;82 + SBCA data1,X ;A2 + SBCA data1 ;92 + SBCA data2 ;B2 + + SBCB #data1 ;C2 + SBCB data1,X ;E2 + SBCB data1 ;D2 + SBCB data2 ;F2 + + SEI ;0F + SEV ;0B + SEC + + STS data1,X + STS data1 + STS data2 + + STAA data1,X ;A7 + STAA data1 ;97 + STAA data2 ;B7 + + STAB data1,X ;E7 + STAB data1 ;D7 + STAB data2 ;F7 + + STD data1,X ;ED + STD data1 ;DD + STD data2 ;FD + + STX data1,X ;EF + STX data1 ;FF + + SUBA #data1 ;80 + SUBA data1,X ;A0 + SUBA data1 ;90 + SUBA data2 ;B0 + + SUBB #data1 ;C0 + SUBB data1,X ;E0 + SUBB data1 ;D0 + SUBB data2 ;F0 + + SUBD #data1 ;83 + SUBD data1,X ;A3 + SUBD data1 ;93 + SUBD data2 ;B3 + + SWI ;3F + + TAB ;16 + TAP ;06 + TPA ;07 + TBA ;17 + + TST data1,X + TST data1 + TST data2 + + TSTA ;4D + TSTB ;5D + + TXS ;35 + TSX ;30 + + WAI ;3E + +; +; Test all the new 68HC11 instructions +; +bmsk .equ 12h +addr1 .equ 34h +addr2 .equ 5678h +imm .equ 55h + + ABY ;183A + ADCA addr1,Y ;18A9 + ADCB addr1,Y ;18E9 + ADDA addr1,Y ;18AB + ADDB addr1,Y ;18EB + ADDD addr1,Y ;18E3 + ANDA addr1,Y ;18A4 + ANDB addr1,Y ;18E4 + ASL addr1,Y ;1868 + ASR addr1,Y ;1867 +lab1 + BCLR addr1,Y,bmsk + BCLR addr1,X,bmsk + BCLR addr1,bmsk + + BITA addr1,Y ;18A5 + BITB addr1,Y ;18E5 + + BRCLR addr1,Y,bmsk,lab1 + BRCLR addr1,X,bmsk,lab1 + BRCLR addr1,bmsk,lab1 + BRCLR addr2,bmsk,lab1 + + BRSET addr1,Y,bmsk,lab1 + BRSET addr1,X,bmsk,lab1 + BRSET addr1,bmsk,lab1 + BRSET addr2,bmsk,lab1 + + BSET addr1,Y,bmsk + BSET addr1,X,bmsk + BSET addr1,bmsk + + CLR addr1,Y ;186F + CMPA addr1,Y ;18A1 + CMPB addr1,Y ;18E1 + COM addr1,Y ;1863 + CPD #imm ;1A83 + CPD addr1,X ;1AA3 + CPD addr1,Y ;CDA3 + CPD addr1 ;1AB3 + CPD addr2 ;1AB3 + CPX addr1,Y ;CDAC + CPY #imm ;188C + CPY addr1,Y ;18AC + CPY addr1,X ;1AAC + CPY addr1 ;18BC + CPY addr2 ;18BC + DEC addr1,Y ;186A + DEY ;1809 + EORA addr1,Y ;18A8 + EORB addr1,Y ;18E8 + FDIV ;03 + IDIV ;02 + INC addr1,Y ;186C + INY ;1808 + JMP addr1,Y ;186E + JSR addr1,Y ;18AD + LDAA addr1,Y ;18A6 + LDAB addr1,Y ;18E6 + LDD addr1,Y ;18EC + LDS addr1,Y ;18AE + LDX addr1,Y ;CDEE + LDY #imm ;18CE + LDY addr1,Y ;18EE + LDY addr1,X ;1AEE + LDY addr1 ;18FE + LDY addr2 ;18FE + LSL addr1,Y ;1868 + LSR addr1,Y ;1864 + NEG addr1,Y ;1860 + ORAA addr1,Y ;18AA + ORAB addr1,Y ;18EA + PSHY ;183C + PULY ;1838 + ROL addr1,Y ;1869 + ROR addr1,Y ;1866 + SBCA addr1,Y ;18A2 + SBCB addr1,Y ;18E2 + STAA addr1,Y ;18A7 + STAB addr1,Y ;18E7 + STD addr1,Y ;18ED + STS addr1,Y ;CDAF + STX addr1,Y ;CDEF + STY addr1,Y ;18EF + STY addr1,X ;1AEF + STY addr1 ;18FF + STY addr2 ;18FF + SUBA addr1,Y ;18A0 + SUBB addr1,Y ;18E0 + SUBD addr1,Y ;18A3 + TST addr1,Y ;186D +; TEST ; + TSY ;1830 2 NOP 4 + TYS ;1835 2 NOP 4 + XGDX ;8F 1 NOP 4 + XGDY ;188F 2 NOP 4 + + .end + + + + diff --git a/trunk/Tools/tasm32/TEST70.ASM b/trunk/Tools/tasm32/TEST70.ASM new file mode 100644 index 00000000..8c9afba5 --- /dev/null +++ b/trunk/Tools/tasm32/TEST70.ASM @@ -0,0 +1,305 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test70.asm 1.1 1993/08/02 01:24:21 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: TMS7000 +; + + + +R0 .equ 0 +R1 .equ 1 +R2 .equ 2 +R3 .equ 3 +R12 .equ 12 +R13 .equ 13 +R7 .equ 7 +data1 .equ $34 +data2 .equ $1287 +table .equ $1234 +P7 .equ 7 + + .org $f000 +start: + ADC B,A + ADC %data1,A + ADC %data1,B + ADC %data1,R7 + ADC R12,A + ADC R13,B + ADC R12,R7 + + ADD B,A + ADD %data1,A + ADD %data1,B + ADD %data1,R7 + ADD R12,A + ADD R13,B + ADD R12,R7 + + AND B,A + AND %data1,A + AND %data1,B + AND %data1,R7 + AND R12,A + AND R13,B + AND R12,R7 + + ANDP A,R7 + ANDP B,R7 + ANDP %data1,R7 + + BTJO B,A,start + BTJO %data1,A,start + BTJO %data1,B,start + BTJO %data1,R7,start + BTJO R12,A,start + BTJO R13,B,start + BTJO R12,R7,start + +loop1 + BTJOP A,P7,loop1 + BTJOP B,P7,loop1 + BTJOP %data1,P7,loop1 + + BTJZ B,A,loop1 + BTJZ %data1,A,loop1 + BTJZ %data1,B,loop1 + BTJZ %data1,R7,loop1 + BTJZ R12,A,loop1 + BTJZ R12,B,loop1 + BTJZ R12,R7,loop1 + + BTJZP A,P7,loop1 + BTJZP B,P7,loop1 + BTJZP %data1,P7,loop1 + + BR @start(B) + BR @start[B] + BR @start + BR *R7 + + CALL @sub1(B) + CALL @sub1 + CALL *R7 + +sub1: CLR A + CLR B + CLR R12 + + CLRC + + CMP B,A + CMP %data1,A + CMP %data1,B + CMP %data1,R7 + CMP R12,A + CMP R12,B + CMP R12,R7 + + CMPA @R7(B) + CMPA @R7[B] + CMPA @R7 + CMPA *R7 + + DAC B,A + DAC %data1,A + DAC %data1,B + DAC %data1,R7 + DAC R12,A + DAC R12,B + DAC R12,R7 + + DEC A + DEC B + DEC R7 + + DECD A + DECD B + DECD R7 + + DINT + + DJNZ A,loop2 + DJNZ B,loop2 + DJNZ R12,loop2 + + DSB B,A + DSB %data1,A + DSB %data1,B + DSB %data1,R7 + DSB R12,A + DSB R12,B + DSB R12,R7 + + EINT + + IDLE + + INC A + INC B + INC R7 + + INV A + INV B + INV R7 +loop2: + JMP loop2 + + JC loop2 + JEQ loop2 + JGE loop2 + JGT loop2 + JHS loop2 + JL loop2 + JN loop2 + JNC loop2 + JNE loop2 + JNZ loop2 + JP loop2 + JPZ loop2 + JZ loop2 + + LDA @table(B) + LDA @table + LDA *R7 + + LDSP + + MOV A,B + MOV B,A + MOV A,R7 + MOV B,R7 + MOV %data1,A + MOV %data1,B + MOV %data1,R7 + MOV R12,A + MOV R12,B + MOV R12,R7 + + MOVD %data2,R7 + MOVD %data2[B],R7 + MOVD R12,R7 + + MOVP A,P7 + MOVP B,P7 + MOVP %data1,P7 + MOVP P7,A + MOVP P7,B + + MPY B,A + MPY %data1,A + MPY %data1,B + MPY %data1,R7 + MPY R12,A + MPY R12,B + MPY R12,R7 + + NOP + + OR B,A + OR %data1,A + OR %data1,B + OR %data1,R7 + OR R12,A + OR R12,B + OR R12,R7 + + ORP A,P7 + ORP B,P7 + ORP %data1,P7 + + POP A + POP B + POP R7 + + POPST + POP ST + + PUSH A + PUSH B + PUSH R7 + + PUSHST + PUSH ST + + RETI + + RETS + + RL A + RL B + RL R7 + + RLC A + RLC B + RLC R7 + + RR A + RR B + RR R7 + + RRC A + RRC B + RRC R7 + + SBB B,A + SBB %data1,A + SBB %data1,B + SBB %data1,R7 + SBB R12,A + SBB R12,B + SBB R12,R7 + + SETC + + STA @table(B) + STA @table + STA *R7 + + STSP + + SUB B,A + SUB %data1,A + SUB %data1,B + SUB %data1,R7 + SUB R12,A + SUB R12,B + SUB R12,R7 + + SWAP A + SWAP B + SWAP R7 + + TRAP 0 + TRAP 1 + TRAP 6 + TRAP 12 + TRAP 23 + + TST A + TSTA + TST B + TSTB + + XCHB A + XCHB R7 + + XOR B,A + XOR %data1,A + XOR %data1,B + XOR %data1,R7 + XOR R12,A + XOR R12,B + XOR R12,R7 + + XORP A,P7 + XORP B,P7 + XORP %data1,P7 + + + .end + diff --git a/trunk/Tools/tasm32/TEST85.ASM b/trunk/Tools/tasm32/TEST85.ASM new file mode 100644 index 00000000..7120d68e --- /dev/null +++ b/trunk/Tools/tasm32/TEST85.ASM @@ -0,0 +1,294 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test85.asm 1.1 1993/08/02 01:24:21 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: 8080/8085 +; + + + +idata16 .equ 1234h +idata8 .equ 12h +port .equ 34h +addr16 .equ 5678h + + .org 1000h + +start: + nop + lxi b,idata16 + stax b + inx b + inr b + dcr b + mvi b,idata8 + rlc + + dad b + ldax b + dcx b + inr c + dcr c + mvi c,idata8 + rrc + +; --- ; 10 + lxi d,idata16 + stax d + inx d + inr d + dcr d + mvi d,idata8 + ral +; --- + dad d + ldax d + dcx d + inr e + dcr e + mvi e,idata8 + rar + + rim ; 20 + lxi h,idata16 + shld addr16 + inx h + inr h + dcr h + mvi h,idata8 + daa +; --- + dad h + lhld addr16 + dcx h + inr l + dcr l + mvi l,idata8 + cma + + sim ; 30 + lxi sp,idata16 + sta addr16 + inx sp + inr m + dcr m + mvi m,idata8 + stc +; --- + dad sp + lda addr16 + dcx sp + inr a + dcr a + mvi a,idata8 + cmc + + mov b,b ; 40 + mov b,c + mov b,d + mov b,e + mov b,h + mov b,l + mov b,m + mov b,a + mov c,b + mov c,c + mov c,d + mov c,e + mov c,h + mov c,l + mov c,m + mov c,a + + mov d,b ; 50 + mov d,c + mov d,d + mov d,e + mov d,h + mov d,l + mov d,m + mov d,a + mov e,b + mov e,c + mov e,d + mov e,e + mov e,h + mov e,l + mov e,m + mov e,a + + mov h,b ; 60 + mov h,c + mov h,d + mov h,e + mov h,h + mov h,l + mov h,m + mov h,a + mov l,b + mov l,c + mov l,d + mov l,e + mov l,h + mov l,l + mov l,m + mov l,a + + mov m,b ; 70 + mov m,c + mov m,d + mov m,e + mov m,h + mov m,l + hlt + mov m,a + mov a,b + mov a,c + mov a,d + mov a,e + mov a,h + mov a,l + mov a,m + mov a,a + + add b ; 80 + add c + add d + add e + add h + add l + add m + add a + adc b ; 88 + adc c + adc d + adc e + adc h + adc l + adc m + adc a + + sub b ; 90 + sub c + sub d + sub e + sub h + sub l + sub m + sub a + sbb b ; 98 + sbb c + sbb d + sbb e + sbb h + sbb l + sbb m + sbb a + + ana b ; a0 + ana c + ana d + ana e + ana h + ana l + ana m + ana a + xra b ; a8 + xra c + xra d + xra e + xra h + xra l + xra m + xra a + + ora b ; b0 + ora c + ora d + ora e + ora h + ora l + ora m + ora a + cmp b ; b8 + cmp c + cmp d + cmp e + cmp h + cmp l + cmp m + cmp a + + rnz ; c0 + pop b + jnz start + jmp start + cnz start + push b + adi idata8 + rst 0 + rz + ret + jz start +; --- + cz start + call start + aci idata8 + rst 1 + + rnc ; d0 + pop d + jnc start + out port + cnc start + push d + sui idata8 + rst 2 + rc +; --- + jc start + in port + cc start +; --- + sbi idata8 + rst 3 + + rpo ; e0 + pop h + jpo start + xthl + cpo start + push h + ani idata8 + rst 4 + rpe + pchl + jpe start + xchg + cpe start +; --- + xri idata8 + rst 5 + + rp ; f0 + pop psw + jp start + di + cp start + push psw + ori idata8 + rst 6 + rm + sphl + jm start + ei + cm start +; --- + cpi idata8 + rst 7 + + .END + diff --git a/trunk/Tools/tasm32/TEST96.ASM b/trunk/Tools/tasm32/TEST96.ASM new file mode 100644 index 00000000..1ed5351a --- /dev/null +++ b/trunk/Tools/tasm32/TEST96.ASM @@ -0,0 +1,887 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: test96.asm 1.1 1997/11/23 15:51:20 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: 8096/8XC196KC +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; + +; CPU "8096.TBL" ; CPU TABLE +; HOF "INT8" ; HEX FORMAT + +#define EQU .equ +#define END .end +#define ORG .org +#define DWL .dw +#define IF #if +#define ENDI #endif + +wreg: EQU 12h ; word register even address +wreg1: EQU 22h ; word register even address +wreg2: EQU 32h ; word register even address +wreg3: EQU 42h ; word register even address +lreg1: EQU 44h ; long register (32 bit) +lreg2: EQU 48h ; long register (32 bit) +breg: EQU wreg+1 ; low byte of reg. where odd is allowed +breg1: EQU wreg+3 ; low byte of reg. where odd is allowed +breg2: EQU wreg+5 ; low byte of reg. where odd is allowed +breg3: EQU wreg+7 ; low byte of reg. where odd is allowed + +imm8: EQU 88H +imm16: EQU 4321H + +addr8: EQU 12H +addr16: EQU 3456H + +ishort: EQU 12H +ishrt: EQU 12H +ilong: EQU 4567H + +count: EQU 7H + + ORG 7418h + +dtable: DWL $1234 + DWL $5678 + DWL $1234 + + +;------------------------------------- +; ADD + add wreg1,#imm8 + add wreg1,#imm16 + add wreg1,wreg2 + add wreg1,addr16 + add wreg1,[wreg2] + add wreg1,[wreg2]+ + add wreg1,addr8[wreg2] + add wreg1,addr16[wreg2] + + add wreg1,wreg2,#imm8 + add wreg1,wreg2,#imm16 + add wreg1,wreg2,wreg3 + add wreg1,wreg2,addr16 + add wreg1,wreg2,[wreg3] + add wreg1,wreg2,[wreg3]+ + add wreg1,wreg2,addr8[wreg3] + add wreg1,wreg2,addr16[wreg3] +;------------------------------------- + +;------------------------------------- +; ADDB + addb breg1,#imm8 + addb breg1,breg2 + addb breg1,addr16 + addb breg1,[wreg2] + addb breg1,[wreg2]+ + addb breg1,addr8[wreg2] + addb breg1,addr16[wreg2] + + addb breg1,breg2,#imm8 + addb breg1,breg2,breg3 + addb breg1,breg2,addr16 + addb breg1,breg2,[wreg3] + addb breg1,breg2,[wreg3]+ + addb breg1,breg2,addr8[wreg3] + addb breg1,breg2,addr16[wreg3] +;------------------------------------- + + +;------------------------------------- +; ADDB + addc wreg1,#imm8 + addc wreg1,#imm16 + addc wreg1,wreg2 + addc wreg1,addr16 + addc wreg1,[wreg2] + addc wreg1,[wreg2]+ + addc wreg1,addr8[wreg2] + addc wreg1,addr16[wreg2] + + ; No three arg form for addc +;------------------------------------- + +;------------------------------------- +; ADDCB + addcb breg1,#imm8 + addcb breg1,breg2 + addcb breg1,addr16 + addcb breg1,[wreg2] + addcb breg1,[wreg2]+ + addcb breg1,addr8[wreg2] + addcb breg1,addr16[wreg2] + + ; No three arg form for addcb +;------------------------------------- + +;------------------------------------- +; AND + and wreg1,#imm8 + and wreg1,#imm16 + and wreg1,wreg2 + and wreg1,addr16 + and wreg1,[wreg2] + and wreg1,[wreg2]+ + and wreg1,addr8[wreg2] + and wreg1,addr16[wreg2] + + and wreg1,wreg2,#imm8 + and wreg1,wreg2,#imm16 + and wreg1,wreg2,wreg3 + and wreg1,wreg2,addr16 + and wreg1,wreg2,[wreg3] + and wreg1,wreg2,[wreg3]+ + and wreg1,wreg2,addr8[wreg3] + and wreg1,wreg2,addr16[wreg3] +;------------------------------------- + +;------------------------------------- +; ANDB + andb breg1,#imm8 + andb breg1,breg2 + andb breg1,addr16 + andb breg1,[wreg2] + andb breg1,[wreg2]+ + andb breg1,addr8[wreg2] + andb breg1,addr16[wreg2] + + andb breg1,breg2,#imm8 + andb breg1,breg2,breg3 + andb breg1,breg2,addr16 + andb breg1,breg2,[wreg3] + andb breg1,breg2,[wreg3]+ + andb breg1,breg2,addr8[wreg3] + andb breg1,breg2,addr16[wreg3] +;------------------------------------- + +;------------------------------------- +; BMOV + bmov lreg1,wreg1 + bmov lreg1,wreg2 +;------------------------------------- + +;------------------------------------- +; BR + br [wreg1] +;------------------------------------- + +;------------------------------------- +; MISC CLR + clr wreg1 + clrb breg1 + clrc + clrvt +;------------------------------------- + + + +;------------------------------------- +; CMP + cmp wreg1,#imm8 + cmp wreg1,#imm16 + cmp wreg1,wreg2 + cmp wreg1,addr16 + cmp wreg1,[wreg2] + cmp wreg1,[wreg2]+ + cmp wreg1,addr8[wreg2] + cmp wreg1,addr16[wreg2] + + ; No three arg form for cmp +;------------------------------------- + +;------------------------------------- +; CMPB + cmpb breg1,#imm8 + cmpb breg1,breg2 + cmpb breg1,addr16 + cmpb breg1,[wreg2] + cmpb breg1,[wreg2]+ + cmpb breg1,addr8[wreg2] + cmpb breg1,addr16[wreg2] + + ; No three arg form for cmpb +;------------------------------------- + +;------------------------------------- +; CMPL + cmpl lreg1,lreg2 +;------------------------------------- + +;------------------------------------- +; DEC + dec wreg1 + decb breg1 +;------------------------------------- + +;------------------------------------- +; DEC + di +;------------------------------------- + + +;------------------------------------- +; DIV + div lreg1,#imm8 + div lreg1,#imm16 + div lreg1,wreg2 + div lreg1,addr16 + div lreg1,[wreg2] + div lreg1,[wreg2]+ + div lreg1,addr8[wreg2] + div lreg1,addr16[wreg2] + + ; No three arg form for div +;------------------------------------- + +;------------------------------------- +; DIVB + divb wreg1,#imm8 + divb wreg1,breg2 + divb wreg1,addr16 + divb wreg1,[wreg2] + divb wreg1,[wreg2]+ + divb wreg1,addr8[wreg2] + divb wreg1,addr16[wreg2] + + ; No three arg form for divb +;------------------------------------- + + +;------------------------------------- +; DIVU + divu lreg1,#imm8 + divu lreg1,#imm16 + divu lreg1,wreg2 + divu lreg1,addr16 + divu lreg1,[wreg2] + divu lreg1,[wreg2]+ + divu lreg1,addr8[wreg2] + divu lreg1,addr16[wreg2] + + ; No three arg form for divu +;------------------------------------- + +;------------------------------------- +; DIVUB + divub wreg1,#imm8 + divub wreg1,breg2 + divub wreg1,addr16 + divub wreg1,[wreg2] + divub wreg1,[wreg2]+ + divub wreg1,addr8[wreg2] + divub wreg1,addr16[wreg2] + + ; No three arg form for divub +;------------------------------------- + + +;------------------------------------- +; DJNZ +rtest1: ;backward reference + djnz breg1,rtest1 + djnz breg1,rtest1 + djnz breg1,rtest2 + djnz breg1,rtest2 +rtest2: ;forward reference +;------------------------------------- + +;------------------------------------- +; DJNZW + djnzw wreg1,rtest1 + djnzw wreg1,rtest1 + djnzw wreg1,rtest3 + djnzw wreg1,rtest3 +rtest3: ;forward reference +;------------------------------------- + +;------------------------------------- +; DPTS + dpts +;------------------------------------- + +;------------------------------------- +; EI + ei +;------------------------------------- + +;------------------------------------- +; EPTS + epts +;------------------------------------- + +;------------------------------------- +; EXT & EXTB + ext lreg1 + ext lreg2 + extb wreg1 + extb wreg2 +;------------------------------------- + +;------------------------------------- +; IDLPD + idlpd #1 + idlpd #2 +;------------------------------------- + +;------------------------------------- +; INC & INCB + inc wreg1 + inc wreg2 + incb breg1 + incb breg2 +;------------------------------------- + + +FLAG: EQU 3 +;------------------------------------- +; JBC + jbc breg1,0,rtest1 + jbc breg1,1,rtest1 + jbc breg1,2,rtest1 + jbc breg1,3,rtest1 + jbc breg1,4,rtest1 + jbc breg1,5,rtest1 + jbc breg1,6,rtest1 + jbc breg1,7,rtest1 +;------------------------------------- + +;------------------------------------- +; JBS + jbs breg1,0,rtest1 + jbs breg1,1,rtest1 + jbs breg1,2,rtest1 + jbs breg1,3,rtest1 + jbs breg1,4,rtest1 + jbs breg1,5,rtest1 + jbs breg1,6,rtest1 + jbs breg1,7,rtest1 +;------------------------------------- + +;------------------------------------- +; MISC Jump backward + jc rtest1 + je rtest1 + jge rtest1 + jgt rtest1 + jh rtest1 + jle rtest1 + jlt rtest1 + jnc rtest1 + jne rtest1 + jnh rtest1 + jnst rtest1 + jnv rtest1 + jnvt rtest1 + jst rtest1 + jv rtest1 + jvt rtest1 +;------------------------------------- + +;------------------------------------- +; MISC Jump forward + jc rtest4 + je rtest4 + jge rtest4 + jgt rtest4 + jh rtest4 + jle rtest4 + jlt rtest4 + jnc rtest4 + jne rtest4 + jnh rtest4 + jnst rtest4 + jnv rtest4 + jnvt rtest4 + jst rtest4 + jv rtest4 +rtest4: jvt rtest4 +;------------------------------------- + +;------------------------------------- +; LCALL + lcall rtest1 + lcall rtest2 + lcall rtest4 + lcall addr8 + lcall addr16 +;------------------------------------- + + +;------------------------------------- +; LD + ld wreg1,#imm8 + ld wreg1,#imm16 + ld wreg1,wreg2 + ld wreg1,addr16 + ld wreg1,[wreg2] + ld wreg1,[wreg2]+ + ld wreg1,addr8[wreg2] + ld wreg1,addr16[wreg2] + + ; No three arg form for ld +;------------------------------------- + +;------------------------------------- +; LDB + ldb breg1,#imm8 + ldb breg1,breg2 + ldb breg1,addr16 + ldb breg1,[wreg2] + ldb breg1,[wreg2]+ + ldb breg1,addr8[wreg2] + ldb breg1,addr16[wreg2] + + ; No three arg form for ldb +;------------------------------------- + +;------------------------------------- +; LDBSE + ldbse wreg1,#imm8 + ldbse wreg1,breg2 + ldbse wreg1,addr16 + ldbse wreg1,[wreg2] + ldbse wreg1,[wreg2]+ + ldbse wreg1,addr8[wreg2] + ldbse wreg1,addr16[wreg2] + + ; No three arg form for ldbse +;------------------------------------- + +;------------------------------------- +; LDBZE + ldbze wreg1,#imm8 + ldbze wreg1,breg2 + ldbze wreg1,addr16 + ldbze wreg1,[wreg2] + ldbze wreg1,[wreg2]+ + ldbze wreg1,addr8[wreg2] + ldbze wreg1,addr16[wreg2] + + ; No three arg form for ldbze +;------------------------------------- + +;------------------------------------- +; LJMP + ljmp addr8 + ljmp addr16 +;------------------------------------- + + +;------------------------------------- +; MUL + mul lreg1,#imm8 + mul lreg1,#imm16 + mul lreg1,wreg2 + mul lreg1,addr16 + mul lreg1,[wreg2] + mul lreg1,[wreg2]+ + mul lreg1,addr8[wreg2] + mul lreg1,addr16[wreg2] + + mul lreg1,wreg2,#imm8 + mul lreg1,wreg2,#imm16 + mul lreg1,wreg2,wreg3 + mul lreg1,wreg2,addr16 + mul lreg1,wreg2,[wreg3] + mul lreg1,wreg2,[wreg3]+ + mul lreg1,wreg2,addr8[wreg3] + mul lreg1,wreg2,addr16[wreg3] + +;------------------------------------- + + +;------------------------------------- +; MULB + mulb wreg1,#imm8 + mulb wreg1,breg2 + mulb wreg1,addr16 + mulb wreg1,[wreg2] + mulb wreg1,[wreg2]+ + mulb wreg1,addr8[wreg2] + mulb wreg1,addr16[wreg2] + + mulb wreg1,breg2,#imm8 + mulb wreg1,breg2,breg3 + mulb wreg1,breg2,addr16 + mulb wreg1,breg2,[wreg3] + mulb wreg1,breg2,[wreg3]+ + mulb wreg1,breg2,addr8[wreg3] + mulb wreg1,breg2,addr16[wreg3] +;------------------------------------- + +;------------------------------------- +; MULU + mulu lreg1,#imm8 + mulu lreg1,#imm16 + mulu lreg1,wreg2 + mulu lreg1,addr16 + mulu lreg1,[wreg2] + mulu lreg1,[wreg2]+ + mulu lreg1,addr8[wreg2] + mulu lreg1,addr16[wreg2] + + mulu lreg1,wreg2,#imm8 + mulu lreg1,wreg2,#imm16 + mulu lreg1,wreg2,wreg3 + mulu lreg1,wreg2,addr16 + mulu lreg1,wreg2,[wreg3] + mulu lreg1,wreg2,[wreg3]+ + mulu lreg1,wreg2,addr8[wreg3] + mulu lreg1,wreg2,addr16[wreg3] + +;------------------------------------- + + +;------------------------------------- +; MULUB + mulub wreg1,#imm8 + mulub wreg1,breg2 + mulub wreg1,addr16 + mulub wreg1,[wreg2] + mulub wreg1,[wreg2]+ + mulub wreg1,addr8[wreg2] + mulub wreg1,addr16[wreg2] + + mulub wreg1,breg2,#imm8 + mulub wreg1,breg2,breg3 + mulub wreg1,breg2,addr16 + mulub wreg1,breg2,[wreg3] + mulub wreg1,breg2,[wreg3]+ + mulub wreg1,breg2,addr8[wreg3] + mulub wreg1,breg2,addr16[wreg3] +;------------------------------------- + +;------------------------------------- +; NEG & NEGB + neg wreg1 + negb breg1 +;------------------------------------- + +;------------------------------------- +; NOP + nop +;------------------------------------- + +;------------------------------------- +; NORML + norml lreg1,breg1 +;------------------------------------- + +;------------------------------------- +; NOT & NOTB + not wreg1 + notb breg1 +;------------------------------------- + + +;------------------------------------- +; OR + or wreg1,#imm8 + or wreg1,#imm16 + or wreg1,wreg2 + or wreg1,addr16 + or wreg1,[wreg2] + or wreg1,[wreg2]+ + or wreg1,addr8[wreg2] + or wreg1,addr16[wreg2] + + ; No three arg form for or +;------------------------------------- + +;------------------------------------- +; ORB + orb breg1,#imm8 + orb breg1,breg2 + orb breg1,addr16 + orb breg1,[wreg2] + orb breg1,[wreg2]+ + orb breg1,addr8[wreg2] + orb breg1,addr16[wreg2] + + ; No three arg form for orb +;------------------------------------- + + +;------------------------------------- +; POP + pop wreg1 + pop [wreg1] + pop [wreg1]+ + pop addr8[wreg1] + pop addr16[wreg1] + + popa + popf +;------------------------------------- + +;------------------------------------- +; PUSH + push wreg1 + push [wreg1] + push [wreg1]+ + push addr8[wreg1] + push addr16[wreg1] + + pusha + pushf +;------------------------------------- + + +;------------------------------------- +; RET - return + ret +;------------------------------------- + +;------------------------------------- +; RST - reset + rst +;------------------------------------- + +;------------------------------------- +; SCALL - short call +scall1: +scall2: EQU scall1-1015 + scall scall1 + scall scall1 + scall scall2 + scall scall2 + scall scall3 + scall scall4 +scall3: +scall4: EQU scall3+1020 +;------------------------------------- + +;------------------------------------- +; SETC - set carry + setc +;------------------------------------- + +;------------------------------------- +; shl - shift word left + shl wreg1,#count + shl wreg2,breg1 +;------------------------------------- + +;------------------------------------- +; shlb - shift byte left + shlb breg1,#count + shlb breg2,breg1 +;------------------------------------- + +;------------------------------------- +; shll - shift long word left + shll lreg1,#count + shll lreg1,breg1 +;------------------------------------- + +;------------------------------------- +; shr - logical shift word right + shr wreg1,#count + shr wreg2,breg1 +;------------------------------------- + +;------------------------------------- +; shra - arithmetic shift word right + shra wreg1,#count + shra wreg2,breg1 +;------------------------------------- + +;------------------------------------- +; shrab - arithmetic shift byte right + shrab breg1,#count + shrab breg2,breg1 +;------------------------------------- + +;------------------------------------- +; shral - arithmetic shift long word right + shral lreg1,#count + shral lreg1,breg1 +;------------------------------------- + +;------------------------------------- +; shrb - logical shift byte right + shrb breg1,#count + shrb breg2,breg1 +;------------------------------------- + +;------------------------------------- +; shrl - logical shift long word right + shrl lreg1,#count + shrl lreg1,breg1 +;------------------------------------- + + +;------------------------------------- +; SJMP - short jump +sjump1: +sjump2: EQU sjump1-1015 + sjmp sjump1 + sjmp sjump1 + sjmp sjump2 + sjmp sjump2 + sjmp sjump3 + sjmp sjump4 +sjump3: +sjump4: EQU sjump3+1020 +;------------------------------------- + +;------------------------------------- +; skip - two byte nop + skip breg1 +;------------------------------------- + + +;------------------------------------- +; ST - store word + st wreg1,wreg2 + st wreg1,addr16 + st wreg1,[wreg2] + st wreg1,[wreg2]+ + st wreg1,addr8[wreg2] + st wreg1,addr16[wreg2] + + ; No three arg form for st; No immediate +;------------------------------------- + +;------------------------------------- +; STB - store byte + stb breg1,breg2 + stb breg1,addr16 + stb breg1,[wreg2] + stb breg1,[wreg2]+ + stb breg1,addr8[wreg2] + stb breg1,addr16[wreg2] + + ; No three arg form for stb; No immediate +;------------------------------------- + + +;------------------------------------- +; SUB - subtract word + sub wreg1,#imm8 + sub wreg1,#imm16 + sub wreg1,wreg2 + sub wreg1,addr16 + sub wreg1,[wreg2] + sub wreg1,[wreg2]+ + sub wreg1,addr8[wreg2] + sub wreg1,addr16[wreg2] + + sub wreg1,wreg2,#imm8 + sub wreg1,wreg2,#imm16 + sub wreg1,wreg2,wreg3 + sub wreg1,wreg2,addr16 + sub wreg1,wreg2,[wreg3] + sub wreg1,wreg2,[wreg3]+ + sub wreg1,wreg2,addr8[wreg3] + sub wreg1,wreg2,addr16[wreg3] +;------------------------------------- + +;------------------------------------- +; SUBB - subtract byte + subb breg1,#imm8 + subb breg1,breg2 + subb breg1,addr16 + subb breg1,[wreg2] + subb breg1,[wreg2]+ + subb breg1,addr8[wreg2] + subb breg1,addr16[wreg2] + + subb breg1,breg2,#imm8 + subb breg1,breg2,breg3 + subb breg1,breg2,addr16 + subb breg1,breg2,[wreg3] + subb breg1,breg2,[wreg3]+ + subb breg1,breg2,addr8[wreg3] + subb breg1,breg2,addr16[wreg3] +;------------------------------------- + + +;------------------------------------- +; SUBC - subtract word with carry + subc wreg1,#imm8 + subc wreg1,#imm16 + subc wreg1,wreg2 + subc wreg1,addr16 + subc wreg1,[wreg2] + subc wreg1,[wreg2]+ + subc wreg1,addr8[wreg2] + subc wreg1,addr16[wreg2] + + ; No three arg form for subc +;------------------------------------- + +;------------------------------------- +; SUBCB - subtract byte with carry + subcb breg1,#imm8 + subcb breg1,breg2 + subcb breg1,addr16 + subcb breg1,[wreg2] + subcb breg1,[wreg2]+ + subcb breg1,addr8[wreg2] + subcb breg1,addr16[wreg2] + + ; No three arg form for subcb +;------------------------------------- + + +;------------------------------------- +; tijmp - table indirect jump + tijmp wreg1,[wreg2],#imm8 + tijmp wreg2,[wreg1],#imm8 + tijmp wreg3,[wreg2],#13 +;------------------------------------- + +;------------------------------------- +; TRAP - software trap + trap +;------------------------------------- + +;------------------------------------- +; XCH - exchange word + xch wreg1,wreg2 + xch wreg1,addr16 + xch wreg1,addr8[wreg2] + xch wreg1,addr16[wreg2] +;------------------------------------- + +;------------------------------------- +; XCHB - exchange byte + xchb breg1,breg2 + xchb breg1,addr16 + xchb breg1,addr8[wreg2] + xchb breg1,addr16[wreg2] +;------------------------------------- + + +;------------------------------------- +; XOR + xor wreg1,#imm8 + xor wreg1,#imm16 + xor wreg1,wreg2 + xor wreg1,addr16 + xor wreg1,[wreg2] + xor wreg1,[wreg2]+ + xor wreg1,addr8[wreg2] + xor wreg1,addr16[wreg2] + + ; No three arg form for xor +;------------------------------------- + +;------------------------------------- +; XORB + xorb breg1,#imm8 + xorb breg1,breg2 + xorb breg1,addr16 + xorb breg1,[wreg2] + xorb breg1,[wreg2]+ + xorb breg1,addr8[wreg2] + xorb breg1,addr16[wreg2] + + ; No three arg form for xorb +;------------------------------------- + + END diff --git a/trunk/Tools/tasm32/TESTTABS.BAT b/trunk/Tools/tasm32/TESTTABS.BAT new file mode 100644 index 00000000..36bbba4c --- /dev/null +++ b/trunk/Tools/tasm32/TESTTABS.BAT @@ -0,0 +1,18 @@ +rem mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm +rem $Id: testtabs.bat 1.3 1998/02/25 12:27:04 toma Exp $ +rem mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm +rem Run TASM on all the table test files. Those that have +rem extended instuctions use the -x option. + +tasm -48 -x test48.asm +tasm -65 -x test65.asm +tasm -51 test51.asm +tasm -85 test85.asm +tasm -80 -x testz80.asm +tasm -05 -x test05.asm +tasm -3210 test3210.asm +tasm -3225 test3225.asm +tasm -68 -x test68.asm +tasm -70 test70.asm +tasm -96 -x test96.asm + diff --git a/trunk/Tools/tasm32/TESTZ80.ASM b/trunk/Tools/tasm32/TESTZ80.ASM new file mode 100644 index 00000000..4f4eb843 --- /dev/null +++ b/trunk/Tools/tasm32/TESTZ80.ASM @@ -0,0 +1,831 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; $Id: testz80.asm 1.4 1998/02/25 12:18:20 toma Exp $ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TASM test file +; Test all instructions and addressing modes. +; Processor: Z80 +; +; SEPT. 16,1987 +; CARL A. WALL +; VE3APY +; +; + +#define equ .equ +#define end .end + +n: equ 20h +nn: equ 0584h +dddd: equ 07h +addr16: equ $1234 +port: equ 3 +imm8: equ 56h ;immediate data (8 bits) +offset: equ 7 +offset_neg: equ -7 + +; try a few cases that have two expressions in the args and +; one is inside (). + LD (IX+offset),n+1+4+8-9 + LD (IX+offset+5),n-1 + LD (IX+dddd),n + LD (IX+offset),n + LD (IX+offset),n + +; Try all possible instructions + + ADC A,(HL) + ADC A,(IX+offset) + ADC A,(IX+offset_neg) + ADC A,(IY+offset) + ADC A,(IY+offset_neg) + ADC A,A + ADC A,B + ADC A,C + ADC A,D + ADC A,E + ADC A,H + ADC A,L + ADC A,n + ADC HL,BC + ADC HL,DE + ADC HL,HL + ADC HL,SP + + ADD A,(HL) + ADD A,(IX+offset) + ADD A,(IY+offset) + ADD A,A + ADD A,B + ADD A,C + ADD A,D + ADD A,E + ADD A,H + ADD A,L + ADD A,n + ADD HL,BC + ADD HL,DE + ADD HL,HL + ADD HL,SP + ADD IX,BC + ADD IX,DE + ADD IX,IX + ADD IX,SP + ADD IY,BC + ADD IY,DE + ADD IY,IY + ADD IY,SP + + AND (HL) + AND (IX+offset) + AND (IY+offset) + AND A + AND B + AND C + AND D + AND E + AND H + AND L + AND n + + BIT 0,(HL) + BIT 0,(IX+offset) + BIT 0,(IY+offset) + BIT 0,A + BIT 0,B + BIT 0,C + BIT 0,D + BIT 0,E + BIT 0,H + BIT 0,L + + BIT 1,(HL) + BIT 1,(IX+offset) + BIT 1,(IY+offset) + BIT 1,A + BIT 1,B + BIT 1,C + BIT 1,D + BIT 1,E + BIT 1,H + BIT 1,L + + BIT 2,(HL) + BIT 2,(IX+offset) + BIT 2,(IY+offset) + BIT 2,A + BIT 2,B + BIT 2,C + BIT 2,D + BIT 2,E + BIT 2,H + BIT 2,L + + BIT 3,(HL) + BIT 3,(IX+offset) + BIT 3,(IY+offset) + BIT 3,A + BIT 3,B + BIT 3,C + BIT 3,D + BIT 3,E + BIT 3,H + BIT 3,L + + BIT 4,(HL) + BIT 4,(IX+offset) + BIT 4,(IY+offset) + BIT 4,A + BIT 4,B + BIT 4,C + BIT 4,D + BIT 4,E + BIT 4,H + BIT 4,L + + BIT 5,(HL) + BIT 5,(IX+offset) + BIT 5,(IY+offset) + BIT 5,A + BIT 5,B + BIT 5,C + BIT 5,D + BIT 5,E + BIT 5,H + BIT 5,L + + BIT 6,(HL) + BIT 6,(IX+offset) + BIT 6,(IY+offset) + BIT 6,A + BIT 6,B + BIT 6,C + BIT 6,D + BIT 6,E + BIT 6,H + BIT 6,L + + BIT 7,(HL) + BIT 7,(IX+offset) + BIT 7,(IY+offset) + BIT 7,A + BIT 7,B + BIT 7,C + BIT 7,D + BIT 7,E + BIT 7,H + BIT 7,L + + CALL C,addr16 + CALL M,addr16 + CALL NC,addr16 + CALL NZ,addr16 + CALL P,addr16 + CALL PE,addr16 + CALL PO,addr16 + CALL Z,addr16 + CALL addr16 + + CCF + + CP (HL) + CP (IX+offset) + CP (IY+offset) + CP A + CP B + CP C + CP D + CP E + CP H + CP L + CP imm8 + CPD + CPDR + CPIR + CPI + CPL + + DAA + + DEC (HL) + DEC (IX+offset) + DEC (IY+offset) + DEC A + DEC B + DEC BC + DEC C + DEC D + DEC DE + DEC E + DEC H + DEC HL + DEC IX + DEC IY + DEC L + DEC SP + DI +loop1: + DJNZ loop1 + + EI + EX (SP),HL + EX (SP),IX + EX (SP),IY + EX AF,AF' + EX DE,HL + EXX + HALT + + IM 0 + IM 1 + IM 2 + + IN A,(C) + IN B,(C) + IN C,(C) + IN D,(C) + IN E,(C) + IN H,(C) + IN L,(C) + IN A,(port) + + IN0 B,(n) + IN0 C,(n) + IN0 D,(n) + IN0 E,(n) + IN0 H,(n) + IN0 L,(n) + + INC (HL) + INC (IX+offset) + INC (IY+offset) + INC A + INC B + INC BC + INC C + INC D + INC DE + INC E + INC H + INC HL + INC IX + INC IY + INC L + INC SP + + IND + INDR + INI + INIR + + JP addr16 + JP (HL) + JP (IX) + JP (IY) + JP C,addr16 + JP M,addr16 + JP NC,addr16 + JP NZ,addr16 + JP P,addr16 + JP PE,addr16 + JP PO,addr16 + JP Z,addr16 + +loop2: + JR C,loop2 + JR NC,loop2 + JR NZ,loop2 + JR Z,loop2 + JR loop2 + + LD (BC),A + LD (DE),A + LD (HL),A + LD (HL),B + LD (HL),C + LD (HL),D + LD (HL),E + LD (HL),H + LD (HL),L + LD (HL),n + LD (IX+offset),A + LD (IX+offset),B + LD (IX+offset),C + LD (IX+offset),D + LD (IX+offset),E + LD (IX+offset),H + LD (IX+offset),L + LD (IX+offset),n + LD (IY+offset),A + LD (IY+offset),B + LD (IY+offset),C + LD (IY+offset),D + LD (IY+offset),E + LD (IY+offset),H + LD (IY+offset),L + LD (IY+offset),n + LD (nn),A + LD (nn),BC + LD (nn),DE + LD (nn),HL + LD (nn),IX + LD (nn),IY + LD (nn),SP + LD A,(BC) + LD A,(DE) + LD A,(HL) + LD A,(IX+offset) + LD A,(IY+offset) + LD A,(nn) + LD A,A + LD A,B + LD A,C + LD A,D + LD A,E + LD A,H + LD A,I + LD A,L + LD A,n + LD A,R + LD B,(HL) + LD B,(IX+offset) + LD B,(IY+offset) + LD B,A + LD B,B + LD B,C + LD B,D + LD B,E + LD B,H + LD B,L + LD B,n + LD BC,(nn) + LD BC,nn + LD C,(HL) + LD C,(IX+offset) + LD C,(IY+offset) + LD C,A + LD C,B + LD C,C + LD C,D + LD C,E + LD C,H + LD C,L + LD C,n + LD D,(HL) + LD D,(IX+offset) + LD D,(IY+offset) + LD D,A + LD D,B + LD D,C + LD D,D + LD D,E + LD D,H + LD D,L + LD D,n + LD DE,(nn) + LD DE,nn + LD E,(HL) + LD E,(IX+offset) + LD E,(IY+offset) + LD E,A + LD E,B + LD E,C + LD E,D + LD E,E + LD E,H + LD E,L + LD E,n + LD H,(HL) + LD H,(IX+offset) + LD H,(IY+offset) + LD H,A + LD H,B + LD H,C + LD H,D + LD H,E + LD H,H + LD H,L + LD H,n + LD HL,(nn) + LD HL,nn + LD I,A + LD IX,(nn) + LD IX,nn + LD IY,(nn) + LD IY,nn + LD L,(HL) + LD L,(IX+offset) + LD L,(IY+offset) + LD L,A + LD L,B + LD L,C + LD L,D + LD L,E + LD L,H + LD L,L + LD L,n + LD R,A + LD SP,(nn) + LD SP,HL + LD SP,IX + LD SP,IY + LD SP,nn + + LDD + LDDR + LDI + LDIR + + MLT BC + MLT DE + MLT HL + MLT SP + + NEG + NOP + + OR (HL) + OR (IX+offset) + OR (IY+offset) + OR A + OR B + OR C + OR D + OR E + OR H + OR L + OR imm8 + + OTDR + OTIR + + OUT (C),A + OUT (C),B + OUT (C),C + OUT (C),D + OUT (C),E + OUT (C),H + OUT (C),L + OUT (port),A + + OUT0 (imm8),A + OUT0 (imm8),B + OUT0 (imm8),C + OUT0 (imm8),D + OUT0 (imm8),E + OUT0 (imm8),H + OUT0 (imm8),L + + OUTD + OUTI + OTIM + OTDM + OTIMR + OTDMR + + POP AF + POP BC + POP DE + POP HL + POP IX + POP IY + + PUSH AF + PUSH BC + PUSH DE + PUSH HL + PUSH IX + PUSH IY + + RES 0,(HL) + RES 0,(IX+offset) + RES 0,(IY+offset) + RES 0,A + RES 0,B + RES 0,C + RES 0,D + RES 0,E + RES 0,H + RES 0,L + + RES 1,(HL) + RES 1,(IX+offset) + RES 1,(IY+offset) + RES 1,A + RES 1,B + RES 1,C + RES 1,D + RES 1,E + RES 1,H + RES 1,L + + RES 2,(HL) + RES 2,(IX+offset) + RES 2,(IY+offset) + RES 2,A + RES 2,B + RES 2,C + RES 2,D + RES 2,E + RES 2,H + RES 2,L + + RES 3,(HL) + RES 3,(IX+offset) + RES 3,(IY+offset) + RES 3,A + RES 3,B + RES 3,C + RES 3,D + RES 3,E + RES 3,H + RES 3,L + + RES 4,(HL) + RES 4,(IX+offset) + RES 4,(IY+offset) + RES 4,A + RES 4,B + RES 4,C + RES 4,D + RES 4,E + RES 4,H + RES 4,L + + RES 5,(HL) + RES 5,(IX+offset) + RES 5,(IY+offset) + RES 5,A + RES 5,B + RES 5,C + RES 5,D + RES 5,E + RES 5,H + RES 5,L + + RES 6,(HL) + RES 6,(IX+offset) + RES 6,(IY+offset) + RES 6,A + RES 6,B + RES 6,C + RES 6,D + RES 6,E + RES 6,H + RES 6,L + + RES 7,(HL) + RES 7,(IX+offset) + RES 7,(IY+offset) + RES 7,A + RES 7,B + RES 7,C + RES 7,D + RES 7,E + RES 7,H + RES 7,L + + RET + RET C + RET M + RET NC + RET NZ + RET P + RET PE + RET PO + RET Z + RETI + RETN + + RL (HL) + RL (IX+offset) + RL (IY+offset) + RL A + RL B + RL C + RL D + RL E + RL H + RL L + RLA + + RLC (HL) + RLC (IX+offset) + RLC (IY+offset) + RLC A + RLC B + RLC C + RLC D + RLC E + RLC H + RLC L + RLCA + RLD + + RR (HL) + RR (IX+offset) + RR (IY+offset) + RR A + RR B + RR C + RR D + RR E + RR H + RR L + RRA + + RRC (HL) + RRC (IX+offset) + RRC (IY+offset) + RRC A + RRC B + RRC C + RRC D + RRC E + RRC H + RRC L + RRCA + RRD + + RST 00H + RST 08H + RST 10H + RST 18H + RST 20H + RST 28H + RST 30H + RST 38H + + SBC A,n + SBC A,(HL) + SBC A,(IX+offset) + SBC A,(IY+offset) + SBC A,A + SBC A,B + SBC A,C + SBC A,D + SBC A,E + SBC A,H + SBC A,L + SBC HL,BC + SBC HL,DE + SBC HL,HL + SBC HL,SP + SCF + + SET 0,(HL) + SET 0,(IX+offset) + SET 0,(IY+offset) + SET 0,A + SET 0,B + SET 0,C + SET 0,D + SET 0,E + SET 0,H + SET 0,L + + SET 1,(HL) + SET 1,(IX+offset) + SET 1,(IY+offset) + SET 1,A + SET 1,B + SET 1,C + SET 1,D + SET 1,E + SET 1,H + SET 1,L + + SET 2,(HL) + SET 2,(IX+offset) + SET 2,(IY+offset) + SET 2,A + SET 2,B + SET 2,C + SET 2,D + SET 2,E + SET 2,H + SET 2,L + + SET 3,(HL) + SET 3,(IX+offset) + SET 3,(IY+offset) + SET 3,A + SET 3,B + SET 3,C + SET 3,D + SET 3,E + SET 3,H + SET 3,L + + SET 4,(HL) + SET 4,(IX+offset) + SET 4,(IY+offset) + SET 4,A + SET 4,B + SET 4,C + SET 4,D + SET 4,E + SET 4,H + SET 4,L + + SET 5,(HL) + SET 5,(IX+offset) + SET 5,(IY+offset) + SET 5,A + SET 5,B + SET 5,C + SET 5,D + SET 5,E + SET 5,H + SET 5,L + + SET 6,(HL) + SET 6,(IX+offset) + SET 6,(IY+offset) + SET 6,A + SET 6,B + SET 6,C + SET 6,D + SET 6,E + SET 6,H + SET 6,L + + SET 7,(HL) + SET 7,(IX+offset) + SET 7,(IY+offset) + SET 7,A + SET 7,B + SET 7,C + SET 7,D + SET 7,E + SET 7,H + SET 7,L + + SLA (HL) + SLA (IX+offset) + SLA (IY+offset) + SLA A + SLA B + SLA C + SLA D + SLA E + SLA H + SLA L + + SLP + + SRA (HL) + SRA (IX+offset) + SRA (IY+offset) + SRA A + SRA B + SRA C + SRA D + SRA E + SRA H + SRA L + + SRL (HL) + SRL (IX+offset) + SRL (IY+offset) + SRL A + SRL B + SRL C + SRL D + SRL E + SRL H + SRL L + + SUB (HL) + SUB (IX+offset) + SUB (IY+offset) + SUB A + SUB B + SUB C + SUB D + SUB E + SUB H + SUB L + SUB n + + TST A + TST B + TST C + TST D + TST E + TST (HL) + TST n + + XOR (HL) + XOR (IX+offset) + XOR (IY+offset) + XOR A + XOR B + XOR C + XOR D + XOR E + XOR H + XOR L + XOR n + end diff --git a/trunk/XSource/Makefile b/trunk/XSource/Makefile new file mode 100644 index 00000000..76aa80ea --- /dev/null +++ b/trunk/XSource/Makefile @@ -0,0 +1,412 @@ + +# GCC based makefile +# +# 06/18/2012 2.0 dgg - updated for v2.0 +# +# 02/22/2012 1.5 dgg - modified for assembly under Linux +# +# 01/11/2011 1.4 wbw - added support for ZSDOS/ZDDOS/ZCPR +# +# 12/22/2011 1.3 wbw - removed all built-in config stuff, operation is now entirely +# dependent on variables CONFIG, ROMSIZE, and CPU +# +# 12/02/2011 1.3 wbw - replaced makever functionality with built-in makefile stuff +# +# 11/29/2011 1.3 dwg - uses makever to generate stdincl.inc from the version.hpp file +# +# 11/19/2011 1.3 dwg - added n8vem_vdu to "usage" and "all" rules +# enhanced clean to get files in $(OUTDIR) +# added custom to "all" rule + +# +# The operation of this makefile is entirely dependent on the setting +# of three variables: CONFIG, ROMSIZE, and CPU: +# +# CONFIG determines which configuration to build which means that +# it will determine the config_xxx.asm config settings file to +# include as well as the output file names. So, for example, +# if CONFIG is "n8vem", the config_n8vem.asm file will be used +# for BIOS configuration settings and the output files will be +# n8vem.rom, n8vem.sys, and n8vem.com. +# +# ROMSIZE specifies the size of the ROM image to be produced and +# currently must be either "1024" for a 1MB ROM or "512" for a +# 512KB ROM. +# +# CPU specifies the instruction set to be used in assembly and +# must be either "80" for Z80 or "180" for Z180. Currently, +# you should use 180 for N8 ROMs and 80 for everything else. +# +# SYS specifies the system variant to build in. CPM will +# build traditional CP/M. ZSYS will build ZSystem which +# currently means ZSDOS 1.2 & ZCPR 1.0 +# +# ROMNAME names the output file. It defaults to +# CONFIG. The output of the build will be: +# .rom, .sys, and .com. +# +# These variables can be passed into the makefile by the command +# line, hardcoded in this file, or set as environment variables +# in the OS. To use a command line, use the following format: +# +# make CONFIG= ROMSIZE= CPU= SYS= ROMNAME= +# +# An example of this is: +# +# make CONFIG=n8vem ROMSIZE=512 CPU=80 SYS=CPM ROMNAME=n8vem +# +# Alternatively, you can specify the variables by hardcoding them +# in this file. To do so, uncomment the five lines after these +# comments and change the values as desired. +# If the variables are specified this way, you would then invoke +# the make by simply using "make" +# +# If you want to set them as environment variables, you can +# do this with commands like the following at an OS command +# prompt or in a batch file: +# +# SET CONFIG=n8vem +# SET ROMSIZE=512 +# SET CPU=80 +# SET SYS=CPM +# SET ROMNAME=n8vem +# +# Note: use "make clean" to delete temporary and output files +# +# A good idea is to do a clean with every build and this can be +# accomplished on one command line doing something like this: +# +# make clean all CONFIG=n8vem ROMSIZE=512 CPU=80 SYS=CPM ROMNAME=n8vem +# +# or, if you are using hard coded variables above: +# +# make clean all +# +# Uncomment and update values below to hardcode settings: +# +#CONFIG := n8vem +#ROMSIZE := 512 +#CPU := 80 +#SYS := CPM +#ROMNAME := n8vem + +# Dougs Configuration +CONFIG := zeta +ROMSIZE := 512 +CPU := 80 +SYS := CPM +ROMNAME := dougzeta + +ifndef ROMNAME +ROMNAME := $(CONFIG) +endif + +CPMCP := bin/cpmcp + +ROMDSKFILES := ../RomDsk/$(SYS)_$(ROMSIZE)KB/*.* ../RomDsk/cfg_$(CONFIG)/*.* ../RomDsk/RomApps/*.* + +ifeq "$(SYS)" "CPM" +DOSBIN := bdosb01.bin +CPBIN := ccpb03.bin +CPASM := ccpb03.asm +else +DOSBIN := zsdos.bin +CPBIN := zcprw.bin +CPASM := zcprw.asm +endif + +OUTDIR := ../Output + +TASM := bin/tasm +TASMTABS := bin +export TASMTABS + +ASMOPT80 := -t$(CPU) -g3 +ASMOPT85 := -t85 -g3 + +ASM80 := $(TASM) $(ASMOPT80) -b +ASM85 := $(TASM) $(ASMOPT85) +ASMIMG := $(TASM) $(ASMOPT80) -b -fE5 + +NULL := +SPACE := ${NULL} ${NULL} + +%.bin: %.asm + $(ASM80) -b $< $@ + +%.com: %.asm + $(ASM80) $< $@ + +%.img: %.asm + $(ASMIMG) $< $@ + +%.exe: %.cpp + $(CC) $< -o $@ + +ifneq ($(MAKECMDGOALS),clean) +ifeq "$(and $(CONFIG), $(ROMSIZE), $(CPU), $(SYS), $(ROMNAME))" "" +$(error Usage: make CONFIG= ROMSIZE=[512|1024] CPU=[80|180] SYS=[CPM|ZSYS] ROMNAME=) +endif +endif + +all: $(OUTDIR)/$(ROMNAME).rom $(OUTDIR)/$(ROMNAME).sys $(OUTDIR)/$(ROMNAME).com + +build.inc: + echo ';' >$@ + /bin/echo -n '; RomWBW Configured for '$(CONFIG)' ' >>$@ + date >> $@ + echo ; >>$@ + /bin/echo -n '#DEFINE TIMESTAMP "' >>$@ + date '+%Y%m%d%H%M"' >>$@ + echo ; >>$@ + echo '#DEFINE VARIANT "WBW-$(USERNAME)"' >>$@ + echo ; >>$@ + echo ROMSIZE .EQU $(ROMSIZE) >>$@ + echo ; >>$@ + echo '#INCLUDE "config_'$(CONFIG)'.asm"' >>$@ + echo ; >>$@ + +#loader.bin: loader.asm util.asm +# $(TASM) $(ASMOPT80) -b $< + +loader.bin: loader.asm util.asm + +loader.asm: ../Source/loader.asm + cp $< . + bin/cvt2mac $@ + +bnk1.asm: ../Source/bnk1.asm + cp $< . + bin/cvt2mac $@ + +bdosb01.asm: ../Source/bdosb01.asm + cp $< . + bin/cvt2mac $@ + +bootrom.bin : bootrom.asm memmgr.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +bootrom.asm: ../Source/bootrom.asm config_$(CONFIG).asm + cp $< . + bin/cvt2mac $@ + +bootapp.bin : bootapp.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +bootapp.asm: ../Source/bootapp.asm + cp $< . + bin/cvt2mac $@ + +cbios.asm: ../Source/cbios.asm + cp $< . + bin/cvt2mac $@ + + + +config_$(CONFIG).asm: ../Source/config_$(CONFIG).asm + cp $< . + bin/cvt2mac $@ + +cnfgdata.inc: ../Source/cnfgdata.inc + cp $< . + bin/cvt2mac $@ + +dbgmon.asm: ../Source/dbgmon.asm + cp $< . + bin/cvt2mac $@ + +fd.asm: ../Source/fd.asm + cp $< . + bin/cvt2mac $@ + +fd_data.asm: ../Source/fd_data.asm + cp $< . + bin/cvt2mac $@ + +#hbios.asm: ../Source/hbios.asm +# cp $< . +# bin/cvt2mac $@ + +hbfill.asm: ../Source/hbfill.asm + cp $< . + bin/cvt2mac $@ + +ide.asm: ../Source/ide.asm + cp $< . + bin/cvt2mac $@ + +ide_data.asm: ../Source/ide_data.asm + cp $< . + bin/cvt2mac $@ + +infolist.inc: ../Source/infolist.inc + cp $< . + bin/cvt2mac $@ + +memmgr.asm: ../Source/memmgr.asm + cp $< . + bin/cvt2mac $@ + +pgzero.bin : pgzero.asm std.asm build.inc ver.inc + $(TASM) $(ASMOPT80) $< $@ + +pgzero.asm: ../Source/pgzero.asm + cp $< . + bin/cvt2mac $@ + +ppide.asm: ../Source/ppide.asm + cp $< . + bin/cvt2mac $@ + +ppide_data.asm: ../Source/ppide_data.asm + cp $< . + bin/cvt2mac $@ + +ppp.asm: ../Source/ppp.asm + cp $< . + bin/cvt2mac $@ + +ppp_data.asm: ../Source/ppp_data.asm + cp $< . + bin/cvt2mac $@ + +prefix.asm: ../Source/prefix.asm + cp $< . + bin/cvt2mac $@ + +prp.asm: ../Source/prp.asm + cp $< . + bin/cvt2mac $@ + +prp_data.asm: ../Source/prp_data.asm + cp $< . + bin/cvt2mac $@ + +romfill.bin: romfill.asm + $(TASM) $(ASMOPT80) -b $< $@ + +romfill.asm: ../Source/romfill.asm + cp $< . + bin/cvt2mac $@ + +sd.asm: ../Source/sd.asm + cp $< . + bin/cvt2mac $@ + +sd_data.asm: ../Source/sd_data.asm + cp $< . + bin/cvt2mac $@ + +std.asm: ../Source/std.asm + cp $< . + bin/cvt2mac $@ + +syscfg.asm: ../Source/syscfg.asm + cp $< . + bin/cvt2mac $@ + +uart.asm: ../Source/uart.asm + cp $< . + bin/cvt2mac $@ + +util.bin: util.asm + +util.asm: ../Source/util.asm + cp $< . + bin/cvt2mac $@ + +vdu.asm: ../Source/vdu.asm + cp $< . + bin/cvt2mac $@ + +ver.inc: ../Source/ver.inc + cp $< . + bin/cvt2mac $@ + +zcprw.bin : zcprw.asm zcpr.asm + $(TASM) $(ASMOPT85) $< $@ + +zsdos.bin : zsdos.asm zsdos.lib zsdos-gp.z80 + $(TASM) $(ASMOPT80) $< $@ + +hbfill.bin: hbfill.asm fd.asm ide.asm ppide.asm sd.asm prp.asm ppp.asm std.asm ver.inc build.inc + +cbios.bin: cbios.asm fd_data.asm ide_data.asm ppide_data.asm sd_data.asm prp_data.asm ppp_data.asm uart.asm vdu.asm std.asm ver.inc build.inc infolist.inc + $(ASM80) -b -dBLD_SYS=SYS_$(SYS) $< $@ + +cbios.asm: ../Source/cbios.asm + cp $< . + bin/cvt2mac $@ + +dbgmon.bin: dbgmon.asm hbfill.bin std.asm ver.inc build.inc + +syscfg.bin: syscfg.asm std.asm build.inc ver.inc cnfgdata.inc + +$(CPASM): ../Source/$(CPASM) + cp $< . + bin/cvt2mac $@ + +$(OUTDIR)/$(ROMNAME).rom: diskdefs rom0.bin rom1.bin $(ROMDISKFILES) $(OUTDIR)/$(ROMNAME).sys blank$(ROMSIZE)KB.dat + for d in ../Apps/*; do \ + if test -e $$d/*.com; then \ + cp $$d/*.com ../RomDsk/RomApps; \ + fi; \ + done; + for d in ../Apps/*; do \ + if test -e $$d/*.man; then \ + cp $$d/*.man ../RomDsk/RomApps; \ + fi; \ + done; + for d in ../Apps/*; do \ + if test -e $$d/*.bsp; then \ + cp $$d/*.bsp ../RomDsk/RomApps; \ + fi; \ + done; + cp blank$(ROMSIZE)KB.dat RomDisk.tmp + $(CPMCP) -f rom$(ROMSIZE)KB RomDisk.tmp $(ROMDSKFILES) 0: + $(CPMCP) -f rom$(ROMSIZE)KB RomDisk.tmp ../Output/$(ROMNAME).sys 0:$(SYS).sys + cat rom0.bin rom1.bin RomDisk.tmp >>$@ + +diskdefs: bin/diskdefs + cp bin/diskdefs . + bin/cvt2mac diskdefs + +$(OUTDIR)/$(ROMNAME).com: bootapp.bin syscfg.bin loader.bin bnk1.bin dbgmon.bin sys.bin + cat bootapp.bin syscfg.bin loader.bin bnk1.bin dbgmon.bin sys.bin >>$@ + +$(OUTDIR)/$(ROMNAME).sys: prefix.bin sys.bin + cat prefix.bin sys.bin >>$(OUTDIR)/$(ROMNAME).sys + +rom0.bin: pgzero.bin bootrom.bin syscfg.bin loader.bin romfill.bin dbgmon.bin sys.bin hbfill.bin + cat $< >>rom0.bin + +rom1.bin: pgzero.bin bootrom.bin syscfg.bin loader.bin bnk1.bin + cat $< >>rom1.bin + +sys.bin: $(CPBIN) $(DOSBIN) cbios.bin hbfill.bin ccpb03.bin + echo at sys.bin target, about to cat + cat $(CPBIN) $(DOSBIN) cbios.bin hbfill.bin >>$@ + +prefix.bin: prefix.asm + +blank512KB.dat: ../Source/blank512KB.dat + cp $< . + +blank1024KB.dat: ../Source/blank1024KB.dat + cp $< . + +#cbios.asm: ../Source/cbios.asm +# cp $< . +# bin/cvt2mac $@ + +ccpb03.asm: ../Source/ccpb03.asm + cp $< . + bin/cvt2mac $@ + +clean: + rm -f *.asm *.obj *.bin *.com *.img *.rom *.lst *.exp *.tmp *.inc + rm -f $(OUTDIR)/*.* + rm -f ../RomDsk/RomApps/*.* + rm -f diskdefs + rm -f blank$(ROMSIZE)KB.dat + diff --git a/trunk/XSource/README.TXT b/trunk/XSource/README.TXT new file mode 100644 index 00000000..ed728c8e --- /dev/null +++ b/trunk/XSource/README.TXT @@ -0,0 +1,5 @@ +The Mac OS X Makefile is not fully debugged yet and is +not usable in it's current form. It will be updated and +posted when it is working correctly. + +Douglas Goodall