DIRECTORY Ascii USING [CR, FF, LF, NUL, SP, TAB], Atom USING [GetPropFromList], Convert USING [Error, RealFromRope], Graph USING [CaretIndex, CaretSpec, ColorIndex, Entity, FontIndex, GraphHandle, NtNan, ROPE, TargetSpec, ValueList, XY], GraphOps USING [AddCurve, NewGraph, SetXValues], GraphPrivate USING [DataError, RopeList, SyntaxError], GraphUtil USING [BlinkMsg, LengthOfVL], Imager USING [Box], IO USING [Backup, EndOfStream, Error, GetCedarToken, GetChar, GetID, int, PeekChar, PutFR, SetIndex, STREAM, TokenError, TokenKind], List USING [Kill], Real USING [Fix, LargestNumber], RefText USING [Equal, ObtainScratch, ReleaseScratch, TrustTextAsRope], Rope USING [Equal, FromRefText, Substr]; GraphReadAscii: CEDAR PROGRAM IMPORTS Atom, Convert, GraphOps, GraphPrivate, IO, GraphUtil, List, Real, RefText, Rope EXPORTS GraphPrivate = { OPEN Graph, GraphOps, GraphPrivate, GraphUtil; TextDataKeys: TYPE = {varsKey, nVarsKey, valuesKey, noneKey}; LVL: TYPE = LIST OF ValueList; ReadAsciiFile: PUBLIC PROC [handle: GraphHandle, s: IO.STREAM] RETURNS [msg: ROPE _ NIL] = { ok: BOOL _ TRUE; key: ROPE _ s.GetID[ ! IO.EndOfStream, IO.Error => ok _ FALSE]; IF ok THEN ok _ key.Equal["graph", FALSE]; IF ok THEN msg _ ReadAsciiComplex[handle, s] ELSE { s.SetIndex[0]; msg _ ReadAsciiSimple[handle, s]; }; }; -- ReadAsciiFile ReadAsciiComplex: PROC [handle: GraphHandle, s: IO.STREAM] RETURNS [msg: ROPE _ NIL] = { msg _ "Not implemented yet." }; -- ReadAsciiComplex ReadAsciiSimple: PROC [handle: GraphHandle, s: IO.STREAM] RETURNS [msg: ROPE _ NIL] = { buffer: REF TEXT _ RefText.ObtainScratch[512]; tokenKind: IO.TokenKind _ tokenCOMMENT; token: REF TEXT; charsSkipped: INT; error: IO.TokenError; get: BOOL _ TRUE; endOfFile: BOOL _ FALSE; key: TextDataKeys _ noneKey; nVars, specifiedN, guessedN, finalN, iRow, iCol: INT; -- iRow, iCol: last row/col processed so far. varsSpecified, nVarsSpecified, valuesSpecified, nVarsGuessed, nToBeGuessed, endOfGroup: BOOL; vars, lastVar: RopeList; xvalues: ValueList; yvalues, tlvl: LVL; status: ROPE; AppendIDtoNames: PROC [] = { nl: RopeList _ CONS[Rope.FromRefText[token], NIL]; IF lastVar = NIL THEN {vars _ lastVar _ nl} ELSE {lastVar.rest _ nl; lastVar _ nl}; nVars _ nVars + 1; varsSpecified _ TRUE; }; -- AppendIDtoNames AppendROPEtoNames: PROC [] = { -- othere input/output: vars and lastVar name: ROPE _ IF token.length <= 2 THEN "" ELSE Rope.FromRefText[token].Substr[1, token.length - 2]; nl: RopeList _ CONS[name, NIL]; IF lastVar = NIL THEN {vars _ lastVar _ nl} ELSE {lastVar.rest _ nl; lastVar _ nl}; nVars _ nVars + 1; varsSpecified _ TRUE; }; -- AppendROPEtoNames ProcessTokenID: PROC [] = { currKey: TextDataKeys _ key; nextChar: CHAR; [nextChar, endOfFile] _ PeekNextNonBlankChar[s]; IF endOfFile THEN SELECT currKey FROM varsKey, nVarsKey, noneKey => SIGNAL DataError["can't find values"]; valuesKey => endOfGroup _ TRUE; ENDCASE ELSE IF nextChar = ': THEN { [] _ s.GetChar[]; key _ GetKeyWord[token, s]; SELECT key FROM varsKey => { IF currKey = varsKey THEN SIGNAL SyntaxError["duplicate vars key"]; IF valuesSpecified THEN endOfGroup _ TRUE ELSE IF varsSpecified THEN SIGNAL SyntaxError["duplicate vars key"]; }; nVarsKey => { IF currKey = nVarsKey THEN SIGNAL SyntaxError["duplicate nVars key"]; IF valuesSpecified THEN endOfGroup _ TRUE ELSE IF nVarsSpecified THEN SIGNAL SyntaxError["duplicate nVars key"]; }; valuesKey => { IF currKey = valuesKey THEN endOfGroup _ TRUE; -- values must have been specified. [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; ENDCASE; -- nothing else after GetKeyWord. } ELSE SELECT key FROM varsKey => AppendIDtoNames[]; valuesKey => { -- values must have been specified. endOfGroup _ TRUE; key _ varsKey; get _ FALSE; }; nVarsKey => { -- nVarsSpecified must have been specified. IF varsSpecified THEN { IF valuesSpecified THEN { endOfGroup _ TRUE; key _ varsKey; get _ FALSE; } ELSE SIGNAL SyntaxError["possibly missing `:' after keyword"]; } ELSE { -- vars not specified. key _ varsKey; get _ FALSE; }; }; ENDCASE => { -- noneKey, so values, vars, and nName are not specified. key _ varsKey; get _ FALSE; }; }; -- ProcessTokenID UNTIL endOfFile DO xmin, ymin: REAL _ Real.LargestNumber; xmax, ymax: REAL _ -xmin; nVars _ specifiedN _ guessedN _ iRow _ iCol _ 0; finalN _ -1; varsSpecified _ nVarsSpecified _ nVarsGuessed _ nToBeGuessed _ valuesSpecified _ endOfGroup _ FALSE; vars _ lastVar _ NIL; xvalues _ NIL; yvalues _ tlvl _ NIL; status _ NIL; UNTIL endOfGroup OR endOfFile DO IF get THEN [tokenKind, token, charsSkipped, error] _ s.GetCedarToken[buffer] ELSE get _ TRUE; SELECT tokenKind FROM tokenCOMMENT => LOOP; tokenERROR => SIGNAL SyntaxError[]; tokenEOF => { IF NOT valuesSpecified THEN SIGNAL DataError["can't find values"]; endOfFile _ TRUE; EXIT; }; ENDCASE => SELECT key FROM noneKey => { -- can happen only at first time in the loop. errorMsg: ROPE _ "key word, rope, or values expected"; SELECT tokenKind FROM tokenROPE => {key _ varsKey; get _ FALSE}; tokenID => ProcessTokenID[]; tokenREAL, tokenDECIMAL => { key _ valuesKey; get _ FALSE; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; tokenSINGLE => SELECT token[0] FROM '-, '+, '* => { IO.Backup[s, token[0]]; key _ valuesKey; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; ENDCASE => SIGNAL SyntaxError[errorMsg]; ENDCASE => SIGNAL SyntaxError[errorMsg]; }; nVarsKey => { status _ "after nVars key"; SELECT tokenKind FROM tokenDECIMAL, tokenREAL => { IF nVarsSpecified THEN { key _ valuesKey; get _ FALSE; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; } ELSE { ok: BOOL _ TRUE; r: REAL; IF tokenKind = tokenREAL THEN SIGNAL DataError["nVars should be an integer"]; r _ Convert.RealFromRope[RefText.TrustTextAsRope[token] ! Convert.Error => {ok _ FALSE; CONTINUE}]; IF ok THEN { IF r > LAST[INT] THEN SIGNAL DataError["nVars too big"]; IF r < 1 THEN SIGNAL DataError["nVars < 1"]; specifiedN _ Real.Fix[r]; nVarsSpecified _ TRUE; } ELSE SIGNAL DataError[status]; }; }; ENDCASE => { IF NOT nVarsSpecified THEN SIGNAL DataError["can't find the number of variables"]; -- currently doesn't allow '+ in front of the number of vars. SELECT tokenKind FROM tokenSINGLE => SELECT token[0] FROM '-, '+, '* => { IO.Backup[s, token[0]]; key _ valuesKey; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; ENDCASE => LOOP; tokenID => ProcessTokenID[]; tokenROPE => { IF varsSpecified THEN SIGNAL DataError["names have been listed"]; key _ varsKey; get _ FALSE; }; ENDCASE => SIGNAL SyntaxError[status]; }; }; varsKey => { status _ "getting vars"; SELECT tokenKind FROM tokenROPE => AppendROPEtoNames[]; tokenID => ProcessTokenID[]; ENDCASE => { IF NOT varsSpecified THEN SIGNAL DataError["can't find the names of variables"]; SELECT tokenKind FROM tokenSINGLE => SELECT token[0] FROM '-, '+, '* => { IO.Backup[s, token[0]]; key _ valuesKey; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; ENDCASE => LOOP; tokenDECIMAL, tokenREAL => { key _ valuesKey; get _ FALSE; [finalN, vars, yvalues] _ InitData[nVarsSpecified, specifiedN, nVars, vars]; }; ENDCASE => SIGNAL SyntaxError[status]; }; }; -- varsKey valuesKey => { status _ "parsing values"; SELECT tokenKind FROM tokenDECIMAL, tokenREAL, tokenSINGLE => { ok, normal: BOOL _ TRUE; negative: BOOL _ FALSE; r: REAL; IF tokenKind # tokenSINGLE THEN r _ Convert.RealFromRope[RefText.TrustTextAsRope[token] ! Convert.Error => {ok _ FALSE; CONTINUE}] ELSE SELECT token[0] FROM '-, '+ => { negative _ token[0] = '-; [tokenKind, token, charsSkipped, error] _ s.GetCedarToken[buffer]; SELECT tokenKind FROM tokenDECIMAL, tokenREAL => r _ Convert.RealFromRope[ RefText.TrustTextAsRope[token] ! Convert.Error => {ok _ FALSE; CONTINUE}]; ENDCASE => ok _ FALSE; IF negative THEN r _ -r; }; '* => {r _ NtNan; normal _ FALSE} ENDCASE => LOOP; IF NOT ok THEN SIGNAL DataError[status]; IF iCol = finalN OR iCol = 0 THEN {iCol _ 1; iRow _ iRow + 1} ELSE iCol _ iCol + 1; IF iCol = 1 THEN { xvalues _ CONS[r, xvalues]; tlvl _ yvalues; IF normal THEN {xmin _ MIN[r, xmin]; xmax _ MAX[r, xmax]}; } ELSE { IF tlvl = NIL THEN SIGNAL DataError["gee!"]; -- incredible? tlvl.first _ CONS[r, tlvl.first]; tlvl _ tlvl.rest; IF normal THEN {ymin _ MIN[r, ymin]; ymax _ MAX[r, ymax]}; }; valuesSpecified _ TRUE; }; tokenID => IF valuesSpecified THEN ProcessTokenID[] ELSE SIGNAL DataError["can't find values"]; tokenROPE => { IF NOT valuesSpecified THEN SIGNAL DataError["can't find values"]; endOfGroup _ TRUE; key _ varsKey; get _ FALSE; }; ENDCASE => SIGNAL SyntaxError[status]; }; -- valuesKey ENDCASE; ENDLOOP; IF valuesSpecified THEN handle _ AddNewGraph[oldGraph: handle, fileName: NARROW[Atom.GetPropFromList[s.propList, $Name]], vars: vars, xvalues: xvalues, yvalues: yvalues, bounds: [xmin, ymin, xmax, ymax] ]; ENDLOOP; RefText.ReleaseScratch[token]; }; -- ReadAsciiSimple KeyFromToken: PROC [token: REF TEXT] RETURNS [key: TextDataKeys _ noneKey] = { IF token # NIL THEN RETURN [SELECT TRUE FROM RefText.Equal[token, "nVars", FALSE], RefText.Equal[token, "nVariables", FALSE] => nVarsKey, RefText.Equal[token, "values", FALSE] => valuesKey, RefText.Equal[token, "vars", FALSE], RefText.Equal[token, "variables", FALSE] => varsKey, ENDCASE => noneKey]; }; -- KeyFromToken GetKeyWord: PROC [token: REF TEXT, s: IO.STREAM] RETURNS [key: TextDataKeys] = { [] _ s.GetChar[]; -- skip the colon. key _ KeyFromToken[token]; IF key = noneKey THEN SIGNAL SyntaxError["unknown key word"]; }; -- GetKeyWord InitData: PROC [nVarsSpecified: BOOL, specifiedN, nVars: INT, names: RopeList] RETURNS [finalN: INT, vars: RopeList, lvl: LVL _ NIL] = { -- , toGuess: BOOL _ FALSE] = { finalN _ nVars; vars _ names; IF vars = NIL AND NOT nVarsSpecified THEN SIGNAL DataError["number of variables unknown."]; IF vars = NIL AND nVarsSpecified THEN finalN _ specifiedN ELSE IF nVarsSpecified AND vars # NIL THEN { IF specifiedN # nVars THEN BlinkMsg["number of vars listed # specified nVars. The latter is discarded."]; }; IF finalN <= 1 THEN SIGNAL DataError["number of variables <= 1"]; IF vars = NIL THEN FOR i: INT IN [1..finalN] DO vars _ CONS[NIL, vars]; ENDLOOP; FOR j: INT IN [2..finalN] DO lvl _ CONS[NIL, lvl]; ENDLOOP; }; -- InitData BlankChar: PROC [char: CHAR] RETURNS [BOOL] = { OPEN Ascii; RETURN [SELECT char FROM SP, TAB, LF, CR, FF, NUL => TRUE, ENDCASE => FALSE] }; -- BlankChar PeekNextNonBlankChar: PROC [s: IO.STREAM] RETURNS [char: CHAR, eof: BOOL _ FALSE] = { ENABLE IO.EndOfStream => {eof _ TRUE; CONTINUE}; WHILE BlankChar[char _ s.PeekChar[]] DO [] _ s.GetChar[] ENDLOOP; }; -- PeekNextNonBlankChar AddNewGraph: PROC [oldGraph: GraphHandle, fileName: ROPE, vars: RopeList, xvalues: ValueList, yvalues: LVL, bounds: Imager.Box] RETURNS [newGraph: GraphHandle] = { tlvl: LVL; lengthX, lengthY, iCurve, groupId: INT _ 0; IF oldGraph = NIL OR vars = NIL OR xvalues = NIL OR yvalues = NIL THEN RETURN; lengthX _ LengthOfVL[xvalues]; FOR tlvl _ yvalues, tlvl.rest UNTIL tlvl = NIL DO iCurve _ iCurve + 1; IF (lengthY _ LengthOfVL[tlvl.first]) # lengthX THEN SIGNAL DataError[ IO.PutFR["%g-th variable has %g values but x has %g values", IO.int[iCurve], IO.int[lengthY], IO.int[lengthX]]]; ENDLOOP; [newGraph, groupId] _ NewGraph[ fileName: fileName, comment: fileName, xName: vars.first, bounds: bounds, oldGraph: oldGraph ]; [] _ SetXValues[handle: newGraph, values: xvalues, groupId: groupId]; -- xvalues is reversed, and it will be cleaned up. tlvl _ yvalues; FOR tn: RopeList _ vars.rest, tn.rest UNTIL tn = NIL DO [] _ AddCurve[handle: newGraph, values: tlvl.first, groupId: groupId, name: tn.first]; tlvl _ tlvl.rest; ENDLOOP; TRUSTED { List.Kill[LOOPHOLE[yvalues]]; List.Kill[LOOPHOLE[vars]]; }; }; -- AddNewGraph }. LOG. SChen, November 16, 1985 9:40:08 pm PST, created. όGraphReadAscii.mesa, Copyright c 1985 by Xerox Corporation. All rights reserved. Last Edited by: Sweetsun Chen, November 20, 1985 4:29:05 pm PST read more complicated graph file in text format. If values have been read, then vars key or nVars key will end previous group, and start a new group of data. other input: s, token, varsSpecified; other output: key, get, eog. s is possibly affected too. For nVarsKey and valuesKey, one must make sure the thing they indicate has been specified before calling this. else ok. else ok. begin and end keys are not to be specified. here we must find a legal key. ELSE IF vars # NIL AND NOT nVarsSpecified THEN finalN _ nVars ELSE { finalN _ -1; -- toGuess _ TRUE}; IF NOT toGuess THEN { autoBounds: FALSE, ReadValueWithGuessedN: PROC [] = { nextChar: CHAR; IF NOT nVarsGuessed THEN { vl: ValuesList _ CONS[r, NIL]; ttlvl: LVL _ CONS[vl, NIL]; IF finalN = -1 THEN finalN _ 1 ELSE finalN _ finalN + 1; iCol _ finalN; vars _ CONS[NIL, vars]; IF iCol = 1 THEN xvalues _ vl ELSE IF tlvl = NIL THEN {yvalues _ tlvl _ ttlvl} ELSE {tlvl.rest _ ttlvl; tlvl _ ttlvl}; nextChar _ s.PeekChar[]; WHILE BlankChar[(nextChar _ s.PeekChar[])] DO ENABLE IO.EndOfStream => {endOfFile _ TRUE; GOTO found}; SELECT nextChar FROM Ascii.CR, Ascii.LF => GOTO guessed; ENDCASE => s.GetChar[]; nextChar _ s.PeekChar[]; ENDLOOP; EXITS found => { nVarsGuessed _ TRUE; ttlvl.first _ NIL; tlvl _ NIL; }; } ELSE { -- nVarsGuessed IF iCol = finalN THEN iCol _ 1 ELSE iCol _ iCol + 1; }; }; -- ReadValuesWithGuessedN ΚΛ˜JšœΟmœ1™Qšœ™Icode™/—J˜šΟk ˜ Jšœžœžœžœžœžœžœžœ˜'Jšœžœ˜Jšœžœ˜$JšœžœLžœžœ˜xJšœ žœ"˜0Jšœ žœ$˜6Jšœ žœ˜'Jšœžœ˜Jšžœžœ]žœ˜„Jšœžœ˜Jšœžœ˜ Jšœžœ9˜FJšœžœ˜(J˜—šœžœž˜Jšžœ(žœ&˜WJšžœ˜—J˜Jšžœ*˜.J˜Jšœžœ+˜=Jšžœžœžœžœ ˜J˜šΟn œžœžœžœžœžœžœžœ˜\Jšœžœžœ˜Jš œžœžœžœžœ˜?Jšžœžœžœ˜*Jšžœžœ"˜,šžœ˜J˜Jšœ!˜!J˜—JšœΟc˜J˜šŸœžœžœžœžœžœžœ˜XJ™0J˜Jšœ ˜J˜—J™lšŸœžœžœžœžœžœžœ˜WJšœžœžœ˜.Jšœ žœ˜'Jšœžœžœ˜Jšœžœ˜Jšœžœ ˜J˜Jšœžœžœ˜Jšœ žœžœ˜Jšœ˜J˜šœ1žœ˜5Jš -˜-—JšœXžœ˜]Jšœ˜Jšœ˜Jšœžœ˜Jšœžœ˜ J˜šŸœžœ˜Jšœžœžœ˜2Jšžœ žœžœ˜+Jšžœ#˜'J˜Jšœžœ˜Jšœ ˜J˜—šŸœžœ (˜GJš œžœžœžœžœ5˜cJšœžœžœ˜Jšžœ žœžœ˜+Jšžœ#˜'J˜Jšœžœ˜Jšœ ˜J˜J™—šŸœžœ˜Jšœ^™^Jšœn™nJšœ˜Jšœ žœ˜Jšœ0˜0šžœ žœžœ ž˜%Jšœžœ ˜DJšœžœ˜Jšž˜—šžœžœžœ˜J˜Jšœ˜šžœž˜šœ ˜ Jšžœžœžœ#˜CJšžœžœž˜)Jšžœžœžœžœ#˜DJ™J˜—šœ ˜ Jšžœžœžœ$˜EJšžœžœž˜)Jšžœžœžœžœ$˜FJ™J˜—šœ˜Jšžœžœžœ #˜RJšœL˜LJ˜—Jšžœ !˜*—J˜—šž˜šžœž˜Jšœ˜šœ #˜2Jšœ žœ˜Jšœžœ˜J˜—šœ +˜9šžœžœ˜šžœžœ˜Jšœ žœ˜Jšœžœ˜J˜—Jšžœžœ3˜>J˜—šžœ ˜Jšœžœ˜J˜—J˜—šžœ 9˜FJšœžœ˜J˜———Jšœ ˜J˜—šžœ ž˜Jšœ žœ˜&Jšœ žœ ˜Jšœ0˜0J˜ Jšœ^žœ˜dJšœžœ˜Jšœ žœ˜Jšœžœ˜Jšœ žœ˜ šžœ žœ ž˜ JšžœžœB˜MJšžœžœ˜šžœ ž˜Jšœžœ˜Jšœžœ˜#šœ ˜ Jšžœžœžœžœ ˜BJšœ žœ˜Jšžœ˜J˜—šžœžœžœ˜šœ  -˜:Jšœ žœ(˜6šžœ ž˜Jšœ#žœ˜*Jšœ˜šœ˜Jšœžœ˜JšœL˜LJšœ˜—šœžœ ž˜#šœ˜Jšžœ˜Jšœ˜JšœL˜LJ˜—Jšžœžœ˜(—Jšžœžœ˜(—J˜—šœ ˜ Jšœ˜šžœ ž˜šœ˜šžœžœ˜Jšœžœ˜JšœL˜LJšœ˜—šžœ˜Jšœžœžœ˜Jšœžœ˜Jšžœžœžœ)˜Mšœ7˜7Jšœžœžœ˜+—šžœžœ˜ Jš žœžœžœžœžœ˜8Jšžœžœžœ˜,Jšœ˜Jšœžœ˜J˜—Jšžœžœ˜J˜—J˜—šžœ˜ Jš žœžœžœžœ2 =˜šžœ ž˜šœžœ ž˜#˜Jšžœ˜Jšœ˜JšœL˜LJ˜—Jšžœžœ˜—Jšœ˜šœ˜Jšžœžœžœ%˜AJšœžœ˜J˜—Jšžœžœ˜&—J˜——J˜—šœ ˜ Jšœ˜šžœ ž˜Jšœ!˜!Jšœ˜šžœ˜ Jšžœžœžœžœ0˜Pšžœ ž˜šœžœ ž˜#˜Jšžœ˜Jšœ˜JšœL˜LJ˜—Jšžœžœ˜—šœ˜Jšœžœ˜JšœL˜LJšœ˜—Jšžœžœ˜&—J˜——Jšœ  ˜ —šœ˜Jšœ˜šžœ ž˜šœ)˜)Jšœ žœžœ˜Jšœ žœžœ˜Jšœžœ˜šžœžœ˜ šœ7˜7Jšœžœžœ˜*——šžœžœ ž˜˜ Jšœ˜JšœB˜Bšžœ ž˜šœ4˜4Jšœ˜Jšœžœžœ˜+—Jšžœ žœ˜—Jšžœ žœ˜J˜—Jšœžœ˜!Jšžœžœ˜—Jšžœžœžœžœ˜(Jšžœžœ žœ˜=Jšžœ˜šžœ žœ˜Jšœ žœ ˜J˜Jšžœžœ žœžœ ˜:J˜—šžœ˜Jš žœžœžœžœ ˜Jšœ žœ*˜:Jšœ/˜/Jšœ ˜ Jšœ˜——Jšžœ˜—J˜Jšœ ˜—˜š Ÿ œžœ žœžœžœ"˜NJšœ+™+š žœ žœžœžœžœžœž˜,šœžœ˜%Jšœ#žœ˜6—Jšœžœ˜3šœžœ˜$Jšœ"žœ ˜4—Jšžœ ˜—Jšœ ˜J˜—šŸ œžœ žœžœžœžœžœ˜PJšœ ˜$Jšœ˜J™Jšžœžœžœ!˜=Jšœ  ˜J˜—šŸœžœžœžœžœ žœžœžœ ˜¨Jšœ˜Jšœ ˜ Jš žœžœžœžœžœžœ+˜[šžœžœžœžœ˜9Jš žœžœžœžœžœ™=—š žœžœžœžœžœ˜,JšžœžœO˜iJ˜—šžœ™Jšœ  ™ Jšžœžœ žœ™—Jšžœ žœžœ'˜Aš žœžœžœžœžœžœ ž˜/Jšœžœžœ˜Jšžœ˜—Jšžœžœžœ žœžœžœžœ˜;Jšœ  ˜J˜—š Ÿ œžœžœžœžœžœ˜;šžœžœž˜Jšžœžœžœžœžœžœžœžœžœ˜3—Jšœ  ˜J˜—šŸœžœžœžœžœžœžœžœ˜UJšžœžœžœžœ˜0Jšžœ žœžœ˜AJšœ ˜J˜—šŸ œžœ#žœ˜9Jšœ-žœžœ˜iJšœžœ˜ Jšœ#žœ˜+Jšžœ žœžœžœžœ žœžœ žœžœžœ˜NJšœ˜šžœžœžœž˜1J˜šžœ.žœžœ ˜Fšžœ:˜