DIRECTORY CD, CDBasics, CDCells, CDCellsInteractions, CDDefaultProcs, CDDirectory, CDEnvironment, CDImports, CDInstances, CDOps, CDSatellites, CDSequencer, CDSequencerExtras, CDViewer, CDViewHighlight, IO, List, Pipal, PipalCD, PipalInt, PipalIO, PipalMos, PipalOps, PipalUI, PW, RefTab, Rope, SymTab, TerminalIO, ViewerClasses, ViewerOps; PipalUIImpl: CEDAR PROGRAM IMPORTS CD, CDBasics, CDCells, CDCellsInteractions, CDDefaultProcs, CDDirectory, CDEnvironment, CDImports, CDInstances, CDOps, CDSatellites, CDSequencerExtras, CDViewer, CDViewHighlight, IO, List, Pipal, PipalCD, PipalInt, PipalIO, PipalMos, PipalOps, PW, RefTab, Rope, SymTab, TerminalIO, ViewerOps EXPORTS PipalUI SHARES CDImports = BEGIN OPEN PipalUI; ROPE: TYPE = Rope.ROPE; stupidCDProps: LIST OF REF _ LIST [$GeneratorProc, $CDxDrawSymbolics, $layerOfPin, $CDSatellitesGroupId, $CDBringoverLibraryName, $CDSatellitesOGroup, $OwnerDesign, $SatellitesCounter, $FileVersion, $CDSatellitesMax, $WireIconsConvertedFrom23, $FiddleKey]; otherProps: LIST OF REF _ LIST [$X, $PinOrder, $InstanceName, $DontFlatten, $Export, $MintDiscardMe]; UnknownProp: SIGNAL [key: ATOM, val: REF] = CODE; DesignRoot: PUBLIC PROC [design: Design] RETURNS [root: Pipal.Object] = { Each: CDDirectory.EachEntryAction = { [] _ SymTab.Store[directory, name, PipalCD.CDToPObject[ob]]; }; top: Pipal.Object _ PipalCD.CDToPObject[CDOps.RealTopCell[design]]; satellites: Pipal.Objects _ NIL; directory: SymTab.Ref _ SymTab.Create[]; FOR props: CD.PropList _ design.properties^, props.rest WHILE props#NIL DO key: REF _ props.first.key; val: REF _ props.first.val; IF ISTYPE [key, ATOM] THEN SELECT TRUE FROM List.Memb[key, stupidCDProps] => {}; List.Memb[key, otherProps] => top _ Pipal.CreateAnnotation[top, NARROW [key], val]; ENDCASE => { SIGNAL UnknownProp[NARROW [key], val]; otherProps_ CONS [key, otherProps]; }; ENDLOOP; FOR list: CD.InstanceList _ CDSatellites.GetSatellites[design], list.rest WHILE list#NIL DO satellites _ CONS [PipalCD.CDToPInstance[list.first], satellites]; ENDLOOP; [] _ CDDirectory.Enumerate[design, Each]; root _ Convert[PipalIO.CreateDirectory[design.name, PipalMos.CreateStar[top, satellites], directory], RefTab.Create[]]; }; highlightClass: CD.ObjectClass _ PW.RegisterClass[ objectType: $PipalHighlight, expand: ExpandHighlight, interestRect: CDDefaultProcs.InterestRect, drawMe: HighlightDrawMe, quickDrawMe: HighlightDrawMe, showMeSelected: CDDefaultProcs.ShowMeSelected ]; ExpandHighlight: CDDirectory.ExpandProc = {ERROR}; HighlightDrawMe: CD.DrawProc = { pr _ NEW [CD.DrawInformation _ pr^]; pr.drawRect _ HighlightDrawRect; pr.drawChild[pr, NARROW [ob.specific], trans]; }; HighlightDrawRect: CD.DrawRectProc = { CDDefaultProcs.DrawRect[pr, r, CD.shadeLayer]; }; CreateHighlight: PROC [cdobj: CD.Object] RETURNS [ob: CD.Object] = { ob _ NEW [CD.ObjectRep _ [ bbox: cdobj.bbox, class: highlightClass, immutable: TRUE, specific: cdobj ]]; }; HighlightDesign: PUBLIC PROC [design: Design, transformation: PipalInt.Transformation _ [], object: Pipal.Object _ NIL, viewer: ViewerClasses.Viewer _ NIL, label: ROPE _ NIL, rescale: BOOL _ TRUE] = { bbox: CD.Rect; cdhighlight: CD.Instance; IF viewer=NIL THEN viewer _ FindViewer[design, label]; IF object=NIL THEN { CDViewHighlight.ShowInstance[v: viewer, instOrList: NIL]; RETURN; }; cdhighlight _ CDInstances.NewInst[ CreateHighlight[PipalCD.PToCDObject[object].cdobj], PipalCD.PToCDTrans[transformation] ]; bbox _ CDInstances.InstRectO[cdhighlight]; CDViewHighlight.ShowInstance[v: viewer, instOrList: cdhighlight]; ViewerOps.OpenIcon[viewer]; IF NOT CDBasics.NonEmpty[bbox] THEN RETURN; IF CDBasics.NonEmpty[bbox] AND rescale THEN CDViewer.ShowAndScale[viewer, bbox]; CDOps.ImmediateRedraw[design, bbox, FALSE]; }; FindViewer: PUBLIC PROC [design: Design, label: ROPE _ NIL] RETURNS [viewer: ViewerClasses.Viewer] = { viewer _ CDViewer.LastViewer[]; IF CDViewer.DesignOf[viewer]#design THEN { viewers: CDViewer.ViewerList _ CDViewer.ViewersOf[design]; IF viewers=NIL THEN { viewer _ CDViewer.CreateViewer[design]; IF label#NIL THEN ViewerOps.SetViewer[viewer: viewer, data: label, op: $Label]; } ELSE viewer _ viewers.first; }; }; EnumerateSelectedObjects: PUBLIC PROC [design: Design, each: EachSelectedProc] RETURNS [quit: BOOL _ FALSE] = { pushPath: PipalOps.Path; ThisInstance: CDCells.InstEnumerator = { path: PipalOps.Path; trans: PipalInt.Transformation; child: Pipal.Object; subPath: PipalOps.Path; found: BOOL; cdtrans: CD.Transformation; IF NOT inst.selected THEN RETURN; IF design.actual.first.mightReplace=NIL THEN cdtrans _ inst.trans ELSE { cdaux: CD.Transformation _ design.actual.first.mightReplace.trans; cdtrans _ [ CDBasics.DeMapPoint[inst.trans.off, cdaux], CDBasics.DecomposeOrient[itemInWorld: inst.trans.orient, cellInWorld: cdaux.orient] ]; }; trans _ PipalCD.CDToPTrans[cdtrans]; child _ PipalCD.CDToPObject[inst.ob]; [subPath, found] _ PipalOps.FindIntPath[ [], pushed, -- We do not deal here with pushed cell path WRONG trans, child ]; IF NOT found THEN ERROR; path _ PipalOps.ConcatPath[pushPath, subPath]; quit _ each[path, trans, child] }; pushed: Pipal.Object _ PipalCD.CDToPObject[CDOps.PushedTopCell[design]]; IF pushed=Pipal.void THEN RETURN; pushPath _ PipalOps.ExtendPath[NIL, ops, 0]; quit _ CDCells.EnumerateInstances[CDOps.PushedTopCell[design], ThisInstance]; }; TheSelectedObject: PUBLIC PROC [design: Design] RETURNS [thePath: PipalOps.Path, theTrans: PipalInt.Transformation, theChild: Pipal.Object _ NIL] = { Each: EachSelectedProc = { IF theChild=NIL THEN {thePath _ path; theTrans _ trans; theChild _ child} ELSE quit _ TRUE; }; IF EnumerateSelectedObjects[design, Each] THEN theChild _ NIL; IF theChild=NIL THEN TerminalIO.PutF["*** Several selected objects: cannot do it.\n"]; }; ReplaceInDesign: PUBLIC PROC [design: Design, path: PipalOps.Path, table: PipalOps.ReplaceTable, replaceMethod: ReplaceMethod] = { root: Pipal.Object _ DesignRoot[design]; SELECT replaceMethod FROM all => PipalOps.TransitiveReplace[root, table]; alongPath => PipalOps.ReplaceInPathWithTable[root, path, table]; ENDCASE => { PipalOps.TransitiveReplace[root, table]; }; }; CommandTarget: TYPE = {any, theSelection, eachSelection}; CommandData: TYPE = REF CommandDataRec; CommandDataRec: TYPE = RECORD [ target: CommandTarget, refProc: REF, replaceMethod: ReplaceMethod _ all, -- only valid for replacements data: REF ]; cdCommandData: RefTab.Ref _ RefTab.Create[]; -- maps keys to registration data CDCommandDispatcher: PROC [comm: CDSequencer.Command] = { design: Design = comm.design; commandData: CommandData _ NARROW [RefTab.Fetch[cdCommandData, comm.key].val]; IF commandData=NIL THEN ERROR; -- command not registered! WITH commandData.refProc SELECT FROM refCommandProc: REF CommandProc => { IF commandData.target#any THEN ERROR; refCommandProc^[ design, [comm.pos.x, comm.pos.y], [comm.sPos.x, comm.sPos.y], commandData.data, comm.ref ]; }; refReplaceCommandProc: REF ReplaceCommandProc => { table: PipalOps.ReplaceTable _ RefTab.Create[]; SELECT commandData.target FROM theSelection => { thePath: PipalOps.Path; theTrans: PipalInt.Transformation; theChild: Pipal.Object _ NIL; [thePath, theTrans, theChild] _ TheSelectedObject[design]; refReplaceCommandProc^[design, theChild, table, commandData.data, comm.ref]; ReplaceInDesign[design, thePath, table, commandData.replaceMethod]; }; eachSelection => { Each: EachSelectedProc = { refReplaceCommandProc^[design, child, table, commandData.data, comm.ref]; ReplaceInDesign[design, path, table, commandData.replaceMethod]; }; [] _ EnumerateSelectedObjects[design, Each]; }; ENDCASE => ERROR; }; ENDCASE => ERROR; }; RegisterCommand: PUBLIC PROC [key: ATOM, proc: CommandProc, queue, markChanged: BOOL _ TRUE, data: REF _ NIL] = { commandData: CommandData _ NEW [CommandDataRec _ [ target: any, refProc: NEW [CommandProc _ proc], data: data ]]; CDSequencerExtras.RegisterCommand[key, CDCommandDispatcher, NIL, IF queue THEN IF markChanged THEN doQueueAndMark ELSE doQueue ELSE IF markChanged THEN ERROR ELSE dontQueue]; [] _ RefTab.Store[cdCommandData, key, commandData]; }; RegisterReplaceSelectionCommand: PUBLIC PROC [key: ATOM, proc: ReplaceCommandProc, allSelected: BOOL, replaceMethod: ReplaceMethod, queue, markChanged: BOOL _ TRUE, data: REF _ NIL] = { commandData: CommandData _ NEW [CommandDataRec _ [ target: IF allSelected THEN eachSelection ELSE theSelection, refProc: NEW [ReplaceCommandProc _ proc], replaceMethod: replaceMethod, data: data ]]; CDSequencerExtras.RegisterCommand[key, CDCommandDispatcher, NIL, IF queue THEN IF markChanged THEN doQueueAndMark ELSE doQueue ELSE IF markChanged THEN ERROR ELSE dontQueue]; [] _ RefTab.Store[cdCommandData, key, commandData]; }; Contains: PUBLIC PROC [object: Pipal.Object, candidateTrans: PipalInt.Transformation, candidateObject: Pipal.Object] RETURNS [BOOL] = { ContainsChild: PipalInt.EachChildProc = { IF transformation=candidateTrans AND child=candidateObject THEN RETURN [TRUE]; IF NOT PipalInt.IsInsideRectangle[PipalInt.BBox[child, transformation], PipalInt.BBox[candidateObject, candidateTrans]] THEN RETURN [FALSE]; quit _ PipalInt.HasEnumerate[child] AND PipalInt.Enumerate[child, ContainsChild, transformation]; }; SubCandidateNotContained: PipalInt.EachChildProc = { quit _ NOT Contains[object, transformation, child]; }; IF ContainsChild[[], object] THEN RETURN [TRUE]; IF NOT PipalInt.HasEnumerate[candidateObject] THEN RETURN [FALSE]; RETURN [NOT PipalInt.Enumerate[candidateObject, SubCandidateNotContained, candidateTrans]]; }; SameInstances: PUBLIC PROC [trans1: PipalInt.Transformation, object1: Pipal.Object, trans2: PipalInt.Transformation, object2: Pipal.Object] RETURNS [BOOL] = { RETURN [Contains[PipalInt.TransformObject[trans1, object1], trans2, object2] AND Contains[PipalInt.TransformObject[trans2, object2], trans1, object1]]; }; GetTopInstances: PUBLIC PROC [design: Design] RETURNS [topInstances: TopInstanceLists _ NIL] = { GetInstances: PROC [design: Design] = { thisTops: Pipal.Objects _ NIL; stack: LIST OF CD.PushRec _ NIL; trail: LIST OF CD.PushRec _ NIL; FOR stack _ design.actual, stack.rest UNTIL stack.rest=NIL DO trail _ stack; ENDLOOP; thisTops _ LIST [PipalCD.CDToPObject[stack.first.dummyCell.ob]]; -- old code used to be slightly different here! (BS) IF trail#NIL THEN thisTops _ CONS [PipalCD.CDToPInstance[trail.first.mightReplace], thisTops]; FOR cl: LIST OF CDImports.Cache _ CDImports.GetCacheList[design].list, cl.rest UNTIL cl=NIL DO IF RefTab.Insert[processedDesigns, cl.first.importee, $Done] THEN GetInstances[cl.first.importee]; ENDLOOP; topInstances _ CONS[[design, thisTops], topInstances]; }; processedDesigns: RefTab.Ref _ RefTab.Create[]; GetInstances[design]; }; schematicLambda: PUBLIC INT _ CD.FetchTechnology[$cmosB].lambda; schematicFudge: PUBLIC INT _ schematicLambda / 2; FetchKeyLine: PUBLIC PROC [fileName, key: ROPE] RETURNS [entry: ROPE _ NIL] = { entry _ CDEnvironment.FetchKeyLine[fileName, key]; }; ExecuteInTerminal: PUBLIC PROC [entry: ROPE] = { [] _ CDEnvironment.StuffToCommandTool[entry]; }; Draw: PUBLIC PROC [object: Pipal.Object] RETURNS [design: Design] = { design _ PW.Draw[PipalCD.PToCDObject[object].cdobj]; }; TranslateCedarExpressionToScheme: PROC [in: ROPE] RETURNS [out: ROPE] = { SELECT TRUE FROM Rope.Match[" CoreOps.CreateWire[]", in] => RETURN ["(createwire)"]; Rope.Match["CoreClasses.CreateTransistor[nE, l, w]", in] => RETURN ["(createtransistor 'ne l w)"]; Rope.Match["CoreClasses.CreateTransistor[pE, l, w]", in] => RETURN ["(createtransistor 'pe l w)"]; Rope.Match["*[*", in] => { TerminalIO.PutF["*** PipalCDImpl.TranslateCedarToScheme: not translated: '%g'.\n", IO.rope[in]]; RETURN [out]; }; ENDCASE => RETURN [out]; }; MatchProc: TYPE = PROC [old: ROPE] RETURNS [BOOL]; MatchTransistor: MatchProc = {RETURN [Rope.Match["*CreateTransistor[[*", old]]}; MatchAmpersand: MatchProc = {RETURN [Rope.Match["*&*_*", old]]}; MatchName: MatchProc = {RETURN [Rope.Match["name _ \"*\"", old]]}; MatchSchCI: MatchProc = {RETURN [Rope.Match["*cI*_*ES[\"*\",*cx]", old]]}; MatchCodeCI: MatchProc = {RETURN [Rope.Match["*cI*_*", old]]}; MatchCodeWI: MatchProc = {RETURN [Rope.Match["*wI*_*", old]]}; MatchWire: MatchProc = {RETURN [Rope.Match["*wire*_*", old]]}; MatchDeclare: MatchProc = {RETURN [Rope.Match[ "*Sisyph.Store[cx,*\"*\",*NEW[*_*]]", old]]}; Convert: PROC [old: Pipal.Object, table: PipalOps.ReplaceTable] RETURNS [new: Pipal.Object] = { new _ RefTab.Fetch[table, old].val; IF new#NIL THEN RETURN; WITH old SELECT FROM icon: PipalMos.SchematicIcon => { IF icon.code THEN new _ PipalMos.CreateSchematicIcon[Convert[icon.child, table], TranslateCedarExpressionToScheme[icon.expression], icon.code, icon.type]; }; annotation: Pipal.Annotation => { SELECT annotation.key FROM ENDCASE => {}; }; ENDCASE => {}; IF new=NIL THEN { PipalOps.TransitiveReplace[old, table]; new _ RefTab.Fetch[table, old].val; }; IF new=NIL THEN new _ old; [] _ RefTab.Store[table, old, new]; }; END. PipalUIImpl.mesa Copyright ำ 1988 by Xerox Corporation. All rights reserved. Louis Monier January 18, 1988 10:05:47 am PST Bertrand Serlet May 16, 1988 0:00:03 am PDT Preamble Design Highlight and Viewer Specific REF contains a CD.Object needing to be drawn highlighted. Selection -- We do not deal here with pushed cell path WRONG SelectInstance: PUBLIC PROC [design: Design, transformation: PipalInt.Transformation, object: Pipal.Object] RETURNS [done: BOOL] = { FOR worldInstances: CD.InstanceList _ design.actual.first.specific.contents, worldInstances.rest UNTIL worldInstances=NIL DO worldInstance: CD.Instance _ worldInstances.first; IF SameInstances[ PipalCD.CDToPTrans[worldInstance.trans], PipalCD.CDToPObject[worldInstance.ob], transformation, object ] THEN {worldInstance.selected _ TRUE; done _ TRUE; EXIT}; REPEAT FINISHED => done _ FALSE; ENDLOOP; }; Push PushInstance: PUBLIC PROC [design: Design, transformation: PipalInt.Transformation, object: Pipal.Object] RETURNS [done: BOOL] = { FOR worldInstances: CD.InstanceList _ design.actual.first.specific.contents, worldInstances.rest UNTIL worldInstances=NIL DO worldInstance: CD.Instance _ worldInstances.first; IF SameInstances[ PipalCD.CDToPTrans[worldInstance.trans], PipalCD.CDToPObject[worldInstance.ob], transformation, object ] THEN {done _ CDCellsInteractions.PushInCellInstance[design, worldInstance]; EXIT}; REPEAT FINISHED => done _ FALSE; ENDLOOP; }; Replacement For now, we suppose the root is just design. Of course, this is bogus! -- Wrong of course! Command Registration Object Comparisons Junk Yard Random Debug Convertion code Change: PROC [master: REF, location: ROPE] RETURNS [needInteraction: ROPE _ NIL] = { news: ROPES; FOR list: ROPES _ NARROW [CDProperties.GetProp[master, Sisyph.expressionsProp]], list.rest WHILE list#NIL DO old: ROPE = list.first; SELECT TRUE FROM MatchName[old] => { new: ROPE = Rope.Substr[old, 8, Rope.Length[old]-9]; TerminalIO.PutF["changed '%g' to '%g'.\n", IO.rope[old], IO.rope[new]]; news _ CONS [new, news]; }; MatchSchCI[old] => { pos1: INT _ Rope.Find[old, "\""]; pos2: INT _ Rope.Find[old, "\"", pos1+1]; sch: ROPE = Rope.Substr[old, pos1+1, pos2-pos1-1]; TerminalIO.PutF["changed '%g' to an $IconFor property '%g'.\n", IO.rope[old], IO.rope[sch]]; CDProperties.PutProp[master, $IconFor, sch]; CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]}; MatchCodeCI[old] => { code: ROPE = Rope.Substr[old, Rope.Find[old, "_"]+1]; TerminalIO.PutF["changed '%g' to an $CodeFor property '%g'.\n", IO.rope[old], IO.rope[code]]; CDProperties.PutProp[master, $IconFor, NIL]; -- because $IconFor was not the truth in CD24! CDProperties.PutProp[master, $CodeFor, code]; CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractCellIcon]}; MatchCodeWI[old] => { code: ROPE = Rope.Substr[old, Rope.Find[old, "_"]+1]; TerminalIO.PutF["changed '%g' to an $CodeFor property '%g'.\n", IO.rope[old], IO.rope[code]]; CDProperties.PutProp[master, $CodeFor, code]; CDProperties.PutProp[master, Sisyph.mode.extractProcProp, $SisyphExtractNamedWireIcon]}; MatchWire[old] OR MatchTransistor[old] => { TerminalIO.PutF["*** Found expression %g '%g' that is not converted automatically.\n", IO.rope[location], IO.rope[old]]; news _ CONS [old, news]}; MatchAmpersand[old] => { TerminalIO.PutF["*** Found expression %g '%g' that uses a variable starting with '&'.\n", IO.rope[location], IO.rope[old]]; news _ CONS [old, news]}; MatchDeclare[old] => { pos1: INT _ Rope.Find[old, "\""]; pos2: INT _ Rope.Find[old, "\"", pos1+1]; pos3: INT _ Rope.Find[old, "_", pos2+1]; pos4: INT _ Rope.Find[old, "]", pos3+1]; new: ROPE _ Rope.Cat[Rope.Substr[old, pos1+1, pos2-pos1-1], " ~ ", Rope.Substr[old, pos3+1, pos4-pos3-1]]; TerminalIO.PutF["changed '%g' to '%g'.\n", IO.rope[old], IO.rope[new]]; news _ CONS [new, news]}; ENDCASE => news _ CONS [old, news]; ENDLOOP; CDProperties.PutProp[master, Sisyph.expressionsProp, news]; IF MatchTransistor[NARROW [CDProperties.GetProp[master, $CodeFor]]] THEN TerminalIO.PutF["*** Found $CodeFor %g '%g' that cannot be converted automatically.\n", IO.rope[location], IO.rope[NARROW [CDProperties.GetProp[master, $CodeFor]]]]; FOR list: ROPES _ CDSatellites.GetSatelliteRopes[master], list.rest WHILE list#NIL DO old: ROPE = list.first; SELECT TRUE FROM MatchName[old] OR MatchSchCI[old] OR MatchCodeCI[old] OR MatchCodeWI[old] OR MatchWire[old] OR MatchDeclare[old] OR MatchTransistor[old] OR MatchAmpersand[old] => { needInteraction _ Rope.Cat["'", old, "' ", needInteraction]}; ENDCASE => {}; ENDLOOP}; Initialization สฝ– "cedar" style˜codešœ™Kšœ<™œœ˜[Kšœ œ1˜BKšœ˜—Kšœ)˜)Jšœw˜wJšœ˜——™šœœœ˜2Kšœ˜Kšœ˜Kšœ*˜*Kšœ˜Kšœ˜Kšœ-˜-Kšœ˜Kšœ œ œ(™BK™—šžœœ˜2K˜—šžœœ ˜ Jšœœœ˜$Jšœ ˜ Kšœœ˜.Kšœ˜K˜—šžœœ˜&Kšœœ ˜.Kšœ˜K˜—š žœœ œ œœ ˜Dšœœœ˜Kšœ4œ˜IKšœ˜—K˜K˜—šžœœœWœ!œ œœ œœ˜ศKšœœ˜Kšœ œ ˜Kšœœœ$˜6šœœœ˜Jšœ4œ˜9Jšœ˜J˜—šœ"˜"Jšœ4˜4Jšœ"˜"Jšœ˜—Kšœ*˜*JšœA˜AKšœ˜Kšœœœœ˜+Kšœœ œ%˜PKšœ$œ˜+K˜K˜—š ž œœœœœœ#˜fKšœ˜šœ"œ˜*Kšœ:˜:šœ œœ˜Kšœ'˜'Kšœœœ>˜OK˜—Kšœ˜K˜—Kšœ˜——™ š žœœœ*œœœ˜oKšœ˜šž œ˜(KšœI˜IKšœœ˜$Kšœ œ˜Kšœœœœ˜!šœ"˜'Kšœœ˜ Kšœœ9˜Bšœ ˜ Kšœ,˜,KšœS˜SKšœ˜—K˜—KšœJ˜Jšœ(˜(Kšœ ฯcะbc/˜?Kšœ ˜ Kšœ˜—Kšœœœœ˜Kšœ.˜.Kšœ ˜ K˜—KšœH˜HJšœœœ˜!Jš 2™2Kšœœ ˜,KšœM˜MK˜K˜—š žœœœœVœ˜•šžœ˜Kš œ œœ6œœ˜[K˜—Kšœ(œ œ˜>Kšœ œœB˜VK˜K™—š žœœœQœœ™„š œœKœœ™|Kšœœ!™2šœ™KšœP™PKšœ™Kš œœœ œœ™:—Kšœœ œ™!Kšœ™—K™—K˜—™š ž œœœQœœ™‚š œœKœœ™|Kšœœ!™2šœ™KšœP™PKšœ™KšœœHœ™T—Kšœœ œ™!Kšœ™—K™——™ šžœœœf˜‚KšœG™GKšœ(˜(šœ˜Kšœ/˜/Kšœ@˜@šœ˜ Kš ™Kšœ(˜(K˜——K˜——™Kšœœ&˜9Kšœ œœ˜'šœœœ˜K˜Kšœ œ˜ KšœB˜BKšœ˜ K˜K˜—Kšœ-Ÿ!˜Nšžœœ ˜9Kšœ˜Kšœœ-˜NKš œ œœœŸ˜9šœœ˜$šœœ˜$Kšœœœ˜%šœ˜Kšœ>˜>Kšœ˜Kšœ˜—K˜—šœœ˜2Kšœ/˜/šœ˜˜KšœTœ˜XKšœ:˜:KšœL˜LKšœC˜CK˜—˜šžœ˜KšœI˜IKšœ@˜@K˜—Kšœ,˜,K˜—Kšœœ˜—K˜—Kšœœ˜—K˜K˜—šžœœœœ)œœœœ˜qšœœ˜2Kšœœ!˜:Kšœ˜—Kšœ<œœœœ œœ œœ œœœ ˜ฎKšœ3˜3K˜K˜—šžœœœœ)œ4œœœœ˜นšœœ˜2Kšœœ œœ˜=Kšœ œF˜RKšœ˜—Kšœ<œœœœ œœ œœ œœœ ˜ฎKšœ3˜3K˜——™š žœœœ`œœ˜‡šž œ˜)Kš œœœœœ˜NKš œœrœœœ˜ŒKšœ$œ:˜aK˜—šžœ˜4Kšœœ)˜3Kšœ˜—Kšœœœœ˜0Kš œœ(œœœ˜BKšœœP˜[K˜K˜—š ž œœœrœœ˜žKšœGœG˜—K˜——™ š žœœœœ#œ˜`šž œœ˜'Kšœœ˜Kš œœœœ œ˜ Kš œœœœ œ˜ šœ#œ œ˜=Kšœ˜Kšœ˜—Kšœ œ2Ÿ  (˜uKšœœœ œ=˜^š œœœ@œœ˜^Kšœ;œ!˜bKšœ˜—Kšœœ#˜6K˜—K˜/Kšœ˜K˜K˜——™Kšœœœœ ˜@šœœœ˜1K˜—šž œœœœœ œœ˜OKšœ2˜2K˜K˜—šžœœœ œ˜0Kšœ-˜-K˜——™šžœœœœ˜EKšœ œ)˜4K˜——™š ž œœœœœ˜Išœœ˜Kšœ+œ˜CKšœ<œ ˜bKšœ<œ ˜bšœ˜KšœSœ ˜`Kšœ˜ Kšœ˜—Kšœœ˜—K˜K˜—Jš œ œœœœœ˜2Jšžœœ,˜QJšžœœ˜@Jšž œœ$˜DJšž œœ+˜LJšž œœ˜@Jšž œœ˜@Jšž œœ ˜Ašž œœ;˜^J˜—šžœœ œ œœœœ™TJšœœ™ š œœœCœœ™lJšœœ™šœœ™šœ™Jšœœ+™4Jšœ+œ œ ™GJšœœ ™J™—šœ™Jšœœ™!Jšœœ ™)Jšœœ)™2Jšœ@œ œ ™\Jšœ,™,JšœS™S—šœ™Jšœœ+™5Jšœ@œ œ ™]Jšœ'œŸ.™[Jšœ-™-JšœS™S—šœ™Jšœœ+™5Jšœ@œ œ ™]Jšœ-™-JšœX™X—šœœ™+JšœWœœ ™xJšœœ™—šœ™JšœZœœ ™{Jšœœ™—šœ™Jšœœ™!Jšœœ ™)Jšœœ™(Jšœœ™(Jšœœa™jJšœ+œ œ ™GJšœœ™—Jšœ œ ™$—Jšœ™—Jšœ;™;Jš œœ+œYœœœ,™๎š œœ5œœ™UJšœœ™šœœ™šœœœœœœœœ™คJšœ=™=—Jšœ ™—Jšœ™ —J™—šžœœ3œ˜_Jšœ#˜#Jšœœœœ˜šœœ˜šœ!˜!Jšœ œ‰˜šJ˜—šœ!˜!šœ˜Jšœ˜—J˜—Jšœ˜—šœœœ˜Jšœ'˜'Jšœ#˜#J˜—Jšœœœ ˜Jšœ#˜#J˜——™K˜—Kšœ˜K˜—…—2ฬV