TKCallsgTimeDatgThreadsgSystemTgStringsgStoragegStop gSort gSlist gRandom gPanosMCgPanosErgOSStoragMathLibgM2Path gM2Dump gM2dbInfgHashStrgGoto gFields gExtensigExceptigEnv gCharCodgArithmegArchTypgArchiveg p?31Ѕ Йmp?#1R Й]p? 1»&Й6p? Й5p?л0s"Й p?Ы0 Исp?Н0J Ипp?ї0Е Икp?±0U Идp?Ј0ю ИЯp? ИЬp? ИПp?y0» ИМp?j0j И®p?[02 ИЈp?N0L Иўp?@0 ИЎp?10і p?"0К 0y Иyp? ?o*»3 ,p?Ш/ И+p?Л/ И)p?ѕ/ p?°/R p?ў/м (*********************************************************************) (* Title: ArchiveLib - Implementation *) (* Author: Mick Jordan,107,x304 *) (* Copyright (C) 1985 by Acorn Research Centre *) (*********************************************************************) $Revision$ $Author$ $Date$ $Source$ $State$ IMPLEMENTATION MODULE ArchiveLib; FROM SYSTEM IMPORT WORD, TSIZE, BYTESPERWORD, ADR, ADDRESS, MAXINT; FROM SystemTypes IMPORT LongCARDINAL, LongINTEGER; FROM Storage IMPORT ALLOCATE, DEALLOCATE; FROM Streams IMPORT Stream, SeekMode, ErrorCode, Create, StreamProcs, OptionalFunction; FROM StreamRep IMPORT DefaultProcs, Procs; FROM CharCodes IMPORT NewLineCh, SpaceCh; IMPORT Strings; IMPORT ChunkLib; FROM ChunkFlFmt IMPORT ChunkEntry; FROM ArchTypes IMPORT ArchiveDirEntry; TYPE MemberId = CARDINAL; (* chunk index of member's data *) ArchiveRec = RECORD chunkHandle: ChunkLib.ChunkHandle; dirData: ADDRESS; (* directory chunk *) dirSize: CARDINAL; (* size of directory in bytes *) bytesUsed: CARDINAL; (* during FindNextMember *) END; TYPE ArchiveId = POINTER TO ArchiveRec; MemberData = POINTER TO ARRAY [0 .. MAXINT DIV 4] OF CHAR; Member = POINTER TO RECORD memberdata: MemberData; memberDataSize: CARDINAL; index: CARDINAL; END; PROCEDURE OpenArchive(name: ARRAY OF CHAR; VAR arcid: ArchiveId): BOOLEAN; VAR xChunkHandle: ChunkLib.ChunkHandle; xDirData: ADDRESS; entry: CARDINAL; chunkEntry: ChunkEntry; BEGIN IF ChunkLib.OpenChunkFile(name, xChunkHandle) THEN IF ChunkLib.FindChunk(xChunkHandle, "ARCHDIR", entry) THEN ChunkLib.GetEntry(xChunkHandle, entry, chunkEntry); ALLOCATE(xDirData, chunkEntry.size); IF ChunkLib.GetChunk(xChunkHandle, entry, xDirData) THEN NEW(arcid); WITH arcid^ DO chunkHandle := xChunkHandle; dirData := xDirData; bytesUsed := 0; dirSize := chunkEntry.size; END; RETURN TRUE; END; END; END; RETURN FALSE; END OpenArchive; PROCEDURE CloseArchive(a: ArchiveId); VAR r: INTEGER; BEGIN ChunkLib.CloseChunkFile(a^.chunkHandle); DEALLOCATE(a^.dirData, a^.dirSize); DISPOSE(a); END CloseArchive; PROCEDURE GetNextMember(archiveId: ArchiveId; VAR name: ARRAY OF CHAR; VAR memberId: MemberId): BOOLEAN; TYPE ArchiveDirEntryPtr = POINTER TO ArchiveDirEntry; VAR dirName: Strings.String; dirEntry: ArchiveDirEntryPtr; dirData: ADDRESS; BEGIN dirData := archiveId^.dirData + archiveId^.bytesUsed; WHILE archiveId^.bytesUsed < archiveId^.dirSize DO dirEntry := ArchiveDirEntryPtr(dirData); INC(archiveId^.bytesUsed, dirEntry^.entryLength); IF dirEntry^.chunkIndex # 0 THEN dirName := Strings.String(CARDINAL(dirData) + TSIZE(ArchiveDirEntry)); Strings.CopySC(dirName, name); memberId := dirEntry^.chunkIndex; RETURN TRUE; END; INC(dirData, dirEntry^.entryLength); END; RETURN FALSE; END GetNextMember; PROCEDURE FindMember(archiveId: ArchiveId; name: ARRAY OF CHAR; VAR memberId: MemberId): BOOLEAN; VAR nextName: ARRAY [0..255] OF CHAR; BEGIN archiveId^.bytesUsed := 0; WHILE GetNextMember(archiveId, nextName, memberId) DO IF Strings.EqualCC(name, nextName) THEN RETURN TRUE END; END; RETURN FALSE; END FindMember; PROCEDURE CreateInput(archiveId: ArchiveId; name: ARRAY OF CHAR): Stream; VAR memberId: MemberId; s: Stream; BEGIN s := Create(StreamProcs(procs), 0); IF FindMember(archiveId, name, memberId) THEN Initialise(s, archiveId, memberId); ELSE s^.status := StreamError; END (* if *); RETURN s; END CreateInput; PROCEDURE CreateFastInput(archiveId: ArchiveId; memberId: MemberId): Stream; VAR s: Stream; BEGIN s := Create(StreamProcs(procs), 0); Initialise(s, archiveId, memberId); RETURN s; END CreateFastInput; PROCEDURE Initialise(s: Stream; archiveId: ArchiveId; memberId: MemberId); VAR member: Member; chunkEntry: ChunkEntry; BEGIN NEW(member); s^.instanceData := WORD(member); ChunkLib.GetEntry(archiveId^.chunkHandle, memberId, chunkEntry); WITH member^ DO memberDataSize := chunkEntry.size; ALLOCATE(memberdata, memberDataSize); index := 0; IF NOT ChunkLib.GetChunk(archiveId^.chunkHandle, memberId, memberdata) THEN DEALLOCATE(memberdata, memberDataSize); DISPOSE(member); s^.status := StreamError; END; END (* with *); END Initialise; PROCEDURE Get(s: Stream): WORD; VAR member: Member; BEGIN member := Member(s^.instanceData); WITH member^ DO IF index >= memberDataSize THEN s^.status := EndOfStream; RETURN WORD(0C); ELSE INC(index); RETURN WORD(memberdata^[index-1]); END (* if *); END (* with *); END Get; PROCEDURE GetN(s: Stream; a: ADDRESS; n: CARDINAL): CARDINAL; VAR member: Member; getBuf: MemberData; i, toGet: CARDINAL; BEGIN member := Member(s^.instanceData); getBuf := MemberData(a); IF member^.memberDataSize - member^.index >= n THEN toGet := n; ELSE toGet := member^.memberDataSize - member^.index; IF toGet = 0 THEN s^.status := EndOfStream; END (* if *); END (* if *); IF toGet > 0 THEN FOR i := 0 TO toGet-1 DO getBuf^[i] := member^.memberdata^[i+member^.index]; END (* for *); INC(member^.index, toGet); END (* if *); RETURN toGet; END GetN; PROCEDURE Backspace(s: Stream); VAR member: Member; BEGIN member := Member(s^.instanceData); IF member^.index > 0 THEN DEC(member^.index); END (* if *); END Backspace; PROCEDURE Tell(s: Stream; VAR p: LongCARDINAL); VAR member: Member; BEGIN member := Member(s^.instanceData); p := member^.index; END Tell; PROCEDURE Seek(s: Stream; seekMode: SeekMode; offset: LongINTEGER); VAR member: Member; BEGIN member := Member(s^.instanceData); WITH member^ DO CASE seekMode OF Beginning: index := CARDINAL(offset); | Current: index := CARDINAL(INTEGER(index)+offset); | End: index := CARDINAL(INTEGER(memberDataSize)+offset); END (* case *); END (* with *); END Seek; PROCEDURE Delete(s: Stream); VAR member: Member; BEGIN member := Member(s^.instanceData); DEALLOCATE(member^.memberdata, member^.memberDataSize); DISPOSE(member); END Delete; PROCEDURE Implements(s: Stream; f: OptionalFunction): BOOLEAN; BEGIN RETURN TRUE; END Implements; PROCEDURE InitProcs(): Procs; VAR p: Procs; BEGIN p := DefaultProcs(8); p^.Get := Get; p^.GetN := GetN; p^.Delete := Delete; p^.Seek := Seek; p^.Tell := Tell; p^.Backspace := Backspace; RETURN p; END InitProcs; VAR procs: Procs; BEGIN procs := InitProcs(); END ArchiveLib. $Log$ IMPLEMENTATION MODULE ArchTypes; (* Null implementation *) BEGIN END ArchTypes . Title: Arithmetic - Implementation LastEdit: "Mon Sep 17 14:07:17 1984" Author: pr Cambridge University Computer Laboratory IMPLEMENTATION MODULE Arithmetic; FROM Exceptions IMPORT RAISE; CONST ImaginarySquareRoot = "ImaginarySquareRoot"; CONST RZero = 0.0; ROne = 1.0; RTwo = 2.0; SmallReal = 0.000001; PROCEDURE CMax (x, y: CARDINAL): CARDINAL; BEGIN IF x > y THEN RETURN x ELSE RETURN y END; END CMax; PROCEDURE CMin (x, y: CARDINAL): CARDINAL; BEGIN IF x < y THEN RETURN x ELSE RETURN y END; END CMin; PROCEDURE ISign (x: INTEGER): INTEGER; BEGIN IF x = 0 THEN RETURN 0; ELSE IF x > 0 THEN RETURN +1; ELSE RETURN -1; END; END; END ISign; PROCEDURE IMax (x, y: INTEGER): INTEGER; BEGIN IF x > y THEN RETURN x ELSE RETURN y END; END IMax; PROCEDURE IMin (x, y: INTEGER): INTEGER; BEGIN IF x < y THEN RETURN x ELSE RETURN y END; END IMin; PROCEDURE Fix (x: REAL): INTEGER; BEGIN IF x >= RZero THEN RETURN TRUNC (x); ELSE RETURN - INTEGER (TRUNC (-x)); END (* if *); END Fix; PROCEDURE RSign (x: REAL): REAL; BEGIN IF x = RZero THEN RETURN RZero; ELSE IF x > RZero THEN RETURN ROne; ELSE RETURN - ROne; END; END; END RSign; PROCEDURE RMax (x, y: REAL): REAL; BEGIN IF x > y THEN RETURN x ELSE RETURN y END; END RMax; PROCEDURE RMin (x, y: REAL): REAL; BEGIN IF x < y THEN RETURN x ELSE RETURN y END; END RMin; PROCEDURE SquareRoot (y: REAL): REAL; VAR invert: BOOLEAN; x, delta: REAL; BEGIN IF y <= RZero THEN IF y = RZero THEN RETURN RZero; END; RAISE(ImaginarySquareRoot); END; invert := y < ROne; IF invert THEN y := ROne / y; END; x := y; REPEAT delta := (x * x - y) / (RTwo * x); x := x - delta; UNTIL ABS (delta) < (SmallReal * y); IF invert THEN RETURN ROne / x; ELSE RETURN x; END; END SquareRoot; PROCEDURE Round (x: REAL): INTEGER; BEGIN IF x >= 0.0 THEN RETURN TRUNC (x + 0.5); ELSE RETURN -INTEGER (TRUNC (0.5 - x)); END; END Round; BEGIN END Arithmetic. Title: CharCodes - Implementation LastEdit: "Wed May 23 09:49:29 1984" Author: Mick Jordan Acorn Research Centre IMPLEMENTATION MODULE CharCodes; PROCEDURE CapitalCh(ch: CHAR): CHAR; BEGIN IF (ch >= 'a') AND (ch <= 'z') THEN RETURN VAL(CHAR, ORD(ch) + ORD('A') - ORD('a')); ELSE RETURN ch; END (* if *); END CapitalCh; BEGIN END CharCodes . IMPLEMENTATION MODULE Env; IMPORT Handler; PROCEDURE ResumeEnvironment (env: Handler.UsersEnvironment); BEGIN END ResumeEnvironment; END Env. Title: Exceptions - Implementation LastEdit: "Tue Nov 13 09:09:20 1984" Author: Trevor Morris Cambridge University Computer Laboratory NS32000/Panos version *) (* $T-, $R- *) IMPLEMENTATION MODULE Exceptions; IMPORT SYSTEM, PanosMCI, M2dbInfo, Strings; IMPORT CharCodes; IMPORT Env; IMPORT Program, IO, Store, Convert, Error, GlobalString; FROM Dump IMPORT Dump, DumpContent, DumpContentBits; FROM Handler IMPORT ConditionHandlerType, TypeCode, PointerToModuleRecord, ModuleRecord, RegisterTypes, RegisterType, UsersEnvironment, UsersEnvironmentPTR, Signal, Escape, DeclareEventHandler, SetEventStatus, RemoveEventHandler; MODULE Output; IMPORT SYSTEM, IO, CharCodes, Strings; EXPORT QUALIFIED String, Chars, Hex, Ch, NewLine; PROCEDURE String(err: CARDINAL; string: Strings.String); VAR i: CARDINAL; BEGIN i := 0; WHILE string^[i] # 0C DO Ch(err, string^[i]); INC(i); END; END String; PROCEDURE Chars(err: CARDINAL; chars: ARRAY OF CHAR); VAR i: CARDINAL; BEGIN i := 0; WHILE (i <= HIGH(chars)) AND (chars[i] # 0C) DO Ch(err, chars[i]); INC(i); END; END Chars; PROCEDURE Hex(err: CARDINAL; card: CARDINAL); BEGIN HexInField(err, card, SYSTEM.BYTESPERWORD * 2); END Hex; PROCEDURE HexInField(err: CARDINAL; card, field: CARDINAL); BEGIN IF (card DIV 16 > 0) OR (field > 1) THEN HexInField(err, card DIV 16, field - 1); END; IF card MOD 16 < 10 THEN Ch(err, CHAR(CARDINAL("0") + (card MOD 16))); ELSE Ch(err, CHAR(CARDINAL("A") + (card MOD 16) - 10)); END; END HexInField; PROCEDURE NewLine(err: CARDINAL); BEGIN Ch(err, CharCodes.NewLineCh); END NewLine; PROCEDURE Ch(err: CARDINAL; ch: CHAR); VAR ignore: INTEGER; BEGIN ignore := IO.SWriteByte(err, CARDINAL(ch)); (* can't do anything about it if it fails *) END Ch; END Output; PROCEDURE RAISE(ex: ARRAY OF CHAR); VAR s: ARRAY [0..255] OF CHAR; i: CARDINAL; BEGIN (* ensure message is null terminated - may truncate to 254! *) i := 0; WHILE (i <= HIGH(ex)) AND (i < HIGH(s)) AND (ex[i] # 0C) DO s[i] := ex[i]; INC(i); END; s[i] := 0C; Signal(M2dbInfo.M2ExceptionSignal, SYSTEM.ADR(s)); Program.Stop(M2dbInfo.Failed); END RAISE; PROCEDURE RAISEC(code: StdException); VAR s: ARRAY [0..50] OF CHAR; BEGIN CASE code OF CaseIndexOutOfRange: s := "CASE index out of range"; | AssignmentOutOfRange: s := "Assigned value out of range"; | ArrayIndexOutOfRange: s := "Array index out of range"; | ReturnMissing: s := "missing RETURN in function"; | HaltFault: s := "HALT"; END (* case *); (* 's' is null terminated *) Signal(M2dbInfo.M2ExceptionSignal, SYSTEM.ADR(s)); Program.Stop(M2dbInfo.Failed); END RAISEC; PROCEDURE GlobalStringPresent(VAR val: ARRAY OF CHAR; name: ARRAY OF CHAR): BOOLEAN; VAR l: CARDINAL; BEGIN RETURN (GlobalString.GetGlobalString(val, l, name) >= 0) AND (l > 0); END GlobalStringPresent; PROCEDURE DecodeError(errStream: CARDINAL; error: INTEGER); VAR detect, inter: ARRAY [0..127] OF CHAR; message: ARRAY [0..255] OF CHAR; l: CARDINAL; BEGIN IF (error < 0) AND (Error.GetErrorMessage(detect, l, inter, l, message, l, error) >= 0) THEN Output.Chars(errStream, message); Output.Chars(errStream, ": detected by "); Output.Chars(errStream, detect); ELSE Output.Chars(errStream, "Unknown Panos exception: "); Output.Hex(errStream, CARDINAL(error)); END; END DecodeError; PROCEDURE DoDump(err: CARDINAL; VAR env: UsersEnvironment); VAR envPtr: UsersEnvironmentPTR; filename: ARRAY [0..127] OF CHAR; error: INTEGER; BEGIN IF GlobalStringPresent(filename, M2dbInfo.DumpStringName) THEN envPtr := SYSTEM.ADR(env); Output.Chars(err, "Dumping program to: "); Output.Chars(err, filename); Output.NewLine(err); error := Dump(filename, M2dbInfo.Content, envPtr); IF error >= 0 THEN Output.Chars(err, "Dump finished"); ELSE Output.Chars(err, "Dump failed - "); DecodeError(err, error); END; Output.NewLine(err); ELSE Output.Chars(err, 'No dump made - global string "'); Output.Chars(err, M2dbInfo.DumpStringName); Output.Chars(err, '" not set up'); Output.NewLine(err); END; END DoDump; (* Procedures for doing a back trace *) PROCEDURE Backtrace(err: CARDINAL; fp: M2dbInfo.FramePtr); CONST MaxDepth = 255; VAR count: INTEGER; BEGIN count := MaxDepth; Output.Chars(err, "Backtrace:"); Output.NewLine(err); WHILE (fp^.framePtr # M2dbInfo.FramePtr(0)) AND (count > 0) DO FindModule(err, fp); fp := fp^.framePtr; DEC(count); END; IF count = 0 THEN Output.Chars(err, "Stopping backtrace - too long"); Output.NewLine(err); END; Output.Chars(err, "End of backtrace"); Output.NewLine(err); END Backtrace; PROCEDURE FindModule(err: CARDINAL; fp: M2dbInfo.FramePtr); VAR mod: PointerToModuleRecord; pc, base, offset, i, upb: CARDINAL; lmt: PanosMCI.LMTablePtr; lmod: PanosMCI.ModuleDataPtr; found: BOOLEAN; BEGIN pc := CARDINAL(fp^.savedPC); lmt := PanosMCI.GetLMTablePtr(); upb := PanosMCI.GetGFTableUpb(); i := 0; found := FALSE; WHILE (i <= upb) AND NOT found DO lmod := lmt^[i].moduledata; base := CARDINAL(lmod^.codeBase); IF (base <= pc) AND (pc < base + lmod^.codeLength) THEN found := TRUE; offset := pc - base; ELSE INC(i); END; END; IF NOT found THEN mod := PointerToModuleRecord(fp^.savedMOD MOD 10000H); offset := pc - CARDINAL(mod^.ProgramBase); END; Output.Chars(err, " Offset "); Output.Hex(err, offset); Output.Chars(err, " in module "); IF found THEN Output.Ch(err, "'"); Output.Chars(err, lmt^[i].name^); Output.Ch(err, "'"); ELSE Output.Hex(err, CARDINAL(mod)); END; Output.NewLine(err); END FindModule; gM2HandlerState: (NotSetUp, Present, AboutToGo, Gone); gM2dbEntry: UsersEnvironmentPTR; gUserHandler: ConditionHandlerType; gM2dbRunning: BOOLEAN; gActions: Actions; gKillEnv: UsersEnvironment; gStoppingEnv: UsersEnvironment; PROCEDURE SetEnv(VAR env: UsersEnvironment); VAR currentFP: M2dbInfo.FramePtr; BEGIN currentFP := M2dbInfo.FramePtr(SYSTEM.REGISTER(M2dbInfo.FP)); env.PC := currentFP^.savedPC; env.SP1 := SYSTEM.ADDRESS(currentFP) + SYSTEM.TSIZE(M2dbInfo.Frame) + SYSTEM.TSIZE(SYSTEM.WORD); (* one word for parameter *) env.FP := currentFP^.framePtr; env.Mod := PointerToModuleRecord(currentFP^.savedMOD MOD 10000H); env.Validity := RegisterTypes{pc,sp1,fp,mod}; END SetEnv; PROCEDURE Kill; (* somewhere for m2db to jump to and kill the program *) BEGIN SetEnv(gKillEnv); IF gM2HandlerState # NotSetUp THEN Program.Stop(0); END; END Kill; PROCEDURE SetActions(a: Actions); VAR dummy: INTEGER; BEGIN IF (a * Actions{BacktraceOnEscape, DumpOnEscape} # Actions{}) OR gM2dbRunning THEN dummy := SetEventStatus(Escape, 1 (* enable *)); ELSE dummy := SetEventStatus(Escape, 2 (* fatal *)); END; gActions := a; END SetActions; PROCEDURE BeingDebugged(VAR env: UsersEnvironmentPTR): BOOLEAN; VAR programName, globalStringName, globalStringM2dbEntry: ARRAY [0..127] OF CHAR; l, c: CARDINAL; BEGIN IF (Program.Name(programName) >= 0) AND GlobalStringPresent(globalStringName, M2dbInfo.ProgramStringName) AND (Strings.CompareCC(globalStringName, programName, Strings.IgnoreCase) = Strings.EQ) AND GlobalStringPresent(globalStringM2dbEntry, M2dbInfo.M2dbEntryStringName) AND (Convert.StringToCardinal(c, globalStringM2dbEntry) >= 0) THEN env := UsersEnvironmentPTR(c); RETURN TRUE; ELSE RETURN FALSE; END; END BeingDebugged; PROCEDURE SwitchEnvironment( reason: M2dbInfo.EntryType; error: INTEGER; VAR old: UsersEnvironment); VAR p: M2dbInfo.StackImagePtr; BEGIN p := M2dbInfo.StackImagePtr(gM2dbEntry^.FP); (* first store the old environment away *) p^.envCopy := old; p^.stop := SYSTEM.ADR(gKillEnv); p^.env := SYSTEM.ADR(p^.envCopy); p^.error := error; p^.reason := reason; p^.initialising := FALSE; old := gM2dbEntry^; END SwitchEnvironment; CONST (* should be exported from Handler! *) OnlyHandler = 2; PROCEDURE EscapeHandle(): CARDINAL; BEGIN (* just want something that will be constant per run of the program *) RETURN CARDINAL(SYSTEM.ADR(gM2HandlerState)); END EscapeHandle; PROCEDURE EscapeHandler(event, data1, data2, handle: INTEGER; VAR env: UsersEnvironment); VAR errStream: CARDINAL; BEGIN IF (event = Escape) AND (handle = INTEGER(EscapeHandle())) THEN IF gM2dbRunning THEN SwitchEnvironment(M2dbInfo.EscapeEntry, 0, env); ELSE errStream := CARDINAL(IO.ErrorStream()); Output.Chars(errStream, "Escape - detected by Modula-2 handler"); Output.NewLine(errStream); IF BacktraceOnEscape IN gActions THEN Backtrace(errStream, M2dbInfo.FramePtr(env.FP)); END; IF DumpOnEscape IN gActions THEN DoDump(errStream, env); END; Program.Stop(M2dbInfo.Failed); END; END; END EscapeHandler; PROCEDURE Handler(code: TypeCode; error: INTEGER; VAR current, exception: UsersEnvironment): INTEGER; VAR r, dummy: INTEGER; stopEnv: UsersEnvironment; BEGIN CASE code OF Init: gM2HandlerState := NotSetUp; gM2dbRunning := FALSE; SetActions(Actions{BacktraceOnException, DumpOnException}); | Stop: IF gM2HandlerState = Present THEN gM2HandlerState := AboutToGo; ELSIF gM2HandlerState = AboutToGo THEN dummy := RemoveEventHandler(EscapeHandler, Escape, EscapeHandle()); gM2HandlerState := Gone; END; | Except: IF (error = M2dbInfo.M2InitSignal) THEN IF (gM2HandlerState = NotSetUp) THEN gUserHandler := DefaultUserHandler; dummy := DeclareEventHandler( EscapeHandler, Escape, OnlyHandler, EscapeHandle()); gM2dbRunning := BeingDebugged(gM2dbEntry); IF gM2dbRunning THEN dummy := SetEventStatus(Escape, 1 (* enable *)); Kill (* initialisation *) END; gM2HandlerState := Present; END; END; ELSE END; IF (gM2HandlerState = Present) OR (gM2HandlerState = AboutToGo) THEN IF (code = Except) AND gM2dbRunning THEN SwitchEnvironment(M2dbInfo.ExceptionEntry, error, exception); RETURN 1; (* this will now resume with the m2db environment... *) ELSIF (code = Stop) AND gM2dbRunning THEN SetEnv(gStoppingEnv); IF gM2dbRunning THEN gM2dbRunning := FALSE; SwitchEnvironment(M2dbInfo.StopEntry, 0, gStoppingEnv); Env.ResumeEnvironment(gStoppingEnv); ELSE RETURN 1; END; ELSE r := gUserHandler(code, error, current, exception); IF r = 0 THEN (* user handler didn't handle the condition *) RETURN NormalHandler(code, error, current, exception); ELSIF r < 0 THEN Program.Stop(0); ELSE RETURN r; END; END; ELSE (* handlers not set up - give up and hand condition to Panos *) RETURN 0; END; END Handler; PROCEDURE DefaultUserHandler(code: TypeCode; error: INTEGER; VAR current, exception: UsersEnvironment): INTEGER; BEGIN RETURN 0; END DefaultUserHandler; PROCEDURE NormalHandler(code: TypeCode; error: INTEGER; VAR current, exception: UsersEnvironment): INTEGER; VAR errStream: CARDINAL; env: UsersEnvironmentPTR; BEGIN IF code = Except THEN IF error = M2dbInfo.M2InitSignal THEN (* Modula 2 initialisation - return ok *) RETURN 1; ELSE errStream := CARDINAL(IO.ErrorStream()); (* if it fails there's nothing that can be done! *) IF error = M2dbInfo.M2ExceptionSignal THEN Output.Chars(errStream, "Modula-2 exception - "); Output.String(errStream, Strings.String(exception.Register[1])); ELSE DecodeError(errStream, error); END; Output.NewLine(errStream); IF BacktraceOnException IN gActions THEN Backtrace(errStream, M2dbInfo.FramePtr(exception.FP)); END; IF DumpOnException IN gActions THEN DoDump(errStream, exception); END; Program.Stop(M2dbInfo.Failed); END; ELSE (* initialisation or can't handle it *) RETURN 0; END; END NormalHandler; PROCEDURE SetM2Handler(handler: ConditionHandlerType); BEGIN gUserHandler := handler; END SetM2Handler; END Exceptions. (*********************************************************************) (* Title: Extensions - Implementation *) (* Author: Trevor Morris *) (* Copyright (C) 1985 by Acorn Research Centre *) (*********************************************************************) $Revision: 1.1 $ $Author: mjj $ $Date: 85/06/26 09:46:10 $ $Source: /util/m2/ns16k/lib/RCS/Extensions.mod,v $ $State: Exp $ IMPLEMENTATION MODULE Extensions; (* $T-, $R- *) FROM SYSTEM IMPORT ADR, MAXCARD; FROM Exceptions IMPORT RAISEC, StdException; FROM Strings IMPORT String, New, Dispose, CopyCC, CopyCS, CopySS, LengthC, FindC, FindS; CONST DeviceCh = ':'; PROCEDURE SepConcatXX(head, tail: String; headSize, hTail: CARDINAL; dir: BOOLEAN): String; VAR lHead, lTail, lTo, i, j: CARDINAL; to: String; sep: CHAR; BEGIN (* cannot use LengthS, since original C array may not be null terminated *) lTail := 0; WHILE (lTail <= hTail) AND (tail^[lTail] # 0C) DO INC(lTail) END (* while *); IF dir THEN (* head length not known - 'headSize' is upper bound *) lHead := 0; WHILE (lHead <= headSize) AND (head^[lHead] # 0C) DO INC(lHead) END (* while *); IF (lHead > 0) AND (lTail > 0) AND (head^[lHead-1] # DeviceCh) THEN sep := DirSepCh; ELSE sep := 0C; END; ELSE (* ext *) (* head length already known *) lHead := headSize; sep := ExtSepCh; END; lTo := lHead + lTail; IF sep # 0C THEN INC(lTo) END; to:= New(lTo); i:= 0; WHILE i < lHead DO to^[i]:= head^[i]; INC(i) END; IF sep # 0C THEN to^[i] := sep; INC(i); END; j := 0; WHILE i < lTo DO to^[i]:= tail^[j]; INC(i); INC(j) END; RETURN to; END SepConcatXX; PROCEDURE DirConcatSS(head, tail: String): String; BEGIN RETURN SepConcatXX(head, tail, MAXCARD, MAXCARD, TRUE); END DirConcatSS; PROCEDURE DirConcatCS(head: ARRAY OF CHAR; tail: String): String; BEGIN RETURN SepConcatXX(String(ADR(head)), tail, HIGH(head), MAXCARD, TRUE); END DirConcatCS; PROCEDURE DirConcatSC(head: String; tail: ARRAY OF CHAR): (* to *) String; BEGIN RETURN SepConcatXX(head, String(ADR(tail)), MAXCARD, HIGH(tail), TRUE); END DirConcatSC; PROCEDURE SepConcatCC(head, tail: ARRAY OF CHAR; dir: BOOLEAN; lHead: CARDINAL; VAR to: ARRAY OF CHAR); VAR i, j, highTail: CARDINAL; tailCopy: String; sep: CHAR; BEGIN (* care needed, since to=head or to=tail is ok but compiler might optimise to call by reference *) IF ADR(tail) = ADR(to) THEN (* same array (call by reference) *) tailCopy := CopyCS(tail); highTail := MAXCARD; ELSE tailCopy := String(ADR(tail)); highTail := HIGH(tail) END (* if *); IF ADR(head) # ADR(to) THEN CopyCC(head, to); END (* if *); IF dir THEN (* Length of head not known *) j := LengthC(head); IF (j > 0) AND (tailCopy^[0] # 0C) AND (head[j-1] # DeviceCh) THEN sep := DirSepCh; ELSE sep := 0C; END; ELSE (* ext *) (* length of head passed in 'lHead' *) j := lHead; sep := ExtSepCh; END; IF sep # 0C THEN IF j > HIGH(to) THEN RAISEC(ArrayIndexOutOfRange); ELSE to[j] := sep; END; INC(j); END; i := 0; WHILE (i <= highTail) AND (tailCopy^[i] # 0C) DO IF (j) > HIGH(to) THEN RAISEC(ArrayIndexOutOfRange); ELSE to[j] := tailCopy^[i]; END (* if *); INC(i); INC(j); END (* while *); IF j <= HIGH(to) THEN to[j] := 0C; END (* if *); IF ADR(tail) = ADR(to) THEN Dispose(tailCopy); END; END SepConcatCC; PROCEDURE DirConcatCC(head, tail: ARRAY OF CHAR; VAR to: ARRAY OF CHAR); BEGIN SepConcatCC(head, tail, TRUE, 0, to); END DirConcatCC; PROCEDURE TailX(s: String; high: CARDINAL; VAR lwb, upb: CARDINAL); VAR ch: CHAR; BEGIN upb := 0; lwb := 0; LOOP IF upb > high THEN EXIT END; ch := s^[upb]; IF ch = 0C THEN EXIT END; INC(upb); IF (ch = DirSepCh) OR (ch = DeviceCh) THEN lwb := upb END; END; END TailX; PROCEDURE TailC(name: ARRAY OF CHAR; VAR lwb, upb: CARDINAL); BEGIN TailX(String(ADR(name)), HIGH(name), lwb, upb); END TailC; PROCEDURE TailS(name: String; VAR lwb, upb: CARDINAL); BEGIN TailX(name, MAXCARD, lwb, upb); END TailS; CONST MaxM2ExtensionLength = 3; (* check this by looking at following procedure (grubby!) *) PROCEDURE M2ExtensionChars(m2Ext: M2Extension; VAR ext: ARRAY OF CHAR); BEGIN CASE m2Ext OF Def: CopyCC("def", ext); | Sym: CopyCC("sym", ext); | Mod: CopyCC("mod", ext); | Ref: CopyCC("ref", ext); | Key: CopyCC("key", ext); | Obj: CopyCC("aof", ext); | Exe: CopyCC("rif", ext); | Asm: CopyCC("asm", ext); | Dec: CopyCC("dec", ext); END; END M2ExtensionChars; PROCEDURE M2ExtendC(file: ARRAY OF CHAR; m2Ext: M2Extension; VAR to: ARRAY OF CHAR); VAR ext: ARRAY [0..MaxM2ExtensionLength] OF CHAR; BEGIN M2ExtensionChars(m2Ext, ext); ExtendC(file, ext, to); END M2ExtendC; PROCEDURE M2ExtendS(file: String; m2Ext: M2Extension): String; VAR ext: ARRAY [0..MaxM2ExtensionLength] OF CHAR; BEGIN M2ExtensionChars(m2Ext, ext); RETURN ExtendS(file, ext); END M2ExtendS; PROCEDURE Min(a, b: CARDINAL): CARDINAL; BEGIN IF a < b THEN RETURN a ELSE RETURN b END; END Min; PROCEDURE ExtendC(file, ext: ARRAY OF CHAR; VAR to: ARRAY OF CHAR); VAR lwb, upb, look: CARDINAL; BEGIN TailC(file, lwb, upb); look := lwb; IF FindC(file, ExtSepCh, look) THEN CopyCC(file, to); ELSE upb := Min(lwb + MaxFileNameLength, upb); SepConcatCC(file, ext, FALSE, upb, to); END; END ExtendC; PROCEDURE ExtendS(file: String; ext: ARRAY OF CHAR): String; VAR lwb, upb, look: CARDINAL; BEGIN TailS(file, lwb, upb); look := lwb; IF FindS(file, ExtSepCh, look) THEN RETURN CopySS(file); ELSE upb := Min(lwb + MaxFileNameLength, upb); RETURN SepConcatXX(file, String(ADR(ext)), upb, HIGH(ext), FALSE); END; END ExtendS; END Extensions. $Log: Extensions.mod,v $ Revision 1.1 85/06/26 09:46:10 mjj Initial revision Title: Fields - Implementation LastEdit: "Thu Jan 31 12:39:00 1985" Author: Mick Jordan Cambridge University Computer Laboratory IMPLEMENTATION MODULE Fields; (* $T-,$R- *) FROM SYSTEM IMPORT BITSPERWORD, BYTESPERWORD, ADR, WORD; FROM SystemTypes IMPORT Byte, Short; P2Mod: ARRAY [0 .. BITSPERWORD-1] OF CARDINAL; P2Div: ARRAY [0 .. BITSPERWORD-1] OF CARDINAL; PROCEDURE Extract(v: WORD; low, high: WordBitRange): CARDINAL; BEGIN IF low # 0 THEN v := WORD(CARDINAL(v) DIV P2Div[low]); DEC(high, low); END (* if *); IF high = BITSPERWORD-1 THEN RETURN CARDINAL(v) ELSE RETURN CARDINAL(v) MOD P2Mod[high]; END (* if *); END Extract; PROCEDURE Insert(VAR v: WORD; low, high: WordBitRange; field: CARDINAL); VAR i: CARDINAL; bvp: POINTER TO BITSET; BEGIN IF low # 0 THEN field := field * P2Div[low]; END (* if *); bvp := ADR(v); FOR i := low TO high DO EXCL(bvp^, i); END (* for *); v := WORD(BITSET(v) + BITSET(field)); END Insert; TYPE CHARPTR = POINTER TO ARRAY [0..BYTESPERWORD-1] OF CHAR; PROCEDURE ExtractByte(v: WORD; byteno: ByteRange): Byte; VAR cp: CHARPTR; BEGIN cp := ADR(v); RETURN Byte( cp^[byteno] ); END ExtractByte; PROCEDURE InsertByte(VAR v: WORD; byteno: ByteRange; value: Byte); VAR cp: CHARPTR; BEGIN cp := ADR(v); cp^[byteno] := CHAR( value ); END InsertByte; PROCEDURE ExtractShort(v: WORD; shortno: ShortRange): Short; BEGIN IF shortno=0 THEN RETURN CARDINAL(v) MOD 65536 ELSE RETURN CARDINAL(v) DIV 65536; END (* if *); END ExtractShort; PROCEDURE InsertShort(VAR v: WORD; shortno: ShortRange; value: Short); BEGIN IF shortno=0 THEN v := WORD( BITSET(v) - BITSET(0FFFFH) + BITSET(value)); ELSE v := WORD (BITSET(v) - BITSET(0FFFF0000H) + BITSET(value*65536)); END (* if *); END InsertShort; PROCEDURE Initialise; VAR ix: CARDINAL; BEGIN P2Div[0] := 1; P2Mod[0] := 2; FOR ix := 1 TO BITSPERWORD-1 DO P2Div[ix] := P2Div[ix-1]*2; P2Mod[ix] := P2Div[ix]*2; END (* for *); END Initialise; BEGIN Initialise; END Fields. Title: Goto - Implementation LastEdit: "Tue Nov 13 09:10:34 1984" Author: Mick Jordan Acorn Research Centre Panos/32000 version IMPLEMENTATION MODULE Goto; IMPORT SYSTEM, M2dbInfo, Env(* temporary.. *); FROM Storage IMPORT ALLOCATE, DEALLOCATE; IMPORT Handler; (* SetGoto uses global variables to ensure that registers R4-R7 are not used within its body. What a hack! VAR gFP: M2dbInfo.FramePtr; gEnv: Handler.UsersEnvironmentPTR; PROCEDURE SetGoto(VAR env: GotoLabel); BEGIN gFP := M2dbInfo.FramePtr(SYSTEM.REGISTER(M2dbInfo.FP)); NEW(gEnv); gEnv^.PC := gFP^.savedPC; gEnv^.SP1 := SYSTEM.ADDRESS(gFP) + SYSTEM.TSIZE(M2dbInfo.Frame) + SYSTEM.TSIZE(SYSTEM.WORD); (* one word for parameter *) gEnv^.FP := gFP^.framePtr; gEnv^.Mod := Handler.PointerToModuleRecord(gFP^.savedMOD MOD 10000H); gEnv^.Register[4] := SYSTEM.WORD(SYSTEM.REGISTER(4)); gEnv^.Register[5] := SYSTEM.WORD(SYSTEM.REGISTER(5)); gEnv^.Register[6] := SYSTEM.WORD(SYSTEM.REGISTER(6)); gEnv^.Register[7] := SYSTEM.WORD(SYSTEM.REGISTER(7)); gEnv^.Validity := Handler.RegisterTypes{ Handler.pc,Handler.sp1,Handler.fp,Handler.mod, Handler.r4..Handler.r7}; env := gEnv; END SetGoto; PROCEDURE LongGoto(env: GotoLabel); BEGIN Env.ResumeEnvironment(env^); END LongGoto; PROCEDURE UnSetGoto(env: GotoLabel); BEGIN DISPOSE(env); END UnSetGoto; END Goto. (*********************************************************************) (* Title: HashStrings - Implementation *) (* Author: Mick Jordan,107,x304 *) (* Copyright (C) 1985 by Acorn Research Centre *) (*********************************************************************) $Revision: 1.3 $ $Author: mjj $ $Date: 85/06/04 18:05:24 $ $Source: /util/m2/lib/Standard/RCS/HashStrings.mod,v $ $State: Exp $ (* $T-, $R- module is self checking *) This version uses a table of linked lists. The computed hash value identifies a table entry and this the head of one of the linked lists. An object entered in the hashtable is identified by the address of the record element in the list. IMPLEMENTATION MODULE HashStrings; FROM SYSTEM IMPORT WORD, TSIZE, ADR, MAXINT; FROM Storage IMPORT ALLOCATE, DEALLOCATE; IMPORT Strings; FROM Strings IMPORT String, CaseMode, Comparison; FROM CharCodes IMPORT CapitalCh; IMPORT Slist; CONST HashTableUpb = 4096; (* nominal max size *) TYPE HashPtr = POINTER TO Hash; Hash = RECORD link: HashPtr; s: String; value: WORD; END (* record *); HashId = HashPtr; HashTable = POINTER TO RECORD size: CARDINAL; caseMode: CaseMode; table: POINTER TO ARRAY [0 .. HashTableUpb] OF HashPtr; END (* record *); hashval: CARDINAL; PROCEDURE NewC(s: CARDINAL; cM: CaseMode): HashTable; VAR i: CARDINAL; ht: HashTable; BEGIN NEW(ht); WITH ht^ DO size := s; caseMode := cM; ALLOCATE(table, s*TSIZE(HashPtr)); FOR i := 0 TO s-1 DO table^[i] := NIL; END (* for *); END (* with *); RETURN ht; END NewC; PROCEDURE New(s: CARDINAL): HashTable; BEGIN RETURN NewC(s, ConsiderCase); END New; PROCEDURE Dispose(VAR ht: HashTable); VAR h, nh: HashId; i: CARDINAL; BEGIN WITH ht^ DO FOR i := 0 TO size-1 DO IF table^[i] # NIL THEN h := table^[i]; WHILE h # NIL DO nh := h^.link; Strings.Dispose(h^.s); DISPOSE(h); h := nh; END (* while *); END (* if *); END (* for *); DEALLOCATE(table, size*TSIZE(HashPtr)); END (* with *); DISPOSE(ht); ht := NIL; END Dispose; PROCEDURE EnterChars(ht: HashTable; chars: ARRAY OF CHAR; VAR h: HashId): BOOLEAN; BEGIN IF LookupChars(ht, chars, h) THEN RETURN FALSE; ELSE NEW(h); h^.s := Strings.CopyCS(chars); Slist.Add(ht^.table^[hashval], h); RETURN TRUE; END (* if *); END EnterChars; PROCEDURE EnterString(ht: HashTable; s: String; VAR h: HashId): BOOLEAN; BEGIN IF LookupString(ht, s, h) THEN RETURN FALSE; ELSE NEW(h); h^.s := Strings.CopySS(s); Slist.Add(ht^.table^[hashval], h); RETURN TRUE; END (* if *); END EnterString; PROCEDURE LookupString(ht: HashTable; s: String; VAR h: HashId): BOOLEAN; BEGIN h := ComputeHashVal(ht, s, MAXINT); WHILE h # NIL DO IF ht^.caseMode = ConsiderCase THEN IF (s^[0] = h^.s^[0]) AND Strings.EqualSS(s, h^.s) THEN RETURN TRUE; END (* if *); ELSE IF (CapitalCh(s^[0]) = CapitalCh(h^.s^[0])) AND (Strings.CompareSS(s, h^.s, IgnoreCase) = EQ) THEN RETURN TRUE; END; END; h := h^.link; END (* while *); RETURN FALSE; END LookupString; PROCEDURE LookupChars(ht: HashTable; chars: ARRAY OF CHAR; VAR h: HashId): BOOLEAN; BEGIN h := ComputeHashVal(ht, String(ADR(chars)), HIGH(chars)); WHILE h # NIL DO IF ht^.caseMode = ConsiderCase THEN IF (chars[0] = h^.s^[0]) AND Strings.EqualCS(chars, h^.s) THEN RETURN TRUE; END (* if *); ELSE IF (CapitalCh(chars[0]) = CapitalCh(h^.s^[0])) AND (Strings.CompareCS(chars, h^.s, IgnoreCase) = EQ) THEN RETURN TRUE; END; END; h := h^.link; END (* while *); RETURN FALSE; END LookupChars; PROCEDURE ComputeHashVal(ht: HashTable; s: String; limit: CARDINAL): HashId; VAR i: CARDINAL; lhashval: CARDINAL; BEGIN i := 0; lhashval := 0; IF ht^.caseMode = ConsiderCase THEN WHILE (s^[i] # 0C) AND (i <= limit) DO INC(lhashval, CARDINAL(s^[i])); INC(i); END (* while *); ELSE WHILE (s^[i] # 0C) AND (i <= limit) DO INC(lhashval, CARDINAL(CapitalCh(s^[i]))); INC(i); END (* while *); END; lhashval := lhashval MOD ht^.size; hashval := lhashval; RETURN ht^.table^[lhashval]; END ComputeHashVal; PROCEDURE Assoc(ht: HashTable; h: HashId; w: WORD); (* Since elements are actually identified by addresses which are unique across all hash tables, 'ht' is redundant. BEGIN h^.value := w; END Assoc; PROCEDURE Retrieve(ht: HashTable; h: HashId): WORD; BEGIN RETURN h^.value; END Retrieve; PROCEDURE StringAt(ht: HashTable; h: HashId): String; BEGIN RETURN h^.s; END StringAt; PROCEDURE CharsAt(ht: HashTable; h: HashId; VAR chars: ARRAY OF CHAR); BEGIN Strings.CopySC(h^.s, chars); END CharsAt; END HashStrings. $Log: HashStrings.mod,v $ Revision 1.3 85/06/04 18:05:24 mjj Make Dispose set argument to NIL. Fix storage leak in Dispose (not disposing copied strings) Revision 1.2 85/04/10 11:56:10 mjj Add case-insensitive hashing. IMPLEMENTATION MODULE M2dbInfo; PROCEDURE ReturnM2InitSignal(): INTEGER; BEGIN RETURN M2InitSignal; END ReturnM2InitSignal; END M2dbInfo. IMPLEMENTATION MODULE M2Dump; (* Null implementation *) BEGIN END M2Dump . IMPLEMENTATION MODULE M2Path; FROM Streams IMPORT Stream, ErrorCode, Get, Backspace, Delete; FROM Storage IMPORT DEALLOCATE; FROM CharCodes IMPORT NewLineCh, CReturnCh; IMPORT FileStream; IMPORT GlobalString, Convert; CONST UseGlobalM2Path = "m2$GlobalPath"; GlobalM2Path = "m2$Path"; CONST AlternativeSepCh = '%'; PROCEDURE UseGlobalStringM2Path(): BOOLEAN; VAR boolChars: ARRAY [0..19] OF CHAR; bool: BOOLEAN; l: CARDINAL; BEGIN RETURN (GlobalString.GetGlobalString(boolChars, l, UseGlobalM2Path) >= 0) AND (Convert.StringToBoolean(bool, boolChars) >= 0) AND bool; END UseGlobalStringM2Path; PROCEDURE GetCh(s: Stream; VAR ch: CHAR): BOOLEAN; BEGIN ch := CHAR(Get(s)); RETURN s^.status = Success; END GetCh; PROCEDURE FileM2Path(VAR m2path: ARRAY OF CHAR): BOOLEAN; VAR s: Stream; res, end: BOOLEAN; pos: CARDINAL; ch, next: CHAR; BEGIN s := FileStream.CreateInput("m2path"); IF s^.status = Success THEN pos := 0; end := FALSE; WHILE (NOT end) AND GetCh(s, ch) DO IF (ch = NewLineCh) OR (ch = CReturnCh) THEN IF GetCh(s, next) THEN m2path[pos] := M2PathSepCh; INC(pos); Backspace(s); ELSE end := TRUE; END; ELSE IF ch = AlternativeSepCh THEN m2path[pos] := M2PathSepCh; ELSE m2path[pos] := ch; END; INC(pos); END; END; m2path[pos] := 0C; res := TRUE; ELSE res := FALSE; END; Delete(s); DISPOSE(s); RETURN res; END FileM2Path; PROCEDURE GlobalStringM2Path(VAR m2path: ARRAY OF CHAR): BOOLEAN; VAR pos, l: CARDINAL; BEGIN IF GlobalString.GetGlobalString(m2path, l, GlobalM2Path) >= 0 THEN pos := 0; WHILE pos < l DO IF m2path[pos] = AlternativeSepCh THEN m2path[pos] := M2PathSepCh; END; INC(pos); END; RETURN TRUE; ELSE RETURN FALSE; END; END GlobalStringM2Path; PROCEDURE GetM2Path(VAR m2path: ARRAY OF CHAR); VAR m2PathFound: BOOLEAN; BEGIN IF UseGlobalStringM2Path() THEN m2PathFound := GlobalStringM2Path(m2path) OR FileM2Path(m2path); ELSE m2PathFound := FileM2Path(m2path) OR GlobalStringM2Path(m2path); END; IF NOT m2PathFound THEN m2path[0] := 0C; END; END GetM2Path; PROCEDURE GetM2PathFromFile(VAR m2path: ARRAY OF CHAR); BEGIN IF NOT FileM2Path(m2path) THEN m2path[0] := 0C; END; END GetM2PathFromFile; END M2Path. Title: MathLib - Implementation LastEdit: "Tue Sep 11 12:06:49 1984" Author: jd Cambridge University Computer Laboratory IMPLEMENTATION MODULE MathLib; (* These routines are transcribed from the VAX C versions. A restriction introduced by the transcription is that sin and cos will not work for real numbers which are outside INTEGER range. This should be fixed by providing the machine dependent C routine modf to grub around in the representation of real numbers. This library is machine-independent with the addition of the range restriction FROM Exceptions IMPORT RAISE; CONST SinCosArgTooLarge = "SinCosArgTooLarge"; ExpOverflow = "ExpOverflow"; VAR degreestoradians: REAL; epow2, TwoPow : ARRAY [-6..6] OF REAL ; PROCEDURE Radians (degrees: REAL): REAL; BEGIN RETURN degrees * degreestoradians; END Radians; PROCEDURE Degrees (radians: REAL): REAL; BEGIN RETURN radians / degreestoradians; END Degrees; MODULE SinCos; IMPORT RAISE, SinCosArgTooLarge; EXPORT Sin, Cos; CONST twoopi = 0.63661977236758134308; CONST p0 = 0.1357884097877375669092680E8; CONST p1 = -0.4942908100902844161158627E7; CONST p2 = 0.4401030535375266501944918E6; CONST p3 = -0.1384727249982452873054457E5; CONST p4 = 0.1459688406665768722226959E3; CONST q0 = 0.8644558652922534429915149E7; CONST q1 = 0.4081792252343299749395779E6; CONST q2 = 0.9463096101538208180571257E4; CONST q3 = 0.1326534908786136358911494E3; PROCEDURE Sinus(arg: REAL; quad: CARDINAL): REAL; VAR e, f, ysq, x, y, temp1, temp2: REAL; VAR k: CARDINAL; BEGIN x := arg; IF x < 0.0 THEN x := -x; quad := quad + 2; END; x := x * twoopi; (* underflow? *) IF ABS (x - FLOAT (TRUNC (x))) > 1.0 THEN RAISE(SinCosArgTooLarge); END (* if *); k := TRUNC (x); y := x - FLOAT (k); quad := (quad + k) MOD 4; IF ODD (quad) THEN y := 1.0 - y; END; IF quad > 1 THEN y := 0.0 - y; END; ysq := y*y; temp1 := ((((p4*ysq+p3)*ysq+p2)*ysq+p1)*ysq+p0)*y; temp2 := ((((ysq+q3)*ysq+q2)*ysq+q1)*ysq+q0); RETURN temp1/temp2; END Sinus; PROCEDURE Cos (arg: REAL): REAL; BEGIN IF arg < 0.0 THEN arg := 0.0 - arg END; RETURN Sinus (arg, 1); END Cos; PROCEDURE Sin (arg: REAL): REAL; BEGIN RETURN Sinus (arg, 0); END Sin; END SinCos; MODULE ArcTan; EXPORT Atan, Atan2; (* atan coefficients are #5077 from Hart & Cheney. (19.56D) *) CONST sq2p1 = 2.414213562373095048802e0; CONST sq2m1 = 0.414213562373095048802e0; CONST pio2 = 1.570796326794896619231e0; CONST pio4 = 0.785398163397448309615e0; CONST p4 = 0.161536412982230228262e2; CONST p3 = 0.26842548195503973794141e3; CONST p2 = 0.11530293515404850115428136e4; CONST p1 = 0.178040631643319697105464587e4; CONST p0 = 0.89678597403663861959987488e3; CONST q4 = 0.5895697050844462222791e2; CONST q3 = 0.536265374031215315104235e3; CONST q2 = 0.16667838148816337184521798e4; CONST q1 = 0.207933497444540981287275926e4; CONST q0 = 0.89678597403663861962481162e3; (* xatan evaluates a series valid in the range [-0.414...,+0.414...]. *) PROCEDURE xatan(arg: REAL): REAL; VAR argsq, value: REAL; BEGIN argsq := arg * arg; value := ((((p4 * argsq + p3) * argsq + p2) * argsq + p1) * argsq + p0); value := value / (((((argsq + q4) * argsq + q3) * argsq + q2) * argsq + q1) * argsq + q0); RETURN value*arg; END xatan; (* satan reduces its positive argument to the range [0,0.414...] and calls xatan. *) PROCEDURE satan (arg: REAL): REAL; BEGIN IF arg < sq2m1 THEN RETURN xatan(arg); ELSIF arg > sq2p1 THEN RETURN pio2 - xatan(1.0 / arg); ELSE RETURN pio4 + xatan ((arg - 1.0) / (arg + 1.0)); END; END satan; (* atan makes its argument positive and calls satan. *) PROCEDURE Atan (arg: REAL): REAL; BEGIN IF arg > 0.0 THEN RETURN satan (arg); ELSE RETURN 0.0 - satan (0.0 - arg); END; END Atan; (* atan2 discovers what quadrant the angle is in and calls atan. *) PROCEDURE Atan2 (arg1, arg2: REAL): REAL; BEGIN IF arg2 = 0.0 THEN IF arg1 >= 0.0 THEN RETURN pio2; ELSE RETURN 0.0 - pio2; END; ELSIF arg2 < 0.0 THEN IF arg1 >= 0.0 THEN RETURN pio2 + pio2 - satan(0.0 - arg1/arg2); ELSE RETURN 0.0 - pio2 - pio2 + satan(arg1/arg2); END; ELSIF arg1 > 0.0 THEN RETURN satan(arg1/arg2); ELSE RETURN 0.0 - satan(0.0 - arg1/arg2); END; END Atan2; END ArcTan; PROCEDURE Exp (x : REAL) : REAL ; (* Not the quickest code, but simple *) VAR Power : INTEGER ; Reciprocate : BOOLEAN ; Result : REAL ; BEGIN IF x > 88.029 THEN RAISE(ExpOverflow); ELSIF x < -88.0 THEN RETURN 0.0 ELSE IF x > 0.0 THEN Reciprocate := FALSE ELSIF x = 0.0 THEN RETURN 1.0 ELSE Reciprocate := TRUE ; x := - x END (* if *) ; Result := 1.0 ; FOR Power := 6 TO -6 BY -1 DO IF x > TwoPow [Power] THEN x := x - TwoPow [Power] ; Result := Result * epow2 [Power] END (* if *) END (* for *); (**** x is now less than 2 ** -6 so terms in the power series to x ** 4 will suffice ****) Result := Result * (1.0 + x * (1.0 + x * (0.5 + x * (0.16666667 + x * 0.041666667)))) ; IF Reciprocate THEN RETURN 1.0 / Result ELSE RETURN Result END (* if *) END (* if *) END Exp ; BEGIN degreestoradians := (2.0 * Pi) / 360.0; (* epow2 [r] := exp (2 ** r) *) epow2 [-6] := 1.01574771E+00 ; epow2 [-5] := 1.03174341E+00 ; epow2 [-4] := 1.06449446E+00 ; epow2 [-3] := 1.13314845E+00 ; epow2 [-2] := 1.28402542E+00 ; epow2 [-1] := 1.64872127E+00 ; epow2 [0] := 2.71828183E+00 ; epow2 [1] := 7.38905610E+00 ; epow2 [2] := 5.45981500E+01 ; epow2 [3] := 2.98095799E+03 ; epow2 [4] := 8.88611052E+06 ; epow2 [5] := 7.89629602E+13 ; epow2 [6] := 6.23514908E+27 ; (* TwoPow [r] := 2 ** r *) TwoPow [-6] := 0.015625 ; TwoPow [-5] := 0.031250 ; TwoPow [-4] := 0.062500 ; TwoPow [-3] := 0.125000 ; TwoPow [-2] := 0.250000 ; TwoPow [-1] := 0.500000 ; TwoPow [0] := 1.000000 ; TwoPow [1] := 2.000000 ; TwoPow [2] := 4.000000 ; TwoPow [3] := 8.000000 ; TwoPow [4] := 16.000000 ; TwoPow [5] := 32.000000 ; TwoPow [6] := 64.000000 END MathLib. Title: OSStorage - Implementation LastEdit: "Mon Oct 1 16:24:20 1984" Author: tjm Cambridge University Computer Laboratory NS32000 Heap Allocator for TSIZE (WORD) = 4 Panos version - just uses 'Store'. May be inefficient (c.f. Tripos 68k version) IMPLEMENTATION MODULE OSStorage; FROM SYSTEM IMPORT ADDRESS; IMPORT Store; CONST MinBlock = 4096; PROCEDURE HeapAllocate (of: CARDINAL; VAR base: ADDRESS; VAR size: CARDINAL): BOOLEAN; VAR r: INTEGER; BEGIN IF of < MinBlock THEN of := MinBlock END; r := Store.Allocate(base, of); IF r >= 0 THEN size := CARDINAL(r); RETURN TRUE ELSE RETURN FALSE END; END HeapAllocate; END OSStorage. IMPLEMENTATION MODULE PanosError; FROM Streams IMPORT Stream; IMPORT Fields; FROM Error IMPORT Facility, ErrorFacilityErrors, ArgumentFacilityErrors, WildFacilityErrors, IOFacilityErrors, LoaderFacilityErrors, ConvertFacilityErrors, EnvFacilityErrors, StoreFacilityErrors, TimeFacilityErrors, FileFacilityErrors, ControlFacilityErrors, EventFacilityErrors, ExceptionFacilityErrors; CONST ErrorCodeLSB = 0; ErrorCodeMSB = 8; ReservedLSB = 9; ReservedMSB = 11; DetectingFacilityLSB = 12; DetectingFacilityMSB = 19; InterfaceFacilityLSB = 20; InterfaceFacilityMSB = 27; InfoLSB = 28; InfoMSB = 30; ErrorBit = 31; FacilityValueLSB = 0; FacilityValueMSB = 5; FacilityTypeLSB = 6; FacilityTypeMSB = 7; PROCEDURE ExtractFacility(r: INTEGER; lsb, msb: CARDINAL): Facility; VAR full: CARDINAL; BEGIN full := Fields.Extract(r, lsb, msb); IF Fields.Extract(full, FacilityTypeLSB, FacilityTypeMSB) = 0 THEN RETURN Facility(Fields.Extract(full, FacilityValueLSB, FacilityValueMSB)); ELSE RETURN NS32000Facility; (* TheLargestFacility; no its not its the smallest *) END; END ExtractFacility; PROCEDURE DecodeError(errorCode : INTEGER; VAR error : PanosError; VAR interface : Facility): BOOLEAN; VAR code: CARDINAL; BEGIN IF errorCode < 0 THEN error.facility := ExtractFacility(errorCode, DetectingFacilityLSB, DetectingFacilityMSB); interface := ExtractFacility(errorCode, InterfaceFacilityLSB, InterfaceFacilityMSB); code := Fields.Extract(errorCode, ErrorCodeLSB, ErrorCodeMSB); CASE error.facility OF NS32000Facility: error.ns32000Error := code; | ConvertFacility: error.convertError := ConvertFacilityErrors(code); | StoreFacility: error.storeError := StoreFacilityErrors(code); | IOFacility: error.ioError := IOFacilityErrors(code); | LoaderFacility: error.loaderError := LoaderFacilityErrors(code); | TimeFacility: error.timeError := TimeFacilityErrors(code); | ExceptionFacility: error.exceptionError := ExceptionFacilityErrors(code); | EventFacility: error.eventError := EventFacilityErrors(code); | EnvFacility: error.envError := EnvFacilityErrors(code); | ControlFacility: error.controlError := ControlFacilityErrors(code); | KernelFacility: error.kernelError := code; | BBCFacility: error.bbcError := code; | ArgumentKeyFacility, ArgumentUserFacility: error.argumentError := ArgumentFacilityErrors(code); | FileFacility: error.fileError := FileFacilityErrors(code); | CLIFacility: error.cliError := code; | ErrorFacility: error.errorError := ErrorFacilityErrors(code); | WildFacility: error.wildError := WildFacilityErrors(code); ELSE (* Never happens (!?) *) END; RETURN TRUE; ELSE RETURN FALSE; END; END DecodeError; END PanosError. Title: PanosMCI - Implementation LastEdit: "Tue Nov 13 09:11:21 1984" Author: Mick Jordan Acorn Computers Ltd IMPLEMENTATION MODULE PanosMCI; FROM SYSTEM IMPORT CALLEXTFUNC; (* these procedures are all implemented in the SYSTEM module, which is coded in assembler. PROCEDURE GetGFTablePtr(): GFTablePtr; BEGIN RETURN GFTablePtr( CALLEXTFUNC("SYSTEM.GFT") ); END GetGFTablePtr; PROCEDURE GetLMTablePtr(): LMTablePtr; BEGIN RETURN LMTablePtr( CALLEXTFUNC("SYSTEM.GFTL") ); END GetLMTablePtr; PROCEDURE GetGFTableUpb(): CARDINAL; BEGIN RETURN CARDINAL( CALLEXTFUNC("SYSTEM.GFTUPB") ); END GetGFTableUpb; END PanosMCI . (*********************************************************************) (* Title: Random - Implementation *) (* Author: Jeremy Dion *) (*********************************************************************) $Revision: 1.2 $ $Author: mjj $ $Date: 85/07/04 10:03:18 $ $Source: /util/m2/lib/Standard/RCS/Random.mod,v $ $State: Exp $ IMPLEMENTATION MODULE Random; (* $T- *) VAR fibonacci: ARRAY BOOLEAN OF CARDINAL; VAR b: BOOLEAN; PROCEDURE Seed (c: CARDINAL); BEGIN fibonacci [b] := c; b := NOT b; END Seed; PROCEDURE RandomCard(): CARDINAL; BEGIN fibonacci [b] := fibonacci [TRUE] + fibonacci [FALSE]; b := NOT b; RETURN fibonacci [b]; END RandomCard; PROCEDURE Uniform (lwb, upb: CARDINAL): CARDINAL; BEGIN IF upb <= lwb THEN RETURN lwb ELSE RETURN (RandomCard () MOD (upb - lwb + 1)) + lwb; END; END Uniform; PROCEDURE ZeroTo (l: CARDINAL): CARDINAL; BEGIN RETURN Uniform (0, l); END ZeroTo; PROCEDURE OneTo (l: CARDINAL): CARDINAL; BEGIN RETURN Uniform (1, l); END OneTo; BEGIN b := FALSE; fibonacci [FALSE] := 214376922; fibonacci [TRUE] := 436098648; END Random. $Log: Random.mod,v $ Revision 1.2 85/07/04 10:03:18 mjj Remove unnecessary range checking. Title: Singly-linked list package - Implementation LastEdit: "Tue May 3 16:44:15 1983" Author: Mick Jordan Cambridge University Computer Laboratory IMPLEMENTATION MODULE Slist; FROM SYSTEM IMPORT ADDRESS, WORD, ADR; PROCEDURE Add(VAR listhead: ADDRESS; newelement: ADDRESS); BEGIN newelement^ := WORD(listhead); listhead := newelement; END Add; PROCEDURE AddE(VAR listhead: ADDRESS; newelement: ADDRESS); VAR t, tf: ADDRESS; BEGIN t := ADR(listhead); LOOP tf := ADDRESS(t^); IF tf = NIL THEN EXIT; ELSE t := tf; (* onto next *) END; END; t^ := WORD(newelement); newelement^ := WORD(NIL); END AddE; PROCEDURE JoinE(VAR listhead: ADDRESS; newlist: ADDRESS); VAR t, tf: ADDRESS; BEGIN t := ADR(listhead); LOOP tf := ADDRESS(t^); IF tf = NIL THEN EXIT; ELSE t := tf; (* onto next *) END; END; t^ := WORD(newlist); END JoinE; PROCEDURE Remove(VAR listhead: ADDRESS; element: ADDRESS); VAR t, tf: ADDRESS; BEGIN t := ADR(listhead); LOOP tf := ADDRESS(t^); IF tf = NIL THEN EXIT ELSIF tf = element THEN (* match *) t^ := tf^; (* remove it *) EXIT; ELSE t := tf; (* onto next *) END; END; END Remove; END Slist . Title: Sort - Implementation LastEdit: "Mon Sep 10 10:41:57 1984" Author: pr Cambridge University Computer Laboratory Shell sort IMPLEMENTATION MODULE Sort; FROM SYSTEM IMPORT WORD; PROCEDURE Sort(VAR data: ARRAY OF WORD; length: CARDINAL; Precedes: Comparator); step, i, j, k: CARDINAL; x: WORD; BEGIN IF length = 0 THEN RETURN END (* if *); step := length; (* length > 0 *) REPEAT step := (step + 2) DIV 3; FOR i := step+1 TO length DO j := i-1; LOOP IF j <= step-1 THEN EXIT END; k := j - step; IF Precedes (data [k], data [j]) THEN EXIT; END; x := data [j]; data [j] := data [k]; data [k] := x; j := k; END; END; UNTIL step <= 1; END Sort; PROCEDURE INTEGERComparator(l, r: WORD): BOOLEAN; BEGIN RETURN INTEGER(l) < INTEGER(r); END INTEGERComparator; PROCEDURE CARDINALComparator(l, r: WORD): BOOLEAN; BEGIN RETURN CARDINAL(l) < CARDINAL(r); END CARDINALComparator; END Sort. Title: Stop - Implementation LastEdit: "Tue Nov 13 09:11:04 1984" Author: Mick Jordan Cambridge University Computer Laboratory IMPLEMENTATION MODULE Stop; IMPORT Streams; IMPORT Program; (* Panos *) PROCEDURE Stop(rc: INTEGER); BEGIN Streams.Finalise; Program.Stop(rc); END Stop; END Stop. (*********************************************************************) (* Title: Storage - Implementation *) (* Author: Jeremy Dion, Mick Jordan *) (* CUCL, ARC *) (*********************************************************************) $Revision: 1.3 $ $Author: mjj $ $Date: 85/06/04 18:01:46 $ $Source: /util/m2/lib/Standard/RCS/Storage.mod,v $ $State: Exp $ IMPLEMENTATION MODULE Storage; FROM OSStorage IMPORT WordAlign, AddressesPerUnit, HeapAllocate; FROM SYSTEM IMPORT ADDRESS, WORD, MAXCARD, TSIZE; FROM Exceptions IMPORT RAISE; (* $T-,$R- *) (* This is a machine-independent storage allocator based on the idea of keeping lists of free blocks of differing sizes. Each block in the heap has a free word at the front. When the block is free, this word contains the size of the block, and the next word is used as a chain pointer to blocks of similar size. If the block is in use, the first word contains either the negative of the size of the block, if the block is large enough to be on the overflow list, or the negative of the index of the block in the array of free lists, otherwise. The reason for the negative is to trap deallocations of already free objects. All sizes in this code are in the (arbitrary) storage units defined by TSIZE (WORD). The block sizes are allocated in intervals of about 20%. This means that fragmentation is about 10%. The last slot in the block list is used for very large allocations. This is the only slot for which the dependent list of free blocks will not all have the same size. To allocate a block of memory, we first go to the list of blocks of size just greater than that requested. If this is NIL, then we make a new block of this size by getting it from the end of the current block of heap. Otherwise, we chain down the list looking for a block which is large enough. In all cases but the overflow list, the first block on the list will be found. In order to avoid the case where the outside world has no more space to give and a particular list is exhausted, large blocks are recycled when there is more deallocated space the allocated. To dispose of a block, we look at the index word stored with it. This must be negative if the block is indeed in use, and if so, consider its absolute value. If this is small, it is the index of the list on which to chain the word. Otherwise it is the actual size of the block, which must be put on the overflow list. We insist that the argument given to DEALLOCATE be at least as large as the actual size of the object. TYPE Block = POINTER TO BlockData; BlockData = RECORD size: INTEGER; (* or FreeList index in used blocks *) block: Block; (* only in free blocks *) END; CONST Overflow = 56; VAR freeList: ARRAY [1..Overflow] OF BlockData; base: ADDRESS; (* base of free space block *) free: CARDINAL; (* size of free space block *) resetBase: BOOLEAN; (* after recycling *) allocated, (* ALLOCATEd and not DEALLOCATEd *) deAllocated: CARDINAL; (* DEALLOCATEd and not ALLOCATEd *) CONST AllocateFailed = "ALLOCATE failed"; DeAllocateFailed = "DEALLOCATE failed"; PROCEDURE ALLOCATE (VAR a: ADDRESS; n: CARDINAL); VAR index, half, need: INTEGER; rem: CARDINAL; b, p: Block; BEGIN IF WordAlign THEN rem := n MOD TSIZE (WORD); IF rem # 0 THEN INC (n, TSIZE (WORD) - rem) END END; need := n + TSIZE (INTEGER); (* allow space for the size word *) (* now find the correct slot by binary chop, biased towards small sizes *) index := Overflow DIV 4; half := index DIV 2; LOOP IF need > freeList [index].size THEN INC (index, half); IF index = Overflow THEN EXIT END; ELSIF need > freeList [index-1].size THEN EXIT ELSE DEC (index, half); IF index = 1 THEN EXIT END; END; IF half > 1 THEN half := half DIV 2 END; END; (* now either choose a free block of the right size or get a new one *) b := freeList [index].block; p := NIL; WHILE (b # NIL) AND (b^.size < need) DO p := b; b := b^.block END; IF b = NIL THEN IF index # Overflow THEN need :=freeList[index].size END; IF (INTEGER (free) < need) AND NOT GetBlock (index, need) THEN RAISE(AllocateFailed); END; b := base; INC (base, need * AddressesPerUnit); DEC (free, CARDINAL (need)); ELSE DEC(deAllocated, b^.size); IF p = NIL THEN freeList [index].block := b^.block; ELSE p^.block := b^.block END; END; INC (allocated, n); a := ADDRESS (b) + AddressesPerUnit*TSIZE(INTEGER); IF index = Overflow THEN b^.size := -need ELSE b^.size := -index END END ALLOCATE; PROCEDURE DEALLOCATE (VAR a: ADDRESS; n: CARDINAL); VAR b: Block; index, rem: CARDINAL; BEGIN IF a # NIL THEN IF WordAlign THEN rem := n MOD TSIZE (WORD); IF rem # 0 THEN INC (n, TSIZE (WORD) - rem) END END; b := Block (a - AddressesPerUnit*TSIZE(WORD)); IF b^.size < 0 THEN index := -b^.size ELSE RAISE(DeAllocateFailed) END; IF index < Overflow THEN IF INTEGER (n) > freeList [index].size THEN RAISE(DeAllocateFailed) END; b^.block := freeList [index].block; b^.size := freeList [index].size; freeList [index].block := b; ELSE IF INTEGER (n) > -b^.size THEN RAISE(DeAllocateFailed) END; b^.block := freeList [Overflow].block; freeList [Overflow].block := b; b^.size := -b^.size; END; INC (deAllocated, n); DEC (allocated, n); a := NIL; END; END DEALLOCATE; PROCEDURE GetBlock (index, n: CARDINAL): BOOLEAN; VAR ix: CARDINAL; p, b: Block; BEGIN (* this is a rather crude attempt to recycle disposed blocks once they begin to accumulate *) IF resetBase THEN base := NIL END; resetBase := FALSE; IF ((index # Overflow) AND (deAllocated > allocated)) OR NOT HeapAllocate(n, base, free) THEN FOR ix := Overflow TO index+1 BY -1 DO b := freeList [ix].block; p := NIL; WHILE (b # NIL) AND (b^.size < INTEGER(n)) DO p := b; b := b^.block; END; IF b # NIL THEN base := b; free := b^.size; DEC(deAllocated, free); IF p = NIL THEN freeList [ix].block := b^.block; ELSE p^.block := b^.block END; resetBase := TRUE; (* so that when we next go to HeapAllocate, 'base' is reset correctly. *) RETURN TRUE; END; END; (* in case we came in because deAllocated > allocated and failed *) RETURN HeapAllocate(n, base, free); END; RETURN TRUE; END GetBlock; PROCEDURE Set8 (index, s1, s2, s3, s4, s5, s6, s7, s8: CARDINAL); VAR i, s: CARDINAL; BEGIN FOR i := index TO index + 7 DO CASE i-index OF 0: s := s1 | 1: s := s2; | 2: s := s3; | 3: s := s4; | 4: s := s5; | 5: s := s6; | 6: s := s7; | 7: s := s8; END; WITH freeList[i] DO size := s*TSIZE(WORD); block := NIL; END; END; END Set8; BEGIN allocated := 0; deAllocated := 0; base := NIL; resetBase := TRUE; free := 0; Set8 (1, 2, 3, 4, 5, 6, 7, 8, 9); Set8 (9, 10, 11, 12, 13, 14, 15, 16, 17); Set8 (17, 18, 19, 20, 21, 22, 23, 24, 25); Set8 (25, 26, 27, 28, 29, 30, 31, 32, 33); Set8 (33, 39, 47, 57, 65, 82, 98, 117, 129); Set8 (41, 168, 201, 241, 257, 290, 348, 418, 501); Set8 (49, 601, 722, 1039, 1246, 1496, 1795, 2154, 2585); END Storage. $Log: Storage.mod,v $ Revision 1.3 85/06/04 18:01:46 mjj Modify strategy to recycle large blocks once deallocations occur in large numbers. Title: Strings - Implementation LastEdit: "Thu Nov 1 15:55:09 1984" Author: Mick Jordan/Lee Smith Acorn Computers. IMPLEMENTATION MODULE Strings; (* $T-, $R- *) (* T+ switched on as necessary throughout *) FROM SYSTEM IMPORT ADR, MAXCARD; FROM SystemTypes IMPORT Comparison; FROM Exceptions IMPORT RAISEC, ArrayIndexOutOfRange; FROM Storage IMPORT ALLOCATE, DEALLOCATE; FROM CharCodes IMPORT CapitalCh; PROCEDURE New(n: CARDINAL): String; (* allocate a string of length 'l' terminated with 0C *) VAR s: String; BEGIN INC(n); ALLOCATE(s,n); REPEAT DEC(n); s^[n]:= 0C; UNTIL n=0; RETURN s; END New; PROCEDURE LengthC(chars: ARRAY OF CHAR): CARDINAL; (* Return the number of characters in 'chars' *) VAR len: CARDINAL; BEGIN len:= 0; WHILE (len <= HIGH(chars)) AND (chars[len] # 0C) DO INC(len) END; RETURN len END LengthC; PROCEDURE LengthS(s: String): CARDINAL; VAR len: CARDINAL; BEGIN len:= 0; WHILE s^[len] # 0C DO INC(len) END; RETURN len END LengthS; PROCEDURE Dispose (VAR s: String); BEGIN DEALLOCATE (s, LengthS(s)+1) END Dispose; PROCEDURE CopyXX(from, to: String; hFrom, hTo: CARDINAL); i: CARDINAL; BEGIN (* generic copy procedure, with explicit index check *) i := 0; WHILE (i <= hFrom) AND (from^[i] # 0C) DO IF i > hTo THEN RAISEC(ArrayIndexOutOfRange) ELSE to^[i] := from^[i]; END (* if *); INC(i); END (* while *); IF i <= hTo THEN to^[i] := 0C; END (* if *); END CopyXX; PROCEDURE CopyCC(from: ARRAY OF CHAR; VAR to: ARRAY OF CHAR); BEGIN CopyXX(String(ADR(from)), String(ADR(to)), HIGH(from), HIGH(to)); END CopyCC; PROCEDURE CopyCS(from: ARRAY OF CHAR): String; VAR to: String; l: CARDINAL; BEGIN l:= LengthC(from); to:= New(l); IF l # 0 THEN DEC(l) END (* if *); CopyXX(String(ADR(from)), to, l, l); RETURN to; END CopyCS; PROCEDURE CopySC(from: String; VAR to: ARRAY OF CHAR); BEGIN CopyXX(from, String(ADR(to)), MAXCARD, HIGH(to)); END CopySC; PROCEDURE CopySS(from: String): String; VAR l: CARDINAL; to: String; BEGIN l:= LengthS(from); to:= New(l); IF l # 0 THEN DEC(l); END (* if *); CopyXX(from, to, l, l); RETURN to; END CopySS; PROCEDURE ConcatXX(head, tail: String; hHead, hTail: CARDINAL): String; VAR lHead, lTail, lTo: CARDINAL; i: CARDINAL; to: String; BEGIN (* generic procedures for ConcatSS, ConcatCS, ConcatSC *) (* cannot use LengthS, since original C array may not be null terminated *) lHead := 0; lTail := 0; WHILE (lHead <= hHead) AND (head^[lHead] # 0C) DO INC(lHead) END (* while *); WHILE (lTail <= hTail) AND (tail^[lTail] # 0C) DO INC(lTail) END (* while *); lTo := lHead + lTail; to:= New(lTo); i:= 0; WHILE i < lHead DO to^[i]:= head^[i]; INC(i) END; WHILE i < lTo DO to^[i]:= tail^[i-lHead]; INC(i) END; RETURN to; END ConcatXX; PROCEDURE ConcatSS(head, tail: String): String; BEGIN RETURN ConcatXX(head, tail, MAXCARD, MAXCARD); END ConcatSS; PROCEDURE ConcatCS(head: ARRAY OF CHAR; tail: String): String; BEGIN RETURN ConcatXX(String(ADR(head)), tail, HIGH(head), MAXCARD); END ConcatCS; PROCEDURE ConcatSC(head: String; tail: ARRAY OF CHAR): (* to *) String; BEGIN RETURN ConcatXX(head, String(ADR(tail)), MAXCARD, HIGH(tail)); END ConcatSC; PROCEDURE ConcatCC(head, tail: ARRAY OF CHAR; VAR to: ARRAY OF CHAR); VAR i, j, highTail: CARDINAL; tailCopy: String; BEGIN (* care needed, since to=head or to=tail is ok but compiler might optimise to call by reference IF ADR(tail) = ADR(to) THEN (* same array (call by reference) *) tailCopy := CopyCS(tail); highTail := MAXCARD; ELSE tailCopy := String(ADR(tail)); highTail := HIGH(tail) END (* if *); IF ADR(head) # ADR(to) THEN CopyCC(head, to); END (* if *); i := 0; j := LengthC(head); WHILE (i <= highTail) AND (tailCopy^[i] # 0C) DO IF (i+j) > HIGH(to) THEN RAISEC(ArrayIndexOutOfRange); ELSE to[i+j] := tailCopy^[i]; END (* if *); INC(i); END (* while *); IF i+j <= HIGH(to) THEN to[i+j] := 0C; END (* if *); IF ADR(tail) = ADR(to) THEN Dispose(tailCopy); END; END ConcatCC; (* *** comparison and equality primitives *** *) PROCEDURE EqualCC(l, r: ARRAY OF CHAR): BOOLEAN; VAR i: CARDINAL; BEGIN i:= 0; WHILE (i <= HIGH(l)) AND (i <= HIGH(r)) DO IF l[i] # r[i] THEN RETURN FALSE; ELSIF l[i] = 0C THEN RETURN TRUE; (* cos r[i] = 0C by above equality *) ELSE INC(i); END (* if *); END (* while *); (* fallen off the end of one, equal so far *) IF i > HIGH(l) THEN RETURN (i > HIGH(r)) OR (r[i] = 0C); ELSE RETURN (i > HIGH(l)) OR (l[i] = 0C); END (* if *); END EqualCC; PROCEDURE EqualSS(l, r: String): BOOLEAN; i: CARDINAL; BEGIN i := 0; LOOP IF l^[i] # r^[i] THEN RETURN FALSE; ELSIF l^[i] = 0C THEN RETURN TRUE (* cos r^[i] = 0C by above equality *) ELSE INC(i); END (* if *); END (* loop *); END EqualSS; PROCEDURE EqualCS(chars: ARRAY OF CHAR; s: String): BOOLEAN; i: CARDINAL; BEGIN i := 0; LOOP IF (i > HIGH(chars)) THEN RETURN s^[i] = 0C; ELSIF chars[i] # s^[i] THEN RETURN FALSE; ELSIF s^[i] = 0C THEN RETURN chars[i] = 0C; ELSE INC(i); END (* if *); END (* loop *); END EqualCS; PROCEDURE CompareXX(l, r: String; hl, hr: CARDINAL; c: CaseMode): Comparison; (* Compare two strings *) VAR i: CARDINAL; c1, c2: CHAR; BEGIN i:= 0; WHILE (i <= hl) AND (i <= hr) DO c1:= l^[i]; c2:= r^[i]; IF (c1 = 0C) AND (c2 = 0C) THEN RETURN EQ END; IF c = IgnoreCase THEN c1 := CapitalCh(c1); c2 := CapitalCh(c2); END (* if *); IF c1 = c2 THEN INC(i) ELSE IF c1 < c2 THEN RETURN LT ELSE RETURN GT END; END; END (* while *); (* fallen off the end of one, equal so far *) IF hl = hr THEN RETURN EQ ELSIF i > hl THEN IF (i > hr) OR (r^[i] = 0C) THEN RETURN EQ ELSE RETURN LT END (* if *); ELSE IF (i > hl) OR (l^[i] = 0C) THEN RETURN EQ ELSE RETURN GT END (* if *); END (* if *); END CompareXX; PROCEDURE CompareCC(l, r: ARRAY OF CHAR; c: CaseMode): Comparison; BEGIN RETURN CompareXX(String(ADR(l)), String(ADR(r)), HIGH(l), HIGH(r), c); END CompareCC; PROCEDURE CompareSS(l, r: String; c: CaseMode): Comparison; BEGIN RETURN CompareXX(l, r, MAXCARD, MAXCARD, c); END CompareSS; PROCEDURE CompareCS(l: ARRAY OF CHAR; r: String; c: CaseMode): Comparison; BEGIN RETURN CompareXX(String(ADR(l)), r, HIGH(l), MAXCARD, c); END CompareCS; PROCEDURE FindC(s: ARRAY OF CHAR; ch: CHAR; VAR index: CARDINAL): BOOLEAN; BEGIN WHILE (index <= HIGH(s)) AND (s[index] # 0C) DO IF s[index] = ch THEN RETURN TRUE ELSE INC(index) END; END; (* Assert: index > HIGH(s) OR s[index] = 0C *) RETURN FALSE; END FindC; PROCEDURE FindS(s: String; ch: CHAR; VAR index: CARDINAL): BOOLEAN; BEGIN WHILE (s^[index] # 0C) DO IF s^[index] = ch THEN RETURN TRUE ELSE INC(index) END; END; (* Assert: s[index] = 0C *) RETURN FALSE; END FindS; PROCEDURE ExtractCC(from: ARRAY OF CHAR; lwb, upb: CARDINAL; VAR to: ARRAY OF CHAR); (* *** includes from[lwb]; excludes from[upb] *** *) VAR j: CARDINAL; BEGIN j:=0; WHILE (lwb < upb) DO (* $T+ *) to[j]:= from[lwb]; INC(j); INC(lwb); (* $T= *) END (* while *); IF j <= HIGH(to) THEN to[j]:= 0C; END (* if *); END ExtractCC; PROCEDURE ExtractSS(from: String; lwb, upb: CARDINAL): String; VAR j: CARDINAL; to: String; BEGIN j:=0; IF lwb < upb THEN to := New(upb-lwb); ELSE to := New(0); END (* if *); WHILE (lwb < upb) DO to^[j]:= from^[lwb]; INC(j); INC(lwb); END (* while *); RETURN to; END ExtractSS; PROCEDURE ExtractSC(from: String; lwb, upb: CARDINAL; VAR to: ARRAY OF CHAR); (* *** includes from^[lwb]; excludes from[upb] *** *) VAR j: CARDINAL; BEGIN j:=0; WHILE (lwb < upb) DO (* $T+ *) to[j]:= from^[lwb]; INC(j); INC(lwb); (* $T= *) END (* while *); IF j <= HIGH(to) THEN to[j]:= 0C; END (* if *); END ExtractSC; END Strings. IMPLEMENTATION MODULE SystemTypes; BEGIN END SystemTypes . (*********************************************************************) (* Title: Threads of Control - Implementation *) (* LastEdit: "Wed Oct 31 16:58:05 1984" by Mick Jordan *) (* Author: Mick Jordan *) (* Copyright (C) 1984 by Acorn Research Centre *) (*********************************************************************) (* An implementation in terms of coroutines *) IMPLEMENTATION MODULE Threads; FROM SYSTEM IMPORT NEWPROCESS, PROCESS, WORD, ADDRESS, SIZE, TRANSFER; FROM Storage IMPORT ALLOCATE, DEALLOCATE; TYPE CoRoutine = PROCESS; Stack = POINTER TO ARRAY [0..1023] OF WORD; ThreadStatus = (Alive, Finished, Dead); Thread = POINTER TO ThreadState; ThreadState = RECORD link: Thread; (* to next thread in list *) joinQueue: Thread; (* list of processes waiting to Join *) state: CoRoutine; realForkee: Forkee; (* user supplied procedure *) status: ThreadStatus; priority: Priority; stack: Stack; argOrResult: WORD; END (* record *); Mutex = POINTER TO RECORD isLocked: BOOLEAN; queue: Thread; END (* record *); Condition = POINTER TO RECORD wakeupWaiting: BOOLEAN; queue: Thread; END (* record *); ReadyQueue = ARRAY Priority OF Thread; CONST StandardPriority = 10; VAR currentThread: Thread; readyQueue: ReadyQueue; PROCEDURE InitMutex(VAR mutex: Mutex); BEGIN NEW(mutex); WITH mutex^ DO isLocked := FALSE; queue := NIL; END (* with *); END InitMutex; PROCEDURE InitCondition(VAR cv: Condition); BEGIN NEW(cv); WITH cv^ DO wakeupWaiting := FALSE; queue := NIL; END (* with *); END InitCondition; PROCEDURE Acquire(VAR mutex: Mutex); BEGIN IF mutex^.isLocked THEN Queue.InsertAtTail(mutex^.queue, currentThread); ELSE mutex^.isLocked := TRUE; Queue.InsertAtTail(readyQueue[currentThread^.priority], currentThread); END (* if *); RunNext; END Acquire; PROCEDURE Release(VAR mutex: Mutex); VAR thread: Thread; BEGIN IF mutex^.queue # NIL THEN thread := Queue.RemoveFromHead(mutex^.queue); Queue.InsertAtTail(readyQueue[thread^.priority], thread); ELSE mutex^.isLocked := FALSE; END (* if *); Queue.InsertAtTail(readyQueue[currentThread^.priority], currentThread); RunNext; END Release; PROCEDURE Wait(VAR mutex: Mutex; VAR condition: Condition); VAR thread: Thread; BEGIN IF condition^.wakeupWaiting THEN condition^.wakeupWaiting := FALSE; ELSE Queue.InsertAtTail(condition^.queue, currentThread); (* release mutex *) IF mutex^.queue # NIL THEN thread := Queue.RemoveFromHead(mutex^.queue); Queue.InsertAtTail(readyQueue[thread^.priority], thread); ELSE mutex^.isLocked := FALSE; END (* if *); RunNext; Acquire(mutex); END; END Wait; PROCEDURE Signal(VAR cv: Condition); VAR thread: Thread; BEGIN IF cv^.queue = NIL THEN cv^.wakeupWaiting := TRUE; ELSE thread := Queue.RemoveFromHead(cv^.queue); Queue.InsertAtTail(readyQueue[thread^.priority], thread); END (* if *); Queue.InsertAtTail(readyQueue[currentThread^.priority], currentThread); RunNext; END Signal; PROCEDURE Broadcast(VAR cv: Condition); VAR thread: Thread; BEGIN IF cv^.queue = NIL THEN cv^.wakeupWaiting := TRUE; ELSE thread := Queue.RemoveFromHead(cv^.queue); WHILE thread # NIL DO Queue.InsertAtTail(readyQueue[thread^.priority], thread); thread := Queue.RemoveFromHead(cv^.queue); END (* while *); END (* if *); Queue.InsertAtTail(readyQueue[currentThread^.priority], currentThread); RunNext; END Broadcast; PROCEDURE Fork(forkee: Forkee; forkeeArg: ForkeeArg): Thread; VAR thread: Thread; BEGIN NEW(thread); WITH thread^ DO NEW(stack); NEWPROCESS(RunForkee, ADDRESS(stack), SIZE(stack^), state); argOrResult := forkeeArg; realForkee := forkee; joinQueue := NIL; priority := currentThread^.priority; status := Alive; END; Queue.InsertAtTail(readyQueue[thread^.priority], thread); Queue.InsertAtTail(readyQueue[currentThread^.priority], currentThread); RunNext; RETURN thread END Fork; PROCEDURE CurrentThread(): Thread; BEGIN RETURN(currentThread); END CurrentThread; PROCEDURE RunForkee; (* This procedure is the place that the first TRANSFER takes place to. Now we can call the 'forkee' with the argument passed in 'Fork' VAR thread: Thread; BEGIN WITH currentThread^ DO argOrResult := realForkee(argOrResult); (* another thread may have tried to Join *) IF joinQueue # NIL THEN thread := Queue.RemoveFromHead(joinQueue); WHILE thread # NIL DO Queue.InsertAtTail(readyQueue[thread^.priority], thread); thread := Queue.RemoveFromHead(joinQueue); END; END; (* we can now safely destroy currentThread. Actually we cant dispose the ThreadState cos RunNext needs it to do the transfer. *) status := Finished; DISPOSE(stack); (* DISPOSE(currentThread); *) END; RunNext; END RunForkee; PROCEDURE Join(thread: Thread): ForkeeReturn; BEGIN IF thread^.status = Alive THEN Queue.InsertAtTail(thread^.joinQueue, currentThread); RunNext; ELSE currentThread^.argOrResult := thread^.argOrResult; END; (* when control returns here 'thread' must have completed, and 'RunForkee' will have copied its result to (what is now) currentThread^.argOrResult *) RETURN currentThread^.argOrResult END Join; PROCEDURE GetPriority(thread: Thread): Priority; BEGIN RETURN(thread^.priority); END GetPriority; PROCEDURE SetPriority(thread: Thread; priority: Priority); VAR currentPriority: Priority; tail, current, prev: Thread; BEGIN (* If the thread is not in the ready queue, then I claim (with Mick's assiatance) that nothing needs to be done. If it is not ready then it is running or blocked in which case it will be placed on the proper ready queue when the time comes. If it is on the ready queue, then it needs to be moved to the right queue now. *) currentPriority := thread^.priority; tail := readyQueue[currentPriority]; IF (currentPriority # priority) AND (tail # NIL) THEN (* Try to find the thread on the ready queue *) current := tail^.link; prev := tail; WHILE (current # thread) AND (current # tail) DO prev := current; current := current^.link; END; IF current = thread THEN (* remove current from queue *) IF prev = current THEN (* single item queue - now empty *) readyQueue[currentPriority] := NIL; ELSE prev^.link := current^.link; END; thread^.priority := priority; Queue.InsertAtTail(readyQueue[priority], thread); END; END; Queue.InsertAtTail(readyQueue[currentThread^.priority], currentThread); RunNext; END SetPriority; PROCEDURE RunNext; VAR oldThread: Thread; i: Priority; BEGIN oldThread := currentThread; i := HighestPriority; (* We are theoretically guaranteed that there is at least one process additionally eventually i will get a range fault or some bogus thread will be found at a random address preceding the readyQueue. *) WHILE readyQueue[i] = NIL DO INC(i); END; IF i > LowestPriority THEN HALT (* Empty ready queue *) ELSE currentThread := Queue.RemoveFromHead(readyQueue[i]); TRANSFER(oldThread^.state, currentThread^.state); END; END RunNext; (* ----------------------------------------------------------------------- *) MODULE Queue; IMPORT Thread; EXPORT QUALIFIED InsertAtTail, RemoveFromHead; PROCEDURE InsertAtTail(VAR q: Thread; p: Thread); BEGIN IF q = NIL THEN p^.link := p; ELSE p^.link := q^.link; (* connect to head *) q^.link := p; (* connect old tail to new *) END (* if *); q := p; END InsertAtTail; PROCEDURE RemoveFromHead(VAR q: Thread): Thread; VAR head: Thread; BEGIN IF q = NIL THEN head := NIL ELSE head := q^.link; q^.link := head^.link; IF head = q THEN q := NIL; END (* if *); END (* if *); RETURN head; END RemoveFromHead; END Queue; PROCEDURE InitReadyQueue(); VAR i: Priority; BEGIN FOR i:= HighestPriority TO LowestPriority DO readyQueue[i] := nilThread; END; END InitReadyQueue; BEGIN nilThread := NIL; InitReadyQueue(); (* create anonymous main thread *) NEW(currentThread); WITH currentThread^ DO joinQueue := NIL; status := Alive; priority := StandardPriority; END; END Threads. Title: TimeDate - Implementation LastEdit: "Mon Oct 1 16:20:07 1984" Author: Mick Jordan Acorn Computers Ltd 16032 Panos version IMPLEMENTATION MODULE TimeDate; IMPORT TimeAndDate; MODULE SystemTime; (* this module only produces valid times after Jan 1 1904 *) IMPORT TimeAndDate; EXPORT TIME, GetTime; TYPE TIME = RECORD time, date: CARDINAL; END; CONST low=0; high=1; secondsperminute = 60; minutesperday = 1440; ticksperday = 33750; daysPer4Years = 1461; daysInLeapYear = 366; daysInYear = 365; VAR dmonth: ARRAY [1 .. 12] OF CARDINAL; PROCEDURE GetTime(VAR tim : TIME); VAR ticks, daysSince1904, secsToday, minsToday: CARDINAL; panosTime: TimeAndDate.TimeStamp; yr, mth, dy: CARDINAL; r: INTEGER; BEGIN r := TimeAndDate.BinaryTime(panosTime); IF r >= 0 THEN (* get high order 32 bits *) ticks := (panosTime.LS DIV 256) + (panosTime.MS*65536*256); secsToday := (((ticks MOD ticksperday)*256) + (panosTime.LS MOD 256)) DIV 100; minsToday := secsToday DIV secondsperminute; (* minutes *) (* 1900 was not a leap year, so avoid it *) IF (ticks DIV ticksperday) < daysPer4Years THEN daysSince1904 := 0; ELSE daysSince1904 := (ticks DIV ticksperday) - daysPer4Years + 1; END; dy := daysSince1904+1; (* from a base of 1 *) (* Groups of 4 years - 3 ordinary + 1 leap.*) yr := 4 + 4 * (daysSince1904 DIV daysPer4Years); dy := dy MOD daysPer4Years; (* Single years. *) LOOP IF (yr MOD 4) = 0 THEN IF dy > daysInLeapYear THEN dy := dy - daysInLeapYear; ELSE EXIT END ELSE IF dy > daysInYear THEN dy := dy - daysInYear; ELSE EXIT END END; yr := yr + 1 END; (* Months. *) mth := 1; LOOP IF mth = 2 THEN IF (yr MOD 4) = 0 THEN (* Leap February. *) IF dy > 29 THEN dy := dy - 29 ELSE EXIT END ELSE IF dy > 28 THEN dy := dy - 28 ELSE EXIT END END ELSE IF dy > dmonth[mth] THEN dy := dy - dmonth[mth] ELSE EXIT END END; mth := mth + 1 END; WITH tim DO time := ((minsToday DIV 60) * 64 + (minsToday MOD 60)) * 64 + (secsToday MOD 60); date := ((yr * 16) + mth) * 32 + dy; END; ELSE tim.time := 0; tim.date := 0; END; END GetTime; BEGIN dmonth[1] := 31; dmonth[2] := 28; dmonth[3] := 31; dmonth[4] := 30; dmonth[5] := 31; dmonth[6] := 30; dmonth[7] := 31; dmonth[8] := 31; dmonth[9] := 30; dmonth[10] := 31; dmonth[11] := 30; dmonth[12] := 31 END SystemTime; (* -----------------portable exported procedures of TimeDate -------------- *) VAR monthstrings: ARRAY [0 .. 12*3] OF CHAR; PROCEDURE Time(): CARDINAL; VAR t: TIME; BEGIN GetTime(t); RETURN t.time END Time; PROCEDURE Date(): CARDINAL; VAR t: TIME; BEGIN GetTime(t); RETURN t.date; END Date; PROCEDURE Plant2(VAR v: ARRAY OF CHAR; i: CARDINAL; val: CARDINAL); VAR f: CARDINAL; BEGIN IF val>9 THEN f := val DIV 10; val := val MOD 10; ELSE f := 0; END; v[i] := CHAR(ORD('0') + f); v[i+1] := CHAR(ORD('0') + val); END Plant2; PROCEDURE TimeString(time: CARDINAL; VAR ts: ARRAY OF CHAR); BEGIN ts[2] := ':'; ts[5] := ':'; ts[8] := 0C; Plant2(ts, 0, time DIV (64*64)); Plant2(ts, 3, (time DIV 64) MOD 64); Plant2(ts, 6, time MOD 64); END TimeString; PROCEDURE DateString(date: CARDINAL; VAR ds: ARRAY OF CHAR); VAR mx, i: CARDINAL; BEGIN mx :=(((date DIV 32) MOD 16) - 1)*3; ds[2] := '-'; ds[6] := '-'; ds[9] := 0C; Plant2(ds, 0, date MOD 32); FOR i := 0 TO 2 DO ds[3+i] := monthstrings[mx+i]; END (* for *); Plant2(ds, 7, (date DIV (32*16)) MOD 128); END DateString; BEGIN monthstrings := "JanFebMarAprMayJunJulAugSepOctNovDec"; END TimeDate. (* This is a totally unsupported module, it may well be absent in future releases. USE IT AT YOUR OWN PERIL. *) IMPLEMENTATION MODULE TKCalls; FROM SYSTEM IMPORT REGISTER, TKCALL; PROCEDURE TKCall(VAR r: Registers); (* Performs the TK call specified by the Register array. Goes about it in a backhanded manner to get round compiler bug. The compiler tries to slave 'r' in a register given half a chance and this knackers any attempt to use all 8 registers in the TKCALL BEGIN RegTKCall(r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); END TKCall; PROCEDURE RegTKCall(VAR r0, r1, r2, r3, r4, r5, r6, r7: CARDINAL); BEGIN r0 := CARDINAL(TKCALL(r0, r1, r2, r3, r4, r5, r6, r7)); r1 := CARDINAL(REGISTER(1)); r2 := CARDINAL(REGISTER(2)); r3 := CARDINAL(REGISTER(3)); r4 := CARDINAL(REGISTER(4)); r5 := CARDINAL(REGISTER(5)); r6 := CARDINAL(REGISTER(6)); r7 := CARDINAL(REGISTER(7)); END RegTKCall ; END TKCalls. ееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееееее