DIRECTORY BcdOps USING [MTHandle], BootFile USING [ Entry, Header, maxEntriesPerHeader, maxEntriesPerTrailer, Trailer, currentVersion], Environment USING [bytesPerPage, wordsPerPage], Inline USING [HighHalf, LongMult, LowHalf], LongString USING [AppendString], MB USING [BHandle, DoAllModules, DumpSegs, Handle, StartControlLink, Zero], MBOut USING [CR, FileName, NumberFormat, Char, Line, LongNumber, Number, Spaces, Text], MBStorage USING [Pages, FreePages], MBTTY USING [Handle, PutLine, PutString], MBVM USING [ Base, CodeSeg, CopyRead, CopyWrite, DataSeg, FileSeg, GetPage, ReleaseCodeSegs, Seg, SortSegs, Write], PageMap USING [Flags, flagsClean, flagsWriteProtected, Value], PrincOps USING [GlobalFrame], Segments USING [ FHandle, GetFileLength, NewFile, Read, ReleaseFile, SegmentAddress, SetFileLength, SetFileTimes, SHandle, SwapIn, Unlock, Write], StartList USING [Base, Entry, Index, StartIndex, SwapUnitIndex, SwapUnitInfo], Streams USING [ CreateStream, Destroy, Handle, GetBlock, GetIndex, GetLength, PutBlock, PutWord, Read, SetIndex, Write], Time USING [Packed]; MBOutput: PROGRAM IMPORTS Inline, MB, MBOut, MBStorage, MBTTY, MBVM, Segments, Streams, String: LongString EXPORTS MB = BEGIN OPEN MBVM; wordsPerPage: CARDINAL = Environment.wordsPerPage; bytesPerPage: CARDINAL = Environment.bytesPerPage; data: MB.Handle _ NIL; header: LONG POINTER TO BootFile.Header _ NIL; trailer: LONG POINTER TO BootFile.Trailer _ NIL; nEntries, currentEntry: CARDINAL; filePage: MBVM.Base; trailerIndex: LONG CARDINAL; EtherHeader: TYPE = MACHINE DEPENDENT RECORD [ version(0): CARDINAL _ 1, mustBeZero(1): LONG CARDINAL _ 0, createTime(3): BCPLTime ]; BCPLTime: TYPE = MACHINE DEPENDENT RECORD [high, low: CARDINAL]; InitOutput: PUBLIC PROC [h: MB.Handle] = {data _ h}; FinishOutput: PUBLIC PROC = { IF header # NIL THEN {MBStorage.FreePages[header]; header _ NIL}; IF trailer # NIL THEN {MBStorage.FreePages[trailer]; trailer _ NIL}; IF data.bootStream # NIL THEN { Streams.SetIndex[data.bootStream, Streams.GetLength[data.bootStream]]; Streams.Destroy[data.bootStream]; data.bootStream _ NIL; }; MBVM.ReleaseCodeSegs[]; data _ NIL; }; WriteBootFile: PUBLIC PROC = { tty: MBTTY.Handle = data.ttyHandle; segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg _ MBVM.SortSegs[]; MBTTY.PutString[tty, "Writing boot file..."L]; InitializeBootFile[]; WriteVM[data.bootStream, segs ! UNWIND => MBStorage.FreePages[BASE[segs]]]; MBStorage.FreePages[BASE[segs]]; FinalizeBootFile[]; MBTTY.PutLine[tty, "finished writing."L]; IF data.etherFormat THEN MakeEtherFile[]; }; InitializeBootFile: PROC = { name: STRING _ [40]; bootFile: Segments.FHandle; String.AppendString[name, data.output]; bootFile _ Segments.NewFile[name, Segments.Write]; Segments.SetFileLength[bootFile, Inline.LongMult[data.nFilePages, bytesPerPage] ! UNWIND => Segments.ReleaseFile[bootFile] ]; data.bootStream _ Streams.CreateStream[bootFile, Streams.Write]; Segments.SetFileTimes[file: bootFile, create: data.buildTime]; Streams.SetIndex[data.bootStream, bytesPerPage]; -- skip over header page data.bootHeader _ header _ MBStorage.Pages[1]; MB.Zero[header, wordsPerPage]; header^ _ BootFile.Header[ creationDate: data.buildTime, pStartListHeader: data.header.table, inLoadMode: load, continuation: [vp: initial[mdsi: [data.mdsBase/256], destination: MB.StartControlLink[]]], countData: data.nBootPages, entries: ]; trailer _ NIL; nEntries _ BootFile.maxEntriesPerHeader; currentEntry _ 0; filePage _ 2; }; FinalizeBootFile: PROC = { length: LONG CARDINAL = Streams.GetIndex[data.bootStream]; Streams.SetIndex[data.bootStream, 0]; [] _ Streams.PutBlock[data.bootStream, header, wordsPerPage]; Streams.SetIndex[data.bootStream, length]; Streams.Destroy[data.bootStream]; data.bootStream _ NIL; }; WriteVM: PROC [stream: Streams.Handle, segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg] = { OPEN MBOut; tty: MBTTY.Handle = data.ttyHandle; i: CARDINAL; seg: MBVM.Seg; scriptBase: StartList.Base = data.scriptBase; index: StartList.Index _ StartList.StartIndex; CR[]; CR[]; Line["BOOT FILE MAP"L]; CR[]; Line[" Bootloaded Memory"L]; Line[" File VM Map Type"L]; Line[" Page Address Flags"L]; Number[1, [8,FALSE,FALSE,6]]; -- header page Line[" Header Page"L]; MBTTY.PutString[tty, "bootloaded memory..."L]; FOR i IN [0..LENGTH[segs]) DO seg _ segs[i]; IF ~seg.bootLoaded THEN LOOP; WITH s: seg SELECT FROM data => WriteDataSeg[stream, @s]; code => WriteCodeSeg[stream, @s]; file => WriteFileSeg[stream, @s]; ENDCASE; ENDLOOP; IF trailer # NIL THEN [] _ WriteTrailerPage[stream]; CR[]; Line[" Nonresident Memory"L]; Line[" File VM Pages Type Source[base,pages]"L]; Line[" Page Address"L]; MBTTY.PutString[tty, "nonresident memory..."L]; FOR i IN [0..LENGTH[segs]) DO info: StartList.SwapUnitInfo; seg _ segs[i]; info _ scriptBase[seg.index].info; WITH s: seg SELECT FROM data => IF info.state # resident THEN AppendDataSeg[stream, @s] ELSE data.nResidentPages _ data.nResidentPages + 1; code => AppendCodeSeg[stream, @s]; file => IF info.state # resident THEN AppendFileSeg[stream, @s] ELSE data.nResidentPages _ data.nResidentPages + 1; ENDCASE; ENDLOOP; }; WriteDataSeg: PROC [stream: Streams.Handle, seg: MBVM.DataSeg] = { lp: LONG POINTER; v: PageMap.Value _ MapValueForSeg[seg]; FOR page: CARDINAL IN [seg.base..seg.base+seg.pages) DO IF page = 376B THEN LOOP; EnterPage[page: page, value: v, stream: stream]; data.nBootLoadedPages _ data.nBootLoadedPages + 1; BootPageToLoadmap[filePage: filePage, vmPage: page, flags: v.flags, type: "data"L]; lp _ MBVM.GetPage[page]; IF lp = NIL THEN WriteEmptyPage[stream] ELSE WritePage[stream, lp]; ENDLOOP; }; WriteCodeSeg: PROC [stream: Streams.Handle, seg: MBVM.CodeSeg] = { page: CARDINAL; nUnits: CARDINAL _ IF seg.sph = NIL THEN 1 ELSE seg.sph.length; index: StartList.SwapUnitIndex _ seg.index; v: PageMap.Value _ MapValueForSeg[seg]; scriptBase: StartList.Base = data.scriptBase; lp: LONG POINTER; su: POINTER TO swapUnit StartList.Entry; lp _ OpenSegForTransfer[seg.segment]; page _ seg.base; FOR i: CARDINAL IN [0..nUnits) DO su _ @scriptBase[index]; FOR j: CARDINAL IN [0..su.pages) DO IF scriptBase[su.parent].bootLoaded THEN { EnterPage[page: page, value: v, stream: stream]; data.nBootLoadedPages _ data.nBootLoadedPages + 1; BootPageToLoadmap[filePage: filePage, vmPage: page, flags: v.flags, type: "code"L]; WritePage[stream, lp]}; lp _ lp + wordsPerPage; page _ page + 1; ENDLOOP; index _ index + SIZE[swapUnit StartList.Entry]; ENDLOOP; CloseSegAfterTransfer[seg.segment]; }; WriteFileSeg: PROC [stream: Streams.Handle, seg: MBVM.FileSeg] = { v: PageMap.Value _ MapValueForSeg[seg]; lp: LONG POINTER _ OpenSegForTransfer[seg.segment]; FOR page: CARDINAL IN [seg.base..seg.base+seg.pages) DO EnterPage[page: page, value: v, stream: stream]; data.nBootLoadedPages _ data.nBootLoadedPages + 1; BootPageToLoadmap[filePage: filePage, vmPage: page, flags: v.flags, type: "file"L]; WritePage[stream, lp]; lp _ lp + wordsPerPage; ENDLOOP; CloseSegAfterTransfer[seg.segment]; }; AppendDataSeg: PROC [stream: Streams.Handle, seg: MBVM.DataSeg] = { lp: LONG POINTER; SegToLoadmap[seg, filePage, seg.pages]; FOR page: CARDINAL IN [seg.base..seg.base+seg.pages) DO lp _ MBVM.GetPage[page]; IF lp = NIL THEN WriteEmptyPage[stream] ELSE WritePage[stream, lp]; ENDLOOP; }; AppendCodeSeg: PROC [stream: Streams.Handle, seg: MBVM.CodeSeg] = { lp: LONG POINTER; nUnits: CARDINAL = (IF seg.sph = NIL THEN 1 ELSE seg.sph.length); index: StartList.SwapUnitIndex; scriptBase: StartList.Base = data.scriptBase; su: POINTER TO swapUnit StartList.Entry; pagesToWrite: CARDINAL _ 0; first: BOOL _ TRUE; index _ seg.index; FOR i: CARDINAL IN [0..nUnits) DO su _ @scriptBase[index]; IF su.info.state ~= resident THEN pagesToWrite _ pagesToWrite + su.pages; index _ index + SIZE[swapUnit StartList.Entry]; ENDLOOP; IF pagesToWrite = 0 THEN RETURN; lp _ OpenSegForTransfer[seg.segment]; index _ seg.index; SegToLoadmap[seg, filePage, pagesToWrite]; FOR i: CARDINAL IN [0..nUnits) DO su _ @scriptBase[index]; IF data.debug AND su.info.state # resident THEN { IF first THEN {MBOut.Spaces[26]; MBOut.Text["SwapUnits["L]; first _ FALSE} ELSE MBOut.Text[", "L]; MBOut.Number[index, [8,FALSE,FALSE,1]]}; FOR j: CARDINAL IN [0..su.pages) DO IF su.info.state # resident THEN WritePage[stream, lp] ELSE data.nResidentPages _ data.nResidentPages + 1; lp _ lp + wordsPerPage; ENDLOOP; index _ index + SIZE[swapUnit StartList.Entry]; ENDLOOP; IF --data.debug AND-- ~first THEN {MBOut.Char[']]; MBOut.CR[]}; CloseSegAfterTransfer[seg.segment]; }; AppendFileSeg: PROC [stream: Streams.Handle, seg: MBVM.FileSeg] = { lp: LONG POINTER; SegToLoadmap[seg, filePage, seg.pages]; IF data.debug THEN { index: StartList.SwapUnitIndex _ seg.index; MBOut.Spaces[26]; MBOut.Text["SwapUnits["L]; FOR i: CARDINAL IN [0..seg.nUnits) DO MBOut.Number[index, [8,FALSE,FALSE,1]]; IF i ~= seg.nUnits - 1 THEN MBOut.Text[", "L]; index _ index + SIZE[swapUnit StartList.Entry]; ENDLOOP; MBOut.Char[']]; MBOut.CR[]}; lp _ OpenSegForTransfer[seg.segment]; FOR i: CARDINAL IN [0..seg.pages) DO WritePage[stream, lp]; lp _ lp + wordsPerPage; ENDLOOP; CloseSegAfterTransfer[seg.segment]; }; GermMDS: CARDINAL = 37000B; BootXferLocation: POINTER = LOOPHOLE[1376B]; GermPageCountLocation: POINTER = LOOPHOLE[1377B]; WriteGermFile: PUBLIC PROC = { tty: MBTTY.Handle = data.ttyHandle; segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg _ MBVM.SortSegs[]; IF data.debug THEN MB.DumpSegs[segs, "WRITING GERM"L]; MBTTY.PutString[tty, "Writing germ file..."L]; InitializeGermFile[]; data.nFilePages _ data.nResidentPages _ data.nBootLoadedPages _ WriteGerm[data.bootStream, segs ! UNWIND => MBStorage.FreePages[BASE[segs]]]; MBStorage.FreePages[BASE[segs]]; FinalizeGermFile[]; MBTTY.PutLine[tty, "finished writing."L]; IF data.etherFormat THEN MakeEtherFile[]; }; InitializeGermFile: PROC = { name: STRING _ [40]; bootFile: Segments.FHandle; String.AppendString[name, data.output]; bootFile _ Segments.NewFile[name, Segments.Write]; data.bootStream _ Streams.CreateStream[bootFile, Streams.Write]; Segments.SetFileTimes[file: bootFile, create: data.buildTime]; filePage _ 1; }; FinalizeGermFile: PROC = { Streams.Destroy[data.bootStream]; data.bootStream _ NIL; }; WriteGerm: PROC [stream: Streams.Handle, segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg] RETURNS [germPages: CARDINAL] = { OPEN MBOut; relocationPages: CARDINAL; [germPages, relocationPages] _ RelocateGerm[segs]; CR[]; CR[]; Line["GERM FILE MAP"L]; CR[]; Line[" File VM Map Type"L]; Line[" Page Address Flags"L]; FOR i: CARDINAL IN [0..LENGTH[segs]) DO WITH s: segs[i] SELECT FROM data => WriteGermData[stream, @s, relocationPages]; code => WriteGermCode[stream, @s, relocationPages]; file => ERROR; ENDCASE; ENDLOOP; }; RelocateGerm: PROC [segs: LONG DESCRIPTOR FOR ARRAY OF MBVM.Seg] RETURNS [germPages: CARDINAL, relocationPages: CARDINAL] = { codeRelocation: LONG CARDINAL = Inline.LongMult[(relocationPages _ GermMDS - data.mdsBase), wordsPerPage]; RelocateOneModule: PROC [loadee: MB.BHandle, mth: BcdOps.MTHandle] RETURNS [BOOL] = { gf: PrincOps.GlobalFrame; MBVM.CopyRead[from: loadee.mt[mth.gfi].frame, to: @gf, nwords: SIZE[PrincOps.GlobalFrame]]; gf.code.longbase _ gf.code.longbase + codeRelocation; MBVM.CopyWrite[to: loadee.mt[mth.gfi].frame, from: @gf, nwords: SIZE[PrincOps.GlobalFrame]]; RETURN[FALSE] }; [] _ MB.DoAllModules[RelocateOneModule]; germPages _ 0; FOR i: CARDINAL IN [0..LENGTH[segs]) DO germPages _ germPages + segs[i].pages; ENDLOOP; MBVM.Write[p: BootXferLocation, v: MB.StartControlLink[]]; MBVM.Write[p: GermPageCountLocation, v: germPages]; }; WriteGermData: PROC [stream: Streams.Handle, seg: MBVM.DataSeg, relocationPages: CARDINAL] = { lp: LONG POINTER; v: PageMap.Value _ MapValueForSeg[seg]; FOR page: CARDINAL IN [seg.base..seg.base+seg.pages) DO BootPageToLoadmap[ filePage: filePage, vmPage: page+relocationPages, flags: v.flags, type: "data"L]; lp _ MBVM.GetPage[page]; IF lp = NIL THEN WriteEmptyPage[stream] ELSE WritePage[stream, lp]; ENDLOOP; }; WriteGermCode: PROC [stream: Streams.Handle, seg: MBVM.CodeSeg, relocationPages: CARDINAL] = { v: PageMap.Value _ MapValueForSeg[seg]; lp: LONG POINTER _ OpenSegForTransfer[seg.segment]; SegmentSourceToLoadmap[seg]; MBOut.Char[':]; MBOut.CR[]; FOR page: CARDINAL IN [seg.base..seg.base+seg.pages) DO BootPageToLoadmap[ filePage: filePage, vmPage: page+relocationPages, flags: v.flags, type: "code"L]; WritePage[stream, lp]; lp _ lp + wordsPerPage; ENDLOOP; CloseSegAfterTransfer[seg.segment]; }; MapValueForSeg: PROC [seg: MBVM.Seg] RETURNS [PageMap.Value] = { flags: PageMap.Flags _ IF ~seg.info.readOnly THEN PageMap.flagsClean ELSE PageMap.flagsWriteProtected; RETURN[PageMap.Value[logSingleError: FALSE, flags: flags, realPage: 0]] }; OpenSegForTransfer: PROC [seg: Segments.SHandle] RETURNS [lp: LONG POINTER] = { Segments.SwapIn[seg]; lp _ Segments.SegmentAddress[seg]; }; CloseSegAfterTransfer: PROC [seg: Segments.SHandle] = INLINE {Segments.Unlock[seg]}; EnterPage: PROC [page: MBVM.Base, value: PageMap.Value, stream: Streams.Handle] = { entries: LONG POINTER TO ARRAY [0..0) OF BootFile.Entry; IF currentEntry = nEntries THEN AddTrailerPage[stream]; entries _ IF nEntries = BootFile.maxEntriesPerTrailer THEN @trailer.entries ELSE @header.entries; entries[currentEntry] _ [page: page, value: value]; currentEntry _ currentEntry + 1; }; AddTrailerPage: PROC [stream: Streams.Handle] = { IF trailer # NIL THEN trailerIndex _ WriteTrailerPage[stream] ELSE { trailer _ MBStorage.Pages[1]; trailerIndex _ Streams.GetIndex[stream]; }; Streams.SetIndex[stream, trailerIndex+bytesPerPage]; MB.Zero[trailer, wordsPerPage]; trailer.version _ BootFile.currentVersion; nEntries _ BootFile.maxEntriesPerTrailer; currentEntry _ 0; MBOut.Number[filePage, [8,FALSE,FALSE,6]]; MBOut.Line[" Trailer Page"L]; filePage _ filePage + 1; }; WriteTrailerPage: PROC [stream: Streams.Handle] RETURNS [index: LONG CARDINAL] = { index _ Streams.GetIndex[stream]; Streams.SetIndex[stream, trailerIndex]; [] _ Streams.PutBlock[stream, trailer, wordsPerPage]; Streams.SetIndex[stream, index]; }; WritePage: PROC [s: Streams.Handle, p: LONG POINTER] = { filePage _ filePage + 1; IF Streams.PutBlock[s, p, wordsPerPage] # wordsPerPage THEN ERROR; }; WriteEmptyPage: PROC [s: Streams.Handle] = { filePage _ filePage + 1; THROUGH [0..wordsPerPage) DO Streams.PutWord[s, 0] ENDLOOP; }; BootPageToLoadmap: PROC [filePage, vmPage: MBVM.Base, flags: PageMap.Flags, type: STRING] = { OPEN MBOut; Number[filePage, [8,FALSE,FALSE,6]]; Spaces[2]; LongNumber[(LONG[vmPage] * wordsPerPage), [8,FALSE,FALSE,8]]; Spaces[3]; Char[IF flags.writeProtected THEN 'W ELSE ' ]; Char[IF flags.dirty THEN 'D ELSE ' ]; Char[IF flags.referenced THEN 'R ELSE ' ]; Spaces[5]; Text[type]; CR[]; }; SegToLoadmap: PROC [s: MBVM.Seg, backingPage: MBVM.Base, pages: CARDINAL] = { OPEN MBOut; octal: NumberFormat = NumberFormat[8,FALSE,FALSE,1]; Number[backingPage, [8,FALSE,FALSE,6]]; Spaces[2]; LongNumber[LONG[s.base]*wordsPerPage, [8,FALSE,FALSE,8]]; Spaces[2]; Number[pages, [8,FALSE,FALSE,4]]; Spaces[4]; WITH seg: s SELECT FROM data => Text["data"L]; code => {Text["code"L]; Spaces[3]; SegmentSourceToLoadmap[s]}; file => {Text["file"L]; Spaces[3]; SegmentSourceToLoadmap[s]}; ENDCASE; CR[]; }; SegmentSourceToLoadmap: PROC [seg: MBVM.Seg] = { OPEN MBOut; octal: NumberFormat = NumberFormat[8,FALSE,FALSE,1]; file: Segments.FHandle; fileBase: CARDINAL; WITH s: seg SELECT FROM code => {file _ s.file; fileBase _ s.fileBase}; file => {file _ s.file; fileBase _ s.fileBase}; ENDCASE; FileName[file]; Char['[]; Number[fileBase, octal]; Char[',]; Number[seg.pages, octal]; Char[']]; }; MakeEtherFile: PROC = { tty: MBTTY.Handle = data.ttyHandle; name: STRING _ [40]; bufferPages: CARDINAL = 50; inFile, outFile: Segments.FHandle; inStream, outStream: Streams.Handle _ NIL; buffer: LONG POINTER _ MBStorage.Pages[bufferPages]; PutEtherHeader: PROC [s: Streams.Handle] = { etherHeader: EtherHeader _ [createTime: MesaToBCPLTime[data.buildTime]]; [] _ Streams.PutBlock[s, @etherHeader, SIZE[EtherHeader]]; [] _ Streams.PutBlock[s, data.output, SIZE[StringBody[data.output.maxlength]]]; THROUGH [SIZE[EtherHeader]+SIZE[StringBody[data.output.maxlength]]..wordsPerPage) DO Streams.PutWord[s, 0]; ENDLOOP; }; MesaToBCPLTime: PROC [t: Time.Packed] RETURNS [BCPLTime] = INLINE {RETURN [[high: Inline.HighHalf[t], low: Inline.LowHalf[t]]]}; MBTTY.PutString[tty, "Writing ether "L]; MBTTY.PutString[tty, IF data.germ THEN "germ"L ELSE "boot"L]; MBTTY.PutString[tty, "file..."L]; String.AppendString[name, data.output]; inFile _ Segments.NewFile[name, Segments.Read]; name.length _ 0; String.AppendString[name, data.etherOutput]; outFile _ Segments.NewFile[name, Segments.Write]; {ENABLE UNWIND => { IF inStream ~= NIL THEN Streams.Destroy[inStream] ELSE Segments.ReleaseFile[inFile]; IF outStream ~= NIL THEN Streams.Destroy[outStream] ELSE Segments.ReleaseFile[outFile]; MBStorage.FreePages[buffer]; }; Segments.SetFileLength[outFile, Segments.GetFileLength[inFile] + bytesPerPage]; inStream _ Streams.CreateStream[inFile, Streams.Read]; outStream _ Streams.CreateStream[outFile, Streams.Write]; PutEtherHeader[outStream]; DO words: CARDINAL = Streams.GetBlock[inStream, buffer, bufferPages*wordsPerPage]; IF words = 0 THEN EXIT; IF Streams.PutBlock[outStream, buffer, words] ~= words THEN ERROR; ENDLOOP; }; Streams.Destroy[inStream]; Streams.Destroy[outStream]; MBStorage.FreePages[buffer]; MBTTY.PutLine[tty, "finished writing."L]; }; END. ¬MBOutput.mesa Edited by Sandman on 6-Aug-81 15:41:43 Edited by Lewis on 25-Sep-81 15:01:46 Edited by Levin on April 5, 1983 3:21 pm the following are implicit name(5): StringBody, fill(5+WordsForString[name]): ARRAY [5+WordsForString[name]..wordsPerPage) OF WORD _ ALL[0] Boot file (not germ) output Germ file output Subroutines reserved = FALSE (0) on a D0 means don't log single bit memory error create trailer page ÊјJšœ™Jšœ&™&Jšœ%™%Jšœ(™(J˜šÏk ˜ Jšœœ ˜šœ œ˜J˜S—Jšœ œ˜/Jšœœ˜+Jšœ œ˜ JšœœC˜KJšœœœH˜WJšœ œ˜#Jšœœ˜)šœœ˜ J˜f—Jšœœ1˜>Jšœ œ˜šœ œ˜J˜—Jšœ œ?˜Nšœœ˜J˜h—Jšœœ ˜J˜—šœ ˜š˜Jšœœœœ'˜P—Jšœœ˜ —J˜Jš˜J˜Jšœœ˜ J˜Jšœœ˜2Jšœœ˜2J˜Jšœœ œ˜J˜Jš œœœœœ˜.Jš œ œœœœ˜0Jšœœ˜!Jšœ œ˜Jšœœœ˜J˜š œ œœ œœ˜.Jšœ œ˜Jšœœœ˜!J˜Jšœ™Jšœ™Jšœ[™[J˜J˜—Jš œ œœ œœ œ˜@J˜JšÏn œœœœ˜4J˜šž œœœ˜Jšœ œœ(œ˜AJšœ œœ*œ˜Dšœœœ˜J˜FJ˜!Jšœ˜Jšœ˜—Jšœ˜Jšœ˜ Jšœ˜J˜—Jšœ™J˜šž œœœ˜Jšœœ˜#Jšœœ œœœœœœ ˜>Jšœ)˜.J˜Jšœ œœ ˜KJšœœ˜ J˜Jšœ$˜)Jšœœ˜)Jšœ˜J˜—šžœœ˜Jšœœ˜J˜J˜'J˜2˜OJšœœ"˜*Jšœ˜—J˜@J˜>Jšœ2Ïc˜JJ˜.Jšœ˜˜J˜BJ˜FJšœ œ;˜JJšœ˜—Jšœ œ˜J˜(J˜J˜ J˜J˜—šžœœ˜Jšœœœ%˜:J˜%J˜=J˜*J˜!Jšœœ˜J˜J˜—šžœœ œ œœœœœ ˜WJšœ˜ Jšœœ˜#Jšœœ˜ Jšœœ˜J˜-J˜.Jšœœ˜ J˜Jšœ˜J˜J˜)J˜!Jšœ œœŸ˜-J˜Jšœ)˜.šœœœ˜J˜Jšœœœ˜šœœ˜J˜!J˜!J˜!Jšœ˜—Jšœ˜—Jšœ œœ˜4Jšœ˜J˜J˜=J˜Jšœ*˜/šœœœ˜J˜J˜J˜"šœœ˜˜Jšœœ˜7Jšœ/˜3—J˜"˜Jšœœ˜7Jšœ/˜3—Jšœ˜—Jš˜—šœ˜J˜——šž œœœ ˜BJšœœœ˜J˜'šœœœ ˜7Jšœ œœ˜J˜0J˜2J˜SJšœœ˜Jšœœœœ˜CJš˜—šœ˜J˜——šž œœœ ˜BJšœœ˜Jš œœœ œœœ˜?J˜+J˜'J˜-Jšœœœ˜Jšœœœ˜(J˜%J˜šœœœ ˜!J˜šœœœ˜#šœ"œ˜*J˜0J˜2J˜SJ˜—J˜J˜Jšœ˜—Jšœœ˜/Jšœ˜—J˜#J˜J˜—šž œœœ ˜BJ˜'Jšœœœ#˜3šœœœ ˜7J˜0J˜2J˜SJ˜J˜Jšœ˜—J˜#J˜J˜—šž œœœ ˜CJšœœœ˜J˜'šœœœ ˜7Jšœœ˜Jšœœœœ˜CJš˜—šœ˜J˜——šž œœœ ˜CJšœœœ˜Jš œœœ œœœ˜AJ˜J˜-Jšœœœ˜(Jšœœ˜Jšœœœ˜J˜šœœœ ˜!J˜Jšœœ(˜IJšœœ˜/Jšœ˜—Jšœœœ˜ J˜%J˜J˜*šœœœ ˜!J˜šœ œœ˜1Jšœœ7œ˜JJšœ˜Jšœœœ˜(—šœœœ˜#Jšœœ˜6Jšœ/˜3J˜Jšœ˜—Jšœœ˜/Jšœ˜—JšœŸœœœ˜?J˜#J˜J˜—šž œœœ ˜CJšœœœ˜J˜'šœ œ˜J˜+J˜,šœœœ˜%Jšœœœ˜'Jšœœ˜.Jšœœ˜/Jšœ˜—Jšœœ˜—J˜%šœœœ˜$J˜/Jšœ˜—J˜#J˜J˜—Jšœ™J˜Jšœ œ ˜Jšœœœ˜,Jšœœœ˜1J˜šž œœœ˜Jšœœ˜#Jšœœ œœœœœœ ˜>Jšœ œœ!˜6Jšœ)˜.J˜˜?Jšœ"œœ ˜M—Jšœœ˜ J˜Jšœ$˜)Jšœœ˜)Jšœ˜J˜—šžœœ˜Jšœœ˜J˜J˜'J˜2J˜@J˜>J˜ J˜J˜—šžœœ˜J˜!Jšœ˜Jšœ˜J˜—šž œœ œ œœœœœ˜UJšœ œ˜!Jšœ˜ Jšœœ˜J˜2Jšœœ˜ J˜Jšœ˜J˜)J˜!š œœœœ˜'šœ œ˜J˜3J˜3Jšœœ˜Jšœ˜—Jš˜—šœ˜J˜——šž œœœ œœœœœ˜@Jšœ œœ˜<šœœœ˜J˜J—š žœœ œ œœ˜UJ˜Jšœ;œ˜[J˜5Jšœ<œ˜\Jšœœ˜ Jšœ˜—Jšœœ!˜(J˜Jš œœœœœ(œ˜WJšœœ˜:Jšœ/˜3Jšœ˜J˜—šž œœœœ˜^Jšœœœ˜J˜'šœœœ ˜7˜J˜Q—Jšœœ˜Jšœœœœ˜CJš˜—šœ˜J˜——šž œœœœ˜^J˜'Jšœœœ#˜3Jšœ3œ˜8šœœœ ˜7˜J˜Q—J˜J˜Jšœ˜—J˜#J˜J˜—Jšœ ™ J˜šžœœœœ˜@˜Jšœœœ˜O—JšœD™DJšœœ˜GJšœ˜J˜—š žœœœœœ˜OJ˜J˜"J˜J˜—šžœœœ˜TJ˜—šž œœœ8˜SJš œ œœœœœ˜8Jšœœ˜7˜ Jšœ*œœ˜W—J˜3J˜ J˜J˜—šžœœ˜1Jšœ œœ(˜=šœ˜Jšœ™J˜J˜(J˜—J˜4Jšœ˜J˜*J˜)J˜Jšœœœ˜*J˜J˜J˜J˜—š žœœœ œœ˜RJ˜!J˜'J˜5J˜ J˜J˜—šž œœœœ˜8J˜Jšœ5œ˜BJšœ˜J˜—šžœœ˜,J˜Jšœœ˜;Jšœ˜J˜—šžœœœ#œ˜]Jšœ˜ Jšœœœ˜$J˜ Jšœ œœœ˜=J˜ Jšœœœœ˜.Jšœœ œœ˜%Jšœœœœ˜*J˜ J˜ Jšœ˜Jšœ˜J˜—š ž œœœœœ˜MJšœ˜ Jšœ%œœ˜4Jšœœœ˜'J˜ Jšœ œœœ˜9J˜ Jšœœœ˜!J˜ šœœ˜J˜J˜?J˜?Jšœ˜—Jšœ˜Jšœ˜J˜—šžœœœ ˜0Jšœ˜ Jšœ%œœ˜4J˜Jšœ œ˜šœœ˜J˜/J˜/Jšœ˜—J˜2J˜/J˜J˜—šž œœ˜Jšœœ˜#Jšœœ˜Jšœ œ˜J˜"Jšœ&œ˜*Jšœœœ ˜4šžœœ˜,J˜HJšœ'œ˜:Jšœ&œ%˜Ošœœœ3˜TJ˜Jšœ˜—J˜—šžœœœ˜AJšœœ7˜>—Jšœ#˜(Jšœœ œ œ ˜=Jšœ˜!J˜'J˜/J˜=J˜1šœœœ˜Jšœ œœœ˜TJšœœœœ˜WJ˜J˜J˜OJ˜6J˜9J˜š˜Jšœœ@˜OJšœ œœ˜Jšœ5œœ˜BJšœ˜—J˜—J˜J˜J˜Jšœ$˜)J˜J˜—Jšœ˜J˜J˜—…—D¬Y)