DIRECTORY File USING [wordsPerPage], IO USING [Put1, PutChar, PutF, PutF1, PutFL, PutFR1, PutRope, RopeFromROS, ROS, STREAM], MobDefs USING [Base, CTIndex, CTNull, CTRecord, EVIndex, EVNull, EVRecord, EXPIndex, EXPLink, EXPRecord, FPIndex, FPRecord, FTIndex, FTNull, FTRecord, FTSelf, IMPIndex, IMPRecord, LFIndex, LFNull, Link, LinkFrag, Mob, MobBase, MTIndex, MTRecord, Namee, NameRecord, NameString, NTIndex, NTNull, NTRecord, nullLink, RefLitFrag, RFIndex, RFNull, SGHandle, SGIndex, SGNull, SGRecord, SpaceID, SPIndex, SPRecord, TFIndex, TFNull, TypeFrag, TYPIndex, TYPNull, TYPRecord, VersionStamp], MobLister USING [], MobListerUtils USING [FreeMob, MobErr, nullName, PrintName, PrintSei, PrintVersion, ReadMob, SubString], OSMiscOps USING [bytesPerUnit], Rope USING [Concat, Equal, Match, ROPE], SymbolOps USING [DecodeBitAddr, DecodeCard, FirstCtxSe, LinkMode, NameForSe, NextSe, STB, SubString, SubStringForName, TransferTypes], Symbols USING [BitAddress, BodyRecord, BTIndex, BTNull, CBTIndex, ContextLevel, CSEIndex, CSENull, CTXIndex, CTXNull, CTXRecord, HTIndex, ISEIndex, ISENull, lG, MDFirst, RootBti, SEIndex, SENull, SERecord, typeTYPE], SymbolSegment USING [Base, biases, bodyType, ctxType, ExtFirst, extType, FGHeader, htType, ltType, mdType, seType, ssType, STHeader, stType, treeType, VersionID], SymbolTable USING [SymbolTableBaseRep], SymbolTablePrivate USING [SymbolTableBase, SymbolTableBaseRep], Table USING [Base]; MobListerImpl: PROGRAM IMPORTS IO, MobListerUtils, Rope, SymbolOps EXPORTS MobLister, SymbolTable = { bytesPerUnit: NAT = BYTES[WORD]; unitsPerFilePage: NAT = File.wordsPerPage; bytesPerFilePage: NAT = unitsPerFilePage*bytesPerUnit; bitsPerByte: CARD = 8; bitsPerUnit: CARD = OSMiscOps.bytesPerUnit*bitsPerByte; UnitsToFilePages: PROC[units: INT] RETURNS[INT] = { RETURN[(units+unitsPerFilePage-1)/unitsPerFilePage]}; BytesToFilePages: PROC[bytes: INT] RETURNS[INT] = { RETURN[(bytes+bytesPerFilePage-1)/bytesPerFilePage]}; Base: TYPE = MobDefs.Base; Mob: TYPE = MobDefs.Mob; BitAddress: TYPE = Symbols.BitAddress; BodyRecord: TYPE = Symbols.BodyRecord; BTIndex: TYPE = Symbols.BTIndex; RootBti: BTIndex = Symbols.RootBti; CBTIndex: TYPE = Symbols.CBTIndex; ContextLevel: TYPE = Symbols.ContextLevel; lG: ContextLevel = Symbols.lG; CSEIndex: TYPE = Symbols.CSEIndex; CSENull: CSEIndex = Symbols.CSENull; typeTYPE: CSEIndex = Symbols.typeTYPE; CTIndex: TYPE = MobDefs.CTIndex; CTNull: CTIndex = MobDefs.CTNull; CTRecord: TYPE = MobDefs.CTRecord; CTXIndex: TYPE = Symbols.CTXIndex; CTXNull: CTXIndex = Symbols.CTXNull; CTXRecord: TYPE = Symbols.CTXRecord; EVIndex: TYPE = MobDefs.EVIndex; EVNull: EVIndex = MobDefs.EVNull; EVRecord: TYPE = MobDefs.EVRecord; EXPIndex: TYPE = MobDefs.EXPIndex; EXPLink: TYPE = MobDefs.EXPLink; EXPRecord: TYPE = MobDefs.EXPRecord; FPIndex: TYPE = MobDefs.FPIndex; FPRecord: TYPE = MobDefs.FPRecord; FTIndex: TYPE = MobDefs.FTIndex; FTNull: FTIndex = MobDefs.FTNull; FTSelf: FTIndex = MobDefs.FTSelf; FTRecord: TYPE = MobDefs.FTRecord; HTIndex: TYPE = Symbols.HTIndex; ISEIndex: TYPE = Symbols.ISEIndex; ISENull: ISEIndex = Symbols.ISENull; ISERecord: TYPE = SERecord.id; LFIndex: TYPE = MobDefs.LFIndex; LFNull: LFIndex = MobDefs.LFNull; LFRecord: TYPE = MobDefs.LinkFrag; Link: TYPE = MobDefs.Link; nullLink: Link = MobDefs.nullLink; Namee: TYPE = MobDefs.Namee; NameRecord: TYPE = MobDefs.NameRecord; NameString: TYPE = MobDefs.NameString; NTIndex: TYPE = MobDefs.NTIndex; NTNull: NTIndex = MobDefs.NTNull; NTRecord: TYPE = MobDefs.NTRecord; IMPIndex: TYPE = MobDefs.IMPIndex; IMPRecord: TYPE = MobDefs.IMPRecord; MTIndex: TYPE = MobDefs.MTIndex; MTRecord: TYPE = MobDefs.MTRecord; RefMob: TYPE = REF Mob; RefMTRecord: TYPE = REF MTRecord; RefSGRecord: TYPE = REF SGRecord; RFIndex: TYPE = MobDefs.RFIndex; RFNull: RFIndex = MobDefs.RFNull; RFRecord: TYPE = MobDefs.RefLitFrag; ROPE: TYPE = Rope.ROPE; SEIndex: TYPE = Symbols.SEIndex; SENull: SEIndex = Symbols.SENull; SERecord: TYPE = Symbols.SERecord; SGIndex: TYPE = MobDefs.SGIndex; SGNull: SGIndex = MobDefs.SGNull; SGRecord: TYPE = MobDefs.SGRecord; SpaceID: TYPE = MobDefs.SpaceID; SPIndex: TYPE = MobDefs.SPIndex; SPRecord: TYPE = MobDefs.SPRecord; STREAM: TYPE = IO.STREAM; SymbolTableBase: TYPE = REF SymbolTableBaseRep; SymbolTableBaseRep: PUBLIC TYPE = SymbolTablePrivate.SymbolTableBaseRep; TFIndex: TYPE = MobDefs.TFIndex; TFNull: TFIndex = MobDefs.TFNull; TFRecord: TYPE = MobDefs.TypeFrag; TYPIndex: TYPE = MobDefs.TYPIndex; TYPNull: TYPIndex = MobDefs.TYPNull; TYPRecord: TYPE = MobDefs.TYPRecord; VersionStamp: TYPE = MobDefs.VersionStamp; ListMob: PUBLIC PROC[stream: IO.STREAM, mob: MobDefs.MobBase, cmd: ATOM] = { PrintStamps: PROC = { stream.PutRope["Imports:\n\n"]; FOR iti: IMPIndex ฌ IMPIndex.FIRST, iti + IMPRecord.SIZE UNTIL iti = mob.impLimit DO ip: LONG POINTER TO IMPRecord = @itb[iti]; IF LOOPHOLE[iti, CARD] > LOOPHOLE[mob.impLimit, CARD] THEN GO TO Bogus; IF ip.namedInstance THEN {PutInstanceName[[0,0,import[iti]]]; stream.PutRope[": "]}; PutName[ip.name]; PutFileStamp[ip.file, ip.name]; REPEAT Bogus => PrintGarbage[]; ENDLOOP; stream.PutRope["\nExports:\n\n"]; FOR eti: EXPIndex ฌ EXPIndex.FIRST, eti + etb[eti].nLinks*EXPLink.SIZE + EXPRecord.SIZE UNTIL eti = mob.expLimit DO ee: LONG POINTER TO EXPRecord = @etb[eti]; IF LOOPHOLE[eti, CARD] > LOOPHOLE[mob.expLimit, CARD] THEN GO TO Bogus; IF ee.namedInstance THEN {PutInstanceName[[0,0,export[eti]]]; stream.PutRope[": "]}; PutName[ee.name]; PutFileStamp[ee.file, ee.name]; REPEAT Bogus => PrintGarbage[]; ENDLOOP; stream.PutRope["\nModules:\n\n"]; FOR mti: MTIndex ฌ MTIndex.FIRST, mti + MTSize[mti] UNTIL mti = mob.mtLimit DO mm: LONG POINTER TO MTRecord = @mtb[mti]; IF LOOPHOLE[mti, CARD] > LOOPHOLE[mob.mtLimit, CARD] THEN GO TO Bogus; IF mm.namedInstance THEN {PutInstanceName[[0,0,module[mti]]]; stream.PutRope[": "]}; PutName[mm.name]; PutFileStamp[mm.file, mm.name]; REPEAT Bogus => PrintGarbage[]; ENDLOOP; }; PutFileStamp: PROC[fti: FTIndex, mName: NameRecord] = { SELECT fti FROM FTNull => stream.PutRope["(null)"]; FTSelf => stream.PutRope["(self)"]; ENDCASE => { ftr: LONG POINTER TO FTRecord = @ftb[fti]; IF ftr.name # mName THEN {stream.PutRope[", file: "]; PutName[ftr.name]}; stream.PutRope[", version: "]; MobListerUtils.PrintVersion[ftr.version, stream]}; stream.PutChar['\n]}; PrintHeader: PROC = { stream.PutF1["Configurations: %g", [cardinal[mob.nConfigs]]]; stream.PutF1[", Modules: %g", [cardinal[mob.nModules]]]; stream.PutF1[", Imports: %g", [cardinal[mob.nImports]]]; stream.PutF1[", Exports: %g", [cardinal[mob.nExports]]]; stream.PutF1[", Dummy: %g", [cardinal[mob.firstdummy]]]; stream.PutF1[", #Dummies: %g\n", [cardinal[mob.nDummies]]]; IF ~mob.definitions THEN stream.PutChar['~]; stream.PutRope["definitions, "]; IF ~mob.repackaged THEN stream.PutChar['~]; stream.PutRope["repackaged, "]; IF ~mob.typeExported THEN stream.PutChar['~]; stream.PutRope["type exported, "]; IF ~mob.inlineFloat THEN stream.PutChar['~]; stream.PutRope["inline fload, "]; IF ~mob.mappingStarted THEN stream.PutChar['~]; stream.PutRope["mapping started, "]; IF ~mob.mappingFinished THEN stream.PutChar['~]; stream.PutRope["mapping finished, "]; IF ~mob.versions THEN stream.PutChar['~]; stream.PutRope["versions, "]; IF ~mob.extended THEN stream.PutChar['~]; stream.PutRope["extended\n\n"]}; PrintConfigs: PROC = { cti: CTIndex ฌ CTIndex.FIRST; stream.PutF1["Configurations[%g]:\n", [cardinal[mob.ctOffset.units]]]; UNTIL cti = mob.ctLimit DO PrintConfig[cti]; cti ฌ cti + CTRecord.SIZE + ctb[cti].nControls*Namee.SIZE; IF LOOPHOLE[cti, CARD] > LOOPHOLE[mob.ctLimit, CARD] THEN GO TO Bogus; REPEAT Bogus => PrintGarbage[]; ENDLOOP; stream.PutChar['\n]}; PrintConfig: PROC[cti: CTIndex] = { ctp: LONG POINTER TO CTRecord = @ctb[cti]; Tab[2]; PutName[ctp.name]; PrintLongIndex[LOOPHOLE[cti]]; IF ctp.namedInstance THEN { stream.PutRope[", instance name: "]; PutInstanceName[[0,0,config[cti]]]}; stream.PutRope[", file: "]; PrintFileName[ctp.file]; PrintLongIndex[LOOPHOLE[ctp.file]]; IF cti # CTNull THEN { stream.PutRope[", parent: "]; PutName[ctb[cti].name]; PrintLongIndex[LOOPHOLE[cti]]}; stream.PutF1[", #controls: %g", [cardinal[ctp.nControls]]]; IF ctp.nControls # 0 THEN { stream.PutRope[", controls:"]; FOR i: CARDINAL IN [0..ctp.nControls) DO IF i MOD 6 = 0 THEN Tab[6] ELSE stream.PutRope[", "]; WITH c~~ctp.controls[i] SELECT FROM module => { PutName[mtb[c.mti].name]; PrintLongIndex[LOOPHOLE[c.mti]]}; config => { PutName[ctb[c.cti].name]; stream.PutChar['*]; PrintLongIndex[LOOPHOLE[c.cti]]}; ENDCASE => ERROR; ENDLOOP}; stream.PutChar['\n]}; PrintImports: PROC = { iti: IMPIndex ฌ IMPIndex.FIRST; stream.PutF1["Imports[%g]:\n", [cardinal[mob.impOffset.units]]]; UNTIL iti = mob.impLimit DO PrintImport[iti]; iti ฌ iti + IMPRecord.SIZE; IF LOOPHOLE[iti, CARD] > LOOPHOLE[mob.impLimit, CARD] THEN GO TO Bogus; REPEAT Bogus => PrintGarbage[]; ENDLOOP; stream.PutRope["\n\n"]}; PrintImport: PROC[iti: IMPIndex] = { imp: LONG POINTER TO IMPRecord = @itb[iti]; Tab[2]; PutName[imp.name]; PrintLongIndex[LOOPHOLE[iti]]; IF imp.port = $module THEN stream.PutRope[" (module)"]; IF imp.namedInstance THEN { stream.PutRope[", instance name: "]; PutInstanceName[[0,0,import[iti]]]}; stream.PutRope[", file: "]; PrintFileName[imp.file]; PrintLongIndex[LOOPHOLE[imp.file]]; stream.PutF[", gfi: %g, ngfi: %g", [cardinal[imp.modIndex]], [cardinal[1]]]}; PrintGlobals: PROC[] = { amperTable: AmperTable ฌ NIL; units: INT ฌ 0; frames: INT ฌ 0; totalProcs: INT ฌ 0; procs: INT ฌ 0; waste: INT ฌ 0; totalWaste: INT ฌ 0; gfiSlots: INT ฌ 0; AmperTable: TYPE = LIST OF AmperTableEntry; AmperTableEntry: TYPE = RECORD [name: ROPE, count: INT, size: INT]; FOR mti: MTIndex ฌ MTIndex.FIRST, mti + MTSize[mti] UNTIL mti = mob.mtLimit DO mtr: LONG POINTER TO MTRecord = @mtb[mti]; frameSize: CARD ฌ mtr.framesize; gfis: CARDINAL ฌ 1; DoBody: PROC[symbols: SymbolTableBase] = { DoFields: PROC[rSei: CSEIndex] RETURNS[maxSpan: CARDINAL ฌ 0] = { WITH t~~symbols.seb[rSei] SELECT FROM record => maxSpan ฌ DoContext[t.fieldCtx]; ENDCASE; }; DoContext: PROC[ctx: CTXIndex] RETURNS[maxSpan: CARDINAL ฌ 0] = { FOR sei: ISEIndex ฌ SymbolOps.FirstCtxSe[symbols, ctx], SymbolOps.NextSe[symbols, sei] UNTIL sei = ISENull DO IF ~symbols.seb[sei].constant THEN maxSpan ฌ MAX[DoSymbol[sei], maxSpan]; ENDLOOP; }; DoSymbol: PROC[sei: ISEIndex] RETURNS[span: CARDINAL] = { addr: BitAddress = SymbolOps.DecodeBitAddr[symbols.seb[sei].idValue]; size: CARD = (SymbolOps.DecodeCard[symbols.seb[sei].idInfo]+bitsPerUnit-1) / bitsPerUnit; hti: HTIndex = SymbolOps.NameForSe[symbols, sei]; stream.PutRope[" "]; IF hti # MobListerUtils.nullName THEN { ss: MobListerUtils.SubString = SymbolOps.SubStringForName[symbols, hti]; IF ss.length # 0 AND ss.base[ss.offset] = '& THEN { ros: STREAM ฌ IO.ROS[]; rope: ROPE ฌ NIL; MobListerUtils.PrintName[hti, ros, symbols]; rope ฌ ros.RopeFromROS[]; FOR each: AmperTable ฌ amperTable, each.rest WHILE each # NIL DO IF (each.first.name).Equal[rope] THEN { each.first.size ฌ each.first.size + size; each.first.count ฌ each.first.count + 1; GO TO found}; ENDLOOP; amperTable ฌ CONS [[name: rope, count: 1, size: size], amperTable]; EXITS found => {}; }; }; MobListerUtils.PrintName[hti, stream, symbols]; stream.PutF1["\t%g\n", [cardinal[size]]]; RETURN[addr.bd/bitsPerUnit + size]}; CountProcs: PROC RETURNS[n: CARDINAL ฌ 0] = TRUSTED { prev: Symbols.BTIndex ฌ FIRST[Symbols.BTIndex]; bti: Symbols.BTIndex ฌ prev; DO WITH body~~symbols.bb[bti] SELECT FROM Callable => IF NOT body.inline THEN n ฌ n + 1; ENDCASE; IF symbols.bb[bti].firstSon # Symbols.BTNull THEN bti ฌ symbols.bb[bti].firstSon ELSE DO prev ฌ bti; bti ฌ symbols.bb[bti].link.index; IF bti = Symbols.BTNull THEN RETURN; IF symbols.bb[prev].link.which # parent THEN EXIT; ENDLOOP; ENDLOOP; }; bti: CBTIndex ฌ LOOPHOLE[RootBti]; frameOverhead: CARDINAL = 4--words of frame overhead-- * UNITS[WORD]; maxSpan: CARDINAL ฌ frameOverhead-1; typeIn, typeOut: CSEIndex; IF symbols = NIL THEN { stream.PutRope["Sorry, no symbols available (file must be local).\n"]; RETURN}; [typeIn, typeOut] ฌ SymbolOps.TransferTypes[symbols, symbols.bb[bti].ioType]; IF typeIn # CSENull THEN { stream.PutRope[" Global arguments:\n"]; maxSpan ฌ MAX[DoFields[typeIn], maxSpan]}; IF typeOut # CSENull THEN { stream.PutRope[" Global results:\n"]; maxSpan ฌ MAX[DoFields[typeOut], maxSpan]}; IF symbols.bb[bti].localCtx # CTXNull THEN { stream.PutRope[" Global variables: (name & units)\n"]; maxSpan ฌ MAX[DoContext[symbols.bb[bti].localCtx], maxSpan]}; IF ~symbols.bb[bti].hints.noStrings THEN stream.PutRope[" Global string literals or string bodies\n"]; IF maxSpan # frameSize AND frameSize > frameOverhead THEN stream.PutF1[ " %g units not in listed variables or overhead\n", [integer[frameSize - maxSpan]]]; stream.PutRope["\n"]; procs ฌ CountProcs[]}; IF LOOPHOLE[mti, CARD] > LOOPHOLE[mob.mtLimit, CARD] THEN GO TO Bogus; IF mtr.namedInstance THEN {PutInstanceName[[0,0,module[mti]]]; stream.PutRope[": "]}; PutName[mtr.name]; PutFileStamp[mtr.file, mtr.name]; frames ฌ frames + 1; procs ฌ 0; WithSymbolsForModule[mti, DoBody]; IF procs # 0 THEN { waste ฌ 0; stream.PutFL["Global frame size: %g, gfi slots: %g, procs: %g (waste: %g)\n\n", LIST[ [cardinal[frameSize]], [cardinal[gfis]], [cardinal[procs]], [integer[waste]] ]]} ELSE { stream.PutF["Global frame size: %g, gfi slots: %g, procs: ?? (waste: ??)\n\n", [cardinal[frameSize]], [cardinal[gfis]] ]; }; gfiSlots ฌ gfiSlots + gfis; units ฌ units + frameSize; totalWaste ฌ totalWaste + waste; totalProcs ฌ totalProcs + procs; REPEAT Bogus => PrintGarbage[]; ENDLOOP; IF frames > 1 THEN { stream.PutFL["%g units in %g frames using %g gfi slots, %g procs (%g waste)\n", LIST[ [cardinal[units]], [cardinal[frames]], [cardinal[gfiSlots]], [cardinal[totalProcs]], [cardinal[totalWaste]] ]]; stream.PutRope["\n&-variables\n"]; FOR each: AmperTable ฌ amperTable, each.rest WHILE each # NIL DO stream.PutF["\t%g\t%g\t%g\n", [rope[each.first.name]], [integer[each.first.count]], [integer[each.first.size]]]; ENDLOOP; }; }; WithSymbolsForModule: PROC[mti: MTIndex, inner: PROC[symbols: SymbolTableBase]] = { mm: LONG POINTER TO MTRecord = @mtb[mti]; IF mm.sseg = SGNull THEN GO TO loser ELSE { symbols: SymbolTableBase ฌ NIL; sgr: LONG POINTER TO SGRecord = @sgb[mm.sseg]; start: CARD ฌ UnitsToFilePages[sgr.base.units]; pages: CARD ฌ UnitsToFilePages[sgr.units.units]; nMob: MobDefs.MobBase ฌ mob; IF start = 0 OR sgr.units.units = 0 OR sgr.file = FTNull THEN GO TO loser; IF sgr.file # FTSelf THEN { ftr: LONG POINTER TO FTRecord = @ftb[sgr.file]; fileName: ROPE ฌ NameToRope[ftr.name].Concat[".mob"]; nMob ฌ MobListerUtils.ReadMob[fileName ! MobListerUtils.MobErr => GO TO loser ]; }; IF nMob.extended THEN pages ฌ pages + UnitsToFilePages[sgr.extraUnits.units]; DoSymbols[nMob, inner]; IF nMob#mob THEN MobListerUtils.FreeMob[nMob]; }; EXITS loser => inner[NIL]; }; STB: TYPE = REF SymbolTableBaseRep; DoSymbols: PUBLIC PROC [mob: MobDefs.MobBase, proc: PROC[sym: STB]] = { sym: STB ฌ NIL; sgb: MobDefs.Base = LOOPHOLE[mob+mob.sgOffset.units]; mtb: MobDefs.Base = LOOPHOLE[mob+mob.mtOffset.units]; sgh: MobDefs.SGHandle = IF mtb[FIRST[MobDefs.MTIndex]].sseg = MobDefs.SGNull THEN ERROR --NoSymbols ELSE @sgb[mtb[FIRST[MobDefs.MTIndex]].sseg]; stb: LONG POINTER TO SymbolSegment.STHeader = LOOPHOLE[mob+sgh.base.units]; IF mob.nConfigs # 0 THEN ERROR; -- Configuration; IF sgh.file # MobDefs.FTSelf OR sgh.units.units = 0 THEN ERROR; -- NoSymbols; IF stb.versionIdent # SymbolSegment.VersionID THEN ERROR; -- WrongSymbolsVersion; sym ฌ InstallTable[stb]; proc[sym]; }; InstallTable: PROC [node: LONG POINTER] RETURNS [STB] = { b: LONG POINTER = node; tB: SymbolSegment.Base = LOOPHOLE[b]; p: LONG POINTER TO SymbolSegment.STHeader = b; base: STB ฌ NEW[SymbolTableBaseRep]; base.cacheInfo ฌ LOOPHOLE[node]; base.hashVec ฌ b+p.hvBlock.offset; base.htb ฌ tB + p.htBlock.offset - SymbolSegment.biases[SymbolSegment.htType]; base.ssb ฌ b + p.ssBlock.offset - SymbolSegment.biases[SymbolSegment.ssType]; base.seb ฌ tB + p.seBlock.offset - SymbolSegment.biases[SymbolSegment.seType]; base.ctxb ฌ tB + p.ctxBlock.offset - SymbolSegment.biases[SymbolSegment.ctxType]; base.mdb ฌ tB + p.mdBlock.offset - SymbolSegment.biases[SymbolSegment.mdType]; base.bb ฌ tB + p.bodyBlock.offset - SymbolSegment.biases[SymbolSegment.bodyType]; base.tb ฌ tB + p.treeBlock.offset - SymbolSegment.biases[SymbolSegment.treeType]; base.ltb ฌ tB + p.litBlock.offset - SymbolSegment.biases[SymbolSegment.ltType]; base.stb ฌ tB + p.sLitBlock.offset - SymbolSegment.biases[SymbolSegment.stType]; base.extb ฌ tB + p.extBlock.offset - SymbolSegment.biases[SymbolSegment.extType]; base.mdLimit ฌ Symbols.MDFirst + p.mdBlock.size; base.extLimit ฌ SymbolSegment.ExtFirst + p.extBlock.size; base.mainCtx ฌ p.outerCtx; base.stHandle ฌ p; IF p.fgRelBase = 0 OR p.fgCount = 0 THEN { base.sourceFile ฌ NIL; base.fgTable ฌ NIL; } ELSE { q: LONG POINTER TO SymbolSegment.FGHeader = LOOPHOLE[b + p.fgRelBase]; source: LONG STRING = LOOPHOLE[q + SIZE[SymbolSegment.FGHeader[0]] - SIZE[StringBody[0]]]; base.sourceFile ฌ source; base.fgTable ฌ DESCRIPTOR[q + q.offset, q.length]; }; RETURN [base]; }; PrintExports: PROC[printOffset: BOOL] = { eti: EXPIndex ฌ EXPIndex.FIRST; IF printOffset THEN stream.PutF1["Exports[%g]:\n", [cardinal[mob.expOffset.units]]]; UNTIL eti = mob.expLimit DO PrintExport[eti]; eti ฌ eti + etb[eti].nLinks*EXPLink.SIZE + EXPRecord.SIZE; IF LOOPHOLE[eti, CARD] > LOOPHOLE[mob.expLimit, CARD] THEN GO TO Bogus; REPEAT Bogus => PrintGarbage[]; ENDLOOP; IF dumpLinks # all THEN stream.PutChar['\n]; stream.PutChar['\n]}; PrintExport: PROC[eti: EXPIndex] = { etr: LONG POINTER TO EXPRecord = @etb[eti]; size: CARDINAL ฌ etr.nLinks; Tab[2]; PutName[etr.name]; PrintLongIndex[LOOPHOLE[eti]]; IF etr.port = $module THEN stream.PutRope[" (module)"]; IF etr.namedInstance THEN { stream.PutRope[", instance name: "]; PutInstanceName[[0,0,export[eti]]]}; stream.PutRope[", file: "]; PrintFileName[etr.file]; PrintLongIndex[LOOPHOLE[etr.file]]; stream.PutRope[", "]; IF ~etr.typeExported THEN stream.PutChar['~]; stream.PutF1["typeExported, #links: %g", [cardinal[etr.nLinks]]]; IF dumpLinks = all THEN { mobName: ROPE = NameToRope[ftb[etr.file].name].Concat[".mob"]; mobVersion: VersionStamp = ftb[etr.file].version; exmob: MobDefs.MobBase ฌ NIL; inner: PROC[exstb: SymbolTableBase] = { FOR i: CARDINAL IN [0..size) DO link: Link = etr.links[i].from; name: ROPE = NameFromIndex[exstb, i]; isInline: BOOL = Rope.Match["*[inline]*", name, FALSE]; isUnbound: BOOL = link = nullLink AND NOT isInline; IF cmd = $Unbound AND NOT isUnbound THEN LOOP; stream.PutF1["\n\t\t%g: ", [cardinal[i]]]; IF isUnbound THEN stream.PutRope["** unbound ** "]; stream.PutRope[name]; IF cmd = $Unbound THEN LOOP; stream.PutRope[": "]; SELECT link.tag FROM proc => stream.PutF["proc[%g,%g]", [cardinal[link.modIndex]], [cardinal[link.offset]]]; type => stream.PutF1["type[%g]", [cardinal[link.offset]]]; ENDCASE => stream.PutF["var[%g,%g]", [cardinal[link.modIndex]], [cardinal[link.offset]]]; ENDLOOP; }; -- End of inner stream.PutRope[", links:"]; exmob ฌ MobListerUtils.ReadMob[mobName ! MobListerUtils.MobErr => CONTINUE]; SELECT TRUE FROM exmob = NIL => { stream.PutRope[mobName]; stream.PutRope[" not found.\n"]; inner[NIL]}; exmob.version # mobVersion => { stream.PutRope[mobName]; stream.PutRope[", version "]; MobListerUtils.PrintVersion[exmob.version, stream]; stream.PutRope[" found, version "]; MobListerUtils.PrintVersion[mobVersion, stream]; stream.PutRope[" needed.\n"]; inner[NIL]; }; ENDCASE => { DoSymbols[exmob, inner]; }; IF exmob#mob THEN MobListerUtils.FreeMob[exmob ! MobListerUtils.MobErr => CONTINUE]; stream.PutChar['\n]; }; }; PrintExpVars: PROC = { evi: EVIndex ฌ EVIndex.FIRST; evLimit: EVIndex = mob.evLimit; stream.PutRope["Exported variables:\n"]; UNTIL evi = evLimit DO PrintExpVar[evi]; evi ฌ evi + evb[evi].length*CARD.SIZE + EVRecord.SIZE; ENDLOOP; stream.PutChar['\n]}; PrintExpVar: PROC[evi: EVIndex] = { evr: LONG POINTER TO EVRecord = @evb[evi]; Tab[2]; stream.PutF["%g, #offsets: %g, offsets:", [cardinal[LOOPHOLE[evi, CARD]]], [cardinal[evr.length]]]; FOR i: CARDINAL IN [1..evr.length] DO IF i MOD 8 = 1 THEN Tab[4] ELSE stream.PutChar[' ]; stream.PutF1["%b", [cardinal[evr.offsets[i]]]]; IF i # evr.length THEN stream.PutChar[',]; ENDLOOP; stream.PutChar['\n]}; PrintSpaces: PROC = { spi: SPIndex ฌ SPIndex.FIRST; spLimit: SPIndex = mob.spLimit; stream.PutRope["Spaces:\n"]; UNTIL spi = spLimit DO PrintSpace[spi]; spi ฌ spi + SPRecord.SIZE + spb[spi].length*SpaceID.SIZE; ENDLOOP; stream.PutChar['\n]}; PrintSpace: PROC[spi: SPIndex] = { spr: LONG POINTER TO SPRecord = @spb[spi]; Tab[2]; PrintLongIndex[LOOPHOLE[spi, CARD]]; stream.PutF1[", segment: [%g]", [cardinal[LOOPHOLE[spr.seg, CARD]]]]; stream.PutF1[", #code packs: %g", [cardinal[spr.length]]]; IF spr.length # 0 THEN stream.PutRope[", code packs: "]; FOR i: CARDINAL IN [0..spr.length) DO Tab[4]; stream.PutRope[" code pack "]; PutName[spr.spaces[i].name]; stream.PutRope[", "]; IF ~spr.spaces[i].resident THEN stream.PutChar['~]; stream.PutF["resident, offset: %b, pages: %g\n", [cardinal[spr.spaces[i].offset]], [cardinal[spr.spaces[i].pages]]]; ENDLOOP; }; PrintModules: PROC = { mti: MTIndex ฌ MTIndex.FIRST; stream.PutF1["Modules[%g]:\n", [cardinal[mob.mtOffset.units]]]; UNTIL mti = mob.mtLimit DO PrintModule[@mtb[mti], mti]; mti ฌ mti + MTSize[mti]; IF LOOPHOLE[mti, CARD] > LOOPHOLE[mob.mtLimit, CARD] THEN GO TO Bogus; REPEAT Bogus => PrintGarbage[]; ENDLOOP; stream.PutChar['\n]}; PrintModule: PROC[mth: LONG POINTER TO MTRecord, mti: MTIndex] = { Tab[2]; PutName[mth.name]; PrintLongIndex[LOOPHOLE[mti]]; IF mth.namedInstance THEN { stream.PutRope["instance name: "]; PutInstanceName[[0,0,module[mti]]]}; stream.PutRope[", file: "]; PrintFileName[mth.file]; PrintLongIndex[LOOPHOLE[mth.file]]; IF mth.config # CTNull THEN { stream.PutRope[", config: "]; PutName[ctb[mth.config].name]; PrintLongIndex[LOOPHOLE[mth.config]]}; Tab[4]; IF mth.inlineFloat THEN stream.PutRope["inline float, "] ELSE { PutSwitch: PROC[sw: CHAR, value: BOOL] = { IF ~value THEN stream.PutChar['-]; stream.PutChar[sw]}; stream.PutRope["switches: "]; PutSwitch['b, mth.boundsChecks]; PutSwitch['c, mth.long]; PutSwitch['j, mth.crossJumped]; PutSwitch['l, mth.linkLoc = $codePrefix]; PutSwitch['n, mth.nilChecks]; PutSwitch['s, ~mth.initial]; stream.PutRope[", "]}; IF ~mth.packageable THEN stream.PutChar['~]; stream.PutRope["packageable, "]; IF mth.residentFrame THEN stream.PutRope["resident frame, "]; Tab[4]; stream.PutF["framesize: %g, gfi: %g, ngfi: %g, links: ", [cardinal[mth.framesize]], [cardinal[mth.modIndex]], [cardinal[1]]]; IF mth.linkLoc = $framePrefix THEN stream.PutRope["frame"] ELSE stream.PutRope["code"]; Tab[4]; stream.PutRope["code: "]; PrintSegment[mth.code.sgi]; stream.PutF[", offset: %b, length: %b", [cardinal[mth.code.offset]], [cardinal[mth.code.length]]]; IF mth.code.linkspace THEN stream.PutRope[", link space"]; IF mth.code.packed THEN stream.PutRope[", packed"]; Tab[4]; stream.PutRope["symbols: "]; PrintSegment[mth.sseg]; IF mth.variables # EVNull THEN { Tab[4]; stream.PutF1[ "exported variables: [%g]", [cardinal[LOOPHOLE[mth.variables, CARD]]]]; }; BEGIN Tab[4]; PrintLinks[mth.links]; Tab[4]; PrintTypes[mth.types]; IF mth.frameRefs THEN { Tab[5]; stream.PutF1["frame type: %g", [cardinal[mth.frameType]]]}; Tab[4]; PrintRefLits[mth.refLiterals]; END; stream.PutChar['\n]}; MTSize: PROC[mti: MTIndex] RETURNS[NAT] = { RETURN[MTRecord.SIZE] }; PrintLinks: PROC[lfi: LFIndex] = { stream.PutRope["#links: "]; IF lfi = LFNull THEN stream.PutRope["none"] ELSE { stream.Put1[[cardinal[lfb[lfi].length]]]; IF dumpLinks = all THEN { stream.PutRope[", links:"]; FOR i: CARDINAL IN [0..lfb[lfi].length) DO IF i MOD 7 = 0 THEN Tab[6] ELSE stream.PutChar[' ]; PrintControlLink[lfb[lfi].frag[i]]; IF i + 1 # lfb[lfi].length THEN stream.PutChar[',]; ENDLOOP; }; }; }; PrintTypes: PROC[tfi: TFIndex] = { stream.PutRope["#types: "]; IF tfi = TFNull THEN stream.PutRope["none"] ELSE { stream.PutF["%g, offset: %g", [cardinal[tfb[tfi].length]], [cardinal[tfb[tfi].offset]]]; IF dumpLinks # none THEN { stream.PutRope[", indices:"]; FOR i: CARDINAL IN [0..tfb[tfi].length) DO IF i MOD 7 = 0 THEN Tab[6] ELSE stream.PutChar[' ]; stream.PutF1["[%g]", [cardinal[tfb[tfi].frag[i]]]]; IF i + 1 # tfb[tfi].length THEN stream.PutChar[',]; ENDLOOP; }; }; }; PrintRefLits: PROC[rfi: RFIndex] = { stream.PutRope["#ref lits: "]; IF rfi = RFNull THEN stream.PutRope["none"] ELSE { stream.PutF["%g, offset: %g", [cardinal[rfb[rfi].length]], [cardinal[rfb[rfi].offset]]]; IF dumpLinks # none THEN { stream.PutRope[", indices:"]; FOR i: CARDINAL IN [0..rfb[rfi].length) DO IF i MOD 7 = 0 THEN Tab[6] ELSE stream.PutChar[' ]; stream.PutF1["[%g]", [cardinal[rfb[rfi].frag[i]]]]; IF i + 1 # rfb[rfi].length THEN stream.PutChar[',]; ENDLOOP; }; }; }; PrintFramePacks: PROC = { fpi: FPIndex ฌ FPIndex.FIRST; fpLimit: FPIndex = mob.fpLimit; stream.PutRope["Frame Packs:\n"]; UNTIL fpi = fpLimit DO PrintFramePack[fpi]; fpi ฌ fpi + FPRecord.SIZE + fpb[fpi].length*MTIndex.SIZE; ENDLOOP; stream.PutChar['\n]}; PrintFramePack: PROC[fpi: FPIndex] = { fpr: LONG POINTER TO FPRecord = @fpb[fpi]; Tab[2]; PutName[fpr.name]; stream.PutF["[%g], #modules: %g, modules:\n", [cardinal[LOOPHOLE[fpi, CARD]]], [cardinal[fpr.length]]]; FOR i: CARDINAL IN [0..fpr.length) DO IF i MOD 4 = 0 THEN Tab[4] ELSE stream.PutChar[' ]; PutName[mtb[fpr.modules[i]].name]; PrintLongIndex[LOOPHOLE[fpr.modules[i]]]; IF i # CARD[fpr.length - 1] THEN stream.PutChar[',]; ENDLOOP; stream.PutChar['\n]}; PrintSegment: PROC[sgi: SGIndex] = { IF sgi = SGNull THEN stream.PutRope["(null)"] ELSE { PrintFileName[sgb[sgi].file]; stream.PutF[" [base: %g, pages: %g", [cardinal[UnitsToFilePages[sgb[sgi].base.units]]], [cardinal[UnitsToFilePages[sgb[sgi].units.units]]]]; IF sgb[sgi].extraUnits.units # 0 THEN stream.PutF1["+%g", [cardinal[UnitsToFilePages[sgb[sgi].extraUnits.units]]]]; stream.PutChar[']]}; }; PrintFiles: PROC = { fti: FTIndex ฌ FTIndex.FIRST; stream.PutF1["Files[%g]:\n", [cardinal[mob.ftOffset.units]]]; UNTIL fti = mob.ftLimit DO PrintFile[fti]; fti ฌ fti + FTRecord.SIZE; IF LOOPHOLE[fti, CARD] > LOOPHOLE[mob.ftLimit, CARD] THEN { PrintGarbage[]; EXIT}; ENDLOOP; stream.PutRope["\n\n"]}; PrintFile: PROC[fti: FTIndex] = { Tab[2]; SELECT fti FROM FTNull => stream.PutRope["(null)"]; FTSelf => stream.PutRope["(self)"]; ENDCASE => { ftr: LONG POINTER TO FTRecord = @ftb[fti]; PutName[ftr.name]; PrintLongIndex[LOOPHOLE[fti]]; stream.PutRope[", version: "]; MobListerUtils.PrintVersion[ftr.version, stream]}; }; PrintControlLink: PROC[link: Link] = { SELECT link.tag FROM proc => stream.PutF["proc[%g,%g]", [cardinal[link.modIndex]], [cardinal[link.offset]]]; type => stream.PutF1["type[%g]", [cardinal[link.offset]]]; ENDCASE => stream.PutF["var[%g,%g]", [cardinal[link.modIndex]], [cardinal[link.offset]]]; }; PrintFileName: PROC[fti: FTIndex] = { SELECT fti FROM FTNull => stream.PutRope["(null)"]; FTSelf => stream.PutRope["(self)"]; ENDCASE => PutName[ftb[fti].name]; }; PrintIndex: PROC[index: CARDINAL] = { stream.PutF1[" [%g]", [cardinal[index]]]}; PrintLongIndex: PROC[index: CARD] = { stream.PutF1[" [%g]", [cardinal[index]]]}; PrintGarbage: PROC = { Tab[2]; stream.PutRope["? Looks like garbage ...\n"]; }; Tab: PROC[n: CARDINAL] = { stream.PutChar['\n]; THROUGH [1..n/8] DO stream.PutChar['\t] ENDLOOP; THROUGH [1..n MOD 8] DO stream.PutChar[' ] ENDLOOP}; PutName: PROC[n: NameRecord] = { CharSeq: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF CHAR]; ss: LONG POINTER TO CharSeq = LOOPHOLE[ssb]; index: CARDINAL = n+4; len: CARDINAL = ss[index]-0C; FOR i: NAT IN [index+1..index+len] DO stream.PutChar[ss[i]]; ENDLOOP}; NameToRope: PROC[n: NameRecord] RETURNS[ROPE] = { CharSeq: TYPE = RECORD[PACKED SEQUENCE COMPUTED CARDINAL OF CHAR]; ss: LONG POINTER TO CharSeq = LOOPHOLE[ssb]; index: CARDINAL = n+4; len: CARDINAL = ss[index]-0C; ros: STREAM = IO.ROS[]; FOR i: NAT IN [index+1..index+len] DO ros.PutChar[ss[i]]; ENDLOOP; RETURN[ros.RopeFromROS[]]}; PutInstanceName: PROC[n: Namee] = { FindName: PROC[ntb: Base, nti: NTIndex] RETURNS[stop: BOOL] = { RETURN[ntb[nti].item = n]; }; nti: NTIndex = EnumerateNameTable[FindName]; IF nti = NTNull THEN stream.PutRope[" (anon) "] ELSE PutName[ntb[nti].name]}; EnumerateNameTable: PROC[ proc: PROC[Base, NTIndex] RETURNS[BOOL]] RETURNS[nti: NTIndex] = { FOR nti ฌ NTIndex.FIRST, nti + NTRecord.SIZE UNTIL nti = mob.ntLimit DO IF proc[ntb, nti] THEN RETURN[nti]; ENDLOOP; RETURN[NTNull]}; tb: MobDefs.Base; inner: PROC[ptr: LONG POINTER] = { tb ฌ LOOPHOLE[ptr]; ssb ฌ LOOPHOLE[ptr + mob.ssOffset.units]; ctb ฌ tb + mob.ctOffset.units; mtb ฌ tb + mob.mtOffset.units; IF mob.extended THEN { lfb ฌ tb + mob.lfOffset.units; tfb ฌ tb + mob.tfOffset.units; rfb ฌ tb + mob.rfOffset.units}; itb ฌ tb + mob.impOffset.units; etb ฌ tb + mob.expOffset.units; sgb ฌ tb + mob.sgOffset.units; ftb ฌ tb + mob.ftOffset.units; ntb ฌ tb + mob.ntOffset.units; evb ฌ tb + mob.evOffset.units; spb ฌ tb + mob.spOffset.units; fpb ฌ tb + mob.fpOffset.units; SELECT cmd FROM $Globals => PrintGlobals[]; $Exports, $Unbound => PrintExports[FALSE]; $Mob, $ShortMob => { PrintHeader[]; PrintConfigs[]; PrintImports[]; PrintExports[TRUE]; PrintModules[]; PrintFiles[]; PrintFramePacks[]; PrintSpaces[]}; ENDCASE; }; ssb: MobDefs.NameString ฌ NIL; evb: MobDefs.Base ฌ NIL; spb: MobDefs.Base ฌ NIL; fpb: MobDefs.Base ฌ NIL; ctb: MobDefs.Base ฌ NIL; mtb: MobDefs.Base ฌ NIL; lfb: MobDefs.Base ฌ NIL; tfb: MobDefs.Base ฌ NIL; rfb: MobDefs.Base ฌ NIL; itb: MobDefs.Base ฌ NIL; etb: MobDefs.Base ฌ NIL; sgb: MobDefs.Base ฌ NIL; ftb: MobDefs.Base ฌ NIL; ntb: MobDefs.Base ฌ NIL; dumpLinks: {none, all} ฌ IF cmd # $ShortMob THEN all ELSE none; tb ฌ NIL; inner[mob]; }; -- End of ListMob NameFromIndex: PROC[exstb: SymbolTableBase, index: CARDINAL] RETURNS[ROPE ฌ NIL] = { IF exstb # NIL THEN { btr: LONG POINTER TO BodyRecord = @exstb.bb[RootBti]; ctx: CTXIndex ฌ btr.localCtx; ctxr: LONG POINTER TO CTXRecord = @exstb.ctxb[ctx]; root: ISEIndex = exstb.ctxb[ctx].seList; sei: ISEIndex ฌ root; DO sep: LONG POINTER TO ISERecord ฌ NIL; IF sei = SENull THEN EXIT; sep ฌ @exstb.seb[sei]; SELECT TRUE FROM ~sep.mark4 OR SymbolOps.LinkMode[exstb, sei] = $manifest => {}; index = LOOPHOLE[sep.idValue, CARD] => { ros: STREAM = IO.ROS[]; MobListerUtils.PrintSei[sei, ros, exstb]; SELECT TRUE FROM sep.idType = typeTYPE => {}; sep.constant => ros.PutRope[" [inline]"]; ENDCASE; RETURN[ros.RopeFromROS[]]; }; ENDCASE; IF (sei ฌ SymbolOps.NextSe[exstb, sei]) = root THEN EXIT; ENDLOOP; }; RETURN[IO.PutFR1["* * * * item %g", [cardinal[index]]]]}; }. ฎ MobListerImpl.mesa Copyright ำ 1985, 1991 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) October 17, 1985 4:33:46 pm PDT Satterthwaite March 7, 1986 5:41:38 pm PST Andy Litman May 27, 1988 10:57:41 am PDT JKF February 24, 1989 11:32:09 am PST Last tweaked by Mike Spreitzer on November 15, 1989 9:20:01 am PST Willie-s, February 11, 1991 6:40 pm PST Michael Plass, November 26, 1991 4:32 pm PST check for leading & Counts all of the procedures No symbols, so say so We have to pull in the symbols from the file system. Consistency check failed! exmob _ NIL; Utility Prints Utility Puts Executable part of ListMob PrintExpVars[]; Table Bases We found the item! ส%ฒ–(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ ฯeœ7™BKšœฯkœž™3Kšฯy'ะky™*KšŸ% ™(Kšžœ"™%K™BK™'K™,K˜—šž ˜ Kšœžœ˜KšžœžœCžœžœ˜XKšœžœา˜฿Kšœ žœ˜KšœžœT˜hKšœ žœ˜Kšœžœžœ˜(Kšœ žœFžœ.˜†Kšœžœห˜ุKšœžœ˜ขKšœ žœ˜'Kšœžœ'˜?Kšœžœ˜—K˜šฯn œž˜Kšžœžœ!˜+Kšžœ˜"K˜Kšœžœžœžœ˜ Kšœžœ˜*Kšœžœ!˜6Kšœ žœ˜Kšœ žœ&˜7K˜š กœžœžœžœžœ˜3Kšžœ0˜6—š กœžœžœžœžœ˜3Kšžœ0˜6—Kšœžœ˜Kšœžœ˜Kšœ žœ˜&Kšœ žœ˜&šœ žœ˜ Kšกœ˜#—Kšœ žœ˜"šœžœ˜*Kšœ˜—šœ žœ˜"Kšกœ˜$Kšœ&˜&—šœ žœ˜ Kšกœ˜!—Kšœ žœ˜"šœ žœ˜"Kšกœ˜$—Kšœ žœ˜$šœ žœ˜ Kšกœ˜!—Kšœ žœ˜"Kšœ žœ˜"Kšœ žœ˜ Kšœ žœ˜$Kšœ žœ˜ Kšœ žœ˜"šœ žœ˜ Kšกœ˜!Kšกœ˜!—Kšœ žœ˜"Kšœ žœ˜ šœ žœ˜"Kšกœ˜$—Kšœ žœ˜šœ žœ˜ Kšกœ˜!—Kšœ žœ˜"šœžœ˜Kšœ"˜"—Kšœžœ˜Kšœ žœ˜&Kšœ žœ˜&šœ žœ˜ Kšกœ˜!—Kšœ žœ˜"Kšœ žœ˜"Kšœ žœ˜$Kšœ žœ˜ Kšœ žœ˜"Kšœžœžœ˜Kšœ žœžœ ˜!Kšœ žœžœ ˜!šœ žœ˜ Kšกœ˜!—Kšœ žœ˜$Kšžœžœžœ˜šœ žœ˜ Kšกœ˜!—Kšœ žœ˜"šœ žœ˜ Kšกœ˜!—Kšœ žœ˜"Kšœ žœ˜ Kšœ žœ˜ Kšœ žœ˜"Kšžœžœžœžœ˜Kšœžœžœ˜/Kšœžœžœ)˜Hšœ žœ˜ Kšกœ˜!—Kšœ žœ˜"šœ žœ˜"Kšกœ˜$—Kšœ žœ˜$Kšœžœ˜*K˜—š กœžœžœ žœžœžœ˜LK˜šก œžœ˜Kšœ˜š žœžœžœžœž˜TKšœžœžœžœ˜*š žœžœžœžœžœž˜:Kšžœžœ˜ —Kšžœžœ<˜TKšœ˜Kšœ˜šžœ˜K˜—Kšžœ˜—Kšœ!˜!šžœžœ žœ ž˜WKšžœž˜Kšœžœžœžœ˜*Kšžœžœžœžœžœžœžœžœ˜GKšžœžœ<˜TK˜K˜šžœ˜K˜—Kšžœ˜—Kšœ!˜!šžœžœžœž˜NKšœžœžœžœ˜)Kšžœžœžœžœžœžœžœžœ˜FKšžœžœ=˜UK˜K˜šžœ˜K˜—Kšžœ˜—šœ˜K˜——šก œžœ%˜7šžœž˜Kšœ#˜#Kšœ#˜#šžœ˜ Kšœžœžœžœ˜*Kšžœžœ1˜IKšœ˜Kšœ2˜2——Kšœ˜K˜—šก œžœ˜Kšœ=˜=Kšœ8˜8Kšœ8˜8Kšœ8˜8Kšœ8˜8Kšœ;˜;Kšžœžœ˜.Kšœ ˜ Kšžœžœ˜-Kšœ˜Kšžœžœ˜/Kšœ"˜"Kšžœžœ˜.Kšœ!˜!Kšžœžœ˜1Kšœ$˜$Kšžœžœ˜2Kšœ%˜%Kšžœžœ˜+Kšœ˜Kšžœžœ˜+Kšœ ˜ K˜—šก œžœ˜Kšœžœ˜KšœF˜Fšžœž˜K˜Kšœžœžœ˜:Kšžœžœžœžœžœžœžœžœ˜Fšžœ˜K˜—Kšžœ˜—Kšœ˜K˜—šก œžœ˜#Kšœžœžœžœ˜*K˜Kšœ˜Kšœžœ˜šžœžœ˜Kšœ$˜$Kšœ$˜$—Kšœ˜K˜Kšœžœ ˜#šžœžœ˜Kšœ˜Kšœ˜Kšœžœ˜—Kšœ;˜;šžœžœ˜Kšœ˜šžœžœžœž˜(Kšžœžœžœžœ˜5šžœžœž˜#šœ ˜ Kšœ˜Kšœžœ ˜!—šœ ˜ Kšœ˜Kšœ˜Kšœžœ ˜!—Kšžœžœ˜—Kšžœ˜ ——Kšœ˜K˜—šก œžœ˜Kšœžœ˜Kšœ@˜@šžœž˜K˜Kšœžœ˜Kšžœžœžœžœžœžœžœžœ˜Gšžœ˜K˜—Kšžœ˜—Kšœ˜K˜—šก œžœ˜$Kšœžœžœžœ˜+K˜Kšœ˜Kšœžœ˜Kšžœžœ˜7šžœžœ˜Kšœ$˜$Kšœ$˜$—Kšœ˜Kšœ˜Kšœžœ ˜#KšœM˜MK˜—šก œžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœžœžœ˜+Kš œžœžœžœ žœžœ˜Cšžœžœžœž˜NKšœžœžœžœ˜*Kšœ žœ˜ Kšœžœ˜šกœžœ˜*šกœžœžœ žœ ˜Ašžœžœž˜%Kšœ*˜*Kšžœ˜—Kšœ˜—šก œžœžœ žœ ˜AšžœS˜VKšžœž˜Kšžœžœ žœ˜IKšžœ˜—Kšœ˜—šกœžœžœžœ˜9KšœE˜EKšœžœO˜YKšœ1˜1Kšœ˜šžœžœ˜'Kšœ™KšœH˜Hšžœžœžœ˜3Kšœžœžœžœ˜Kšœžœžœ˜Kšœ,˜,Kšœ˜šžœ*žœžœž˜@šžœžœ˜'Kšœ)˜)Kšœ(˜(Kšžœžœ˜ —Kšžœ˜—Kšœ žœ2˜CKšžœ ˜K˜—K˜—Kšœ/˜/Kšœ)˜)Kšžœ˜$—š ก œžœžœžœžœ˜5Kšœ™Kšœžœ˜/Kšœ˜šž˜šžœžœž˜&Kšœ žœžœ žœ ˜.Kšžœ˜—Kšžœ+žœ˜Pšžœž˜K˜ Kšœ!˜!Kšžœžœžœ˜$Kšžœ&žœžœ˜2Kšžœ˜—Kšžœ˜—Kšœ˜—Kšœžœ ˜"Kš œžœฯcœžœžœ˜FKšœ žœ˜$K˜K˜šžœ žœžœ˜Kšœ™KšœF˜FKšžœ˜—K˜KšœM˜Mšžœžœ˜Kšœ(˜(Kšœ žœ˜*—šžœžœ˜Kšœ&˜&Kšœ žœ˜+—šžœ$žœ˜,Kšœ7˜7Kšœ žœ0˜=—šžœ"ž˜(Kšœ>˜>—šžœžœž˜9šœ ˜ K˜3K˜ ——Kšœ˜Kšœ˜—Kšžœžœžœžœžœžœžœžœ˜FKšžœžœ<˜UK˜K˜!K˜K˜K˜ K˜Kšœ"˜"K˜šžœ žœ˜Kšœ ˜ šœPžœ˜UKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜——šžœ˜šœN˜NKšœ˜Kšœ˜Kšœ˜—˜K˜——Kšœ˜Kšœ˜K˜ K˜ K˜šžœ˜K˜—Kšžœ˜—šžœ žœ˜šœPžœ˜UKšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—Kšœ"˜"šžœ*žœžœž˜@šœ˜KšœR˜R—Kšžœ˜—K˜—K˜K˜—šกœžœžœ˜SKšœžœžœžœ˜)Kšžœžœžœžœ˜$šžœ˜Kšœžœ˜Kšœžœžœžœ˜.Kšœžœ$˜/Kšœžœ%˜0Kšœ˜Kš žœ žœžœžœžœžœ˜Jšžœžœ˜Kšœ4™4Kšœžœžœžœ˜/Kšœ žœ'˜5KšœBžœžœ ˜PK˜—Kšžœžœ8˜MKšœ˜Kšžœ žœ˜.K˜—šž˜Kšœžœ˜—K˜K˜—Kšžœžœžœ˜#K˜š ก œžœžœžœžœ˜GKšœžœžœ˜Kšœžœ˜5Kšœžœ˜5Kšœžœžœ)žœžœข žœ žœ˜Kš œžœžœžœžœ˜KKšžœžœžœข˜1Kš žœžœžœžœข ˜Mšžœ,ž˜2K™Kšžœข˜—Kšœ˜K˜ Kšœ˜K˜—š ก œžœžœžœžœžœ˜9Kšœžœžœ˜Kšœžœ˜%Kšœžœžœžœ˜.Kšœžœžœ˜$Kšœžœ˜ K˜"KšœN˜NKšœM˜MKšœN˜NKšœQ˜QKšœN˜NKšœQ˜QKšœQ˜QKšœO˜OKšœP˜PKšœQ˜QKšœ0˜0Kšœ9˜9K˜.šžœžœ˜#šžœ˜Kšœžœ˜Kšœžœ˜Kšœ˜—šžœ˜KšœF˜FKš œžœžœžœžœžœ˜ZKšœ˜Kšœž œ˜2Kšœ˜——Kšžœ˜K˜K˜—šก œžœžœ˜)Kšœžœ˜Kšžœ žœA˜Tšžœž˜K˜Kšœ$žœ žœ˜:Kšžœžœžœžœžœžœžœžœ˜Gšžœ˜K˜—Kšžœ˜—Kšžœžœ˜,Kšœ˜K˜—šก œžœ˜$Kšœžœžœžœ˜+Kšœžœ˜K˜Kšœ˜Kšœžœ˜Kšžœžœ˜7šžœžœ˜Kšœ$˜$Kšœ$˜$—Kšœ˜Kšœ˜Kšœžœ ˜#Kšœ˜Kšžœžœ˜/KšœA˜Ašžœžœ˜Kšœ žœ1˜>Kšœ1˜1Kšœžœ˜šœžœ˜'šžœžœžœ ž˜K˜Kšœžœ˜%Kšœ žœ"žœ˜7Kšœ žœžœžœ ˜3Kš žœžœžœ žœžœ˜.Kšœ*˜*Kšžœ žœ"˜3Kšœ˜Kšžœžœžœ˜Kšœ˜šžœ ž˜˜KšœO˜O—˜Kšœ2˜2—šžœ˜ KšœN˜N——Kšžœ˜—Kšœข˜—Kšœ˜KšœBžœ˜Lšžœžœž˜šœžœ˜Kšœ˜Kšœ ˜ Kšœžœ˜ —šœ˜Kšœ˜Kšœ˜Kšœ3˜3Kšœ#˜#Kšœ0˜0Kšœ˜Kšœ ™ Kšœžœ˜ Kšœ˜—šžœ˜ K˜K˜——Kšžœ žœ9žœ˜TKšœ˜K˜—Kšœ˜K˜—šก œžœ˜Kšœžœ˜K˜Kšœ(˜(šžœž˜K˜Kšœžœžœ žœ˜7Kšžœ˜—Kšœ˜K˜—šก œžœ˜#Kšœžœžœžœ˜*K˜Kšœ4žœžœ˜cšžœžœžœž˜%Kšžœžœžœžœ˜3Kšœ/˜/Kšžœžœ˜*Kšžœ˜—Kšœ˜K˜—šก œžœ˜Kšœžœ˜K˜Kšœ˜šžœž˜K˜Kšœžœžœ˜9Kšžœ˜—Kšœ˜K˜—šก œžœ˜"Kšœžœžœžœ˜*K˜Kšœžœžœ˜$Kšœ*žœ žœ˜EKšœ:˜:Kšžœžœ"˜8šžœžœžœž˜%K˜Kšœ˜Kšœ˜Kšœ˜Kšžœžœ˜3Kšœt˜tKšžœ˜—šœ˜K˜——šก œžœ˜Kšœžœ˜Kšœ?˜?šžœž˜K˜K˜Kšžœžœžœžœžœžœžœžœ˜Fšžœ˜K˜—Kšžœ˜—Kšœ˜K˜—š ก œžœžœžœžœ˜BK˜Kšœ˜Kšœžœ˜šžœžœ˜Kšœ"˜"Kšœ$˜$—Kšœ˜Kšœ˜Kšœžœ ˜#šžœžœ˜Kšœ˜Kšœ˜Kšœžœ˜&—K˜Kšžœžœ"žœ˜?˜šก œžœžœ žœ˜*Kšžœžœ*˜8K˜—Kšœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ)˜)Kšœ˜Kšœ˜Kšœ˜—Kšžœžœ6˜NKšžœžœ$˜=K˜Kšœ}˜}Kšžœžœžœ˜WK˜Kšœ6˜6Kšœb˜bKšžœžœ ˜:Kšžœžœ˜3K˜Kšœ˜Kšœ˜šžœžœ˜ Kšœ˜šœ ˜ Kšœ&žœžœ˜G—Kšœ˜—šž˜˜K˜K˜K˜šžœžœ˜K˜Kšœ;˜;—K˜K˜—Kšžœ˜—Kšœ˜K˜—šกœžœžœžœ˜+Kšžœ žœ˜šœ˜K˜——šก œžœ˜"Kšœ˜Kšžœžœ˜+šžœ˜Kšœ)˜)šžœžœ˜Kšœ˜šžœžœžœž˜*Kšžœžœžœžœ˜3K˜#Kšžœžœ˜3Kšžœ˜—Kšœ˜—Kšœ˜—šœ˜K˜——šก œžœ˜"Kšœ˜Kšžœžœ˜+šžœ˜KšœX˜Xšžœžœ˜Kšœ˜šžœžœžœž˜*Kšžœžœžœžœ˜3Kšœ3˜3Kšžœžœ˜3Kšžœ˜—Kšœ˜—Kšœ˜—šœ˜K˜——šก œžœ˜$Kšœ˜Kšžœžœ˜+šžœ˜KšœX˜Xšžœžœ˜Kšœ˜šžœžœžœž˜*Kšžœžœžœžœ˜3Kšœ3˜3Kšžœžœ˜3Kšžœ˜—Kšœ˜—Kšœ˜—šœ˜K˜——šกœžœ˜Kšœžœ˜K˜Kšœ!˜!šžœž˜K˜Kšœžœžœ˜9Kšžœ˜—Kšœ˜K˜—šกœžœ˜&Kšœžœžœžœ˜*K˜Kšœ˜Kšœ8žœžœ˜gšžœžœžœž˜%Kšžœžœžœžœ˜3Kšœ"˜"Kšœžœ˜)Kšžœžœžœ˜4Kšžœ˜—Kšœ˜K˜—šก œžœ˜$Kšžœžœ˜-šžœ˜K˜KšœŒ˜Œšžœž˜%KšœM˜M—Kšœ˜—˜K˜——šก œžœ˜Kšœžœ˜Kšœ=˜=šžœž˜K˜Kšœžœ˜š žœžœžœžœžœžœ˜;Kšœ˜Kšžœ˜—Kšžœ˜—Kšœ˜K˜—šก œžœ˜!Kšœ˜šžœž˜Kšœ#˜#Kšœ#˜#šžœ˜ Kšœžœžœžœ˜*Kšœ˜Kšœžœ˜Kšœ˜Kšœ2˜2——˜K˜——Kšœ™K˜šกœžœ˜&šžœ ž˜˜KšœO˜O—˜Kšœ2˜2—šžœ˜ KšœN˜N——K˜K˜—šก œžœ˜%šžœž˜Kšœ#˜#Kšœ#˜#Kšžœ˜"—šœ˜K˜——šก œžœžœ˜%Kšœ+˜+—šกœžœžœ˜%Kšœ*˜*K˜—šก œžœ˜K˜Kšœ-˜-K˜K˜—šกœžœžœ˜Kšœ˜Kšžœ žœžœ˜0Kšžœžœžœžœ˜4K˜—Kšœ ™ K˜šกœžœ˜ Kšœ žœžœžœžœžœžœžœžœ˜BKš œžœžœžœ žœ˜,Kšœžœ˜Kšœžœ˜šžœžœžœž˜%Kšœ˜Kšžœ˜ —K˜—šก œžœžœžœ˜1Kšœ žœžœžœžœžœžœžœžœ˜BKš œžœžœžœ žœ˜,Kšœžœ˜Kšœžœ˜Kšœžœžœžœ˜šžœžœžœž˜%Kšœ˜Kšžœ˜—Kšžœ˜K˜—šกœžœ˜#šกœžœžœžœ˜?Kšžœ˜Kšœ˜—K˜,Kšžœžœžœ˜MK˜—šกœžœ˜Kš œžœžœžœžœ˜Bš žœžœžœžœž˜GKšžœžœžœ˜$Kšžœ˜—šžœ ˜K˜——Kšœ™Kšœ˜šœžœžœžœ˜"Kšœžœ˜Kšœžœ˜)K˜K˜šžœžœ˜K˜K˜K˜—K˜K˜K˜K˜K˜K˜K˜K˜šžœž˜šœ ˜ Kšœ˜—šœ˜Kšœ žœ˜—˜Kšœ˜K˜K˜Kšœ žœ˜K™K˜K˜ K˜K˜—Kšžœ˜—K˜—šœ ™ Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜Kšœžœ˜—Kšœžœžœžœ˜?Kšœžœ˜ Kšœ ˜ Kšœข˜K˜—šก œžœ žœ˜