DIRECTORY Basics USING [LongNumber, ShortNumber, BITAND], IO, Rope, VM USING [AddressForPageNumber, SimpleAllocate], MicroDefs, MicroGlobalVars, MicroOps, -- lots and lots MicroUtils USING [ AtomAtPointer, GetCharAtPointer, GetSymbolMemSink, GetSymbolMemSource, MoveBlock, PutCharAtPointer]; MicroProcessImpl: CEDAR PROGRAM IMPORTS Basics, IO, Rope, VM, MicroDefs, MicroGlobalVars, MicroOps, MicroUtils EXPORTS MicroOps = BEGIN OPEN MicroDefs, MicroGlobalVars; expansionPtr: LONG POINTER TO WORD _ NIL; stmtTooLong: ROPE = "Statement too long\n"; ExpandLength: PUBLIC PROC[aPtr: LONG POINTER TO WORD, lx: INTEGER] RETURNS[len: INTEGER] = TRUSTED { ptr: LONG POINTER TO WORD _ aPtr + lx; any: BOOL _ FALSE; len _ lx; UNTIL ptr = aPtr DO ptr _ ptr - 1; IF ptr^ >= 40B THEN LOOP; any _ TRUE; len _ ExpandSize[(ptr-1)^, ptr^] + len - 2; ptr _ ptr - 1; ENDLOOP; RETURN[IF any THEN len ELSE - 1]; }; Expand: PUBLIC PROC[argRef: ArgRef] RETURNS[didExpansion: BOOL] = TRUSTED { len: INTEGER; rPtr, ptr: LONG POINTER TO WORD; aPtr: LONG POINTER TO WORD _ argRef.aPtr; lx: INTEGER _ argRef.lx; IF lx < 2 THEN RETURN[FALSE]; len _ ExpandLength[aPtr, lx]; IF len = -1 THEN RETURN[FALSE]; rPtr _ expansionPtr+len; -- temp storage for expansion ptr _ aPtr + lx; UNTIL ptr = aPtr DO ptr _ ptr - 1; IF ptr^ >= 40B THEN { rPtr _ rPtr - 1; rPtr^ _ ptr^} ELSE { n: INTEGER = ExpandSize[(ptr-1)^, ptr^]; rPtr _ rPtr - n; ExpandValue[(ptr-1)^, ptr^, rPtr]; ptr _ ptr - 1; }; ENDLOOP; argRef.aPtr _ expansionPtr; argRef.lx _ len; RETURN[TRUE]; }; ProcessOneClause: PUBLIC PROC[evalMode: EvalMode] = TRUSTED { val: INTEGER; typ: SymbolType; oldTailTop: NAT = stmtTailTop; oldTailBottom: NAT = stmtTailBottom; gotoOuter: BOOL _ FALSE; stmtTailTop _ stmtTailBottom; DO -- lp label in micproc.pr1 { terminator: CHAR; tailOld: NAT _ stmtTailBottom; [] _ LexicalScan[FALSE, stmtTailTop]; terminator _ MicroOps.GetStmtChar[stmtBufferTop-1]; IF stmtTailBottom # tailOld THEN { IF ( MicroOps.GetStmtValue[stmtTailTop-1] < 40B) AND (tailOld # stmtTailTop) THEN { thisBot: NAT= stmtTailBottom; ExpandTail[stmtTailTop]; tailOld _ tailOld + stmtTailBottom - thisBot; -- adjust for expanded value }; DO -- sym label in micproc.pr1 tailNew: NAT _ stmtTailBottom; addr: NAT _ stmtTailBottom; nChars: NAT _ tailOld - stmtTailBottom; symIndex: INTEGER; sAtom: ATOM; stmtTailBottom _ tailOld; IF MicroOps.GetStmtValue[tailOld-1] < 40B THEN { SELECT MicroOps.GetStmtChar[tailOld-1] FROM symc => symIndex _ MicroOps.GetStmtInteger[tailOld-2]; < 40C => symIndex _ 1; ENDCASE => [symIndex, sAtom] _ MicroOps.LookupSymbol[stmtBuffer+addr, nChars]; } ELSE [symIndex, sAtom] _ MicroOps.LookupSymbol[stmtBuffer+addr, nChars]; SELECT symIndex FROM 0 => { numOK: BOOL _ FALSE; IF MicroOps.GetStmtChar[tailOld-1] = '_ THEN { symIndex _ MicroOps.LookupSymbol[stmtBuffer+addr, nChars-1].symIndex; IF (symIndex # 0) AND (MicroOps.GetSymbol[symIndex].sType = addressType) THEN { aPtr: LONG POINTER TO WORD _ MicroOps.ArgString[2]; aPtr^ _ symIndex; MicroUtils.PutCharAtPointer[aPtr+1, symc]; MicroOps.MacroCall[MicroUtils.GetSymbolMemSink[symIndex], 1]; GOTO loop; }; } ELSE { -- Try for a number sgn: NAT _ 0; ovf: BOOL _ FALSE; addr1, end: NAT; char: CHAR; val _ 0; IF (char _ MicroOps.GetStmtChar[addr]) = '- THEN sgn _ 1; addr1 _ addr + sgn; end _ addr + nChars; WHILE (addr1#end) AND ((char _ MicroOps.GetStmtChar[addr1]) IN ['0..'7]) DO IF Basics.BITAND[LOOPHOLE[val], 160000B]#0 THEN ovf _ TRUE; val _ val*8 + (char - '0); addr1 _ addr1 + 1; ENDLOOP; IF addr1#(addr+sgn) THEN { -- some digits IF addr1 = end THEN { -- all digits IF ovf THEN { IF sAtom = NIL THEN sAtom _ MicroUtils.AtomAtPointer[stmtBuffer+addr, nChars]; MicroOps.ReportError[ IO.PutFR["\n *** Integer %g too large\n", IO.atom[sAtom] ], FALSE]; }; IF sgn # 0 THEN val _ -val; typ _ integerType; numOK _ TRUE; } ELSE { -- literal LiteralSplit[addr, nChars, addr1-addr]; GOTO loop; }; }; IF ~numOK THEN { -- Undefined symbol IF sAtom = NIL THEN sAtom _ MicroUtils.AtomAtPointer[stmtBuffer+addr, nChars]; IF evalMode # fieldStoreVal THEN { MicroOps.ReportError[ IO.PutFR["\n *** %g undefined\n", IO.atom[sAtom] ], FALSE]; GOTO loop; }; val _ MicroOps.PutInSymbol[sAtom, typ _ undefnType].symIndex; }; }; }; -- ends ePtr = 0 1 => { -- encoded number val _ MicroOps.GetStmtInteger[tailOld-2]; typ _ integerType; }; ENDCASE => { -- dispatch on symbol type typ _ MicroOps.GetSymbol[symIndex].sType; SELECT TRUE FROM typ = macroType => { MicroOps.MacroCall[symIndex, 0]; GOTO loop; }; typ = addressType => { IF evalMode = accumulateVal THEN TRUSTED { aPtr: LONG POINTER TO WORD _ MicroOps.ArgString[2]; aPtr^ _ symIndex; MicroUtils.PutCharAtPointer[aPtr+1, symc]; MicroOps.MacroCall[MicroUtils.GetSymbolMemSource[symIndex], 1]; GOTO loop; }; val _ symIndex; typ _ addressType; }; (typ = integerType) AND (evalMode # accumulateVal) => val _ LOOPHOLE[MicroOps.GetSymbol[symIndex].sVal, INTEGER]; (typ = undefnType) AND (evalMode = fieldStoreVal) => val _ symIndex; typ = neutralType => { stmtTailBottom _ tailNew; IF tailOld # stmtTailTop THEN { tailOld _ stmtTailTop; LOOP; }; }; ENDCASE => { MicroOps.ReportError[ IO.PutFR["\n *** Symbol %g not legal as token\n", IO.rope[MicroOps.GetSymbol[symIndex].name] ], FALSE]; GOTO loop; }; }; EXIT; ENDLOOP; -- second DO, corresponds to sym in micproc IF tailOld # stmtTailTop THEN MicroOps.ReportError["\n ***Bad syntax where value required\n", FALSE] ELSE IF (typ # neutralType) AND (terminator # sepc) THEN { stmtTailBottom _ tailOld - 2; MicroOps.PutStmtValue[stmtTailBottom, LOOPHOLE[typ, WORD]]; MicroOps.PutStmtInteger[stmtTailBottom+1, val]; }; }; -- end of if stmtTailBottom # tailOld stmtBufferTop _ stmtBufferTop - 1; IF (terminator # '() AND (terminator # endc) THEN { IF terminator = ', THEN { stmtTailBottom _ oldTailBottom; stmtTailTop _ oldTailBottom}; LOOP; }; stmtTailTop _ oldTailTop; RETURN; EXITS loop => {}; }; ENDLOOP; }; ProcessStmt: PUBLIC PROC[sPtr: LONG POINTER TO WORD, lx: INTEGER, mode: EvalMode] RETURNS[typ: SymbolType, val: WORD] = TRUSTED { old: NAT; IF (lx = 2) AND ((MicroUtils.GetCharAtPointer[sPtr+1] = numc) OR (MicroUtils.GetCharAtPointer[sPtr+1] = num6c)) THEN RETURN[integerType, sPtr^]; IF stmtBufferTop+lx+1 > stmtTailBottom THEN { MicroOps.ReportError[stmtTooLong, FALSE]; RETURN[undefnType, 0]; }; MicroOps.PutStmtChar[stmtBufferTop, '( ]; MicroUtils.MoveBlock[to: stmtBuffer+stmtBufferTop+1, from: sPtr, num: lx]; stmtBufferTop _ stmtBufferTop+lx+1; old _ stmtTailBottom; ProcessOneClause[mode]; IF stmtTailBottom = old THEN { typ _ integerType; val _ 0 } ELSE { typ _ GetStmtTypeAtPos[old-2]; val _ MicroOps.GetStmtValue[old-1]; }; stmtTailBottom _ old; }; EvalArg: PUBLIC PROC[argP: LONG POINTER TO WORD, lx: INTEGER] RETURNS[val: WORD] = TRUSTED { old: NAT; useArgP: LONG POINTER TO WORD _ argP; IF (lx=2) AND ((argP+1)^ < 40B) THEN { -- quick check for number valc: CHAR = MicroUtils.GetCharAtPointer[argP+1]; SELECT valc FROM numc, num6c => RETURN[argP^]; symc => { symb: SymbolObj = MicroOps.GetSymbol[argP^]; IF symb.sType = integerType THEN RETURN[symb.sVal] }; ENDCASE => ERROR; }; IF stmtBufferTop + lx + 1 > stmtTailBottom THEN { MicroOps.ReportError[stmtTooLong, FALSE]; RETURN[0] }; [] _ MicroOps.PushStmtChar['( ]; FOR j: NAT IN [0.. lx) DO [] _ MicroOps.PushStmtValue[useArgP^]; useArgP _ useArgP + 1; ENDLOOP; old _ stmtTailBottom; ProcessOneClause[returnVal]; IF stmtTailBottom = old THEN val _ 0 ELSE { IF GetStmtTypeAtPos[old-2] # integerType THEN MicroOps.ReportError[ IO.PutFR["\n *** Arg %g does not yield integer value\n", IO.atom[MicroUtils.AtomAtPointer[argP, lx]] ], FALSE]; val _ MicroOps.GetStmtValue[old-1]; }; stmtTailBottom _ old; RETURN[val]; }; ExpandSize: PROC[val: WORD, valC: INTEGER] RETURNS[len: INTEGER] = { vc: Basics.ShortNumber = LOOPHOLE[valC]; vcx: CHAR = LOOPHOLE[vc.lo, CHAR]; SELECT vcx FROM symc => RETURN[Rope.Length[MicroOps.GetSymbol[LOOPHOLE[val, INTEGER]].name]]; num6c => RETURN[6]; numc => { len _ 0; DO val _ val/8; len _ len +1; IF val = 0 THEN RETURN[len]; ENDLOOP; }; ENDCASE => RETURN[0]; }; ExpandToRope: PROC[val: WORD, valC: INTEGER] RETURNS[rep: ROPE] = { vc: Basics.ShortNumber = LOOPHOLE[valC]; vcx: CHAR = LOOPHOLE[vc.lo, CHAR]; SELECT vcx FROM symc => rep _ MicroOps.GetSymbol[LOOPHOLE[val, INTEGER]].name; num6c, numc => { ln: Basics.LongNumber; ln.hi _ 0; ln.lo _ LOOPHOLE[val]; rep _ IO.PutFR["%b", IO.int[LOOPHOLE[ln]]]; }; ENDCASE => ERROR MicroDefs.Error["ExpandValue error"]; }; ExpandValue: PROC[val: WORD, valC: INTEGER, ptr: LONG POINTER TO WORD _ NIL] = TRUSTED { name: ROPE _ ExpandToRope[val, valC]; len: NAT _ name.Length[]; IF ptr = NIL THEN { offset: NAT _ stmtTailBottom - len; IF offset <= stmtBufferTop THEN { MicroOps.ReportError[stmtTooLong, FALSE]; RETURN }; stmtTailBottom _ offset; ptr _ stmtBuffer + offset; }; FOR i: NAT IN [0 .. len) DO MicroUtils.PutCharAtPointer[ptr, name.Fetch[i]]; ptr _ ptr + 1; ENDLOOP; }; ExpandTail: PROC[thisTop: NAT] = { nowBottom: NAT; len: NAT = thisTop - stmtTailBottom - 2; temp: IntegerSeq _ NEW[IntegerSeqRec[len]]; FOR i: NAT IN [0..len) DO TRUSTED { temp[i] _ MicroOps.GetStmtInteger[stmtTailBottom+i] }; ENDLOOP; stmtTailBottom _ thisTop; ExpandValue[MicroOps.GetStmtValue[thisTop-2], MicroOps.GetStmtInteger[thisTop-1]]; IF (nowBottom _ stmtTailBottom - len) < stmtBufferTop THEN MicroOps.ReportError[stmtTooLong, FALSE] ELSE { FOR i: NAT IN [0..len) DO MicroOps.PutStmtInteger[nowBottom+i, temp[i]]; ENDLOOP; stmtTailBottom _ nowBottom; }; }; LexicalScan: PROC[symFlag: BOOL, thisTop: NAT] RETURNS[ePtr: INTEGER, symb: ATOM] = { tailOrigin: NAT _ stmtTailBottom; lexicalLen: NAT; thisChar: CHAR; DO thisChar _ MicroOps.GetStmtChar[stmtBufferTop _ stmtBufferTop - 1]; SELECT thisChar FROM ') => { parenTop: NAT _ stmtTailBottom; ProcessOneClause[accumulateVal]; IF ( MicroOps.GetStmtValue[parenTop-1] < 40B) AND (stmtTailBottom#parenTop) AND (parenTop#thisTop) THEN ExpandTail[parenTop]; }; ': => { nextEp: INTEGER; symb: ATOM; sObj: SymbolObj; type: SymbolType; [nextEp, symb] _ LexicalScan[TRUE, stmtTailBottom]; sObj _ MicroOps.GetSymbol[nextEp]; type _ sObj.sType; IF (nextEp=0) OR (type=nullType) OR (type=undefnType) THEN MicroOps.LabelDefn[nextEp, symb] ELSE { tag: ROPE = "\n *** Tag %g already defined\n"; IF nextEp = 0 THEN MicroOps.ReportError[IO.PutFR[tag, IO.atom[symb] ], FALSE] ELSE MicroOps.ReportError[IO.PutFR[tag, IO.rope[sObj.name] ], FALSE]; }; }; '(, ',, endc => { -- rightParen, comma, cr stmtBufferTop _ stmtBufferTop + 1; EXIT }; '] => { numArgs: INTEGER _ MicroOps.CollectArgs[]; symb: ATOM; nextEp: INTEGER; [nextEp, symb] _ LexicalScan[TRUE, stmtTailBottom]; IF nextEp = 0 THEN MicroOps.ReportError[ IO.PutFR["\n *** Macro Name %g not defined\n", IO.atom[symb] ], FALSE] ELSE MicroOps.MacroCall[nextEp, numArgs]; }; '_ => { IF stmtTailBottom = tailOrigin THEN { stmtTailBottom _ stmtTailBottom - 1; MicroOps.MoveValueInStmtBuffer[from: stmtBufferTop, to: stmtTailBottom]; LOOP; }; MicroOps.PutStmtChar[stmtBufferTop+1, sepc]; stmtBufferTop _ stmtBufferTop + 2; EXIT; }; sepc => LOOP; symc, numc, num6c => TRUSTED { -- encoded value IF stmtTailBottom = thisTop THEN { stmtTailBottom _ stmtTailBottom - 1; MicroOps.MoveValueInStmtBuffer[to: stmtTailBottom, from: stmtBufferTop]; stmtBufferTop _ stmtBufferTop - 1; stmtTailBottom _ stmtTailBottom - 1; MicroOps.MoveValueInStmtBuffer[to: stmtTailBottom, from: stmtBufferTop]; LOOP; }; stmtBufferTop _ stmtBufferTop - 1; ExpandValue[MicroOps.GetStmtValue[stmtBufferTop], MicroOps.GetStmtInteger[stmtBufferTop+1]]; }; ENDCASE => TRUSTED { stmtTailBottom _ stmtTailBottom - 1; MicroOps.MoveValueInStmtBuffer[to: stmtTailBottom, from: stmtBufferTop]; }; ENDLOOP; lexicalLen _ tailOrigin - stmtTailBottom; IF lexicalLen = 0 THEN { IF symFlag THEN MicroOps.ReportError["\n ***Missing Macro name or Tag symbol\n", FALSE]; RETURN[0, NIL]; }; IF MicroOps.GetStmtValue[tailOrigin-1] < 40B THEN { val: INTEGER _ MicroOps.GetStmtInteger[tailOrigin-2]; valc: CHAR _ MicroOps.GetStmtChar[tailOrigin-1]; IF lexicalLen = 2 THEN { IF symFlag THEN stmtTailBottom _ tailOrigin; IF valc = symc THEN { IF val < 256 THEN MicroDefs.Error[" Bad symIndex - LexicalScan"]; RETURN[val, NIL]; }; IF symFlag THEN MicroOps.ReportError["\n ***Found number instead of symbol\n", FALSE]; RETURN[0, NIL]; }; ExpandTail[tailOrigin]; lexicalLen _ tailOrigin - stmtTailBottom; }; IF ~symFlag THEN RETURN[0, NIL]; stmtTailBottom _ tailOrigin; [ePtr, symb] _ MicroOps.LookupBufferSymbol[stmtTailBottom-lexicalLen, lexicalLen]; IF ePtr # 0 AND ePtr < 256 THEN MicroDefs.Error[" Bad symIndex - LexicalScan"]; RETURN[ePtr, symb]; -- so can set breakpoint here }; LiteralSplit: PROC[addr: NAT, nChars, kx: INTEGER] = TRUSTED { temp: LONG POINTER TO WORD; ePtr: INTEGER; eName: ATOM; n: INTEGER; i: INTEGER _ 0; IF MicroOps.GetStmtChar[addr] = '- THEN { -- move - from numeric part to symbol kx _ kx - 1; MicroUtils.MoveBlock[to: stmtBuffer+addr, from: stmtBuffer+addr+1, num: kx]; MicroOps.PutStmtChar[addr+kx, '-]; }; n _ LOOPHOLE[Basics.BITAND[LOOPHOLE[kx-1, WORD], 3], INTEGER] + 1; WHILE i < kx DO temp _ MicroOps.ArgString[n]; TRUSTED { FOR j: INTEGER IN [0..n) DO (temp+j)^ _ MicroOps.GetStmtInteger[addr+i+j]; ENDLOOP; }; i _ i + n; n _ 4; ENDLOOP; [ePtr, eName] _ MicroOps.LookupBufferSymbol[addr+kx, nChars-kx]; IF ePtr = 0 THEN MicroOps.ReportError[ IO.PutFR["\n *** Undefined literal symbol in %g %g\n", IO.atom[MicroUtils.AtomAtPointer[stmtBuffer+addr, kx]], IO.atom[eName] ], FALSE] ELSE MicroOps.MacroCall[ePtr, (kx+3)/4]; }; GetStmtTypeAtPos: PROC[offset: NAT] RETURNS[SymbolType] = { RETURN[LOOPHOLE[MicroOps.GetStmtValue[offset], SymbolType]] }; buf: LONG POINTER _ VM.AddressForPageNumber[VM.SimpleAllocate[2].page]; expansionPtr _ LOOPHOLE[buf, LONG POINTER TO WORD]; END. MicroProcessImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Willie-sue, February 27, 1986 2:01:45 pm PST taken from MicProc.bcpl Expand packed values Returns the length of an expanded block, or -1 if no encoded data Expand a block possibly containing encoded data; Returns TRUE iff expansion actually occurred Since Expand is only called for immediate use, we can re-use the same storage if expansion is necessary (claim as of 15 Oct) expand old value Process symbol just found by scanner, set val and typ Val, Typ may be: int value (valmode, fldmode only) adr ep (valmode, fldmode only) und ep (fldmode only) Look inside symbol name might be a store Internal entry to processing loop quick check for a number Evaluate argument stmtBufferTop _ stmtBufferTop+lx+1; Internal procedures Compute the size of the expanded value Expand encoded value into stmtBuffer Expand an excoded datum just below thisTop If symFlag then return the symbol index of a symbol and delete it from tail If not symFlag, leave value on tail Expand encoded values whenever stmtTailBottom # thisTop stmtBuffer[0] contains endc, so don't need to check stmtBufferTop = 0 here Expand the datum after-the-fact Split a literal and set up a macro call the first kx chars are the numeric part Start code ΚC˜šœ™Icodešœ Οmœ1™šœ˜J˜Jšœžœ˜"Jšœžœ žœžœ˜+J˜—šžœ˜ Jšžœ&˜+——J˜—J˜š  œžœžœžœžœžœžœžœžœžœ˜XJ™$Jšœžœ˜%Jšœžœ˜J˜šžœžœžœ˜Jšœžœ˜#šžœžœ˜!Jšœ"žœ˜)Jšž˜Jšœ˜—Jšœ˜Jšœ˜J˜—J˜šžœžœžœ ž˜Jšœ0˜0J˜Jšžœ˜—J˜—J˜š  œžœ žœ˜"J™*Jšœ žœ˜Jšœžœ ˜(Jšœžœ˜+šžœžœžœ ž˜Jšžœ9˜@Jšžœ˜—Jšœ˜JšœR˜Ršžœ4ž˜:Jšœ"žœ˜(šžœ˜šžœžœžœ ž˜Jšœ.˜.Jšžœ˜—Jšœ˜J˜——J˜—J˜š  œžœ žœ žœžœžœžœ˜UJšœK™KJšœ#™#J™7J™JJ™Jšœ žœ˜!Jšœ žœ˜Jšœ žœ˜šž˜J˜JšœC˜Cšžœ ž˜J˜šœ˜Jšœ žœ˜Jšœ ˜ šžœ,ž˜1Jšœžœžœ˜K—J˜—J˜˜Jšœž˜Jšœžœ˜ Jšœ˜Jšœ˜Jšœžœ˜3Jšœ"˜"Jšœ˜šžœ žœžœž˜:Jšœ ˜ šžœ˜Jšœžœ%˜.šžœ ž˜Jšœžœ žœžœ˜:Jšžœžœ žœžœ˜E—J˜——J˜—J˜šœŸ˜+J˜"Jšž˜J˜—J˜˜Jšœ žœ˜*Jšœžœ˜ Jšœžœ˜Jšœžœ˜3šžœ ž˜šœ˜Jšžœ-žœžœ˜F—Jšžœ%˜)—J˜—J˜˜šžœžœ˜%Jšœ$˜$JšœH˜HJšžœ˜J˜—J˜,J˜"Jšžœ˜J˜—J˜Jšœžœ˜ J˜šœžœŸ˜0šžœžœ˜"Jšœ$˜$JšœH˜HJšœ"˜"Jšœ$˜$JšœH˜HJšžœ˜J˜—Jšœ"˜"šœ1˜1Jšœ+˜+—J˜—šžœžœ˜Jšœ$˜$JšœH˜HJ˜——J˜šžœ˜J˜——Jšœ)˜)šžœžœ˜šžœ ž˜JšœAžœ˜H—Jšžœžœ˜J˜—J˜šžœ+žœ˜3Jšœžœ)˜5Jšœžœ&˜0šžœžœ˜Jšžœ žœ˜,šžœ žœ˜Jšžœ žœ0˜AJšžœžœ˜J˜—šžœ ž˜Jšœ?žœ˜F—Jšžœžœ˜—J˜J™J™J˜Jšœ)˜)J˜—J˜Jšžœ žœžœžœ˜ Jšœ˜JšœR˜RJšžœ žœ žœ0˜OJšžœŸ˜2J˜—J˜š   œžœžœžœžœ˜>J™'J™'Jš œžœžœžœžœ˜Jšœžœ˜Jšœžœ˜ Jšœžœ˜ Jšœžœ˜J˜šžœ!žœŸ%˜OJ˜ J˜LJ˜"J˜—Jš œžœžœžœžœžœ˜Bšžœž˜Jšœ˜šžœ˜ Jšžœžœžœž˜Jšœ.˜.Jšžœ˜J˜—J˜ J˜Jšžœ˜J˜—Jšœ@˜@šžœ ž˜šœ˜šžœ4˜6Jšžœ6žœ˜I—Jšžœ˜—Jšžœ$˜(—J˜—J˜š œžœ žœžœ˜:Jšœžœžœ/˜@—J˜—™ J˜Jš œžœžœžœžœ˜GJšœžœžœ˜3J˜Jšžœ˜——…—6Ng