DIRECTORY CD, CDInstances, CDCells, CDCellsInteractions, CDDirectory, CDDirectoryOps, PopUpMenus, CDEvents, CDBasics, CDOps, CDProperties, CDSequencer, IO, Process USING [PauseMsec], RefTab, Rope, TerminalIO; CDCellsInteractionsImpl: CEDAR PROGRAM IMPORTS CD, CDCells, CDInstances, CDDirectory, CDDirectoryOps, CDEvents, CDBasics, PopUpMenus, CDOps, CDProperties, CDSequencer, IO, Process, RefTab, Rope, TerminalIO EXPORTS CDCellsInteractions SHARES CD, CDDirectory = BEGIN EventRegistration: TYPE = CDEvents.EventRegistration; beforeReplace: EventRegistration = CDEvents.RegisterEventType[$BeforeCellReplacement]; afterReplace: EventRegistration = CDEvents.RegisterEventType[$AfterCellReplacement]; pushEvent: EventRegistration = CDEvents.RegisterEventType[$AfterPush]; popEvent: EventRegistration = CDEvents.RegisterEventType[$AfterPop]; createEvent: EventRegistration = CDEvents.RegisterEventType[$InteractiveCreatedCell]; fullPopMenu: PopUpMenus.Menu = PopUpMenus.Create["Pop from cell", "select menu entry to go back outside"]; partialPopMenu: PopUpMenus.Menu = PopUpMenus.Create["Pop from cell", "replace is not possible! it would create recursion"]; emptyPopMenu: PopUpMenus.Menu = PopUpMenus.Create["Pop from cell: empty cell", "cell is empty; you can not create an empty cell"]; expandPopMenu: PopUpMenus.Menu = PopUpMenus.Create["Pop from expanded object"]; expandResultKey: REF = NEW[INT]; Init: PROC [] = { [] _ PopUpMenus.Entry[fullPopMenu, "flush", NIL, $flush, "undo all modifications of cell"]; [] _ PopUpMenus.Entry[partialPopMenu, "flush", NIL, $flush, "undo all modifications of cell"]; [] _ PopUpMenus.Entry[emptyPopMenu, "flush", NIL, $flush, "undo all modifications of cell"]; [] _ PopUpMenus.Entry[fullPopMenu, "new cell", NIL, $new, "create a new cell; original cell is unmodified"]; [] _ PopUpMenus.Entry[partialPopMenu, "new cell", NIL, $new, "create a new cell; original cell is unmodified"]; [] _ PopUpMenus.Entry[fullPopMenu, "replace", NIL, $replace, "make edits permanent in all instances of cell"]; [] _ PopUpMenus.Entry[expandPopMenu, "flush", NIL, $flush, "undo all modifications of cell"]; [] _ PopUpMenus.Entry[expandPopMenu, "new cell this instance", NIL, $new, "create a new cell; original object is unmodified"]; [] _ PopUpMenus.Entry[expandPopMenu, "new cell and replace all instances", NIL, $newAll, "tries to forget original object"]; }; GetNameForCell: PROC [design: CD.Design, cell: CD.Object] RETURNS [abort: BOOL_FALSE] = { name: Rope.ROPE; TerminalIO.PutRope["cell created\n"]; DO name _ TerminalIO.RequestRope["enter name for cell: " ! TerminalIO.UserAbort => GOTO Oops ]; IF Rope.IsEmpty[name] THEN { TerminalIO.PutRope[" new cell is not included in directory\n"]; RETURN; }; IF CDDirectory.Include[design, cell, name, FALSE] THEN { TerminalIO.PutRopes[" cell named ", name, " and included in directory\n"]; RETURN; }; TerminalIO.PutRopes[name, " does already exist\nnot accepted, please repeat\n"]; ENDLOOP; EXITS Oops => abort _ TRUE }; CreateCellSelected: PUBLIC PROC [design: CD.Design, interactiveName: BOOL] RETURNS [done: BOOL _ FALSE, cellInst: CD.Instance _ NIL] = { selected, others: CD.InstanceList; [selected: selected, others: others] _ CDInstances.SplitSelected[CDOps.InstList[design]]; IF selected=NIL THEN { TerminalIO.PutRope["no selection! "]; RETURN [done: FALSE, cellInst: NIL]; }; cellInst _ NEW[CD.InstanceRep_[selected: TRUE, trans: [CDBasics.BaseOfRect[CDInstances.BoundingRectI[selected]], original] ]]; cellInst.ob _ CDCells.CreateCellXTransformed[il: selected, cTrans: cellInst.trans]; IF interactiveName THEN IF GetNameForCell[design: design, cell: cellInst.ob].abort THEN RETURN [FALSE, NIL]; CDOps.SetInstList[design, others]; CDOps.IncludeInstance[design, cellInst, TRUE]; -- redraw removes seletion [] _ CDEvents.ProcessEvent[createEvent, design, cellInst.ob]; RETURN [done: TRUE, cellInst: cellInst] }; PushInCellInstance: PUBLIC PROC [design: CD.Design, inst: CD.Instance, convertIfNecessary: BOOL _ TRUE] RETURNS [done: BOOL _ FALSE] = { IsCellInstance: PROC [inst: CD.Instance] RETURNS [yes: BOOL _ FALSE] = { SELECT TRUE FROM inst=NIL => TerminalIO.PutRope[" no object\n"]; inst.ob=NIL OR inst.ob.specific=NIL => TerminalIO.PutRope[" bad object\n"]; ISTYPE[inst.ob.specific, CD.CellSpecific] => yes _ TRUE; ENDCASE => TerminalIO.PutRopes[" object is not cell but ", CD.Describe[inst.ob, inst.properties, design], "\n"]; }; CheckRecursionForPush: PROC [design: CD.Design, ob: CD.Object] RETURNS [yes: BOOL _ FALSE] = { FOR l: LIST OF CD.PushRec _ design.actual, l.rest WHILE l#NIL DO IF l.first.mightReplace#NIL AND l.first.mightReplace.ob=ob THEN RETURN [yes _ TRUE] ENDLOOP; }; desc: Rope.ROPE; old: CD.Object _ inst.ob; --the original object; or if not a cell: the original conversion WHILE old#NIL AND ~CDCells.IsCell[old] AND convertIfNecessary DO ob2: CD.Object _ CDDirectory.ExpandRecursed[old, design, design]; IF ob2=NIL OR ob2=old THEN {TerminalIO.PutRope["expand failed\n"]; RETURN [FALSE]}; old _ ob2; CDProperties.PutProp[inst, expandResultKey, ob2]; ENDLOOP; IF CDCells.IsCell[old] THEN { dummy: CD.Object = CDCells.CreateEmptyCell[]; oldCp: CD.CellSpecific = NARROW[old.specific]; newCp: CD.CellSpecific = NARROW[dummy.specific]; dummyCellInst: CD.Instance; dummy.bbox _ CDBasics.universe; IF CheckRecursionForPush[design, old] THEN { TerminalIO.PutRopes[" recursive push into ", CD.Describe[old, NIL, design], " not possible\n"]; RETURN [FALSE]; }; newCp^ _ oldCp^; --copies interest rect .... newCp.ir _ CDBasics.MapRect[oldCp.ir, inst.trans]; newCp.contents _ ComposeToList[oldCp.contents, oldCp.sequence, inst.trans]; newCp.sequence _ NIL; newCp.dummyCell _ TRUE; desc _ IF CDDirectory.IsIncluded[design, inst.ob] THEN desc _ CDDirectory.Name[inst.ob, design] ELSE IO.PutFR["{not in directory [%g]}", [rope[CD.Describe[inst.ob, inst.properties, design]]]]; dummyCellInst _ NEW[CD.InstanceRep_[ ob: dummy, trans: [], selected: TRUE, properties: CDProperties.DCopyProps[inst.properties] ]]; CDProperties.CopyProps[inst.ob.properties, dummy]; CDOps.RemoveInstance[design, inst]; design^.actual _ CONS[ CD.PushRec[dummyCell: dummyCellInst, specific: newCp, mightReplace: inst, desc: desc], design^.actual ]; [] _ CDEvents.ProcessEvent[pushEvent, design]; PushForUnDo[design]; RETURN [done _ TRUE]; } }; ComposeToList: PROC [il: CD.InstanceList_NIL, seq: CD.InstanceSequence_NIL, trans: CD.Transformation] RETURNS [cl: CD.InstanceList _ NIL] = { FOR l: CD.InstanceList _ il, l.rest WHILE l#NIL DO cl _ CONS[CDInstances.Composed[l.first, trans], cl]; ENDLOOP; IF seq#NIL THEN FOR n: NAT IN [0..seq.length) DO cl _ CONS[CDInstances.Composed[seq[n], trans], cl]; ENDLOOP; }; PushForUnDo: PROC [design: CD.Design] = { old: CD.PropRef _ design.unDoBuffers; design.unDoBuffers _ CD.InitPropRef[]; CDProperties.PutProp[design.unDoBuffers, $pushed, old]; }; PopForUnDo: PROC [design: CD.Design] = { new: CD.PropRef _ NIL; old: CD.PropRef _ design.unDoBuffers; IF old#NIL THEN WITH CDProperties.GetListProp[old^, $pushed] SELECT FROM used: CD.PropRef => new _ used ENDCASE => NULL; design.unDoBuffers _ (IF new#NIL THEN new ELSE CD.InitPropRef[]); }; PopFromCell: PUBLIC PROC [design: CD.Design, m: CDCellsInteractions.Method_interactive, name: Rope.ROPE_NIL] RETURNS [done: BOOL] = { done _ IPopFromCell[design, m, name]; IF done THEN { [] _ CDEvents.ProcessEvent[popEvent, design]; PopForUnDo[design] } }; IncludeChildrenTransitive: PROC [ob: CD.Object, table: RefTab.Ref_NIL] = { EachChild: CDDirectory.EachObjectProc = { IF me.class.composed THEN { IF RefTab.Insert[table, me, $x] THEN IncludeChildrenTransitive[me, table]; }; }; IF table=NIL THEN table _ RefTab.Create[]; [] _ CDDirectory.EnumerateChildObjects[ob, EachChild, table]; }; IPopFromCell: PROC [design: CD.Design, m: CDCellsInteractions.Method, name: Rope.ROPE] RETURNS [done: BOOL_FALSE] = { currentInst, originalInst: CD.Instance; currentCell, originalCell: CD.Object; recursive: BOOL _ FALSE; CheckRecursion: PROC [] RETURNS [BOOL] = { table: RefTab.Ref _ RefTab.Create[]; IncludeChildrenTransitive[currentCell, table]; RETURN [ RefTab.Fetch[table, originalInst.ob].found ] }; RemoveRemaindsFromExpands: PROC [design: CD.Design, originalInst: CD.Instance] = { IF ~CDCells.IsCell[originalInst.ob] THEN WITH CDProperties.GetProp[originalInst, expandResultKey] SELECT FROM ob: CD.Object => { CDProperties.PutProp[originalInst, expandResultKey, NIL]; [] _ CDDirectoryOps.RemoveIfUnused[design, ob]; }; ENDCASE => NULL; }; DoFlush: PROC [] = { TerminalIO.PutRope["flush\n"]; design^.actual _ design^.actual.rest; CDOps.IncludeInstance[design, originalInst, FALSE]; RemoveRemaindsFromExpands[design, originalInst]; }; DoReplace: PROC [] = { needsRes: BOOL _ FALSE; currentCP: CD.CellSpecific _ NARROW[currentCell.specific]; originalCP: CD.CellSpecific _ NARROW[originalCell.specific]; IF originalCell.immutable THEN { TerminalIO.PutRope["cant change an immutable object\n"]; DoFlush[]; }; [] _ CDEvents.ProcessEvent[beforeReplace, design, originalCell]; TerminalIO.PutRope["replace\n"]; CDProperties.CopyProps[currentCell.properties, originalCell, $Replace]; CDDirectory.SetOwner[design, originalCell, TRUE]; design^.actual _ design^.actual.rest; originalCP.contents _ currentCP.contents; originalCP.sequence _ currentCP.sequence; originalCP.ir _ currentCP.ir; originalCP.specifiedIr _ currentCP.specifiedIr; CDCells.ToSequenceMode[originalCell]; [] _ CDCells.ResizeCell[design, originalCell]; CDOps.IncludeInstance[design, originalInst, FALSE]; [] _ CDEvents.ProcessEvent[afterReplace, design, originalCell]; CDDirectory.PropagateChange[originalCell, design]; CDSequencer.MarkChangedIOOnly[design]; }; DoNewCell: PROC [interactive: BOOL_FALSE, all: BOOL_FALSE] RETURNS [done: BOOL_TRUE] = { IF all THEN TerminalIO.PutRope["new cell and replace all instances\n"] ELSE TerminalIO.PutRope["new cell for this instance\n"]; CDCells.ToSequenceMode[currentCell]; IF interactive THEN { IF GetNameForCell[design, currentCell].abort THEN RETURN [done_FALSE]; }; currentInst.ob _ currentCell; design^.actual _ design^.actual.rest; design^.actual.first.specific.changed _ TRUE; CDOps.IncludeInstance[design, currentInst, FALSE]; [] _ CDEvents.ProcessEvent[createEvent, design, currentCell]; CDDirectory.PropagateChange[currentCell, design]; IF ~CDCells.IsCell[originalCell] AND all THEN { CDDirectory.ReplaceObject[design: design, old: originalCell, new: currentCell] }; IF design.mutability#findOut THEN CDSequencer.MarkChanged[design]; RemoveRemaindsFromExpands[design, originalInst] }; menu: PopUpMenus.Menu _ fullPopMenu; IF design^.actual.rest=NIL THEN { TerminalIO.PutRope["not in cell\n"]; RETURN [FALSE] }; originalInst _ design^.actual.first.mightReplace; originalCell _ originalInst.ob; TerminalIO.PutRopes["Pop from ", CD.Describe[originalCell, originalInst.properties, design], "\n"]; currentCell _ CDCells.CreateCellXTransformed[ il: CDOps.InstList[design], ir: (IF design^.actual.first.specific.specifiedIr THEN design^.actual.first.specific.ir ELSE [0, 0, -1, -1]), cTrans: originalInst.trans]; WITH originalCell.specific SELECT FROM cp: CD.CellSpecific => { curCp: CD.CellSpecific _ NARROW[currentCell.specific]; curCp.simplifyOn _ cp.simplifyOn; curCp.drawBorder _ cp.drawBorder; }; ENDCASE => NULL; currentInst _ NEW[CD.InstanceRep _ [ob: currentCell, trans: originalInst.trans, selected: TRUE, properties: CDProperties.DCopyProps[design^.actual.first.dummyCell.properties]]]; CDProperties.CopyProps[design^.actual.first.dummyCell.ob.properties, currentCell]; IF m=flush OR (m=interactive AND ~design^.actual.first.specific.changed) THEN { DoFlush[]; RETURN [TRUE] }; IF CDBasics.NonEmpty[currentCell.bbox] THEN { IF m=newcell THEN RETURN [DoNewCell[interactive: FALSE]]; IF ~originalCell.immutable THEN recursive _ CheckRecursion[];--else check not necessary IF recursive THEN { TerminalIO.PutRope[" Original cell used inside, replace not possible\n"]; IF m=replace THEN RETURN [DoNewCell[interactive: FALSE, all: FALSE]]; menu _ partialPopMenu; } ELSE IF ~CDCells.IsCell[originalCell] OR originalCell.immutable THEN { IF m=replace THEN RETURN [DoNewCell[interactive: FALSE, all: TRUE]]; menu _ expandPopMenu; } ELSE { --ok, normal case IF m=replace THEN { DoReplace[]; RETURN [TRUE] }; } } ELSE { -- empty TerminalIO.PutRope[" create empty cell not possible\n"]; IF m#interactive THEN {DoFlush[]; RETURN [TRUE]}; menu _ emptyPopMenu; }; Process.PauseMsec[50]; SELECT PopUpMenus.Call[menu] FROM $flush => DoFlush[]; $replace => DoReplace[]; $new => RETURN [DoNewCell[interactive: TRUE, all: FALSE]]; $newAll => RETURN [DoNewCell[interactive: TRUE, all: TRUE]]; ENDCASE => {TerminalIO.PutRope["skipped\n"]; RETURN [FALSE]}; RETURN [TRUE]; }; PopToTopLevel: PUBLIC PROC [design: CD.Design] = { WHILE CDCells.IsPushedIn[design] DO [] _ PopFromCell[design, newcell, "--wasPushedIn--"]; ENDLOOP; }; MakeTopInstance: PUBLIC PROC [design: CD.Design] RETURNS [inst: CD.Instance_NIL] = { done: BOOL; il: CD.InstanceList; PopToTopLevel[design]; il _ CDOps.InstList[design]; IF il=NIL THEN RETURN [NIL]; IF il.rest=NIL THEN RETURN [il.first]; FOR w: CD.InstanceList _ il, w.rest WHILE w#NIL DO w.first.selected _ TRUE ENDLOOP; [done, inst] _ CreateCellSelected[design, FALSE]; [] _ CDDirectory.Include[design, inst.ob, CD.DesignName[design]]; IF inst#NIL AND (~done OR inst.ob=NIL) THEN inst _ NIL; }; Init[]; END. ŽCDCellsInteractionsImpl.mesa (part of ChipNDale) Copyright c 1983, 1986, 1987 by Xerox Corporation. All rights reserved. Created by Christian Jacobi, June 24, 1983 5:00 pm Last Edited by: Christian Jacobi, May 21, 1987 11:39:26 am PDT --verbose if inst is not a cell --Returns "pushing into ob would cause recursion" --pushes undo state --rebuild undo state from before push --(You can't undo pop) --Include children (transitive) of ob into table --doesn't include ob itself --stops including child's children if child is already included --if originalInst wasn't a cell, tries to remove results of original expansion --HACK for CDDirectory-- Κ ˜codešœ2™2Kšœ Οmœ=™HKšœ3™3K™>K˜—šΟk ˜ Kšžœ˜K˜ K˜K˜K˜ K˜Kšœ ˜ K˜ Kšœ ˜ Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœžœ ˜Kšœ˜Kšœ˜Kšœ ˜ —K˜šΟnœžœžœ˜'KšžœŸ˜¦Kšžœ˜Kšžœžœ˜—Kšž˜K˜Kšœžœ˜5K˜K˜VK˜TK˜FK˜D˜UK˜—Kšœj˜jKšœ{˜{Kšœ‚˜‚KšœO˜OK˜Kšœžœžœžœ˜ K˜šŸœžœ˜Kšœ,žœ,˜[Kšœ/žœ,˜^Kšœ-žœ,˜\Kšœ/žœ:˜lKšœ2žœ:˜oKšœ.žœ=˜nKšœ.žœ,˜]Kšœ?žœ<˜~KšœKžœ.˜|Kšœ˜—K˜K˜šŸœžœ žœžœ žœ žœžœ˜YKšœ žœ˜K˜%šžœ˜šœ7˜7Kšœžœ˜#Kšœ˜—šžœžœ˜KšœA˜AKšžœ˜K˜—šžœ)žœžœ˜9KšœM˜MKšžœ˜K˜—KšœP˜PKšžœ˜—Kšžœž˜Kšœ˜—K˜šŸœžœžœ žœžœžœžœžœ žœ žœ˜ˆKšœžœ˜"KšœY˜Yšžœ žœžœ˜Kšœ%˜%Kšžœžœ žœ˜$K˜—šœ žœžœžœ˜/KšœK˜KKšœ˜—KšœS˜Sšžœžœ˜Kš žœ9žœžœžœžœ˜T—Kšœ"˜"Kšœ(žœΟc˜IKšœ=˜=Kšžœžœ˜'Kšœ˜—K˜šŸœž œ žœžœžœžœžœžœžœ˜ˆK˜š Ÿœžœžœ žœžœžœ˜HKšœ™šžœžœž˜Kšœžœ'˜/Kšœžœžœžœ)˜LKšžœžœžœ˜8Kšžœi˜p—Kšœ˜K˜—šŸœžœ žœ žœ žœžœžœ˜^Kš 1™1š žœžœžœžœ!žœžœž˜@Kš žœžœžœžœžœžœ˜SKšžœ˜—Kšœ˜—K˜Kšœ˜Kšœžœ @˜Zš žœžœžœžœž˜@Kšœžœ:˜AKš žœžœžœ žœ)žœžœ˜SKšœ ˜ Kšœ1˜1Kšžœ˜—šžœžœ˜Kšœžœ$˜-Kšœžœžœ˜.Kšœžœžœ˜0Kšœžœ ˜Kšœ˜šžœ$žœ˜,Kšœ-žœžœ˜`Kšžœžœ˜Kšœ˜—Kšœ ˜,Kšœ2˜2KšœK˜KKšœžœ˜Kšœžœ˜šœžœ)˜2Kšžœ)˜-Kšžœžœ(žœ/˜`—šœžœžœ˜$Kšœ ˜ Kšœ ˜ Kšœ žœ˜Kšœ4˜4Kšœ˜—Kšœ2˜2Kšœ$˜$šœžœ˜KšžœU˜WK˜K˜—K˜.Kšœ˜Kšžœ žœ˜K˜—Kšœ˜—K˜šŸ œžœžœžœžœžœ žœžœžœžœ˜š žœžœžœžœž˜2Kšœžœ+˜4Kšžœ˜—šžœžœž˜šžœžœžœž˜ Kšœžœ*˜3Kšžœ˜——Kšœ˜K˜—šŸ œžœ žœ ˜)Kšœ™Kšœžœ˜%Kšœžœ˜&Kšœ7˜7K˜K˜—šŸ œžœ žœ ˜(Kšœ%™%Kšœ™Kšœžœ žœ˜Kšœžœ˜%šžœžœž˜šžœ)žœž˜8Kšœžœ˜Kšžœžœ˜——Kš œžœžœžœžœžœ˜AK˜K˜—šŸ œžœžœ žœ?žœžœžœžœ˜…K˜%šžœžœ˜Kšœ-˜-Kšœ˜Kšœ˜—Kšœ˜—K˜šŸœžœžœžœ˜JKš 0™0Kš ™Kš ?™?šŸ œ ˜)šžœžœ˜Kšžœžœ&˜JK˜—K˜—Kšžœžœžœ˜+Kšœ=˜=K˜—K˜š Ÿ œžœ žœ3žœžœž œ˜uKšœžœ ˜'Kšœžœ˜%Kšœ žœžœ˜K˜šŸœžœžœžœ˜*Kšœ%˜%Kšœ.˜.Kšžœ/˜5Kšœ˜—K˜šŸœžœ žœžœ˜RKšœN™Nšžœ"ž˜(šžœ5žœž˜Dšœžœ ˜Kšœ4žœ˜9Kšœ/˜/K˜—Kšžœžœ˜——Kšœ˜—K˜šŸœžœ˜Kšœ˜K˜%Kšœ,žœ˜3Kšœ0˜0Kšœ˜K˜—šŸ œžœ˜Kšœ žœžœ˜Kšœ žœžœ˜:Kšœ žœžœ˜<šžœžœ˜ Kšœ8˜8Kšœ ˜ Kšœ˜—Kšœ@˜@Kšœ ˜ KšœG˜Gšœ™Kšœ+žœ˜1—K˜%Kšœ)˜)Kšœžœ ˜)Kšœ˜Kšœ/˜/Kšœ%˜%Kšœ.˜.Kšœ,žœ˜3Kšœ?˜?Kšœ2˜2Kšœ&˜&Kšžœ˜—K˜šŸ œžœžœžœžœžœžœžœžœ˜Xšžœ˜Kšžœ;˜?Kšžœ4˜8—Kšœ$˜$šžœ žœ˜Kšžœ+žœžœžœ˜GK˜—Kšœ˜K˜%Kšœ(žœ˜-Kšœ+žœ˜2Kšœ=˜=Kšœ1˜1šžœžœžœ˜/KšœN˜NKšœ˜—Kšžœžœ!˜BKšœ/˜/Kšœ˜—K˜Kšœ$˜$šžœžœžœ˜!Kšœ%˜%Kšžœžœ˜Kšœ˜—Kšœ1˜1Kšœ˜Kšœc˜cšœ-˜-Kšœ˜Kšœžœ+žœ"žœ˜nKšœ˜—šžœžœž˜&šœžœ˜Kšœžœžœ˜6Kšœ!˜!Kšœ!˜!K˜—Kšžœžœ˜—KšœžœžœFžœS˜±KšœR˜Ršžœ žœžœ)žœ˜OKšœ žœžœ˜Kšœ˜—šžœ%žœ˜.Kšžœ žœžœžœ˜9Kšžœžœ ˜Wšžœ žœ˜KšœI˜IKš žœ žœžœžœžœ˜EKšœ˜Kšœ˜—šžœžœžœžœ˜GKš žœ žœžœžœžœ˜DKšœ˜Kšœ˜—šžœ ˜šžœ žœ˜Kšœ ˜ Kšžœžœ˜ Kšœ˜—Kšœ˜—Kšœ˜—šžœ  ˜Kšœ8˜8Kšžœžœ žœžœ˜1Kšœ˜Kšœ˜—Kšœ˜šžœž˜!Kšœ˜Kšœ˜Kšœžœžœžœ˜:Kšœ žœžœžœ˜