DIRECTORY Ascii, Atom, CD, CDBasics, CDCells, CDDirectory, CDErrors, CDInstances, CDProperties, CDTextExtraction, CDSequencer, CDSymbolicObjects, CDTexts, CDOps, IO, Properties, Rope, TerminalIO; CDTextExtractionImpl: CEDAR PROGRAM IMPORTS Ascii, Atom, CD, CDBasics, CDCells, CDDirectory, CDErrors, CDInstances, CDProperties, CDSequencer, CDSymbolicObjects, CDTexts, CDOps, IO, Rope, TerminalIO EXPORTS CDTextExtraction SHARES CDProperties = BEGIN lorPropKey: ATOM = $TextExtraction; PropRec: TYPE = RECORD [key: ATOM_NIL, value: REF_NIL, onOb: BOOL_FALSE]; PutLorProp: PROC [x: REF, text: Rope.ROPE] = BEGIN lor: LIST OF Rope.ROPE _ WITH CDProperties.GetProp[x, lorPropKey] SELECT FROM rl: LIST OF Rope.ROPE => rl, ENDCASE => NIL; lor _ CONS[text, lor]; CDProperties.PutProp[x, lorPropKey, lor]; END; PutPropRec: PROC [inst: CD.Instance, prop: PropRec] = BEGIN IF prop.onOb THEN { IF inst.ob.class.composed THEN CDProperties.PutProp[onto: inst.ob, prop: prop.key, val: prop.value] } ELSE CDProperties.PutProp[onto: inst, prop: prop.key, val: prop.value] END; CheckPropRec: PROC [inst: CD.Instance, prop: PropRec] RETURNS [match: BOOL] = BEGIN Similar: PROC [x, y: REF] RETURNS [BOOL_FALSE] = { IF x=y THEN RETURN [TRUE]; IF ISTYPE[x, Rope.ROPE] AND ISTYPE[y, Rope.ROPE] THEN { RETURN [ Rope.Equal[ NARROW[x, Rope.ROPE], NARROW[y, Rope.ROPE] ] ] }; }; match _ prop.key#NIL AND Similar[prop.value, CDProperties.GetProp[from: (IF prop.onOb THEN inst.ob ELSE inst), prop: prop.key] ] END; ScanPropRec: PROC [ob: CD.Object] RETURNS [PropRec] = BEGIN RemoveBlanks: PROC [r: Rope.ROPE] RETURNS [Rope.ROPE] = { RemoveTrailingBlanks: PROC [r: Rope.ROPE] RETURNS [Rope.ROPE] = INLINE { n: INT _ r.Length[]; WHILE n>0 AND r.Fetch[n-1]=' DO n _ n-1 ENDLOOP; RETURN [r.Substr[start: 0, len: n]]; }; RemoveLeadingBlanks: PROC [r: Rope.ROPE] RETURNS [Rope.ROPE] = INLINE { RETURN [r.Substr[start: r.SkipOver[skip: " "]]] }; RETURN [RemoveLeadingBlanks[RemoveTrailingBlanks[r]]] }; Scan: PROC [text: Rope.ROPE] RETURNS [pRec: PropRec _ [NIL, NIL]] = INLINE { n: INT _ text.SkipTo[skip: ":"]; IF n RETURN [t _ tp.text] ENDCASE => NULL; }; RETURN [Scan[Text[ob]]] END; Public: PROC [key: ATOM] RETURNS [BOOL_TRUE] = BEGIN IF key=NIL THEN RETURN [FALSE] ELSE { pType: CDProperties.PropertyProcs = CDProperties.FetchProcs[key]; RETURN [ pType=NIL OR ~pType.exclusive ]; } END; Kind: TYPE = {stuff, anyProp, topProp, ignore}; KindOf: PROC [ob: CD.Object] RETURNS [kind: Kind_stuff] = BEGIN IF ob.class.wireTyped THEN { IF ob.layer<=CD.selectionLayer THEN kind _ ignore } ELSE IF ob.layer=CD.commentLayer THEN WITH ob.specific SELECT FROM tp: CDTexts.TextSpecific => { fn: Rope.ROPE ~ tp.cdFont.supposedName; IF Ascii.Upper[fn.Fetch[fn.Length[]-1]]='I THEN kind _ ignore ELSE IF fn.Length[]>=27 AND Rope.Equal["Xerox/TiogaFonts/", fn.Substr[len: 17], FALSE] THEN { IF Rope.Equal["Helvetica", fn.Substr[17, 9], FALSE] THEN kind _ anyProp ELSE IF Rope.Equal["TimesRoman", fn.Substr[17, 10], FALSE] THEN kind _ topProp } }; ENDCASE => NULL; END; Separation: TYPE = ARRAY Kind OF CD.InstanceList _ ALL[NIL]; Split: PROC [list: CD.InstanceList] RETURNS [s: Separation] = BEGIN FOR l: CD.InstanceList _ list, l.rest WHILE l#NIL DO k: Kind _ KindOf[l.first.ob]; s[k] _ CONS[l.first, s[k]]; CDProperties.PutInstanceProp[l.first, lorPropKey, NIL]; ENDLOOP; END; UseCPtr: PROC[design: CD.Design, ob: CD.Object] RETURNS [cp: CD.CellSpecific_NIL] = BEGIN IF ob=NIL THEN cp _ design^.actual.first.specific ELSE IF CDCells.IsCell[ob] THEN cp _ NARROW[ob.specific] ELSE IF ob.class.composed THEN { new: CD.Object; ta, ca: BOOL; [new, ta, ca] _ CDDirectory.Expand1[ob]; IF new#NIL AND new#ob AND ta THEN { cp _ UseCPtr[design, new]; } }; END; ExtractProperties: PUBLIC PROC [design: CD.Design, cell: CD.Object_NIL, specialMode: BOOL _ FALSE, checkOnly: BOOL_FALSE] RETURNS [matches: INT_0, errors: INT_0] = BEGIN Message: PROC [text: Rope.ROPE, r, r2: CD.Rect _ CDBasics.universe] = { blow: CD.Number ~ (IF design#NIL THEN design.technology.lambda ELSE 4); [] _ CDErrors.IncludeMessage[design: design, ob: cell, rect: CDBasics.Intersection[CDBasics.Extend[r, blow], CDBasics.Extend[r2, blow]], message: text, owner: $PropertyChecker ]; errors _ errors+1; }; MatchFirst: PROC [tr: CD.Rect, l: CD.InstanceList] RETURNS [BOOL] = INLINE { RETURN [ CDBasics.Intersect[tr, CDInstances.InstRectO[l.first]] AND CDBasics.Intersect[tr, CDInstances.InstRectI[l.first]] ] }; ExtractLORText: PROC [stuff: CD.InstanceList, ti: CD.Instance] = BEGIN tp: CDTexts.TextSpecific ~ NARROW[ti.ob.specific]; tr: CD.Rect ~ CDInstances.InstRectI[ti]; match: BOOL _ FALSE; FOR l: CD.InstanceList _ stuff, l.rest WHILE l#NIL DO IF MatchFirst[tr, l] THEN { match _ TRUE; PutLorProp[l.first, tp.text] } ENDLOOP; IF match THEN matches _ matches+1 ELSE Message["property does not match anything", tr]; END; ExtractANYText: PROC [stuff: CD.InstanceList, ti: CD.Instance] = BEGIN pRec: PropRec ~ ScanPropRec[ti.ob]; tr: CD.Rect ~ CDInstances.InstRectI[ti]; IF Public[pRec.key] THEN { match: BOOL _ FALSE; FOR l: CD.InstanceList _ stuff, l.rest WHILE l#NIL DO IF MatchFirst[tr, l] THEN { match _ TRUE; PutPropRec[l.first, pRec]; } ENDLOOP; IF match THEN matches _ matches+1 } END; CheckANYText: PROC [stuff: CD.InstanceList, ti: CD.Instance] = BEGIN pRec: PropRec ~ ScanPropRec[ti.ob]; tr: CD.Rect ~ CDInstances.InstRectI[ti]; IF Public[pRec.key] THEN { match: BOOL _ FALSE; FOR l: CD.InstanceList _ stuff, l.rest WHILE l#NIL DO IF MatchFirst[tr, l] THEN { match _ TRUE; IF ~CheckPropRec[l.first, pRec] THEN Message["property missmatch", tr, CDInstances.InstRectI[l.first]]; }; ENDLOOP; IF ~match THEN Message["property does not match anything", tr] } ELSE Message["bad or protected property", tr] END; s: Separation; cPtr: CD.CellSpecific ~ UseCPtr[design, cell]; IF cPtr=NIL THEN RETURN [errors _ 1]; CDErrors.RemoveMessages[design, cell, $PropertyChecker]; s _ Split[cPtr.contents]; IF specialMode THEN { FOR l: CD.InstanceList _ s[anyProp], l.rest WHILE l#NIL DO ExtractLORText[s[stuff], l.first] ENDLOOP; } ELSE { IF ~checkOnly THEN FOR l: CD.InstanceList _ s[anyProp], l.rest WHILE l#NIL DO ExtractANYText[s[stuff], l.first]; ENDLOOP; FOR l: CD.InstanceList _ s[anyProp], l.rest WHILE l#NIL DO CheckANYText[s[stuff], l.first] ENDLOOP; }; IF ~checkOnly AND cell#NIL THEN { rl: LIST OF Rope.ROPE_NIL; FOR l: CD.InstanceList _ s[topProp], l.rest WHILE l#NIL DO tp: CDTexts.TextSpecific ~ NARROW[l.first.ob.specific]; rl _ CONS[tp.text, rl] ENDLOOP; CDProperties.PutObjectProp[cell, lorPropKey, rl]; }; END; ExtractTopComm: PROC [comm: CDSequencer.Command] = BEGIN matches, errors: INT; TerminalIO.PutRope["extract properties in top level\n"]; [matches, errors] _ ExtractProperties[comm.design]; TerminalIO.PutF[" %g texts used in top level; %g problem(s) found\n", IO.int[matches], IO.int[errors]]; END; ExtractSelComm: PROC [comm: CDSequencer.Command] = BEGIN inst: CD.Instance _ CDOps.TheInstance[comm.design, "extract properties\n"]; IF inst#NIL THEN { matches, errors: INT; [matches, errors] _ ExtractProperties[comm.design, inst.ob]; TerminalIO.PutF[" %g texts used in `%g'; %g problem(s) found\n", IO.int[matches], IO.rope[CD.Describe[inst.ob, inst.properties]], IO.int[errors]]; } END; ---------------- OkToRemoveProperties: PROC [i: CD.Instance] RETURNS [BOOL_TRUE] = BEGIN IF CDSymbolicObjects.IsSymbolicOb[i.ob] THEN RETURN [FALSE]; IF i.ob.class.wireTyped THEN RETURN [i.ob.layer#CD.errorLayer]; END; RemInstProps: PROC [i: CD.Instance] = BEGIN DoIt: PROC = { copy: CD.PropList _ NIL; FOR l: Properties.PropList _ i.properties, l.rest WHILE l#NIL DO WITH l.first.key SELECT FROM a: ATOM => IF ~Public[a] THEN copy _ CONS[l.first, copy]; ENDCASE => copy _ CONS[l.first, copy]; ENDLOOP; i.properties _ copy; }; IF OkToRemoveProperties[i] THEN CDProperties.DoWithinLock[DoIt] END; RemovePublicProperties: PUBLIC PROC [design: CD.Design, ob: CD.Object_NIL] = BEGIN cPtr: CD.CellSpecific ~ UseCPtr[design, ob]; IF cPtr#NIL THEN FOR l: CD.InstanceList _ cPtr.contents, l.rest WHILE l#NIL DO RemInstProps[l.first]; ENDLOOP; END; RemTopComm: PROC [comm: CDSequencer.Command] = BEGIN TerminalIO.PutRope["remove all properties in top level\n"]; RemovePublicProperties[comm.design]; END; RemSelInstPropsComm: PROC [comm: CDSequencer.Command] = BEGIN inst: CD.Instance _ CDOps.TheInstance[comm.design, "remove properties of instance\n"]; IF inst#NIL THEN { IF OkToRemoveProperties[inst] THEN RemInstProps[inst] ELSE TerminalIO.PutRope["don't remove the properties of this object\n"]; } END; IsAnyText: PROC [ob: CD.Object] RETURNS [yes: BOOL_FALSE] = INLINE BEGIN yes _ CDTexts.IsText[ob] END; SelectFromPropComm: PROC [comm: CDSequencer.Command] = BEGIN inst: CD.Instance _ CDOps.TheInstance[comm.design, "select using property\n"]; IF inst#NIL THEN { design: CD.Design _ comm.design; pRec: PropRec; cnt: INT _ 0; IF IsAnyText[inst.ob] THEN pRec _ ScanPropRec[inst.ob] ELSE IF inst.ob.class.wireTyped OR CDSymbolicObjects.IsSymbolicOb[inst.ob] THEN pRec _ [$SignalName, CDProperties.GetProp[inst, $SignalName], FALSE] ELSE { TerminalIO.PutRope[" not done: selection is neither text (Helvetica) nor rectangle\n"]; RETURN; }; IF pRec.key=NIL THEN { TerminalIO.PutRope[" not done: property key is NIL\n"]; RETURN; }; TerminalIO.PutF[" key: %g, value: %g\n", IO.atom[pRec.key], IO.rope[(IF pRec.value=NIL THEN "NIL" ELSE CDOps.ToRope[pRec.value])] ]; FOR l: CD.InstanceList _ CDOps.InstList[design], l.rest WHILE l#NIL DO IF CheckPropRec[l.first, pRec] THEN { l.first.selected _ TRUE; CDOps.RedrawInstance[design, l.first, FALSE]; cnt _ cnt+1 }; ENDLOOP; IF cnt>0 AND CDTexts.IsText[inst.ob] THEN { inst.selected _ FALSE; CDOps.RedrawInstance[design, inst]; }; TerminalIO.PutF[" %g instance(s) selected\n", IO.int[cnt]]; }; END; PropagateSignalNameComm: PROC [comm: CDSequencer.Command] = BEGIN inst: CD.Instance ~ CDOps.TheInstance[comm.design, "propagate signal name\n"]; IF inst#NIL THEN { design: CD.Design ~ comm.design; foundL: CD.InstanceList _ LIST[inst]; no: INT _ 1; value: REF _ CDProperties.GetProp[from: inst, prop: $SignalName]; IF value=NIL THEN TerminalIO.PutRope[" not done: no signal name\n"] ELSE { WHILE foundL#NIL DO curr: CD.Instance ~ foundL.first; currR: CD.Rect ~ CDInstances.InstRectI[curr]; foundL _ foundL.rest; FOR l: CD.InstanceList _ CDOps.InstList[design], l.rest WHILE l#NIL DO IF ~l.first.selected AND l.first.ob.class.wireTyped AND l.first.ob.layer=curr.ob.layer THEN { IF CDBasics.Intersect[currR, CDInstances.InstRectI[l.first]] THEN { foundL _ CONS[l.first, foundL]; l.first.selected _ TRUE; no _ no+1; CDProperties.PutProp[l.first, $SignalName, value]; CDOps.RedrawInstance[design, l.first, FALSE]; }; }; ENDLOOP; ENDLOOP; TerminalIO.PutF[" %g instance(s) selected\n", IO.int[no]]; }; }; END; FindSelectedProperties: PROC [design: CD.Design] RETURNS [doList: LIST OF PropRec_NIL] = BEGIN Occurs: PROC [list: LIST OF PropRec, key: ATOM] RETURNS [yes: BOOL _ FALSE] = INLINE { FOR pl: LIST OF PropRec _ list, pl.rest WHILE pl#NIL DO IF pl.first.key=key THEN RETURN [yes _ TRUE] ENDLOOP; }; FOR l: CD.InstanceList _ CDOps.InstList[design], l.rest WHILE l#NIL DO IF l.first.selected AND IsAnyText[l.first.ob] THEN { pr: PropRec = ScanPropRec[l.first.ob]; IF ~Public[pr.key] THEN { TerminalIO.PutRope["unknown or restricted property\n"]; [] _ CDErrors.IncludeMessage[design: design, ob: NIL, rect: CDInstances.InstRectI[l.first], message: "bad property", owner: $PropertyChecker ]; } ELSE IF Occurs[doList, pr.key] THEN { TerminalIO.PutF[" ** property: %g, value: %g twice or contradicting! ignored\n", IO.atom[pr.key], IO.rope[(IF pr.value=NIL THEN "NIL" ELSE CDOps.ToRope[pr.value])] ]; } ELSE { TerminalIO.PutF[" property: %g, value: %g\n", IO.atom[pr.key], IO.rope[(IF pr.value=NIL THEN "NIL" ELSE CDOps.ToRope[pr.value])] ]; doList _ CONS[pr, doList]; } } ENDLOOP; END; SetPropWithSelectionComm: PROC [comm: CDSequencer.Command] = BEGIN design: CD.Design _ comm.design; doList: LIST OF PropRec; TerminalIO.PutRope["set properties using the selection\n"]; doList _ FindSelectedProperties[design]; IF doList=NIL THEN TerminalIO.PutRope["no texts selected"] ELSE { FOR il: CD.InstanceList _ CDOps.InstList[design], il.rest WHILE il#NIL DO IF il.first.selected AND ~IsAnyText[il.first.ob] THEN { FOR pl: LIST OF PropRec _ doList, pl.rest WHILE pl#NIL DO PutPropRec[il.first, pl.first] ENDLOOP; } ENDLOOP; TerminalIO.PutRope[" --\n"]; }; END; SetPropToPushedInCell: PROC [comm: CDSequencer.Command] = BEGIN design: CD.Design _ comm.design; doList: LIST OF PropRec; object: REF; IF CDCells.IsPushedIn[design] THEN { TerminalIO.PutRope["set selected properties to the pushed in cell\n"]; object _ design.actual.first.mightReplace.ob; } ELSE { TerminalIO.PutRope["set selected properties to the design\n"]; object _ design; }; doList _ FindSelectedProperties[design]; IF doList=NIL THEN TerminalIO.PutRope["no texts selected"] ELSE { FOR pl: LIST OF PropRec _ doList, pl.rest WHILE pl#NIL DO CDProperties.PutProp[object, pl.first.key, pl.first.value] ENDLOOP; TerminalIO.PutRope[" --\n"]; }; END; Register: PROC [p: CDSequencer.CommandProc, key: ATOM] = { CDSequencer.ImplementCommand[key: key, proc: p]; }; [] _ CDProperties.RegisterProperty[lorPropKey, $chj0]; CDProperties.InstallProcs[ prop: lorPropKey, procs: CDProperties.PropertyProcsRec[exclusive: TRUE, makeCopy: CDProperties.CopyVal] ]; Register[ExtractTopComm, $ExtractPropTop]; Register[ExtractSelComm, $ExtractPropSel]; Register[RemTopComm, $RemPropTop]; Register[RemSelInstPropsComm, $RemPropSel]; Register[SetPropWithSelectionComm, $SetPropWithSelection]; Register[SetPropToPushedInCell, $SetPropPushed]; Register[SelectFromPropComm, $SelectFromProp]; Register[PropagateSignalNameComm, $PropagateSignalName]; END. CDTextExtractionImpl.mesa Copyright c 1985, 1987 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, November 20, 1985 7:59:40 pm PST Last edited by: Christian Jacobi, February 24, 1987 11:49:40 am PST --puts the property onto the instance or the object --checks whether the instance or object has the same prop property --returns x and y are similar (considered ROPE's) --find out property description from text object -- returns rope with leading and trailing spaces removed -- returns rope with trailing spaces removed -- returns rope with leading spaces removed --ScanPropRec -- returns: property key is accessible for interactive actions --anything is stuff except certain objects used by this module --determine usage of an object as property indicator... --Splits instancelist into different lists (reduces number of instances to be considered!) --SideEffect: removes lorProp properties --gets an appropriate CellSpecific... (or NIL) --ExtractProperties --special properties on instances --normal properties on instances --extract ordinary props --check ordinary props --properties on cell itself --removes all public properties of an instance --removes all public properties -- whether ob is a text object --and tells its result with TerminalIO Κξcode˜šœ™Jšœ Οmœ7™BJšœ=™=J™C—J˜šΟk ˜ Jšœ˜Jšœž˜Jšžœ˜Jšœ ˜ J˜Jšœ ˜ Jšœ ˜ J˜ J˜ Jšœ˜J˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ ˜ —J˜šΟnœžœž˜#Jšžœ‡žœ˜’Jšžœ˜Jšžœ˜—Jšžœ˜J˜Jšœ žœ˜#J˜Jš œ žœžœžœ žœžœžœ˜IJ˜šŸ œžœžœ žœ˜,Jšž˜šœžœžœžœ˜šžœ%žœž˜4Jšœžœžœžœ˜Jšžœžœ˜——Jšœžœ ˜Jšœ)˜)Jšžœ˜—J˜šŸ œžœžœ˜5Jšœ3™3Jšž˜šžœ žœ˜šžœžœ˜JšœD˜D—J˜—JšžœB˜FJšžœ˜—J˜š Ÿ œžœžœžœ žœ˜MJšœB™BJšž˜š Ÿœžœžœžœžœžœ˜2J™1Jšžœžœžœžœ˜šžœžœ žœžœžœ žœžœ˜7Jš žœžœ žœžœ žœ˜CJ˜—Jšœ˜—šœžœžœ˜šœ˜Jšœžœ žœ žœ˜QJšœ˜——Jšžœ˜J˜—šŸ œžœžœ žœ ˜5Jšœ0™0Jšž˜J˜š Ÿ œžœ žœžœžœ˜9Jšœ8™8š Ÿœžœ žœžœžœžœ˜HJšœ,™,Jšœžœ˜Jšžœžœžœ žœ˜1Jšžœ˜$J˜—š Ÿœžœ žœžœžœžœ˜GJšœ+™+Jšžœ)˜/J˜—Jšžœ/˜5J˜—J˜šŸœžœ žœžœžœžœžœ˜LJšœžœ˜ šžœžœ˜Jšœžœ;˜MJšœ-˜-šžœžœ˜Jšžœžœžœ˜&Jšœ&˜&J˜—J˜—šžœ˜Jšœ˜Jšžœžœ˜6J˜—Jšœ˜—J˜š Ÿœžœžœ žœ žœžœ˜9šžœ žœž˜Jšœžœ˜1Jšžœžœ˜—Jšœ˜—J™Jšœ ™ Jšžœ˜Jšžœ˜—J˜š Ÿœžœžœžœžœžœ˜/Jšœ>™>Jšž˜Jš žœžœžœžœžœ˜šžœ˜JšœA˜AJšžœ žœžœ˜)J˜—Jšžœ˜—J˜šœžœ%˜/J™>—J˜šŸœžœžœ žœ˜9JšΟc7™7Jšž˜šžœžœ˜Jšžœ žœžœ˜2J˜—šžœžœ žœž˜%šžœ žœž˜šœ˜Jšœ žœ˜'Jšžœ)žœ˜=š žœžœžœ5žœžœ˜^Jšžœ+žœžœ˜GJšžœžœ-žœžœ˜NJ˜—J˜—Jšžœžœ˜——Jšžœ˜—J˜Jš œ žœžœžœžœžœžœ˜Jšž˜Jšœ#˜#Jšœžœ"˜(šžœžœ˜Jšœžœžœ˜š žœžœžœžœž˜5šžœžœ˜Jšœžœ˜ šžœžœ˜%JšœB˜B—Jšœ˜—Jšžœ˜—Jšžœžœ0˜>J˜—Jšžœ)˜-Jšžœ˜—J˜Jšœ™Jšœ˜Jšœžœ&˜.Jšžœžœžœžœ˜%Jšœ8˜8Jšœ˜šžœ žœ˜Jšœ!™!š žœžœ#žœžœž˜:Jšœ!˜!Jšžœ˜—J˜—šžœ˜Jšœ ™ šžœ ž˜Jšœ™š žœžœ#žœžœž˜:Jšœ"˜"Jšžœ˜——Jšœ™š žœžœ#žœžœž˜:Jšœ˜Jšžœ˜—J˜—Jšœ™šžœ žœžœžœ˜!Jš œžœžœžœžœ˜š žœžœ#žœžœž˜:Jšœžœ˜7Jšœžœ ˜Jšžœ˜—Jšœ1˜1J˜—Jšžœ˜—J˜šŸœžœ˜2Jšž˜Jšœžœ˜Jšœ8˜8Jšœ3˜3šœG˜GJšžœžœ˜!—Jšžœ˜—J˜šŸœžœ˜2Jšž˜JšœžœC˜Kšžœžœžœ˜Jšœžœ˜Jšœ<˜<šœB˜BJšžœžœžœ&žœ˜Q—Jšœ˜—Jšžœ˜—J˜J˜J˜J˜š Ÿœžœžœ žœžœžœ˜AJšž˜Jšžœ&žœžœžœ˜žœ˜D—šžœ˜JšœX˜XJšžœ˜J˜—šžœ žœžœ˜Jšœ8˜8Jšžœ˜J˜—šœ+˜+Jšžœ˜Jš žœžœ žœžœžœ˜EJšœ˜—š žœžœ/žœžœž˜Fšžœžœ˜%Jšœžœ˜Jšœ&žœ˜-Jšœ ˜ Jšœ˜—Jšžœ˜—šžœžœžœ˜+Jšœžœ˜Jšœ#˜#J˜—Jšœ/žœ ˜˜>Jšœ˜J˜—Jšœ(˜(Jšžœžœžœ(˜:šžœ˜š žœžœžœžœžœž˜9Jšœ:˜:Jšžœ˜—Jšœ˜J˜—Jšžœ˜—J˜šŸœžœ#žœ˜:Jšœ0˜0Jšœ˜—J˜Jšœ6˜6šœ˜Jšœ˜Jšœ0žœ!˜UJšœ˜—Jšœ*˜*Jšœ*˜*Jšœ"˜"Jšœ+˜+Jšœ:˜:Jšœ0˜0Jšœ.˜.Jšœ8˜8Jšžœ˜—…—7ΨRΘ