DIRECTORY CD, CDCells, CDDirectory, CDEvents, CDInstances, CDMenus, CDOps, CDPanelFonts, CDProperties, CDSatellites, CDSequencer, CDTexts, IO, Rope, TerminalIO; CDSatellitesImpl: CEDAR PROGRAM IMPORTS CDCells, CDEvents, CDDirectory, CDInstances, CDMenus, CDOps, CDPanelFonts, CDProperties, CDSequencer, CDTexts, IO, Rope, TerminalIO EXPORTS CDSatellites = BEGIN OPEN CDSatellites; satellitesProp: PUBLIC ATOM _ RegisterProp[$CDSatellitesSatList, TRUE]; maxGroupIdProp: PUBLIC ATOM _ RegisterProp[$CDSatellitesMaxGroupId, TRUE]; groupIdProp: PUBLIC ATOM _ RegisterProp[$CDSatellitesGroupId, TRUE]; commentProp: PUBLIC ATOM _ RegisterProp[$CDSatellitesComment, TRUE]; prevNumMasters: NAT _ 0; GetSatellites: PUBLIC PROC [from: REF, filterComments: BOOL _ TRUE] RETURNS [sats: InstanceList] = { IF from=NIL THEN sats _ NIL ELSE { sats _ NARROW[CDProperties.GetProp[from, satellitesProp]]; IF filterComments THEN sats _ FilterComments[sats]; }; }; GetSatelliteRopes: PUBLIC PROC [from: REF, filterComments: BOOL _ TRUE] RETURNS [ropes: LIST OF ROPE _ NIL] = { FOR list: InstanceList _ GetSatellites[from, filterComments], list.rest WHILE list#NIL DO rope: ROPE _ NARROW [list.first.ob.specificRef, CDTexts.TextPtr].text; IF CDProperties.GetProp[list.first, commentProp]=NIL THEN ropes _ CONS [rope, ropes]; ENDLOOP; }; EnforceInvariants: PUBLIC PROC [design: CD.Design, world: InstanceList] RETURNS [oSats: InstanceList] = { Node: TYPE = REF NodeRec; NodeRec: TYPE = RECORD [ id: INT _ -1, list: InstanceList _ NIL]; Table: TYPE = REF TableRec; TableRec: TYPE = RECORD [ elements: SEQUENCE size: NAT OF LIST OF Node ]; masterTable: Table _ NEW[TableRec[TableSize[]]]; iSats: InstanceList; maxGroupId: INT; TableSize: PROC [] RETURNS [NAT] = INLINE { FOR sizes: LIST OF NAT _ LIST [7, 17, 31, 67, 253], sizes.rest WHILE sizes#NIL DO IF prevNumMasters <= sizes.first THEN RETURN [sizes.first] ENDLOOP; RETURN [253] }; Hash: PROC [i: INT] RETURNS [INT] = { RETURN[i MOD masterTable.size] }; Store: PROC [inst: CD.Instance] = { id: INT _ GroupIdFast[inst]; hash: INT _ Hash[id]; FOR nl: LIST OF Node _ masterTable[hash], nl.rest WHILE nl#NIL DO IF nl.first.id=id THEN {nl.first.list _ CONS[inst, nl.first.list]; RETURN}; ENDLOOP; masterTable[hash] _ CONS[NEW[NodeRec _ [id: id, list: LIST[inst]]], masterTable[hash]]; }; Fetch: PROC [id: INT] RETURNS [InstanceList] = { hash: INT _ Hash[id]; FOR nl: LIST OF Node _ masterTable[hash], nl.rest WHILE nl#NIL DO IF nl.first.id=id THEN RETURN [nl.first.list]; ENDLOOP; RETURN [NIL]; }; IF CDProperties.GetProp[design, maxGroupIdProp]=NIL THEN CDProperties.PutProp[design, maxGroupIdProp, NEW [INT _ 0]]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF CDTexts.IsText[w.first.ob] THEN {IF CDProperties.GetProp[w.first, groupIdProp]#NIL THEN iSats _ CONS [w.first, iSats]} ELSE {IF CDProperties.GetProp[w.first, groupIdProp]#NIL THEN {Store[w.first]; CDProperties.PutProp[w.first, satellitesProp, NIL]}} ENDLOOP; FOR sl: InstanceList _ iSats, sl.rest WHILE sl#NIL DO Closer: PROC [newMaster: CD.Instance] RETURNS [BOOL] = INLINE { mRect, newMRect, sRect: CD.Rect; IF master=NIL THEN RETURN [TRUE]; mRect _ CDInstances.InstRectO[master]; newMRect _ CDInstances.InstRectO[newMaster]; sRect _ CDInstances.InstRectO[sl.first]; RETURN[RectMinDist[newMRect, sRect] < RectMinDist[mRect, sRect]]; }; master: CD.Instance _ NIL; satGId: INT _ GroupIdFast[sl.first]; FOR ml: InstanceList _ Fetch[satGId], ml.rest WHILE ml#NIL DO IF satGId#GroupIdFast[ml.first] THEN LOOP; IF Closer[ml.first] THEN master _ ml.first; ENDLOOP; IF master=NIL THEN CDProperties.PutProp[sl.first, groupIdProp, NIL] ELSE EnsureSatelliteOnList[master, sl.first]; ENDLOOP; maxGroupId _ NARROW [CDProperties.GetProp[design, maxGroupIdProp], REF INT]^; prevNumMasters _ 0; FOR i: INT IN [0..masterTable.size) DO FOR nl: LIST OF Node _ masterTable[i], nl.rest WHILE nl#NIL DO prevNumMasters _ prevNumMasters+1; FOR ml: InstanceList _ nl.first.list.rest, ml.rest WHILE ml#NIL DO maxGroupId _ maxGroupId+1; CDProperties.PutProp[ml.first, groupIdProp, NEW [INT _ maxGroupId]]; FOR sl: InstanceList _ NARROW[CDProperties.GetProp[ml.first, satellitesProp]], sl.rest WHILE sl#NIL DO CDProperties.PutProp[sl.first, groupIdProp, NEW [INT _ maxGroupId]]; ENDLOOP; ENDLOOP; ENDLOOP; ENDLOOP; CDProperties.PutProp[design, maxGroupIdProp, NEW [INT _ maxGroupId]]; oSats _ NIL; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF CDTexts.IsText[w.first.ob] AND CDProperties.GetProp[w.first, groupIdProp]=NIL THEN oSats _ CONS [w.first, oSats] ENDLOOP; }; EnforceDesignInvariants: CDEvents.EventProc = { EnforceForEachCell: CDDirectory.EachEntryAction = { oSats: InstanceList; IF CDCells.IsCell[ob] THEN { oSats _ EnforceInvariants[design, NARROW[ob.specificRef, CD.CellPtr].contents]; CDProperties.PutObjectProp[ob, satellitesProp, oSats] } }; IF design=NIL THEN RETURN; -- sounds like a hack, but design is sometimes NIL!! [] _ CDDirectory.Enumerate[design, EnforceForEachCell]; [] _ EnforceInvariants[design, CDOps.InstList[design]] }; AfterCellReplacement: CDEvents.EventProc = { ob: CD.Object _ NARROW [x]; oSats: InstanceList _ EnforceInvariants[design, NARROW[ob.specificRef, CD.CellPtr].contents]; CDProperties.PutObjectProp[ob, satellitesProp, oSats] }; SelectInstanceGroupCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; multiple: BOOL; selected: CD.Instance; numSats: INT; [] _ EnforceInvariants[comm.design, world]; [selected, multiple] _ CDOps.SelectedInstance[comm.design]; IF ~SingleSelected[selected, multiple] THEN RETURN; IF CDProperties.GetProp[selected, groupIdProp]=NIL THEN { TerminalIO.WriteRope["Selected instance is not in any instance group.\n"]; RETURN }; IF CDTexts.IsText[selected.ob] THEN numSats _ SelectInstanceGroup[comm.design, world, FindMaster[world, selected]] ELSE numSats _ SelectInstanceGroup[comm.design, world, selected]; TerminalIO.WriteF["Instance group selected: %g satellites(s) in group.\n", IO.int[numSats]]; }; AddInstanceSatelliteCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; multiple: BOOL; selected: CD.Instance; name: ROPE; font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[comm.design]; text: CD.Instance; [] _ EnforceInvariants[comm.design, world]; [selected, multiple] _ CDOps.SelectedInstance[comm.design]; IF ~SingleSelected[selected, multiple] THEN RETURN; IF CDTexts.IsText[selected.ob] THEN { TerminalIO.WriteRope["\n** Selected instance is text--can't put a satellite on it.\n"]; RETURN; }; name _ TerminalIO.RequestRope["Type instance satellite: "]; IF name=NIL THEN {TerminalIO.WriteRope["\n** Empty name--can't do it.\n"]; RETURN}; IF font=NIL THEN {TerminalIO.WriteRope["\n** No current font--can't do it.\n"]; RETURN}; text _ NEW [CD.InstanceRep _ [ob: CDTexts.CreateText[name, font], location: comm.pos]]; CDOps.IncludeInstance[comm.design, text]; MakeInstanceSatellite[comm.design, selected, text]; TerminalIO.WriteRope["Instance satellite added\n"]; }; SetInstanceSatellitesCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; satellites: InstanceList _ NIL; master: CD.Instance _ NIL; [] _ EnforceInvariants[comm.design, world]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO inst: CD.Instance _ w.first; IF ~inst.selected THEN LOOP; IF CDTexts.IsText[inst.ob] THEN satellites _ CONS[inst, satellites] ELSE { IF master#NIL THEN {TerminalIO.WriteRope["\n** More than one master selected--can't do it.\n"]; RETURN}; master _ inst} ENDLOOP; IF master=NIL THEN {TerminalIO.WriteRope["\n** No master selected--can't do it.\n"]; RETURN}; IF CDProperties.GetProp[master, satellitesProp]#NIL THEN FOR sl: InstanceList _ NARROW [CDProperties.GetProp[master, satellitesProp]], sl.rest WHILE sl#NIL DO UnmakeInstanceSatellite[world, sl.first]; ENDLOOP; FOR sl: InstanceList _ satellites, sl.rest WHILE sl#NIL DO UnmakeInstanceSatellite[world, sl.first]; MakeInstanceSatellite[comm.design, master, sl.first]; ENDLOOP; TerminalIO.WriteRope["Instance satellites set\n"]; }; SelectObjectGroupCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; numSats: INT; [] _ EnforceInvariants[comm.design, world]; numSats _ SelectObjectGroup[comm.design, world]; TerminalIO.WriteF["Object group selected: %g satellites(s) in group.\n", IO.int[numSats]]; }; AddObjectSatelliteCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; oSats: InstanceList; name: ROPE; font: CDTexts.CDFont _ CDPanelFonts.CurrentFont[comm.design]; text: CD.Instance; oSats _ EnforceInvariants[comm.design, world]; name _ TerminalIO.RequestRope["Type object satellite: "]; IF name=NIL THEN {TerminalIO.WriteRope["\n** Empty name--can't do it.\n"]; RETURN}; IF font=NIL THEN {TerminalIO.WriteRope["\n** No current font--can't do it.\n"]; RETURN}; text _ NEW [CD.InstanceRep _ [ob: CDTexts.CreateText[name, font], location: comm.pos]]; CDOps.IncludeInstance[comm.design, text]; oSats _ CONS[text, oSats]; CDProperties.PutObjectProp[comm.design.actual.first.dummyCell.ob, satellitesProp, oSats]; TerminalIO.WriteRope["Object satellite added\n"]; }; SetObjectSatellitesCommand: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; oSats: InstanceList _ NIL; master: CD.Instance _ NIL; [] _ EnforceInvariants[comm.design, world]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO inst: CD.Instance _ w.first; IF inst.selected AND CDTexts.IsText[inst.ob] THEN { oSats _ CONS[inst, oSats]; UnmakeInstanceSatellite[world, inst]; } ENDLOOP; CDProperties.PutObjectProp[comm.design.actual.first.dummyCell.ob, satellitesProp, oSats]; TerminalIO.WriteRope["Object satellites set\n"]; }; MakeComment: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; done: BOOL _ FALSE; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF CDTexts.IsText[w.first.ob] AND w.first.selected THEN { textPtr: CDTexts.TextPtr _ NARROW [w.first.ob.specificRef]; oldFontName: ROPE _ textPtr.cdFont.supposedName; CDProperties.PutProp[w.first, commentProp, commentProp]; IF oldFontName=NIL THEN ERROR; IF ~IsItalic[oldFontName] THEN ChangeFont[comm.design, w.first, Rope.Cat[oldFontName, "I"], textPtr.cdFont.scaleI]; done _ TRUE; } ENDLOOP; TerminalIO.WriteRope[IF done THEN "Made comment\n" ELSE "No selected text\n"]; }; UnMakeComment: PROC [comm: CDSequencer.Command] = { world: InstanceList _ CDOps.InstList[comm.design]; done: BOOL _ FALSE; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF CDTexts.IsText[w.first.ob] AND w.first.selected THEN { textPtr: CDTexts.TextPtr _ NARROW [w.first.ob.specificRef]; oldFontName: ROPE _ textPtr.cdFont.supposedName; CDProperties.PutProp[w.first, commentProp, NIL]; IF oldFontName=NIL THEN ERROR; IF IsItalic[oldFontName] THEN ChangeFont[comm.design, w.first, Rope.Substr[oldFontName, 0, Rope.Length[oldFontName]-1], textPtr.cdFont.scaleI]; done _ TRUE; } ENDLOOP; TerminalIO.WriteRope[IF done THEN "UnMade comment\n" ELSE "No selected text\n"] }; MakeInstanceSatellite: PROC [design: CD.Design, master: CD.Instance, text: CD.Instance] = { EnsureSatelliteOnList[master, text]; IF CDProperties.GetProp[master, groupIdProp]=NIL THEN { ref: REF INT _ NARROW[CDProperties.GetProp[design, maxGroupIdProp]]; ref^ _ ref^+1; CDProperties.PutProp[master, groupIdProp, NEW [INT _ ref^]]; }; CDProperties.PutProp[text, groupIdProp, NEW[INT _ GroupId[master]]]; }; UnmakeInstanceSatellite: PROC [world: InstanceList, satellite: CD.Instance] = { sats: InstanceList; master: CD.Instance _ FindMaster[world, satellite]; CDProperties.PutProp[satellite, groupIdProp, NIL]; IF master=NIL OR CDProperties.GetProp[master, satellitesProp]=NIL THEN RETURN; sats _ NARROW[CDProperties.GetProp[master, satellitesProp]]; FOR sl: InstanceList _ NARROW[CDProperties.GetProp[master, satellitesProp]], sl.rest WHILE sl#NIL DO IF sl.first#satellite THEN sats _ CONS[sl.first, sats] ENDLOOP; CDProperties.PutProp[master, satellitesProp, sats] }; FilterComments: PROC [sats: InstanceList] RETURNS [result: InstanceList _ NIL] = { FOR l: InstanceList _ sats, l.rest WHILE l#NIL DO IF CDProperties.GetProp[l.first, commentProp]=NIL THEN result _ CONS [l.first, result]; ENDLOOP; }; GroupId: PROC [inst: CD.Instance] RETURNS [INT] = INLINE { IF CDProperties.GetProp[inst, groupIdProp]#NIL THEN RETURN[NARROW[CDProperties.GetProp[inst, groupIdProp], REF INT]^] ELSE RETURN[-1]; }; GroupIdFast: PROC [inst: CD.Instance] RETURNS [INT] = INLINE { RETURN[NARROW[CDProperties.GetProp[inst, groupIdProp], REF INT]^] }; EnsureSatelliteOnList: PROC [master: CD.Instance, satellite: CD.Instance] = { sats: InstanceList; IF CDProperties.GetInstanceProp[master, satellitesProp]=NIL THEN sats _ LIST[satellite] ELSE { sats _ NARROW[CDProperties.GetInstanceProp[master, satellitesProp], InstanceList]; IF ~Member[sats, satellite] THEN sats _ CONS[satellite, sats]; }; CDProperties.PutInstanceProp[master, satellitesProp, sats]; }; Member: PROC [insances: InstanceList, inst: CD.Instance] RETURNS [BOOL _ FALSE] = { WHILE insances#NIL DO IF insances.first=inst THEN RETURN [TRUE]; insances _ insances.rest; ENDLOOP; }; GroupMember: PROC [instances: InstanceList, inst: CD.Instance] RETURNS [BOOL _ FALSE] = { instGId: INT _ GroupId[inst]; WHILE instances#NIL DO IF GroupId[instances.first]=instGId THEN RETURN [TRUE]; instances _ instances.rest; ENDLOOP; }; FindMaster: PROC [world: InstanceList, satellite: CD.Instance] RETURNS [master: CD.Instance _ NIL] = { satGId: INT _ GroupId[satellite]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF satGId=GroupId[w.first] AND ~CDTexts.IsText[w.first.ob] THEN RETURN [w.first]; ENDLOOP; }; SingleSelected: PROC [selected: CD.Instance, multiple: BOOL] RETURNS [BOOL] = { IF selected=NIL THEN { TerminalIO.WriteRope["\n** No current selection--can't do it.\n"]; RETURN[FALSE]; }; IF multiple THEN { TerminalIO.WriteRope["\n** Multiple instances selected--can't do it.\n"]; RETURN[FALSE]; }; RETURN[TRUE]; }; SelectInstanceGroup: PROC [design: CD.Design, world: LIST OF CD.Instance, master: CD.Instance] RETURNS [numSats: INT] = { satellites: InstanceList; numSats _ 0; IF master=NIL THEN RETURN ELSE satellites _ GetSatellites[master, FALSE]; master.selected _ TRUE; CDOps.RedrawInstance[design, master]; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF ~Member[satellites, w.first] THEN LOOP; w.first.selected _ TRUE; numSats _ numSats + 1; CDOps.RedrawInstance[design, w.first]; ENDLOOP; }; SelectObjectGroup: PROC [design: CD.Design, world: LIST OF CD.Instance] RETURNS [numSats: INT] = { numSats _ 0; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO w.first.selected _ FALSE; ENDLOOP; FOR w: InstanceList _ world, w.rest WHILE w#NIL DO IF ~CDTexts.IsText[w.first.ob] OR CDProperties.GetProp[w.first, groupIdProp]#NIL THEN LOOP; w.first.selected _ TRUE; numSats _ numSats + 1; ENDLOOP; }; IntervalMinDist: PROC [i1min, i1max, i2min, i2max: INT] RETURNS [INT] = INLINE { IF i1maxi2max THEN RETURN [i1min-i2max]; RETURN [0]; }; RectMinDist: PROC [rectA, rectB: CD.Rect] RETURNS [INT] = INLINE { xMinDist: INT _ IntervalMinDist[rectA.x1, rectA.x2, rectB.x1, rectB.x2]; yMinDist: INT _ IntervalMinDist[rectA.y1, rectA.y2, rectB.y1, rectB.y2]; IF xMinDist=0 THEN IF yMinDist=0 THEN RETURN [0] ELSE RETURN [yMinDist] ELSE IF yMinDist=0 THEN RETURN [xMinDist] ELSE RETURN [xMinDist+yMinDist] }; RegisterProp: PROC [prop: ATOM, copy: BOOL _ FALSE] RETURNS [sameAtom: ATOM] = { [] _ CDProperties.RegisterProperty[prop, $CDSatellites]; CDProperties.InstallProcs[prop, [makeCopy: IF copy THEN CDProperties.CopyVal ELSE CDProperties.DontCopy]]; sameAtom _ prop; }; ChangeFont: PROC [design: CD.Design, text: CD.Instance, fontName: ROPE, scale: INT] = { font: CDTexts.CDFont _ CDTexts.MakeFont[fontName, scale]; ob: CD.Object _ CDTexts.CreateText[ text: NARROW[text.ob.specificRef, CDTexts.TextPtr].text, font: font, layer: text.ob.layer]; CDOps.DelayedRedraw[design, CDInstances.InstRectO[text]]; IF ob#NIL THEN text.ob _ ob; CDOps.DelayedRedraw[design, CDInstances.InstRectO[text], FALSE]; }; IsItalic: PROC [fontName: ROPE] RETURNS [BOOL] = { RETURN [Rope.Find[fontName, "i", Rope.Length[fontName]-1, FALSE]#-1] }; [] _ CDMenus.CreateMenu["Satellites and Expressions Menu", $SatellitesMenu]; CDMenus.ImplementCommandToCallMenu[$SatellitesMenu, $SatellitesMenu]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Show Instance Satellites (I-Left)", p: SelectInstanceGroupCommand, key: $SelectInstanceGroup, queue: doQueueAndMark]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Add Instance Satellite (I-Middle)", p: AddInstanceSatelliteCommand, key: $AddInstanceSatellite, queue: doQueueAndMark]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Set Instance Satellites (I-Right)", p: SetInstanceSatellitesCommand, key: $SetInstanceSatellites, queue: doQueueAndMark]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Show Object Satellites (O-Left)", p: SelectObjectGroupCommand, key: $SelectObjectGroup, queue: doQueueAndMark]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Add Object Satellite (O-Middle)", p: AddObjectSatelliteCommand, key: $AddObjectSatellite, queue: doQueueAndMark]; CDMenus.ImplementEntryCommand[menu: $SatellitesMenu, entry: "Set Object Satellites (O-Right)", p: SetObjectSatellitesCommand, key: $SetObjectSatellites, queue: doQueueAndMark]; CDSequencer.ImplementCommand[key: $MakeComment, proc: MakeComment]; CDSequencer.ImplementCommand[key: $UnMakeComment, proc: UnMakeComment]; CDEvents.RegisterEventProc[$BeforeOutput, EnforceDesignInvariants]; CDEvents.RegisterEventProc[$AfterInput, EnforceDesignInvariants]; CDEvents.RegisterEventProc[$AfterCellReplacement, AfterCellReplacement]; CDEvents.RegisterEventProc[$InteractiveCreatedCell, AfterCellReplacement]; END. <CDSatellitesImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Written by Pradeep Sindhu December 20, 1985 1:25:44 pm PST This module is descended from the early implementation of satellites by Monier. It has been rewritten a number of times since then by Sindhu and Serlet to find an implementation that is comfortable to use both from programs and interactively. This last version is a complete rewrite, one hopes for the last time! Pradeep Sindhu March 26, 1986 3:21:40 pm PST Bertrand Serlet March 25, 1986 11:12:20 pm PST This property hangs on a master. Its value is the list of the master's satellites. This property hangs on a design. Its value is the highest numbered satellite group in the design. This property hangs on each instance that is in a satellite group. Its value is the group's groupId. This property hangs on text instances that are comments, and therefore to be ignored. Public functions Check that maxGroupIdProp exists; if not, put it Make masterTable and iSats; at the same time strip masters of their satellite lists For each satellite find its closest master and put it on that master's satellite list Now go through the masterTable and renumber groups with identical group Id's Compute oSats and return it Event Procs for reading and writing satellites from files Event Proc for processing a cell change Command Procs Given a satellite or a master select instance group. Adds a single instance satellite to those already existing for a master. Given zero or more text instances and exactly one non-text instance (the master) remove any previous instance satellites and add the ones currently selected. Find the master and put selected text onto the list of satellites Remove master's old satellites, if any Remove each satellite from its previous master, if any, and put it on to the new one Put selected text onto oSats and remove it from iSats Internal Utilities Returns true if inst is in the list insances Returns true if some instance in intances has the same group Id as inst. Select the satellite group for master Initialization ส5– "cedar" style˜codešœ™Kšœ ฯmœ1™<™:J™\J™ZJ™\J™%—K™,K™.—K™šฯk œ˜ Kšžœžœ˜–—K˜•StartOfExpansion[]šะblœžœž˜Kšžœpžœ˜‹Kšžœ˜Kšžœžœ˜K˜šœžœžœ&žœ˜GJšœR™R—šœžœžœ)žœ˜JJšœa™a—šœ žœžœ&žœ˜DJšœd™d—šœ žœžœ&žœ˜DJšœU™U—K˜Kšœžœ˜Ihead™šฯn œžœžœžœžœžœžœ˜dšžœž˜ Kšžœž˜šžœ˜Kšœžœ-˜:Kšžœžœ˜3K˜——Kšœ˜—K˜š œžœžœžœžœžœžœ žœžœžœžœ˜ošžœEžœžœž˜YKšœžœžœ3˜FKšžœ/žœžœ žœ˜UKšžœ˜—Kšœ˜—K˜š  œžœžœ žœžœ˜iKšœžœžœ ˜šœ žœžœ˜Kšœžœ˜ Kšœžœ˜—Kšœžœžœ ˜šœ žœžœ˜Kš œ žœžœžœžœžœ˜,K˜—Kšœžœ˜0K˜Kšœ žœ˜K˜K˜š   œžœžœžœžœ˜+šžœžœžœžœžœ"žœžœž˜QKšžœžœžœ˜:Kšžœ˜—Kšžœ˜ K˜—K˜š  œžœžœžœžœ˜%Kšžœžœ˜K˜—K˜š œžœžœ˜#Kšœžœ˜Kšœžœ ˜š žœžœžœ#žœžœž˜AKšžœžœžœžœ˜KKšžœ˜—Kšœžœžœžœ˜WK˜—K˜š œžœžœžœ˜0Kšœžœ ˜š žœžœžœ#žœžœž˜AKšžœžœžœ˜.Kšžœ˜—Kšžœžœ˜ K˜Kšœ˜—K˜K™0Kš žœ.žœžœ.žœžœ˜uK˜K™Sšžœ!žœžœž˜2šžœ˜Kš žœžœ,žœžœ žœ˜[Kš žœžœ,žœžœ@žœ˜‚—Kšžœ˜—K˜K™Ušžœ#žœžœž˜5š  œžœ žœ žœžœžœ˜?Kšœžœ˜ Kš žœžœžœžœžœ˜!Kšœ&˜&Kšœ,˜,Kšœ(˜(Kšžœ;˜AK˜—Kšœžœ žœ˜Kšœžœ˜$šžœ+žœžœž˜=Kšžœžœžœ˜*Kšžœžœ˜+Kšžœ˜—šžœž˜ Kšžœ-žœ˜5Kšžœ)˜-—Kšžœ˜—K˜KšœHžœ™LKšœ žœ0žœžœ˜MKšœ˜šžœžœžœž˜&š žœžœžœ žœžœž˜>Kšœ"˜"šžœ0žœžœž˜BK˜Kšœ,žœžœ˜Dš žœžœ:žœžœž˜fKšœ,žœžœ˜DKšžœ˜—Kšžœ˜—Kšžœ˜—Kšžœ˜—Kšœ-žœžœ˜EK˜K™Kšœžœ˜ šžœ!žœžœž˜2Kš žœžœ,žœžœ žœ˜sKšžœ˜—Kšœ˜—K˜L™L™9J˜šฯbœ˜/šœ3˜3Jšœ˜šžœžœ˜Jšœ"žœžœ˜OJšœ5˜5J˜—J˜J˜—Jš žœžœžœžœฯc4˜OJšœ7˜7Jšœ6˜6Jšœ˜—L™L™'šœ,˜,Kšœžœ žœ˜Kšœ0žœžœ˜]Kšœ5˜5K˜—L™ K™K™6š œžœ ˜@Kšœ2˜2Kšœ žœ˜Kšœ žœ ˜Kšœ žœ˜ K˜K˜+K˜Kšœ;˜;Kšžœ%žœžœ˜3šžœ-žœžœ˜9KšœJ˜JKšž˜Kšœ˜—K˜šžœ˜KšžœO˜SKšžœ=˜A—KšœKžœ˜\Kšœ˜—K˜K™Hš œžœ ˜AKšœ2˜2Kšœ žœ˜Kšœ žœ ˜Kšœžœ˜ Kšœ=˜=Kšœžœ ˜K˜K˜+K˜Kšœ;˜;Kšžœ%žœžœ˜3šžœžœ˜%K˜WKšžœ˜K˜—K˜Kšœ;˜;Kšžœžœžœ;žœ˜SKšžœžœžœ@žœ˜XKšœžœžœI˜WK˜)Kšœ3˜3K˜3Kšœ˜—K™K™š œžœ ˜BKšœ2˜2Kšœžœ˜Kšœžœ žœ˜K˜K˜+K™K™Ašžœ!žœžœž˜2Kšœžœ˜Kšžœžœžœ˜šžœ˜Kšžœžœ˜(šžœ˜KšžœžœžœNžœ˜hK˜——Kšžœ˜—KšžœžœžœCžœ˜]K™K™&šžœ.žœž˜8š žœžœ9žœžœž˜eK˜)Kšžœ˜——K™K™Tšžœ(žœžœž˜:K˜)K˜5Kšžœ˜—K˜2Kšœ˜—K˜š œžœ ˜>Kšœ2˜2Kšœ žœ˜ K˜K˜+K˜Kšœ0˜0KšœIžœ˜ZKšœ˜—K˜š œžœ ˜?Kšœ2˜2Kšœ˜Kšœžœ˜ Kšœ=˜=Kšœžœ ˜K˜K˜.K˜Kšœ9˜9Kšžœžœžœ;žœ˜SKšžœžœžœ@žœ˜XKšœžœžœI˜WK˜)Kšœžœ˜K˜YK˜1Kšœ˜—K˜š œžœ ˜@Kšœ2˜2Kšœžœ˜Kšœžœ žœ˜K˜K˜+K™K™5šžœ!žœžœž˜2Kšœžœ˜šžœžœžœ˜3Kšœžœ˜Kšœ'˜'K˜—Kšžœ˜—K˜YK˜0Kšœ˜—K˜š  œžœ ˜1Kšœ2˜2Kšœžœžœ˜K˜šžœ!žœžœž˜2šžœžœžœ˜9Kšœžœ˜;Kšœ žœ˜0K˜8Kšžœ žœžœžœ˜KšžœžœU˜sKšœžœ˜ K˜—Kšžœ˜—Kšœžœžœžœ˜NK˜—K˜š  œžœ ˜3Kšœ2˜2Kšœžœžœ˜K˜šžœ!žœžœž˜2šžœžœžœ˜9Kšœžœ˜;Kšœ žœ˜0Kšœ+žœ˜0Kšžœ žœžœžœ˜Kšžœžœr˜Kšœžœ˜ K˜—Kšžœ˜—Kšœžœžœžœ˜OK˜—K˜K˜L™š  œžœ žœžœžœ˜[Kšœ$˜$šžœ+žœžœ˜7Kšœžœžœžœ/˜DK˜Kšœ*žœžœ ˜Kšžœžœ*žœžœ˜AK˜—K˜š œžœ žœžœ˜MKšœ˜šžœ6ž˜;Kšžœžœ ˜šžœ˜KšœžœE˜RKšžœžœžœ˜>K˜——Kšœ;˜;K˜—K˜Kšœ,™,š  œžœ žœ žœžœžœ˜Sšžœ žœžœ˜Kšžœžœžœžœ˜DKšžœ˜—Kšœ˜K˜—K™Hš   œžœ!žœ žœžœžœ˜YKšœ žœ˜šžœ žœžœ˜Kšžœ"žœžœžœ˜SKšžœ˜—Kšœ˜K˜—K˜š   œžœ"žœ žœ žœ žœ˜fKšœžœ˜!šžœ!žœžœž˜2Kšžœžœžœžœ ˜QKšžœ˜—Kšœ˜—K˜š  œžœ žœžœžœžœ˜Ošžœ žœžœ˜KšœB˜BKšžœžœ˜K˜—šžœ žœ˜KšœI˜IKšžœžœ˜K˜—Kšžœžœ˜ Kšœ˜—K™K™%š œžœ žœžœžœžœžœ žœ žœ˜yKšœ˜Kšœ ˜ K˜Kš žœžœžœžœžœ$žœ˜IKšœžœ˜Kšœ%˜%šžœ!žœžœž˜2Kšžœžœžœ˜*Kšœžœ˜/Kšœ&˜&Kšžœ˜—Kšœ˜—K˜š œžœ žœžœžœžœ žœ žœ˜bKšœ ˜ K˜šžœ!žœžœž˜2Kšœžœ˜Kšžœ˜—K˜šžœ!žœžœž˜2Kš žœžœ,žœžœžœ˜[Kšœžœ˜/Kšžœ˜—Kšœ˜—K˜š  œžœžœžœžœžœ˜PKšžœ žœžœ˜)Kšžœ žœžœ˜)Kšžœ˜ K˜—K˜š   œžœžœžœžœžœ˜BKšœ žœ;˜HKšœ žœ;˜HK˜šžœ ˜ Kš žœžœ žœžœžœžœ ˜9Kš žœžœ žœžœ žœžœ˜I—K˜—K˜š  œžœžœžœžœžœ žœ˜PJšœ8˜8Jšœ+žœžœžœ˜jJšœ˜J˜—J˜š   œžœ žœžœžœ žœ˜WJ˜9šœžœ˜#Jšœžœ,˜8Jšœ ˜ Jšœ˜—Jšœ9˜9Jšžœžœžœ˜Jšœ9žœ˜@J˜—J˜š  œžœ žœžœžœ˜2Jšžœ4žœ˜DJ˜—L™Lšœ™KšœL˜LKšœE˜EK˜K˜Kšœฒ˜ฒKšœด˜ดKšœถ˜ถK˜Kšœฌ˜ฌKšœฎ˜ฎKšœฐ˜ฐK˜KšœC˜CKšœG˜GK˜K˜KšœC˜CKšœA˜AKšœH˜HKšœJ˜JK˜Kšžœ˜K˜——…—FPcม