DIRECTORY Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse], Convert USING [IntFromRope, RopeFromTime], IO USING [int, card, PutF, PutChar, rope, STREAM, Close, EndOfStream], File USING [wordsPerPage], FS USING [Error, StreamOpen, Read, Write], BasicTime USING [TimeNotKnown], Jukebox USING [CloseJukebox, CloseTune, Error, FindJukebox, Handle, Info, OpenJukebox, OpenTune, Tune, TuneSize, instances, EnergyRange, RunArray, RunArrayRange, MissingChirp, bytesPerChirp, singlePktLength, hangoverPackets, ArchiveCloseTune, WindowOrigin, RunComponent, pagesPerChirp, FindChirp], Rope USING [Equal, ROPE], TuneAccess USING [NextTuneNumber, WriteAmbientLevel, GetCreateDate, GetWriteDate, GetReadDate, ReadAmbientLevel, ReadRunArray, InterpretRunArrayElement], TuneArchive USING [TuneInformation, ArchiveTune, PrintArchiveInfo, ReadArchiveHeader, RestoreTune], VM USING [Interval, Allocate, Free, AddressForPageNumber]; TuneCommandsImpl: CEDAR PROGRAM IMPORTS Commander, CommandTool, Convert, IO, FS, BasicTime, Jukebox, Rope, TuneAccess, TuneArchive, VM = BEGIN ListTunes: Commander.CommandProc = { weOpened: BOOL _ FALSE; jukebox: Jukebox.Handle _ NIL; { ENABLE Jukebox.Error => { msg _ rope; GOTO Quit }; highest: INT_-1; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => { msg _ errorMsg; GOTO Quit}]; IF argv.argc > 3 THEN RETURN[$Failure, "Usage: ListTunes [jukeboxname|*_allOpenJukeboxes [upToTuneNumber]]"]; IF argv.argc = 3 THEN highest _ Convert.IntFromRope[argv[2]]; IF argv.argc = 1 OR argv[1].Equal["*"] THEN { FOR list: LIST OF Jukebox.Handle _ Jukebox.instances, list.rest WHILE list # NIL DO PrintData[list.first, cmd.out, highest]; ENDLOOP; IF Jukebox.instances = NIL THEN cmd.out.PutF["No jukeboxes currently open\n"]; RETURN }; TRUSTED { jukebox _ Jukebox.FindJukebox[argv[1]]; IF jukebox = NIL THEN { jukebox _ Jukebox.OpenJukebox[argv[1]]; weOpened _ TRUE; } }; PrintData[jukebox, cmd.out, highest]; IF weOpened THEN TRUSTED {jukebox _ Jukebox.CloseJukebox[jukebox]}; EXITS Quit => { IF weOpened AND jukebox # NIL THEN TRUSTED {jukebox _ Jukebox.CloseJukebox[jukebox]}; RETURN[$Failure, msg] } }}; PrintData: PROC [jukebox: Jukebox.Handle, out: IO.STREAM, highest: INT_-1] = { name: Rope.ROPE; nPages: INT; nTunes: INT; tuneHWM: INT; totalChirpsUsed: INT _ 0; totalTunes: INT _ 0; tune: Jukebox.Tune; tuneSize: INT; currentTuneID: INT _ -1; searchAllOfBox: BOOLEAN _ FALSE; TRUSTED {[name: name, nPages: nPages, nTunes: nTunes, tuneHWM: tuneHWM] _ Jukebox.Info[jukebox]}; out.PutF["Jukebox %g:\n Capacity %d chirps and %d tunes\n Tune usage High Water Mark %d\n", IO.rope[name], IO.int[nPages/Jukebox.pagesPerChirp], IO.int[nTunes], IO.int[tuneHWM]]; IF highest=-1 THEN {highest _ nTunes; searchAllOfBox _ TRUE}; DO ENABLE ABORTED => EXIT; currentTuneID _ TuneAccess.NextTuneNumber[jukebox, currentTuneID]; IF currentTuneID = -1 OR currentTuneID > highest THEN EXIT; TRUSTED {tune _ Jukebox.OpenTune[self: jukebox, tuneId: currentTuneID, write: FALSE ! Jukebox.Error => { IF reason # BadTune THEN REJECT ELSE LOOP; }]}; totalTunes _ totalTunes + 1; TRUSTED {tuneSize _ Jukebox.TuneSize[tune]}; totalChirpsUsed _ totalChirpsUsed + tuneSize; out.PutF[" Tune %6d, %6d chirps\n", IO.int[currentTuneID], IO.int[tuneSize]]; TRUSTED {Jukebox.ArchiveCloseTune[jukebox, tune]}; ENDLOOP; IF searchAllOfBox THEN out.PutF[" Total usage: %d chirps in %d tunes\n", IO.int[totalChirpsUsed], IO.int[totalTunes]] ELSE out.PutF["Usage up to tune %d: %d chirps in %d tunes\n", IO.int[highest], IO.int[totalChirpsUsed], IO.int[totalTunes]] }; PrintTune: Commander.CommandProc = { weOpened: BOOL _ FALSE; jukebox: Jukebox.Handle _ NIL; tune: Jukebox.Tune _ NIL; fixIt: BOOL _ cmd.procData.clientData = $FixTune; {{ ENABLE Jukebox.Error => { msg _ rope; GOTO Quit; }; argv: CommandTool.ArgumentVector; tuneID: INT; tuneSize: INT; runArray: REF Jukebox.RunArray; runLength: INT; totalSamples: INT; fixThisChirp: BOOL; currElement: Jukebox.RunArrayRange; silence: BOOLEAN; skipNextElement: BOOLEAN; runEnergy: Jukebox.EnergyRange; packetsSinceNonSilence: INT _ Jukebox.hangoverPackets; ambientLevel: Jukebox.EnergyRange; lastElement, thisElement: {silent, singlePkt, otherSound}; currTypeLength: INT; SetLooks: PROC [packetsInSample: INT, sampleEnergy: Jukebox.EnergyRange, ambientLevel: Jukebox.EnergyRange, setLooksOnlyOnChange: BOOLEAN] = { IF sampleEnergy>ambientLevel THEN {IF packetsSinceNonSilence > 0 OR ~setLooksOnlyOnChange THEN {packetsSinceNonSilence _ 0; cmd.out.PutF["%L", IO.rope[" "]]}} ELSE IF packetsSinceNonSilence = 0 OR ~setLooksOnlyOnChange THEN {packetsSinceNonSilence _ packetsSinceNonSilence + packetsInSample; cmd.out.PutF["%L", IO.rope[IF packetsSinceNonSilence>Jukebox.hangoverPackets THEN "bI" ELSE "Bi"]] } ELSE { notAlreadyBold: BOOLEAN _ packetsSinceNonSilence<=Jukebox.hangoverPackets; packetsSinceNonSilence _ packetsSinceNonSilence + packetsInSample; IF notAlreadyBold AND packetsSinceNonSilence>Jukebox.hangoverPackets THEN cmd.out.PutF["%L", IO.rope["bI"]] } }; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GOTO Quit}]; IF argv.argc # 3 THEN { msg _ IF fixIt THEN "Usage: FixTune jukeboxName|# tuneNumber" ELSE "Usage: PrintTune jukeboxName|# tuneNumber"; GOTO Quit; }; IF argv[1].Equal["#"] THEN { IF Jukebox.instances=NIL THEN { msg _ "No jukebox open"; GOTO Quit}; jukebox _ Jukebox.instances.first; } ELSE TRUSTED {jukebox _ Jukebox.FindJukebox[argv[1]]}; IF jukebox = NIL THEN TRUSTED { jukebox _ Jukebox.OpenJukebox[argv[1]]; weOpened _ TRUE }; tuneID _ Convert.IntFromRope[argv[2]]; TRUSTED { tune _ Jukebox.OpenTune[self: jukebox, tuneId: tuneID, write: fixIt]; tuneSize _ Jukebox.TuneSize[tune]; }; cmd.out.PutF["Tune %d from jukebox \"%g\": %d chirps\n", IO.int[tuneID], IO.rope[jukebox.jukeboxName], IO.int[tuneSize]]; cmd.out.PutF["Created: %g\n", IO.rope[Convert.RopeFromTime[TuneAccess.GetCreateDate[tune]]]]; cmd.out.PutF["Last written: %g\n", IO.rope[Convert.RopeFromTime[TuneAccess.GetWriteDate[tune]]]]; cmd.out.PutF["Last read: %g\n", IO.rope[Convert.RopeFromTime[TuneAccess.GetReadDate[tune]]]]; FOR chirp: INT IN [0..tuneSize) DO ENABLE { Jukebox.MissingChirp => { SetLooks[Jukebox.bytesPerChirp/Jukebox.singlePktLength, 0, 1, TRUE]; -- these numbers assert "this is silence for one chirp" cmd.out.PutF["\n******Chirp %d missing\n", IO.int[chirp]]; CONTINUE }; }; ambientLevel _ TuneAccess.ReadAmbientLevel[jukebox, tune, chirp]; cmd.out.PutF["\n******Chirp %d: ambient noise %d", IO.int[chirp], IO.int[ambientLevel]]; runArray _ TuneAccess.ReadRunArray[jukebox, tune, chirp]; currElement _ 0; totalSamples _ 0; fixThisChirp _ FALSE; currTypeLength _ 0; -- therefore no need to preset lastElement FOR ri: NAT IN Jukebox.RunArrayRange DO [length: runLength, energy: runEnergy, skipNextArrayElement: skipNextElement, silence: silence] _ TuneAccess.InterpretRunArrayElement[runArray, currElement]; lastElement _ thisElement; thisElement _ IF silence THEN silent ELSE (IF skipNextElement THEN otherSound ELSE singlePkt); IF lastElement # thisElement THEN currTypeLength _ 0; SELECT thisElement FROM silent => { cmd.out.PutF["%L", IO.rope["bI"]]; IF currTypeLength = 0 THEN cmd.out.PutF["\nSilence periods - lengths:"]; IF currTypeLength MOD 8 = 0 THEN cmd.out.PutF["\n "]; cmd.out.PutF["%8d", IO.card[runLength]]; SetLooks[runLength/Jukebox.singlePktLength, 0, 1, FALSE] }; singlePkt => { SetLooks[1, runEnergy, ambientLevel, TRUE]; IF currTypeLength = 0 THEN cmd.out.PutF["\n20ms packets - energies:"]; IF currTypeLength MOD 8 = 0 THEN cmd.out.PutF["\n "]; cmd.out.PutF["%8d", IO.card[runEnergy]]; }; otherSound => { SetLooks[(runLength+Jukebox.singlePktLength/2)/Jukebox.singlePktLength, runEnergy, ambientLevel, TRUE]; IF currTypeLength = 0 THEN cmd.out.PutF["\nNon-standard length packets:"]; cmd.out.PutF["\n Length %6d, energy %7d", IO.card[runLength], IO.card[runEnergy]]; } ENDCASE; totalSamples _ totalSamples + runLength; IF totalSamples = Jukebox.bytesPerChirp THEN EXIT; IF totalSamples > Jukebox.bytesPerChirp THEN GOTO badChirp; currTypeLength _ currTypeLength + 1; currElement _ currElement + (IF skipNextElement THEN 2 ELSE 1) REPEAT badChirp => { fixThisChirp _ TRUE; cmd.out.PutF[IF fixIt THEN "\nBad chirp format/length; fixing . . . " ELSE "\n****** Bad chirp format - use FixTune?"] }; ENDLOOP; cmd.out.PutChar['\n]; IF fixIt AND fixThisChirp THEN TRUSTED { runArray: REF Jukebox.RunArray; runArrayFileWindow: Jukebox.WindowOrigin; runArrayVMWindow: VM.Interval; pointerToVMWindow: LONG POINTER; pageOffsetInChirp: INT = Jukebox.bytesPerChirp/(File.wordsPerPage*2); wordOffsetInPage: INT = (Jukebox.bytesPerChirp MOD (File.wordsPerPage*2))/2; runDataPages: INT = Jukebox.pagesPerChirp - pageOffsetInChirp; runArrayFileWindow _ Jukebox.FindChirp[self: jukebox, tune: tune, chirp: chirp, signalMissingChirp: TRUE, signalEOF: TRUE]; runArrayFileWindow.base _ runArrayFileWindow.base + pageOffsetInChirp; runArrayVMWindow _ VM.Allocate[count: runDataPages]; pointerToVMWindow _ LOOPHOLE[VM.AddressForPageNumber[runArrayVMWindow.page]]; runArray _ LOOPHOLE[pointerToVMWindow + wordOffsetInPage]; FS.Read[file: runArrayFileWindow.file, from: runArrayFileWindow.base, nPages: runDataPages, to: VM.AddressForPageNumber[runArrayVMWindow.page]]; SELECT runArray[currElement].elementType FROM silence => runArray[currElement] _ [silence[runLength - (totalSamples - Jukebox.bytesPerChirp)]]; soundEnergy => runArray[currElement+1] _ [soundLength[runLength - (totalSamples - Jukebox.bytesPerChirp)]]; singlePkt => -- since this is last valid entry in chirp, okay to trample 'nextElement' { runArray[currElement] _ [soundEnergy[NARROW[runArray[currElement], Jukebox.RunComponent[singlePkt]].energy]]; runArray[currElement+1] _ [soundLength[Jukebox.singlePktLength - (totalSamples - Jukebox.bytesPerChirp)]] }; soundLength => -- just replace with silence: this is a really unexpected error (unlikely we'd get here without an error in InterpretRunArrayElement) runArray[currElement] _ [silence[Jukebox.bytesPerChirp - totalSamples]]; ENDCASE; FS.Write[file: runArrayFileWindow.file, from: VM.AddressForPageNumber[runArrayVMWindow.page], nPages: runDataPages, to: runArrayFileWindow.base]; VM.Free[runArrayVMWindow] } ENDLOOP; SetLooks[1,1,0, FALSE]; -- this simply sets the type face of the window back to plain before exiting TRUSTED { IF fixIt THEN Jukebox.CloseTune[jukebox, tune] ELSE Jukebox.ArchiveCloseTune[jukebox, tune]; IF weOpened THEN jukebox _ Jukebox.CloseJukebox[jukebox] }; }; EXITS Quit => TRUSTED {IF tune # NIL THEN { IF fixIt THEN Jukebox.CloseTune[jukebox, tune] ELSE Jukebox.ArchiveCloseTune[jukebox, tune]}; IF weOpened AND jukebox # NIL THEN jukebox _ Jukebox.CloseJukebox[jukebox]; RETURN[$Failure, msg]; }; }; }; SetAmbient: Commander.CommandProc = { weOpened: BOOLEAN _ FALSE; jukebox: Jukebox.Handle; tune: Jukebox.Tune; tuneSize: INT; fromChirp: INT _ 0; -- values passed to WriteAmbientLevel by default toChirp: INT _ -1; { argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GOTO Quit}]; tuneID: INT; ambientLevel: Jukebox.EnergyRange; IF argv.argc # 4 AND argv.argc # 6 THEN { msg _ "Usage: SetAmbient jukeboxName|# tuneNumber energyValue [fromChirpNumber toChirpNumber]"; RETURN }; IF argv.argc = 6 THEN { fromChirp _ Convert.IntFromRope[argv[4]]; toChirp _ Convert.IntFromRope[argv[5]] }; IF argv[1].Equal["#"] THEN { IF Jukebox.instances=NIL THEN { cmd.out.PutF["No jukebox open\n"]; RETURN}; jukebox _ Jukebox.instances.first; } ELSE { TRUSTED {jukebox _ Jukebox.FindJukebox[argv[1]]}; IF jukebox = NIL THEN TRUSTED { jukebox _ Jukebox.OpenJukebox[argv[1] ! Jukebox.Error => {msg _ rope; GOTO Quit}]; weOpened _ TRUE } }; tuneID _ Convert.IntFromRope[argv[2]]; ambientLevel _ Convert.IntFromRope[argv[3]]; TRUSTED {tune _ Jukebox.OpenTune[self: jukebox, tuneId: tuneID, write: TRUE ! Jukebox.Error => {msg _ rope; GOTO Quit}]}; TRUSTED {tuneSize _ Jukebox.TuneSize[tune]}; IF tuneSize > 0 THEN TuneAccess.WriteAmbientLevel[jukebox: jukebox, tune: tune, ambientLevel: ambientLevel, fromChirp: fromChirp, toChirp: toChirp] ELSE cmd.out.PutF["Tune contains no chirps, so that its ambience is a trifle academic\n"]; TRUSTED {Jukebox.CloseTune[jukebox, tune]}; IF weOpened THEN TRUSTED {jukebox _ Jukebox.CloseJukebox[jukebox]} EXITS Quit => { IF weOpened THEN TRUSTED {jukebox _ Jukebox.CloseJukebox[jukebox]}; RETURN[$Failure, msg] } } }; ArchiveTune: Commander.CommandProc = { ENABLE {FS.Error => IF error.group = bug THEN REJECT ELSE {msg _ error.explanation; GOTO Quit}; Jukebox.Error => {msg _ rope; GOTO Quit}; BasicTime.TimeNotKnown => {msg _ "Unable to determine current time: aborting archive"; GOTO Quit} }; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GOTO Quit}]; tuneInformation: TuneArchive.TuneInformation; internalJukeboxName: Rope.ROPE; IF argv.argc # 4 THEN { cmd.out.PutF["Usage: ArchiveTune jukeboxName tuneNumber fileName\n"]; RETURN }; [tuneInformation, internalJukeboxName] _ TuneArchive.ArchiveTune[jukeboxName: argv[1], tuneID: Convert.IntFromRope[argv[2]], toFile: argv[3]]; TuneArchive.PrintArchiveInfo[out: cmd.out, archiveFileName: argv[3], tuneInformation: tuneInformation, archivedJukeboxName: internalJukeboxName] EXITS Quit => RETURN[$Failure, msg] }; TuneArchiveInfo: Commander.CommandProc = { stream: IO.STREAM _ NIL; {ENABLE {FS.Error => IF error.group = bug THEN REJECT ELSE {msg _ error.explanation; GOTO Quit}; IO.EndOfStream => {msg _ "Attempt to read past end of file - not an archive file?"; GOTO Quit}}; tuneInformation: TuneArchive.TuneInformation; archivedJukeboxName: Rope.ROPE; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GOTO Quit}]; IF argv.argc # 2 THEN { cmd.out.PutF["Usage: TuneArchiveInfo archiveFileName\n"]; RETURN }; stream _ FS.StreamOpen[argv[1]]; [tuneInformation, archivedJukeboxName] _ TuneArchive.ReadArchiveHeader[readableFileStream: stream]; TuneArchive.PrintArchiveInfo[out: cmd.out, archiveFileName: argv[1], tuneInformation: tuneInformation, archivedJukeboxName: archivedJukeboxName]; IO.Close[stream] EXITS Quit => { IF stream # NIL THEN IO.Close[stream]; RETURN[$Failure, msg] } }}; RestoreTune: Commander.CommandProc = { ENABLE {FS.Error => IF error.group = bug THEN REJECT ELSE {msg _ error.explanation; GOTO Quit}; IO.EndOfStream => {msg _ "Attempt to read past end of file - not an archive file?"; GOTO Quit}; Jukebox.Error => {msg _ rope; GOTO Quit} }; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd ! CommandTool.Failed => {msg _ errorMsg; GOTO Quit}]; tuneIDused: INT; restoredJukeboxName: Rope.ROPE; IF argv.argc > 4 OR argv.argc < 2 THEN { cmd.out.PutF["Usage: RestoreTune fileName [tuneNumber_numberOriginallyArchived [jukeboxName[jukeboxOriginallyArchived]]\n"]; RETURN }; [tuneIDused, restoredJukeboxName] _ TuneArchive.RestoreTune[fromFile: argv[1], jukeboxName: IF argv.argc = 4 THEN argv[3] ELSE NIL, tuneID: IF argv.argc # 2 THEN Convert.IntFromRope[argv[2]] ELSE -1]; cmd.out.PutF["Restored as tune %d in jukebox %g\n", IO.int[tuneIDused], IO.rope[restoredJukeboxName]] EXITS Quit => RETURN[$Failure, msg] }; Commander.Register[key: "ListTunes", proc: ListTunes, doc: "ListTunes [jukeboxName|*_allOpenJukeboxes [upToTuneNumber]] - print information about tunes in a Jukebox: * means allOpenJukeboxes"]; Commander.Register[key: "PrintTune", proc: PrintTune, doc: "PrintTune jukeboxName|# tuneNumber - print tune information: # represents the first currently open jukebox"]; Commander.Register[key: "FixTune", proc: PrintTune, doc: "FixTune jukeboxName|# tuneNumber - print and fix up a tune: # represents the first currently open jukebox", clientData: $FixTune]; Commander.Register[key: "SetAmbient", proc: SetAmbient, doc: "SetAmbient jukeboxname|# tuneNumber energyValue [fromChirpNumber toChirpNumber] - set ambient energy level in tune: # signifies first open jukebox; if given, fromChirpNumber and toChirpNumber are passed exactly as given to TuneAccess.WriteAmbientLevel, q.v."]; Commander.Register[key: "ArchiveTune", proc: ArchiveTune, doc: "ArchiveTune jukeboxName tuneNumber fileName - archive a tune from a jukebox as an FS file"]; Commander.Register[key: "TuneArchiveInfo", proc: TuneArchiveInfo, doc: "TuneArchiveInfo archiveFileName - list details of the tune archived into a file and of the file"]; Commander.Register[key: "RestoreTune", proc: RestoreTune, doc: "RestoreTune fileName [tuneNumber_numberOriginallyArchived [jukeboxName[jukeboxOriginallyArchived]] - restore a tune archive file back into a jukebox"]; END. RFile: TunecommandsImpl.mesa commands to operate on tunes within a jukebox, plus one to list the tunes in a given jukebox(es) Ades, March 6, 1986 3:54:32 pm PST we use ArchiveCloseTune so that the read/write dates will not be altered by this command this procedure merely makes the output of this command easier to scan: silent periods are bold, hangover periods are italicised and sound periods are in plain script. this procedure is designed to mask how a chirp is constituted. We want to print out how it is constituted: however to save code and make this whole command clearer, we will use this routine and then re-interpret its results from our knowledge of the runArray this is silence regardless of hangover time, so reset looks because we manually reset the looks above, assert setLooksOnlyOnChange = FALSE here although we have used TuneAccess to avoid low level code above, it does not support writing run arrays, so we need to pollute the following with unsafe constructs we have the number of the offending elemens in currElement, so we will read in the whole array again, correct it and wrtie it back. This is not very efficient, but makes the code a lot tidier than trying to use the run array as we have it above [i.e. contains all the unpleasantness in one area] these constants make it clearer whence to pick up the run array data shouldn't get errors on this call, since we've already accessed this chirp now correct the run array, using the variables we set up above we use ArchiveCloseTune when just priniting the tune, so that the read/write dates will not be altered by this command Κΐ˜šœ™J™`Icode™"—J™šΟk ˜ Jšœ œ˜(Jšœ œ!˜2Jšœœ˜*Jšœœ"œ˜FJšœœ˜Jšœœ"˜*Jšœ œ˜Jšœœœ˜©Jšœœ œ˜Jšœ œ‰˜™Jšœ œR˜cJšœœ2˜:J˜—Jšœœ˜Jšœ"œœ5œ˜hJš˜J˜šΟb œ˜$Jšœ œœ˜Jšœœ˜J˜šœ˜J˜ Jšœ˜ J˜—Jšœ œ˜Jšœcœ˜oJšœœœQ˜mJšœœ(˜=šœœœ˜-š œœœ/œœ˜SJšœ(˜(Jšœ˜—Jšœœœ/˜NJš˜J˜—Jš˜˜)šœ œœ˜Jšœ'˜'Jšœ œ˜—J˜—J˜Jšœ%˜%Jšœ œœ+˜C—š˜Jšœ˜š œœ œ œœœ+˜XJšœ˜—J˜—J˜J˜š Οn œœ œœ œ˜NJšœ œ˜Jšœœ˜ Jšœœ˜ Jšœ œ˜ Jšœœ˜Jšœ œ˜J˜Jšœ œ˜Jšœœ˜Jšœœœ˜ J˜JšœZ˜aJš œ^œ œ$œœ˜΄Jšœ œ%œ˜=J˜š˜Jšœœœ˜JšœB˜BJšœœœœ˜<šœGœ˜hJšœœ˜Jšœœ˜ Jšœ˜—J˜Jšœ%˜,Jšœ-˜-Jšœ'œœ˜PJšœ,˜3JšœX™X—Jšœ˜J˜Jšœœ4œœœ:œœœ˜σ—J˜J˜šœ$˜$Jšœ œœ˜Jšœœ˜Jšœœ˜Jšœœ&˜1J˜šœ˜J˜ Jšœ˜ J˜—Jšœ!˜!Jšœœ˜ Jšœ œ˜Jšœ œ˜Jšœ œ˜Jšœœ˜Jšœœ˜J˜$Jšœ œ˜Jšœœ˜J˜Jšœœ˜6J˜"J˜:Jšœœ˜J˜J™¦šŸœœœ^œ˜ŽJšœ˜šœ˜šœœœ˜œΟc7˜|Jšœ+œ ˜:Jš˜J˜—J˜—JšœA˜AJšœ3œ œ˜XJšœ9˜9J˜J˜Jšœœ˜Jšœ *˜>J˜šœœœ˜'Jšœ˜J™‚J™J˜Jš œœ œœœœ œ ˜^Jšœœ˜5J™Jšœ ˜J˜ šœœ˜%Jšœ<™Jš˜J˜Jšœ ˜ šœœ˜Jšœ œœ,œ-˜wJ˜—Jšœ˜—J˜J˜J˜Jšœœœ˜&J™’Jšœ§™§šœ œ˜"Jšœ)˜)Jšœœ ˜Jšœœœ˜ J™J™DJšœœ0˜FJšœœœ˜MJšœœ-˜>J™J™KJšœdœ œ˜{JšœF˜FJ˜Jšœœ˜4Jšœœœ.˜MJšœ œ(˜;Jšœ^œ.˜J˜J™>Jšœ#˜-šœ!˜!Kšœ@˜@—Kšœl˜lšœ  I˜VKšœ˜Kšœ%œB˜mKšœi˜iKšœ˜—šœ lŸ ˜”KšœH˜H—Kšœ˜K˜šœ,œa˜‘Kšœ˜—K˜K˜—Jšœ˜—J˜Jšœœ L˜dJš˜šœœœ"œ)˜_Jšœv™vJšœ œ(˜8—Jšœ˜J˜Jš˜šœ˜Jš œœœœœœ"œ*˜sJšœ œ œœ)˜KJšœ˜Jšœ˜—J˜J˜—J˜šž œ˜%Jšœ œœ˜Jšœ˜Jšœ˜Jšœ œ˜Jšœ œ 0˜DJšœ œ˜J˜šœ˜Jšœcœ˜oJšœœ˜ J˜"—˜Jšœœœ˜(šœb˜bJš˜—J˜J˜Jšœœ˜šœ,˜,Jšœ&˜&—J˜J˜Jšœ˜Jšœ˜š œœœœ&œ˜NJšœ"˜"—Jšœ˜Jšœ˜šœœ*˜4Jšœ œœœ˜šœHœ˜TJšœ ˜—Jšœ˜—Jšœ˜Jšœ&˜&Jšœ,˜,—˜Jšœ@œ!œ ˜yJ˜Jšœ%˜,Jšœ ˜Jšœ˜ƒJšœV˜Z—˜Jšœ$˜+Jšœ œœ*˜B——˜Jš˜šœ˜šœœ œœ+˜GJšœœ˜—J˜—J˜—Jšœ˜J˜šž œ˜&Jš˜Jš œœ œœœœœ˜XJ˜Jšœœ˜)J˜JšœWœ˜aJ˜J˜Jšœcœ˜oJ˜Jšœ-˜-Jšœœ˜J˜šœœ˜šœH˜HJš˜—J˜J˜—JšœŽ˜Žšœ˜J˜——š˜Jšœœ˜—Jšœ˜J˜šžœ˜*Jšœœœœ˜šœ˜Jš œœ œœœœœ˜XJšœQ˜SJšœ˜ —J˜Jšœ-˜-Jšœœ˜ Jšœcœ˜ošœœ˜šœ<˜