DIRECTORY Atom USING [GetPName], Basics USING [bytesPerWord], BasicTime USING [GMT, Now, nullGMT, Period], Buttons USING [Button, ButtonProc, Create, SetDisplayStyle], Checksum USING [ComputeChecksum], Commander USING [CommandProc, Register], Containers USING [ChildXBound, ChildYBound, Create], Convert USING [Error, IntFromRope, RopeFromInt], IO USING [Close, CreateStream, CreateStreamProcs, Flush, PutF, STREAM, StreamProcs], Labels USING [Create], Loader USING [BCDBuildTime], Rope USING [ROPE], Rules USING [Create], SafeStorage USING [NWordsAllocated], STP USING [CompletionProcType, ConfirmProcType, Close, Create, DesiredProperties, Error, GetProperty, Handle, Login, Open, Retrieve, SetDesiredProperties], TypeScript USING [ChangeLooks, Create], UserCredentials USING [Get], VFonts USING [FontHeight, StringWidth], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, RegisterEventProc], ViewerIO USING [CreateViewerStreams], ViewerOps USING [AddProp, ComputeColumn, CreateViewer, FetchProp, MoveViewer, OpenIcon, SetOpenHeight], ViewerTools USING [GetContents, MakeNewTextViewer, SetContents, SetSelection]; Checksummer: CEDAR MONITOR IMPORTS Atom, BasicTime, Buttons, Checksum, Commander, Containers, Convert, IO, Labels, Loader, Rules, SafeStorage, STP, TypeScript, UserCredentials, VFonts, ViewerEvents, ViewerIO, ViewerOps, ViewerTools = BEGIN BYTE: TYPE = [0..100H); ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Viewer: TYPE = ViewerClasses.Viewer; buttonHeight: INT _ VFonts.FontHeight[] + 3; buttonWidth: INT _ VFonts.StringWidth["WrDsk"] + 2*3; ClientData: TYPE = REF ClientDataRep; ClientDataRep: TYPE = RECORD [ log: STREAM _ NIL, in: STREAM _ NIL, pleaseStop: BOOLEAN _ FALSE, user: PROCESS _ NIL, silent: REF BOOL _ NEW[BOOL _ FALSE], version: REF BOOL _ NEW[BOOL _ TRUE], host, files: Viewer _ NIL ]; global: ClientData _ NIL; -- debugging Create: Commander.CommandProc = { viewer, buttons, log: Viewer _ NIL; data: ClientData _ NEW[ClientDataRep _ []]; global _ data; viewer _ ViewerOps.CreateViewer [ flavor: $Container, info: [name: "Checksummer", column: right, iconic: TRUE, scrollable: FALSE]]; [] _ ViewerEvents.RegisterEventProc[Poof, destroy, viewer, TRUE]; ViewerOps.AddProp[viewer, $Checksummer, data]; log _ TypeScript.Create[ [name: "Checksummer.log", wy: 27+4, parent: viewer, border: FALSE], FALSE]; [data.in, data.log] _ ViewerIO.CreateViewerStreams [ name: "Checksummer.log", backingFile: "Checksummer.log", viewer: log, editedStream: FALSE]; Containers.ChildXBound[viewer, log]; Containers.ChildYBound[viewer, log]; CreateButtons[data, viewer, log]; TypeScript.ChangeLooks[log, 'f]; IO.PutF[data.log, "Checksummer of %G.\n\n", [time[Loader.BCDBuildTime[Create]]]]; ViewerOps.OpenIcon[viewer]; }; CreateButtons: ENTRY PROC[data: ClientData, parent, log: Viewer] = { child: Viewer _ NIL; kids: Viewer = Containers.Create[ info: [parent: parent, border: FALSE, scrollable: FALSE, wx: 0, wy: -9999, ww: 9999, wh: 0] ]; Containers.ChildXBound[parent, kids]; child _ MakeRule[kids, child]; child _ data.host _ MakeLabeledText[ parent: kids, sibling: child, name: "Host:", data: "Host", width: VFonts.StringWidth["xxxxxxxxxxxxxxx"], prev: data.host ]; Containers.ChildXBound[parent, child]; child _ data.files _ MakeLabeledText[ parent: kids, sibling: child, name: "Files:", data: "Files", width: 9*VFonts.StringWidth["Big long file name ..........................."], prev: data.files ]; Containers.ChildXBound[parent, child]; child _ MakeRule[kids, child]; child _ MakeBool[name: "Version", init: data.version, clientData: data, parent: kids, x: 2, y: child.wy+child.wh+1]; child _ MakeBool[name: "Silent", init: data.silent, clientData: data, parent: kids, x: child.wx + child.ww + 10, y: child.wy]; child _ MakeRule[kids, child]; child _ MakeLabel[kids, child, "What: "]; child _ MakeButton[kids, child, data, "Stop", StopProc]; child _ MakeButton[kids, child, data, "Check", CheckProc]; child _ MakeRule[kids, child]; { kidsY: INTEGER = 2; kidsH: INTEGER = child.wy + child.wh + 2; ViewerOps.MoveViewer[viewer: log, x: 0, y: kidsY + kidsH, w: log.ww, h: parent.ch - (kids.wy + kidsH), paint: FALSE]; ViewerOps.SetOpenHeight[parent, kidsY + kidsH + 12 * buttonHeight]; IF ~parent.iconic THEN ViewerOps.ComputeColumn[parent.column]; ViewerOps.MoveViewer[viewer: kids, x: kids.wx, y: kidsY, w: kids.ww, h: kidsH]; }; }; Poof: ViewerEvents.EventProc = { data: ClientData _ NARROW[ViewerOps.FetchProp[viewer, $Checksummer]]; IF event # destroy OR before # TRUE THEN ERROR; Stop[data]; IO.Close[data.log]; IO.Close[data.in]; }; StopProc: Buttons.ButtonProc = { data: ClientData _ NARROW[clientData]; Stop[data]; }; Stop: PROC [data: ClientData] = TRUSTED { data.pleaseStop _ TRUE; IF data.user # NIL THEN JOIN data.user; data.user _ NIL; }; CheckProc: Buttons.ButtonProc = { data: ClientData _ NARROW[clientData]; data.pleaseStop _ FALSE; Check[data]; }; streamProcs: REF IO.StreamProcs = IO.CreateStreamProcs[ variety: $output, class: $Checksummer, putBlock: PutBlock, close: Close ]; StreamData: TYPE = REF StreamDataRep; StreamDataRep: TYPE = RECORD [ data: ClientData, fileName: ROPE, sizeRope: ROPE, createRope: ROPE, stream: STREAM, size: INT, create: BasicTime.GMT, bytes: INT, checksum: WORD ]; Words: PROC [bytes: NAT] RETURNS [words: NAT] = { RETURN[(bytes+Basics.bytesPerWord-1)/Basics.bytesPerWord]; }; PutBlock: PROC [self: STREAM, block: REF READONLY TEXT, startIndex: NAT, count: NAT] = { me: StreamData = NARROW[self.streamData]; base: LONG POINTER = LOOPHOLE[block, LONG POINTER]+TEXT[0].SIZE; bytes: LONG POINTER TO PACKED ARRAY [0..NAT.LAST] OF CHAR = LOOPHOLE[base]; IF startIndex # 0 THEN ERROR; count _ MIN[count, block.length]; me.bytes _ me.bytes + count; IF (count MOD 2) # 0 THEN TRUSTED { bytes[count] _ 0C; }; TRUSTED { me.checksum _ Checksum.ComputeChecksum[me.checksum, Words[count], base]; }; }; Close: PROC [self: STREAM, abort: BOOL] = { me: StreamData = NARROW[self.streamData]; data: ClientData _ me.data; IF ~data.silent^ OR (me.size # me.bytes) THEN { checksumRope: ROPE _ Convert.RopeFromInt[me.checksum, 16, FALSE]; IO.PutF[ data.log, "%8G %4G %G %G.\n", [integer[me.size]], [rope[checksumRope]], [rope[me.createRope]], [rope[me.fileName]] ]; }; IF me.size # me.bytes THEN IO.PutF[ data.log, "***** Length mixup. Expected %g bytes, got %G.\n", [integer[me.size]], [integer[me.bytes]] ]; }; Check: PROC [data: ClientData] = { me: StreamData _ NEW[StreamDataRep _ [ data: data, fileName: NIL, sizeRope: NIL, createRope: NIL, size: 0, create: BasicTime.nullGMT, bytes: 0, checksum: 0 ]]; stream: IO.STREAM _ IO.CreateStream[streamProcs: streamProcs, streamData: me]; Open: STP.ConfirmProcType = { me^ _ [ data: data, fileName: file, sizeRope: STP.GetProperty[stp, size], createRope: STP.GetProperty[stp, createDate], size: 0, create: BasicTime.nullGMT, bytes: 0, checksum: 0 ]; IF data.pleaseStop THEN RETURN[abort, NIL]; me.size _ Convert.IntFromRope[me.sizeRope ! Convert.Error => CONTINUE]; RETURN[do, stream]; }; Close: STP.CompletionProcType = { me: StreamData = NARROW[stream.streamData]; totalBytes _ totalBytes + me.bytes; totalFiles _ totalFiles + 1; SELECT what FROM ok => IO.Close[stream]; error => IO.PutF[data.log, "***** STP Says error: %G while processing %G.\n", [rope[fileOrError]], [rope[me.fileName]] ]; ENDCASE => ERROR; }; start: BasicTime.GMT _ BasicTime.Now[]; stop: BasicTime.GMT; seconds: INT; words: INT _ SafeStorage.NWordsAllocated[]; host: ROPE = ViewerTools.GetContents[data.host]; files: ROPE = ViewerTools.GetContents[data.files]; stp: STP.Handle _ STP.Create[]; herald, name, password: ROPE; failed: BOOL _ FALSE; totalBytes: INT _ 0; totalFiles: INT _ 0; desiredProperties: STP.DesiredProperties _ ALL[FALSE]; desiredProperties[size] _ TRUE; desiredProperties[createDate] _ TRUE; desiredProperties[directory] _ TRUE; desiredProperties[nameBody] _ TRUE; desiredProperties[version] _ data.version^; IO.PutF[ data.log, "\n%G Scanning %G on %G.\n\n", [time[BasicTime.Now[]]], [rope[files]], [rope[host]] ]; herald _ STP.Open[stp, host ! STP.Error => { IO.PutF[data.log, " STP Open failed: %G.\n", [rope[error]] ]; failed _ TRUE; CONTINUE }]; IF failed THEN RETURN; [name, password] _ UserCredentials.Get[]; STP.Login[stp, name, password]; STP.SetDesiredProperties[stp, desiredProperties]; STP.Retrieve[stp, files, Open, Close ! STP.Error => { IO.PutF[data.log, " STP Retrieve failed: %G.\n", [rope[error]] ]; CONTINUE }]; STP.Close[stp ! STP.Error => CONTINUE ]; stop _ BasicTime.Now[]; seconds _ BasicTime.Period[from: start, to: stop]; seconds _ MAX[seconds, 1]; words _ SafeStorage.NWordsAllocated[]-words; IO.PutF[ data.log, "\nScanned %G files containing %G bytes in %R => %3.1FK bits/second.\n", [integer[totalFiles]], [integer[totalBytes]], [integer[seconds]], [real[(REAL[totalBytes]*8)/seconds/1000]] ]; IO.PutF[ data.log, "Used %G words => %G words/file or %G words/second.\n", [integer[words]], [integer[words/totalFiles]], [integer[words/seconds]] ]; IO.Flush[data.log]; }; MakeRule: PROC [parent, sibling: Viewer] RETURNS [child: Viewer] = { child _ Rules.Create[ info: [parent: parent, border: FALSE, wy: IF sibling = NIL THEN 0 ELSE sibling.wy + sibling.wh + 2, wx: 0, ww: parent.ww, wh: 1], paint: FALSE ]; Containers.ChildXBound[parent, child]; }; MakeButton: PROC [parent, sibling: Viewer, data: REF ANY, name: ROPE, proc: Buttons.ButtonProc] RETURNS[child: Viewer] = { child _ Buttons.Create[ info: [name: name, parent: parent, border: TRUE, wy: sibling.wy, wx: sibling.wx + sibling.ww - 1, ww: buttonWidth], proc: proc, clientData: data, fork: TRUE, paint: FALSE]; }; SelectorProc: TYPE = PROC [parent: Viewer, clientData: REF, value: ATOM]; Selector: TYPE = REF SelectorRec; SelectorRec: TYPE = RECORD [ value: REF ATOM, change: PROC [parent: Viewer, clientData: REF, value: ATOM], clientData: REF, buttons: LIST OF Buttons.Button, values: LIST OF ATOM ]; MakeSelector: PROC [name: ROPE, values: LIST OF ATOM, init: REF ATOM _ NIL, change: SelectorProc _ NIL, clientData: REF _ NIL, parent: Viewer, x, y: INTEGER] RETURNS [child: Viewer] = { selector: Selector _ NEW [SelectorRec _ [ value: IF init # NIL THEN init ELSE NEW [ATOM _ values.first], change: change, clientData: clientData, buttons: NIL, values: values ] ]; last: LIST OF Buttons.Button _ NIL; child _ Labels.Create[info: [name: name, parent: parent, border: FALSE, wx: x, wy: y] ]; FOR a: LIST OF ATOM _ values, a.rest UNTIL a = NIL DO child _ Buttons.Create[ info: [name: Atom.GetPName[a.first], parent: parent, border: TRUE, wx: child.wx + child.ww + 2, wy: child.wy], proc: SelectorHelper, clientData: selector, fork: TRUE, paint: TRUE]; IF last = NIL THEN last _ selector.buttons _ CONS[first: child, rest: NIL] ELSE { last.rest _ CONS[first: child, rest: NIL]; last _ last.rest }; IF a.first = selector.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack]; ENDLOOP; }; SelectorHelper: Buttons.ButtonProc = { self: Buttons.Button = NARROW[parent]; selector: Selector = NARROW[clientData]; buttons: LIST OF Buttons.Button _ selector.buttons; FOR a: LIST OF ATOM _ selector.values, a.rest UNTIL a = NIL DO IF self = buttons.first THEN { selector.value^ _ a.first; IF selector.change # NIL THEN selector.change[self.parent, selector.clientData, a.first]; Buttons.SetDisplayStyle[buttons.first, $WhiteOnBlack]; } ELSE Buttons.SetDisplayStyle[buttons.first, $BlackOnWhite]; buttons _ buttons.rest; ENDLOOP; }; BoolProc: TYPE = PROC [parent: Viewer, clientData: REF, value: BOOL]; Bool: TYPE = REF BoolRec; BoolRec: TYPE = RECORD [ value: REF BOOL, change: BoolProc, clientData: REF, button: Viewer ]; MakeBool: PROC [name: ROPE, init: REF BOOL, change: BoolProc _ NIL, clientData: REF _ NIL, parent: Viewer, x, y: INTEGER] RETURNS [child: Viewer] = { bool: Bool _ NEW [BoolRec _ [ value: IF init # NIL THEN init ELSE NEW [BOOL _ TRUE], change: change, clientData: clientData, button: NIL ] ]; child _ Buttons.Create[ info: [name: name, parent: parent, border: TRUE, wx: x, wy: y], proc: BoolHelper, clientData: bool, fork: TRUE, paint: TRUE]; bool.button _ child; IF bool.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack]; }; BoolHelper: Buttons.ButtonProc = { self: Buttons.Button = NARROW[parent]; bool: Bool = NARROW[clientData]; bool.value^ _ ~bool.value^; IF bool.value^ THEN Buttons.SetDisplayStyle[bool.button, $WhiteOnBlack] ELSE Buttons.SetDisplayStyle[bool.button, $BlackOnWhite]; IF bool.change # NIL THEN bool.change[self.parent, bool.clientData, bool.value^]; }; MakeLabel: PROC [parent, sibling: Viewer, name: ROPE] RETURNS [child: Viewer] = { child _ Labels.Create[ info: [name: name, parent: parent, border: FALSE, wy: sibling.wy + sibling.wh + (IF sibling.class.flavor = $Button THEN -1 ELSE 2), wx: 2, ww: VFonts.StringWidth[name] + 2*3 + 2], paint: FALSE ]; }; MakeLabeledText: PROC [ parent, sibling: Viewer, name, data: ROPE, prev: Viewer, width: INT, newline: BOOL _ TRUE] RETURNS [child: Viewer] = { buttonWidth: INT _ VFonts.StringWidth[name] + 2*3; x: INTEGER = IF newline THEN 2 ELSE sibling.wx + sibling.ww + 10; y: INTEGER = IF newline THEN sibling.wy + sibling.wh + 1 ELSE sibling.wy; child _ ViewerTools.MakeNewTextViewer[ info: [ parent: parent, wh: buttonHeight, ww: width+10, data: IF prev = NIL THEN data ELSE ViewerTools.GetContents[prev], border: FALSE, wx: x + buttonWidth + 2, wy: y, scrollable: FALSE ], paint: FALSE ]; [] _ Buttons.Create[ info: [name: name, parent: parent, wh: buttonHeight, border: FALSE, wx: x, wy: y], proc: LabeledTextProc, clientData: child, fork: FALSE, paint: FALSE]; RETURN[child]; }; LabeledTextProc: Buttons.ButtonProc = { text: Viewer = NARROW[clientData]; SELECT mouseButton FROM red => ViewerTools.SetSelection[text, NIL]; yellow => NULL; blue => { ViewerTools.SetContents[text, NIL]; ViewerTools.SetSelection[text, NIL] }; ENDCASE => ERROR; }; Commander.Register["Checksummer", Create, "Checksum remote files."]; END. |Checksummer.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Hal Murray, March 9, 1986 0:13:33 am PST Viewer layout parameters [viewer: ViewerClasses.Viewer, event: ViewerEvent, before: BOOL] RETURNS[abort: BOOL _ FALSE] parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL Κτ˜šœ™Icodešœ Οmœ7™BK™(—J˜šΟk ˜ Jšœžœ ˜Jšœžœ˜Jšœ žœžœ˜,Jšœžœ/˜JšœR˜R—J˜—š œ˜ Jšœ;žœ™@Jšžœžœžœ™Jšœžœ,˜EJš žœžœ žœžœžœ˜/Jšœ ˜ Jšžœ˜Jšžœ˜J˜J˜—š œ˜ JšœL™LJšœžœ ˜&Jšœ˜J˜—š‘œžœžœ˜)Jšœžœ˜Jšžœ žœžœžœ ˜'Jšœ žœ˜J˜—š  œ˜!JšœL™LJšœžœ ˜&Jšœžœ˜Jšœ˜J˜—šœ žœžœžœ˜7Kšœ˜Kšœ˜Kšœ˜K˜K˜—Jšœ žœžœ˜%šœžœžœ˜Jšœ˜Jšœ žœ˜Jšœ žœ˜Jšœ žœ˜Jšœžœ˜Jšœžœ˜ Jšœžœ˜Jšœžœ˜ Jšœ žœ˜—J˜š ‘œžœ žœžœ žœ˜1Jšžœ4˜:Jšœ˜—šΠbnœžœžœ žœžœžœžœ žœ˜XJšœžœ˜)Kšœžœžœžœžœžœžœžœ˜@Kšœžœžœžœžœžœžœžœžœžœžœ˜KKšžœžœžœ˜KšœžœΟr œ˜!K˜Kšžœžœžœžœ˜9šžœ˜ KšœK˜K—Jšœ˜—š œžœžœ žœ˜+Jšœžœ˜)J˜šžœžœžœ˜/Jšœžœ(žœ˜Ašžœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜——šžœž˜šžœ˜Jšœ ˜ Jšœ3˜3Jšœ˜Jšœ˜——Jšœ˜—š‘œžœ˜"šœžœ˜&Jšœ ˜ Jšœ žœ˜Jšœ žœ˜Jšœ žœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜—Jšœžœžœžœ8˜Nš œžœ˜šœ˜Jšœ ˜ Jšœ˜Jšœ žœ˜%Jšœ žœ˜-Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜—Jšžœžœžœžœ˜+Jšœ=žœ˜GJšžœ ˜Jšœ˜—š œžœ˜!Jšœžœ˜+J˜#Jšœ˜šžœž˜Jšœžœ˜Jšœ žœn˜yJšžœžœ˜—Jšœ˜—Jšœžœ˜'Jšœžœ˜Jšœ žœ˜ Jšœžœ!˜+Jšœžœ&˜0Jšœžœ'˜2Jšœžœ žœ ˜Jšœžœ˜Jšœžœžœ˜Jšœ žœ˜Jšœ žœ˜Jšœžœžœžœ˜6Jšœžœ˜Jšœ žœ˜%Jšœžœ˜$Jšœžœ˜#Jšœ+˜+šžœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜—šœ žœžœ ˜,Jšžœ<˜>Jšœ žœ˜Jšžœ˜ —Jšžœžœžœ˜Jšœ)˜)Jšžœ˜Jšžœ.˜1šžœ$žœ ˜5Jšžœ@˜BJšžœ˜ —Jšžœ žœ žœ˜(J˜J˜2Jšœ žœ ˜Jšœ,˜,šžœ˜Jšœ ˜ JšœH˜HJšœ˜Jšœ˜Jšœ˜Jšœžœ!˜,—šžœ˜Jšœ ˜ Jšœ7˜7Jšœ˜Jšœ˜Jšœ˜—Jšžœ˜Jšœ˜J˜—š‘œžœžœ˜D˜šœžœ˜%Jš œžœ žœžœžœ;˜[—Jšœžœ˜—Jšœ&˜&Jšœ˜J˜—š ‘ œžœ!žœžœžœžœ˜z˜šœ+žœ˜0J˜B—J˜ J˜Jšœžœ˜ Jšœžœ˜—Jšœ˜J˜—Jš ‘ œžœžœžœ žœ˜IJšœ žœžœ ˜!šœ žœžœ˜Jšœžœžœ˜Jšœžœžœ žœ˜J˜J˜Jšœ žœ˜ J˜—Jšœžœžœžœ˜#JšœAžœ˜Xš žœžœžœžœžœžœž˜5šœ˜Kšœ=žœ-˜nJšœ2žœ žœ˜E—Jš žœžœžœžœžœ˜JJšžœžœžœ˜EJšžœžœ/˜PJšžœ˜ ——J˜š œ˜&JšœL™LJšœžœ ˜&Jšœžœ ˜(Jšœ žœžœ#˜3š žœžœžœžœžœžœž˜>šžœžœ˜J˜Jšžœžœžœ<˜YJšœ8˜8—Jšžœ7˜;J˜Jšžœ˜ ——J˜Jš ‘œžœžœžœ žœ˜EJšœžœžœ ˜šœ žœžœ˜Jšœžœžœ˜Jšœ˜Jšœ žœ˜Jšœ˜—J˜š‘œž˜Kšœžœžœžœžœžœžœžœ˜jKšžœ˜šœ žœ ˜Jšœžœžœžœžœžœžœžœ˜6J˜Jšœ˜Jšœžœ˜—šœ˜Kšœ+žœ˜?Jšœ*žœ žœ˜=—Jšœ˜Jšžœ žœ2˜E—J˜š  œ˜"JšœL™LJšœžœ ˜&Jšœ žœ ˜ Jšœ˜Jšžœ žœ4˜GJšžœ5˜9Jšžœžœžœ<˜U—š‘ œžœ!žœžœ˜Q˜šœ+žœ˜1Jšœžœ žœžœ˜QJ˜Jšœ(˜(—Jšœžœ˜——J˜š‘œžœ˜Jš œ%žœžœ žœžœžœ˜vJšœ žœ"˜2Jš œžœžœ žœžœ˜AJš œžœžœ žœžœ ˜I˜&šœ˜Jšœ/˜/Jš œžœžœžœžœ˜AJšœžœ˜J˜Jšœ žœ˜—Jšœžœ˜—˜Jšœ=žœ˜RJšœ0žœ žœ˜E—Jšžœ ˜J˜—š œ˜'JšœL™LJšœžœ ˜"šžœ ž˜Jšœ&žœ˜+Jšœ žœ˜Jšœ(žœ"žœ˜TJšžœžœ˜——J˜šœD˜DJ˜—Jšžœ˜J˜J˜J˜——…—6tIδ